Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /*
5 ** secutil.c - various functions used by security stuff
6 **
7 */
9 #include "prtypes.h"
10 #include "prtime.h"
11 #include "prlong.h"
12 #include "prerror.h"
13 #include "prprf.h"
14 #include "plgetopt.h"
15 #include "prenv.h"
16 #include "prnetdb.h"
18 #include "basicutil.h"
19 #include <stdarg.h>
20 #include <sys/stat.h>
21 #include <errno.h>
23 #ifdef XP_UNIX
24 #include <unistd.h>
25 #endif
27 #include "secoid.h"
29 extern long DER_GetInteger(const SECItem *src);
31 static PRBool wrapEnabled = PR_TRUE;
33 void
34 SECU_EnableWrap(PRBool enable)
35 {
36 wrapEnabled = enable;
37 }
39 PRBool
40 SECU_GetWrapEnabled(void)
41 {
42 return wrapEnabled;
43 }
45 void
46 SECU_PrintErrMsg(FILE *out, int level, const char *progName, const char *msg,
47 ...)
48 {
49 va_list args;
50 PRErrorCode err = PORT_GetError();
51 const char * errString = PORT_ErrorToString(err);
53 va_start(args, msg);
55 SECU_Indent(out, level);
56 fprintf(out, "%s: ", progName);
57 vfprintf(out, msg, args);
58 if (errString != NULL && PORT_Strlen(errString) > 0)
59 fprintf(out, ": %s\n", errString);
60 else
61 fprintf(out, ": error %d\n", (int)err);
63 va_end(args);
64 }
66 void
67 SECU_PrintError(const char *progName, const char *msg, ...)
68 {
69 va_list args;
70 PRErrorCode err = PORT_GetError();
71 const char * errName = PR_ErrorToName(err);
72 const char * errString = PR_ErrorToString(err, 0);
74 va_start(args, msg);
76 fprintf(stderr, "%s: ", progName);
77 vfprintf(stderr, msg, args);
79 if (errName != NULL) {
80 fprintf(stderr, ": %s", errName);
81 } else {
82 fprintf(stderr, ": error %d", (int)err);
83 }
85 if (errString != NULL && PORT_Strlen(errString) > 0)
86 fprintf(stderr, ": %s\n", errString);
88 va_end(args);
89 }
91 void
92 SECU_PrintSystemError(const char *progName, const char *msg, ...)
93 {
94 va_list args;
96 va_start(args, msg);
97 fprintf(stderr, "%s: ", progName);
98 vfprintf(stderr, msg, args);
99 fprintf(stderr, ": %s\n", strerror(errno));
100 va_end(args);
101 }
103 SECStatus
104 secu_StdinToItem(SECItem *dst)
105 {
106 unsigned char buf[1000];
107 PRInt32 numBytes;
108 PRBool notDone = PR_TRUE;
110 dst->len = 0;
111 dst->data = NULL;
113 while (notDone) {
114 numBytes = PR_Read(PR_STDIN, buf, sizeof(buf));
116 if (numBytes < 0) {
117 return SECFailure;
118 }
120 if (numBytes == 0)
121 break;
123 if (dst->data) {
124 unsigned char * p = dst->data;
125 dst->data = (unsigned char*)PORT_Realloc(p, dst->len + numBytes);
126 if (!dst->data) {
127 PORT_Free(p);
128 }
129 } else {
130 dst->data = (unsigned char*)PORT_Alloc(numBytes);
131 }
132 if (!dst->data) {
133 return SECFailure;
134 }
135 PORT_Memcpy(dst->data + dst->len, buf, numBytes);
136 dst->len += numBytes;
137 }
139 return SECSuccess;
140 }
142 SECStatus
143 SECU_FileToItem(SECItem *dst, PRFileDesc *src)
144 {
145 PRFileInfo info;
146 PRInt32 numBytes;
147 PRStatus prStatus;
149 if (src == PR_STDIN)
150 return secu_StdinToItem(dst);
152 prStatus = PR_GetOpenFileInfo(src, &info);
154 if (prStatus != PR_SUCCESS) {
155 PORT_SetError(SEC_ERROR_IO);
156 return SECFailure;
157 }
159 /* XXX workaround for 3.1, not all utils zero dst before sending */
160 dst->data = 0;
161 if (!SECITEM_AllocItem(NULL, dst, info.size))
162 goto loser;
164 numBytes = PR_Read(src, dst->data, info.size);
165 if (numBytes != info.size) {
166 PORT_SetError(SEC_ERROR_IO);
167 goto loser;
168 }
170 return SECSuccess;
171 loser:
172 SECITEM_FreeItem(dst, PR_FALSE);
173 dst->data = NULL;
174 return SECFailure;
175 }
177 SECStatus
178 SECU_TextFileToItem(SECItem *dst, PRFileDesc *src)
179 {
180 PRFileInfo info;
181 PRInt32 numBytes;
182 PRStatus prStatus;
183 unsigned char *buf;
185 if (src == PR_STDIN)
186 return secu_StdinToItem(dst);
188 prStatus = PR_GetOpenFileInfo(src, &info);
190 if (prStatus != PR_SUCCESS) {
191 PORT_SetError(SEC_ERROR_IO);
192 return SECFailure;
193 }
195 buf = (unsigned char*)PORT_Alloc(info.size);
196 if (!buf)
197 return SECFailure;
199 numBytes = PR_Read(src, buf, info.size);
200 if (numBytes != info.size) {
201 PORT_SetError(SEC_ERROR_IO);
202 goto loser;
203 }
205 if (buf[numBytes-1] == '\n') numBytes--;
206 #ifdef _WINDOWS
207 if (buf[numBytes-1] == '\r') numBytes--;
208 #endif
210 /* XXX workaround for 3.1, not all utils zero dst before sending */
211 dst->data = 0;
212 if (!SECITEM_AllocItem(NULL, dst, numBytes))
213 goto loser;
215 memcpy(dst->data, buf, numBytes);
217 PORT_Free(buf);
218 return SECSuccess;
219 loser:
220 PORT_Free(buf);
221 return SECFailure;
222 }
224 #define INDENT_MULT 4
225 void
226 SECU_Indent(FILE *out, int level)
227 {
228 int i;
230 for (i = 0; i < level; i++) {
231 fprintf(out, " ");
232 }
233 }
235 void SECU_Newline(FILE *out)
236 {
237 fprintf(out, "\n");
238 }
240 void
241 SECU_PrintAsHex(FILE *out, const SECItem *data, const char *m, int level)
242 {
243 unsigned i;
244 int column;
245 PRBool isString = PR_TRUE;
246 PRBool isWhiteSpace = PR_TRUE;
247 PRBool printedHex = PR_FALSE;
248 unsigned int limit = 15;
250 if ( m ) {
251 SECU_Indent(out, level); fprintf(out, "%s:", m);
252 level++;
253 if (wrapEnabled)
254 fprintf(out, "\n");
255 }
257 if (wrapEnabled) {
258 SECU_Indent(out, level); column = level*INDENT_MULT;
259 }
260 if (!data->len) {
261 fprintf(out, "(empty)\n");
262 return;
263 }
264 /* take a pass to see if it's all printable. */
265 for (i = 0; i < data->len; i++) {
266 unsigned char val = data->data[i];
267 if (!val || !isprint(val)) {
268 isString = PR_FALSE;
269 break;
270 }
271 if (isWhiteSpace && !isspace(val)) {
272 isWhiteSpace = PR_FALSE;
273 }
274 }
276 /* Short values, such as bit strings (which are printed with this
277 ** function) often look like strings, but we want to see the bits.
278 ** so this test assures that short values will be printed in hex,
279 ** perhaps in addition to being printed as strings.
280 ** The threshold size (4 bytes) is arbitrary.
281 */
282 if (!isString || data->len <= 4) {
283 for (i = 0; i < data->len; i++) {
284 if (i != data->len - 1) {
285 fprintf(out, "%02x:", data->data[i]);
286 column += 3;
287 } else {
288 fprintf(out, "%02x", data->data[i]);
289 column += 2;
290 break;
291 }
292 if (wrapEnabled &&
293 (column > 76 || (i % 16 == limit))) {
294 SECU_Newline(out);
295 SECU_Indent(out, level);
296 column = level*INDENT_MULT;
297 limit = i % 16;
298 }
299 }
300 printedHex = PR_TRUE;
301 }
302 if (isString && !isWhiteSpace) {
303 if (printedHex != PR_FALSE) {
304 SECU_Newline(out);
305 SECU_Indent(out, level); column = level*INDENT_MULT;
306 }
307 for (i = 0; i < data->len; i++) {
308 unsigned char val = data->data[i];
310 if (val) {
311 fprintf(out,"%c",val);
312 column++;
313 } else {
314 column = 77;
315 }
316 if (wrapEnabled && column > 76) {
317 SECU_Newline(out);
318 SECU_Indent(out, level); column = level*INDENT_MULT;
319 }
320 }
321 }
323 if (column != level*INDENT_MULT) {
324 SECU_Newline(out);
325 }
326 }
328 const char *hex = "0123456789abcdef";
330 const char printable[257] = {
331 "................" /* 0x */
332 "................" /* 1x */
333 " !\"#$%&'()*+,-./" /* 2x */
334 "0123456789:;<=>?" /* 3x */
335 "@ABCDEFGHIJKLMNO" /* 4x */
336 "PQRSTUVWXYZ[\\]^_" /* 5x */
337 "`abcdefghijklmno" /* 6x */
338 "pqrstuvwxyz{|}~." /* 7x */
339 "................" /* 8x */
340 "................" /* 9x */
341 "................" /* ax */
342 "................" /* bx */
343 "................" /* cx */
344 "................" /* dx */
345 "................" /* ex */
346 "................" /* fx */
347 };
349 void
350 SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len)
351 {
352 const unsigned char *cp = (const unsigned char *)vp;
353 char buf[80];
354 char *bp;
355 char *ap;
357 fprintf(out, "%s [Len: %d]\n", msg, len);
358 memset(buf, ' ', sizeof buf);
359 bp = buf;
360 ap = buf + 50;
361 while (--len >= 0) {
362 unsigned char ch = *cp++;
363 *bp++ = hex[(ch >> 4) & 0xf];
364 *bp++ = hex[ch & 0xf];
365 *bp++ = ' ';
366 *ap++ = printable[ch];
367 if (ap - buf >= 66) {
368 *ap = 0;
369 fprintf(out, " %s\n", buf);
370 memset(buf, ' ', sizeof buf);
371 bp = buf;
372 ap = buf + 50;
373 }
374 }
375 if (bp > buf) {
376 *ap = 0;
377 fprintf(out, " %s\n", buf);
378 }
379 }
382 /* This expents i->data[0] to be the MSB of the integer.
383 ** if you want to print a DER-encoded integer (with the tag and length)
384 ** call SECU_PrintEncodedInteger();
385 */
386 void
387 SECU_PrintInteger(FILE *out, const SECItem *i, const char *m, int level)
388 {
389 int iv;
391 if (!i || !i->len || !i->data) {
392 SECU_Indent(out, level);
393 if (m) {
394 fprintf(out, "%s: (null)\n", m);
395 } else {
396 fprintf(out, "(null)\n");
397 }
398 } else if (i->len > 4) {
399 SECU_PrintAsHex(out, i, m, level);
400 } else {
401 if (i->type == siUnsignedInteger && *i->data & 0x80) {
402 /* Make sure i->data has zero in the highest bite
403 * if i->data is an unsigned integer */
404 SECItem tmpI;
405 char data[] = {0, 0, 0, 0, 0};
407 PORT_Memcpy(data + 1, i->data, i->len);
408 tmpI.len = i->len + 1;
409 tmpI.data = (void*)data;
411 iv = DER_GetInteger(&tmpI);
412 } else {
413 iv = DER_GetInteger(i);
414 }
415 SECU_Indent(out, level);
416 if (m) {
417 fprintf(out, "%s: %d (0x%x)\n", m, iv, iv);
418 } else {
419 fprintf(out, "%d (0x%x)\n", iv, iv);
420 }
421 }
422 }
424 #if defined(DEBUG) || defined(FORCE_PR_ASSERT)
425 /* Returns true iff a[i].flag has a duplicate in a[i+1 : count-1] */
426 static PRBool HasShortDuplicate(int i, secuCommandFlag *a, int count)
427 {
428 char target = a[i].flag;
429 int j;
431 /* duplicate '\0' flags are okay, they are used with long forms */
432 for (j = i+1; j < count; j++) {
433 if (a[j].flag && a[j].flag == target) {
434 return PR_TRUE;
435 }
436 }
437 return PR_FALSE;
438 }
440 /* Returns true iff a[i].longform has a duplicate in a[i+1 : count-1] */
441 static PRBool HasLongDuplicate(int i, secuCommandFlag *a, int count)
442 {
443 int j;
444 char *target = a[i].longform;
446 if (!target)
447 return PR_FALSE;
449 for (j = i+1; j < count; j++) {
450 if (a[j].longform && strcmp(a[j].longform, target) == 0) {
451 return PR_TRUE;
452 }
453 }
454 return PR_FALSE;
455 }
457 /* Returns true iff a has no short or long form duplicates
458 */
459 PRBool HasNoDuplicates(secuCommandFlag *a, int count)
460 {
461 int i;
463 for (i = 0; i < count; i++) {
464 if (a[i].flag && HasShortDuplicate(i, a, count)) {
465 return PR_FALSE;
466 }
467 if (a[i].longform && HasLongDuplicate(i, a, count)) {
468 return PR_FALSE;
469 }
470 }
471 return PR_TRUE;
472 }
473 #endif
475 SECStatus
476 SECU_ParseCommandLine(int argc, char **argv, char *progName,
477 const secuCommand *cmd)
478 {
479 PRBool found;
480 PLOptState *optstate;
481 PLOptStatus status;
482 char *optstring;
483 PLLongOpt *longopts = NULL;
484 int i, j;
485 int lcmd = 0, lopt = 0;
487 PR_ASSERT(HasNoDuplicates(cmd->commands, cmd->numCommands));
488 PR_ASSERT(HasNoDuplicates(cmd->options, cmd->numOptions));
490 optstring = (char *)PORT_Alloc(cmd->numCommands + 2*cmd->numOptions+1);
491 if (optstring == NULL)
492 return SECFailure;
494 j = 0;
495 for (i=0; i<cmd->numCommands; i++) {
496 if (cmd->commands[i].flag) /* single character option ? */
497 optstring[j++] = cmd->commands[i].flag;
498 if (cmd->commands[i].longform)
499 lcmd++;
500 }
501 for (i=0; i<cmd->numOptions; i++) {
502 if (cmd->options[i].flag) {
503 optstring[j++] = cmd->options[i].flag;
504 if (cmd->options[i].needsArg)
505 optstring[j++] = ':';
506 }
507 if (cmd->options[i].longform)
508 lopt++;
509 }
511 optstring[j] = '\0';
513 if (lcmd + lopt > 0) {
514 longopts = PORT_NewArray(PLLongOpt, lcmd+lopt+1);
515 if (!longopts) {
516 PORT_Free(optstring);
517 return SECFailure;
518 }
520 j = 0;
521 for (i=0; j<lcmd && i<cmd->numCommands; i++) {
522 if (cmd->commands[i].longform) {
523 longopts[j].longOptName = cmd->commands[i].longform;
524 longopts[j].longOption = 0;
525 longopts[j++].valueRequired = cmd->commands[i].needsArg;
526 }
527 }
528 lopt += lcmd;
529 for (i=0; j<lopt && i<cmd->numOptions; i++) {
530 if (cmd->options[i].longform) {
531 longopts[j].longOptName = cmd->options[i].longform;
532 longopts[j].longOption = 0;
533 longopts[j++].valueRequired = cmd->options[i].needsArg;
534 }
535 }
536 longopts[j].longOptName = NULL;
537 }
539 optstate = PL_CreateLongOptState(argc, argv, optstring, longopts);
540 if (!optstate) {
541 PORT_Free(optstring);
542 PORT_Free(longopts);
543 return SECFailure;
544 }
545 /* Parse command line arguments */
546 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
547 const char *optstatelong;
548 char option = optstate->option;
550 /* positional parameter, single-char option or long opt? */
551 if (optstate->longOptIndex == -1) {
552 /* not a long opt */
553 if (option == '\0')
554 continue; /* it's a positional parameter */
555 optstatelong = "";
556 } else {
557 /* long opt */
558 if (option == '\0')
559 option = '\377'; /* force unequal with all flags */
560 optstatelong = longopts[optstate->longOptIndex].longOptName;
561 }
563 found = PR_FALSE;
565 for (i=0; i<cmd->numCommands; i++) {
566 if (cmd->commands[i].flag == option ||
567 cmd->commands[i].longform == optstatelong) {
568 cmd->commands[i].activated = PR_TRUE;
569 if (optstate->value) {
570 cmd->commands[i].arg = (char *)optstate->value;
571 }
572 found = PR_TRUE;
573 break;
574 }
575 }
577 if (found)
578 continue;
580 for (i=0; i<cmd->numOptions; i++) {
581 if (cmd->options[i].flag == option ||
582 cmd->options[i].longform == optstatelong) {
583 cmd->options[i].activated = PR_TRUE;
584 if (optstate->value) {
585 cmd->options[i].arg = (char *)optstate->value;
586 } else if (cmd->options[i].needsArg) {
587 status = PL_OPT_BAD;
588 goto loser;
589 }
590 found = PR_TRUE;
591 break;
592 }
593 }
595 if (!found) {
596 status = PL_OPT_BAD;
597 break;
598 }
599 }
601 loser:
602 PL_DestroyOptState(optstate);
603 PORT_Free(optstring);
604 if (longopts)
605 PORT_Free(longopts);
606 if (status == PL_OPT_BAD)
607 return SECFailure;
608 return SECSuccess;
609 }
611 char *
612 SECU_GetOptionArg(const secuCommand *cmd, int optionNum)
613 {
614 if (optionNum < 0 || optionNum >= cmd->numOptions)
615 return NULL;
616 if (cmd->options[optionNum].activated)
617 return PL_strdup(cmd->options[optionNum].arg);
618 else
619 return NULL;
620 }
623 void
624 SECU_PrintPRandOSError(const char *progName)
625 {
626 char buffer[513];
627 PRInt32 errLen = PR_GetErrorTextLength();
628 if (errLen > 0 && errLen < sizeof buffer) {
629 PR_GetErrorText(buffer);
630 }
631 SECU_PrintError(progName, "function failed");
632 if (errLen > 0 && errLen < sizeof buffer) {
633 PR_fprintf(PR_STDERR, "\t%s\n", buffer);
634 }
635 }
637 SECOidTag
638 SECU_StringToSignatureAlgTag(const char *alg)
639 {
640 SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
642 if (alg) {
643 if (!PL_strcmp(alg, "MD2")) {
644 hashAlgTag = SEC_OID_MD2;
645 } else if (!PL_strcmp(alg, "MD4")) {
646 hashAlgTag = SEC_OID_MD4;
647 } else if (!PL_strcmp(alg, "MD5")) {
648 hashAlgTag = SEC_OID_MD5;
649 } else if (!PL_strcmp(alg, "SHA1")) {
650 hashAlgTag = SEC_OID_SHA1;
651 } else if (!PL_strcmp(alg, "SHA224")) {
652 hashAlgTag = SEC_OID_SHA224;
653 } else if (!PL_strcmp(alg, "SHA256")) {
654 hashAlgTag = SEC_OID_SHA256;
655 } else if (!PL_strcmp(alg, "SHA384")) {
656 hashAlgTag = SEC_OID_SHA384;
657 } else if (!PL_strcmp(alg, "SHA512")) {
658 hashAlgTag = SEC_OID_SHA512;
659 }
660 }
661 return hashAlgTag;
662 }
664 /* Caller ensures that dst is at least item->len*2+1 bytes long */
665 void
666 SECU_SECItemToHex(const SECItem * item, char * dst)
667 {
668 if (dst && item && item->data) {
669 unsigned char * src = item->data;
670 unsigned int len = item->len;
671 for (; len > 0; --len, dst += 2) {
672 sprintf(dst, "%02x", *src++);
673 }
674 *dst = '\0';
675 }
676 }
678 static unsigned char nibble(char c) {
679 c = PORT_Tolower(c);
680 return ( c >= '0' && c <= '9') ? c - '0' :
681 ( c >= 'a' && c <= 'f') ? c - 'a' +10 : -1;
682 }
684 SECStatus
685 SECU_SECItemHexStringToBinary(SECItem* srcdest)
686 {
687 int i;
689 if (!srcdest) {
690 PORT_SetError(SEC_ERROR_INVALID_ARGS);
691 return SECFailure;
692 }
693 if (srcdest->len < 4 || (srcdest->len % 2) ) {
694 /* too short to convert, or even number of characters */
695 PORT_SetError(SEC_ERROR_BAD_DATA);
696 return SECFailure;
697 }
698 if (PORT_Strncasecmp((const char*)srcdest->data, "0x", 2)) {
699 /* wrong prefix */
700 PORT_SetError(SEC_ERROR_BAD_DATA);
701 return SECFailure;
702 }
704 /* 1st pass to check for hex characters */
705 for (i=2; i<srcdest->len; i++) {
706 char c = PORT_Tolower(srcdest->data[i]);
707 if (! ( ( c >= '0' && c <= '9') ||
708 ( c >= 'a' && c <= 'f')
709 ) ) {
710 PORT_SetError(SEC_ERROR_BAD_DATA);
711 return SECFailure;
712 }
713 }
715 /* 2nd pass to convert */
716 for (i=2; i<srcdest->len; i+=2) {
717 srcdest->data[(i-2)/2] = (nibble(srcdest->data[i]) << 4) +
718 nibble(srcdest->data[i+1]);
719 }
721 /* adjust length */
722 srcdest->len -= 2;
723 srcdest->len /= 2;
724 return SECSuccess;
725 }