|
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 */ |
|
8 |
|
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" |
|
17 |
|
18 #include "basicutil.h" |
|
19 #include <stdarg.h> |
|
20 #include <sys/stat.h> |
|
21 #include <errno.h> |
|
22 |
|
23 #ifdef XP_UNIX |
|
24 #include <unistd.h> |
|
25 #endif |
|
26 |
|
27 #include "secoid.h" |
|
28 |
|
29 extern long DER_GetInteger(const SECItem *src); |
|
30 |
|
31 static PRBool wrapEnabled = PR_TRUE; |
|
32 |
|
33 void |
|
34 SECU_EnableWrap(PRBool enable) |
|
35 { |
|
36 wrapEnabled = enable; |
|
37 } |
|
38 |
|
39 PRBool |
|
40 SECU_GetWrapEnabled(void) |
|
41 { |
|
42 return wrapEnabled; |
|
43 } |
|
44 |
|
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); |
|
52 |
|
53 va_start(args, msg); |
|
54 |
|
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); |
|
62 |
|
63 va_end(args); |
|
64 } |
|
65 |
|
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); |
|
73 |
|
74 va_start(args, msg); |
|
75 |
|
76 fprintf(stderr, "%s: ", progName); |
|
77 vfprintf(stderr, msg, args); |
|
78 |
|
79 if (errName != NULL) { |
|
80 fprintf(stderr, ": %s", errName); |
|
81 } else { |
|
82 fprintf(stderr, ": error %d", (int)err); |
|
83 } |
|
84 |
|
85 if (errString != NULL && PORT_Strlen(errString) > 0) |
|
86 fprintf(stderr, ": %s\n", errString); |
|
87 |
|
88 va_end(args); |
|
89 } |
|
90 |
|
91 void |
|
92 SECU_PrintSystemError(const char *progName, const char *msg, ...) |
|
93 { |
|
94 va_list args; |
|
95 |
|
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 } |
|
102 |
|
103 SECStatus |
|
104 secu_StdinToItem(SECItem *dst) |
|
105 { |
|
106 unsigned char buf[1000]; |
|
107 PRInt32 numBytes; |
|
108 PRBool notDone = PR_TRUE; |
|
109 |
|
110 dst->len = 0; |
|
111 dst->data = NULL; |
|
112 |
|
113 while (notDone) { |
|
114 numBytes = PR_Read(PR_STDIN, buf, sizeof(buf)); |
|
115 |
|
116 if (numBytes < 0) { |
|
117 return SECFailure; |
|
118 } |
|
119 |
|
120 if (numBytes == 0) |
|
121 break; |
|
122 |
|
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 } |
|
138 |
|
139 return SECSuccess; |
|
140 } |
|
141 |
|
142 SECStatus |
|
143 SECU_FileToItem(SECItem *dst, PRFileDesc *src) |
|
144 { |
|
145 PRFileInfo info; |
|
146 PRInt32 numBytes; |
|
147 PRStatus prStatus; |
|
148 |
|
149 if (src == PR_STDIN) |
|
150 return secu_StdinToItem(dst); |
|
151 |
|
152 prStatus = PR_GetOpenFileInfo(src, &info); |
|
153 |
|
154 if (prStatus != PR_SUCCESS) { |
|
155 PORT_SetError(SEC_ERROR_IO); |
|
156 return SECFailure; |
|
157 } |
|
158 |
|
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; |
|
163 |
|
164 numBytes = PR_Read(src, dst->data, info.size); |
|
165 if (numBytes != info.size) { |
|
166 PORT_SetError(SEC_ERROR_IO); |
|
167 goto loser; |
|
168 } |
|
169 |
|
170 return SECSuccess; |
|
171 loser: |
|
172 SECITEM_FreeItem(dst, PR_FALSE); |
|
173 dst->data = NULL; |
|
174 return SECFailure; |
|
175 } |
|
176 |
|
177 SECStatus |
|
178 SECU_TextFileToItem(SECItem *dst, PRFileDesc *src) |
|
179 { |
|
180 PRFileInfo info; |
|
181 PRInt32 numBytes; |
|
182 PRStatus prStatus; |
|
183 unsigned char *buf; |
|
184 |
|
185 if (src == PR_STDIN) |
|
186 return secu_StdinToItem(dst); |
|
187 |
|
188 prStatus = PR_GetOpenFileInfo(src, &info); |
|
189 |
|
190 if (prStatus != PR_SUCCESS) { |
|
191 PORT_SetError(SEC_ERROR_IO); |
|
192 return SECFailure; |
|
193 } |
|
194 |
|
195 buf = (unsigned char*)PORT_Alloc(info.size); |
|
196 if (!buf) |
|
197 return SECFailure; |
|
198 |
|
199 numBytes = PR_Read(src, buf, info.size); |
|
200 if (numBytes != info.size) { |
|
201 PORT_SetError(SEC_ERROR_IO); |
|
202 goto loser; |
|
203 } |
|
204 |
|
205 if (buf[numBytes-1] == '\n') numBytes--; |
|
206 #ifdef _WINDOWS |
|
207 if (buf[numBytes-1] == '\r') numBytes--; |
|
208 #endif |
|
209 |
|
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; |
|
214 |
|
215 memcpy(dst->data, buf, numBytes); |
|
216 |
|
217 PORT_Free(buf); |
|
218 return SECSuccess; |
|
219 loser: |
|
220 PORT_Free(buf); |
|
221 return SECFailure; |
|
222 } |
|
223 |
|
224 #define INDENT_MULT 4 |
|
225 void |
|
226 SECU_Indent(FILE *out, int level) |
|
227 { |
|
228 int i; |
|
229 |
|
230 for (i = 0; i < level; i++) { |
|
231 fprintf(out, " "); |
|
232 } |
|
233 } |
|
234 |
|
235 void SECU_Newline(FILE *out) |
|
236 { |
|
237 fprintf(out, "\n"); |
|
238 } |
|
239 |
|
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; |
|
249 |
|
250 if ( m ) { |
|
251 SECU_Indent(out, level); fprintf(out, "%s:", m); |
|
252 level++; |
|
253 if (wrapEnabled) |
|
254 fprintf(out, "\n"); |
|
255 } |
|
256 |
|
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 } |
|
275 |
|
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]; |
|
309 |
|
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 } |
|
322 |
|
323 if (column != level*INDENT_MULT) { |
|
324 SECU_Newline(out); |
|
325 } |
|
326 } |
|
327 |
|
328 const char *hex = "0123456789abcdef"; |
|
329 |
|
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 }; |
|
348 |
|
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; |
|
356 |
|
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 } |
|
380 |
|
381 |
|
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; |
|
390 |
|
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}; |
|
406 |
|
407 PORT_Memcpy(data + 1, i->data, i->len); |
|
408 tmpI.len = i->len + 1; |
|
409 tmpI.data = (void*)data; |
|
410 |
|
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 } |
|
423 |
|
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; |
|
430 |
|
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 } |
|
439 |
|
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; |
|
445 |
|
446 if (!target) |
|
447 return PR_FALSE; |
|
448 |
|
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 } |
|
456 |
|
457 /* Returns true iff a has no short or long form duplicates |
|
458 */ |
|
459 PRBool HasNoDuplicates(secuCommandFlag *a, int count) |
|
460 { |
|
461 int i; |
|
462 |
|
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 |
|
474 |
|
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; |
|
486 |
|
487 PR_ASSERT(HasNoDuplicates(cmd->commands, cmd->numCommands)); |
|
488 PR_ASSERT(HasNoDuplicates(cmd->options, cmd->numOptions)); |
|
489 |
|
490 optstring = (char *)PORT_Alloc(cmd->numCommands + 2*cmd->numOptions+1); |
|
491 if (optstring == NULL) |
|
492 return SECFailure; |
|
493 |
|
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 } |
|
510 |
|
511 optstring[j] = '\0'; |
|
512 |
|
513 if (lcmd + lopt > 0) { |
|
514 longopts = PORT_NewArray(PLLongOpt, lcmd+lopt+1); |
|
515 if (!longopts) { |
|
516 PORT_Free(optstring); |
|
517 return SECFailure; |
|
518 } |
|
519 |
|
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 } |
|
538 |
|
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; |
|
549 |
|
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 } |
|
562 |
|
563 found = PR_FALSE; |
|
564 |
|
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 } |
|
576 |
|
577 if (found) |
|
578 continue; |
|
579 |
|
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 } |
|
594 |
|
595 if (!found) { |
|
596 status = PL_OPT_BAD; |
|
597 break; |
|
598 } |
|
599 } |
|
600 |
|
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 } |
|
610 |
|
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 } |
|
621 |
|
622 |
|
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 } |
|
636 |
|
637 SECOidTag |
|
638 SECU_StringToSignatureAlgTag(const char *alg) |
|
639 { |
|
640 SECOidTag hashAlgTag = SEC_OID_UNKNOWN; |
|
641 |
|
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 } |
|
663 |
|
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 } |
|
677 |
|
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 } |
|
683 |
|
684 SECStatus |
|
685 SECU_SECItemHexStringToBinary(SECItem* srcdest) |
|
686 { |
|
687 int i; |
|
688 |
|
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 } |
|
703 |
|
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 } |
|
714 |
|
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 } |
|
720 |
|
721 /* adjust length */ |
|
722 srcdest->len -= 2; |
|
723 srcdest->len /= 2; |
|
724 return SECSuccess; |
|
725 } |