|
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 "cryptohi.h" |
|
19 #include "secutil.h" |
|
20 #include "secpkcs7.h" |
|
21 #include "secpkcs5.h" |
|
22 #include <stdarg.h> |
|
23 #include <sys/stat.h> |
|
24 #include <errno.h> |
|
25 |
|
26 #ifdef XP_UNIX |
|
27 #include <unistd.h> |
|
28 #endif |
|
29 |
|
30 /* for SEC_TraverseNames */ |
|
31 #include "cert.h" |
|
32 #include "certt.h" |
|
33 #include "certdb.h" |
|
34 |
|
35 /* #include "secmod.h" */ |
|
36 #include "pk11func.h" |
|
37 #include "secoid.h" |
|
38 |
|
39 static char consoleName[] = { |
|
40 #ifdef XP_UNIX |
|
41 "/dev/tty" |
|
42 #else |
|
43 #ifdef XP_OS2 |
|
44 "\\DEV\\CON" |
|
45 #else |
|
46 "CON:" |
|
47 #endif |
|
48 #endif |
|
49 }; |
|
50 |
|
51 #include "nssutil.h" |
|
52 #include "ssl.h" |
|
53 #include "sslproto.h" |
|
54 |
|
55 static PRBool utf8DisplayEnabled = PR_FALSE; |
|
56 |
|
57 void |
|
58 SECU_EnableUtf8Display(PRBool enable) |
|
59 { |
|
60 utf8DisplayEnabled = enable; |
|
61 } |
|
62 |
|
63 PRBool |
|
64 SECU_GetUtf8DisplayEnabled(void) |
|
65 { |
|
66 return utf8DisplayEnabled; |
|
67 } |
|
68 |
|
69 static void |
|
70 secu_ClearPassword(char *p) |
|
71 { |
|
72 if (p) { |
|
73 PORT_Memset(p, 0, PORT_Strlen(p)); |
|
74 PORT_Free(p); |
|
75 } |
|
76 } |
|
77 |
|
78 char * |
|
79 SECU_GetPasswordString(void *arg, char *prompt) |
|
80 { |
|
81 #ifndef _WINDOWS |
|
82 char *p = NULL; |
|
83 FILE *input, *output; |
|
84 |
|
85 /* open terminal */ |
|
86 input = fopen(consoleName, "r"); |
|
87 if (input == NULL) { |
|
88 fprintf(stderr, "Error opening input terminal for read\n"); |
|
89 return NULL; |
|
90 } |
|
91 |
|
92 output = fopen(consoleName, "w"); |
|
93 if (output == NULL) { |
|
94 fprintf(stderr, "Error opening output terminal for write\n"); |
|
95 return NULL; |
|
96 } |
|
97 |
|
98 p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword); |
|
99 |
|
100 |
|
101 fclose(input); |
|
102 fclose(output); |
|
103 |
|
104 return p; |
|
105 |
|
106 #else |
|
107 /* Win32 version of above. opening the console may fail |
|
108 on windows95, and certainly isn't necessary.. */ |
|
109 |
|
110 char *p = NULL; |
|
111 |
|
112 p = SEC_GetPassword (stdin, stdout, prompt, SEC_BlindCheckPassword); |
|
113 return p; |
|
114 |
|
115 #endif |
|
116 } |
|
117 |
|
118 |
|
119 /* |
|
120 * p a s s w o r d _ h a r d c o d e |
|
121 * |
|
122 * A function to use the password passed in the -f(pwfile) argument |
|
123 * of the command line. |
|
124 * After use once, null it out otherwise PKCS11 calls us forever.? |
|
125 * |
|
126 */ |
|
127 char * |
|
128 SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg) |
|
129 { |
|
130 char* phrases, *phrase; |
|
131 PRFileDesc *fd; |
|
132 PRInt32 nb; |
|
133 char *pwFile = arg; |
|
134 int i; |
|
135 const long maxPwdFileSize = 4096; |
|
136 char* tokenName = NULL; |
|
137 int tokenLen = 0; |
|
138 |
|
139 if (!pwFile) |
|
140 return 0; |
|
141 |
|
142 if (retry) { |
|
143 return 0; /* no good retrying - the files contents will be the same */ |
|
144 } |
|
145 |
|
146 phrases = PORT_ZAlloc(maxPwdFileSize); |
|
147 |
|
148 if (!phrases) { |
|
149 return 0; /* out of memory */ |
|
150 } |
|
151 |
|
152 fd = PR_Open(pwFile, PR_RDONLY, 0); |
|
153 if (!fd) { |
|
154 fprintf(stderr, "No password file \"%s\" exists.\n", pwFile); |
|
155 PORT_Free(phrases); |
|
156 return NULL; |
|
157 } |
|
158 |
|
159 nb = PR_Read(fd, phrases, maxPwdFileSize); |
|
160 |
|
161 PR_Close(fd); |
|
162 |
|
163 if (nb == 0) { |
|
164 fprintf(stderr,"password file contains no data\n"); |
|
165 PORT_Free(phrases); |
|
166 return NULL; |
|
167 } |
|
168 |
|
169 if (slot) { |
|
170 tokenName = PK11_GetTokenName(slot); |
|
171 if (tokenName) { |
|
172 tokenLen = PORT_Strlen(tokenName); |
|
173 } |
|
174 } |
|
175 i = 0; |
|
176 do |
|
177 { |
|
178 int startphrase = i; |
|
179 int phraseLen; |
|
180 |
|
181 /* handle the Windows EOL case */ |
|
182 while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++; |
|
183 /* terminate passphrase */ |
|
184 phrases[i++] = '\0'; |
|
185 /* clean up any EOL before the start of the next passphrase */ |
|
186 while ( (i<nb) && (phrases[i] == '\r' || phrases[i] == '\n')) { |
|
187 phrases[i++] = '\0'; |
|
188 } |
|
189 /* now analyze the current passphrase */ |
|
190 phrase = &phrases[startphrase]; |
|
191 if (!tokenName) |
|
192 break; |
|
193 if (PORT_Strncmp(phrase, tokenName, tokenLen)) continue; |
|
194 phraseLen = PORT_Strlen(phrase); |
|
195 if (phraseLen < (tokenLen+1)) continue; |
|
196 if (phrase[tokenLen] != ':') continue; |
|
197 phrase = &phrase[tokenLen+1]; |
|
198 break; |
|
199 |
|
200 } while (i<nb); |
|
201 |
|
202 phrase = PORT_Strdup((char*)phrase); |
|
203 PORT_Free(phrases); |
|
204 return phrase; |
|
205 } |
|
206 |
|
207 char * |
|
208 SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg) |
|
209 { |
|
210 char prompt[255]; |
|
211 secuPWData *pwdata = (secuPWData *)arg; |
|
212 secuPWData pwnull = { PW_NONE, 0 }; |
|
213 secuPWData pwxtrn = { PW_EXTERNAL, "external" }; |
|
214 char *pw; |
|
215 |
|
216 if (pwdata == NULL) |
|
217 pwdata = &pwnull; |
|
218 |
|
219 if (PK11_ProtectedAuthenticationPath(slot)) { |
|
220 pwdata = &pwxtrn; |
|
221 } |
|
222 if (retry && pwdata->source != PW_NONE) { |
|
223 PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n"); |
|
224 return NULL; |
|
225 } |
|
226 |
|
227 switch (pwdata->source) { |
|
228 case PW_NONE: |
|
229 sprintf(prompt, "Enter Password or Pin for \"%s\":", |
|
230 PK11_GetTokenName(slot)); |
|
231 return SECU_GetPasswordString(NULL, prompt); |
|
232 case PW_FROMFILE: |
|
233 /* Instead of opening and closing the file every time, get the pw |
|
234 * once, then keep it in memory (duh). |
|
235 */ |
|
236 pw = SECU_FilePasswd(slot, retry, pwdata->data); |
|
237 pwdata->source = PW_PLAINTEXT; |
|
238 pwdata->data = PL_strdup(pw); |
|
239 /* it's already been dup'ed */ |
|
240 return pw; |
|
241 case PW_EXTERNAL: |
|
242 sprintf(prompt, |
|
243 "Press Enter, then enter PIN for \"%s\" on external device.\n", |
|
244 PK11_GetTokenName(slot)); |
|
245 (void) SECU_GetPasswordString(NULL, prompt); |
|
246 /* Fall Through */ |
|
247 case PW_PLAINTEXT: |
|
248 return PL_strdup(pwdata->data); |
|
249 default: |
|
250 break; |
|
251 } |
|
252 |
|
253 PR_fprintf(PR_STDERR, "Password check failed: No password found.\n"); |
|
254 return NULL; |
|
255 } |
|
256 |
|
257 char * |
|
258 secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg) |
|
259 { |
|
260 char *p0 = NULL; |
|
261 char *p1 = NULL; |
|
262 FILE *input, *output; |
|
263 secuPWData *pwdata = arg; |
|
264 |
|
265 if (pwdata->source == PW_FROMFILE) { |
|
266 return SECU_FilePasswd(slot, retry, pwdata->data); |
|
267 } |
|
268 if (pwdata->source == PW_PLAINTEXT) { |
|
269 return PL_strdup(pwdata->data); |
|
270 } |
|
271 |
|
272 /* PW_NONE - get it from tty */ |
|
273 /* open terminal */ |
|
274 #ifdef _WINDOWS |
|
275 input = stdin; |
|
276 #else |
|
277 input = fopen(consoleName, "r"); |
|
278 #endif |
|
279 if (input == NULL) { |
|
280 PR_fprintf(PR_STDERR, "Error opening input terminal for read\n"); |
|
281 return NULL; |
|
282 } |
|
283 |
|
284 /* we have no password, so initialize database with one */ |
|
285 PR_fprintf(PR_STDERR, |
|
286 "Enter a password which will be used to encrypt your keys.\n" |
|
287 "The password should be at least 8 characters long,\n" |
|
288 "and should contain at least one non-alphabetic character.\n\n"); |
|
289 |
|
290 output = fopen(consoleName, "w"); |
|
291 if (output == NULL) { |
|
292 PR_fprintf(PR_STDERR, "Error opening output terminal for write\n"); |
|
293 return NULL; |
|
294 } |
|
295 |
|
296 |
|
297 for (;;) { |
|
298 if (p0) |
|
299 PORT_Free(p0); |
|
300 p0 = SEC_GetPassword(input, output, "Enter new password: ", |
|
301 SEC_BlindCheckPassword); |
|
302 |
|
303 if (p1) |
|
304 PORT_Free(p1); |
|
305 p1 = SEC_GetPassword(input, output, "Re-enter password: ", |
|
306 SEC_BlindCheckPassword); |
|
307 if (p0 && p1 && !PORT_Strcmp(p0, p1)) { |
|
308 break; |
|
309 } |
|
310 PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n"); |
|
311 } |
|
312 |
|
313 /* clear out the duplicate password string */ |
|
314 secu_ClearPassword(p1); |
|
315 |
|
316 fclose(input); |
|
317 fclose(output); |
|
318 |
|
319 return p0; |
|
320 } |
|
321 |
|
322 SECStatus |
|
323 SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile) |
|
324 { |
|
325 return SECU_ChangePW2(slot, passwd, 0, pwFile, 0); |
|
326 } |
|
327 |
|
328 SECStatus |
|
329 SECU_ChangePW2(PK11SlotInfo *slot, char *oldPass, char *newPass, |
|
330 char *oldPwFile, char *newPwFile) |
|
331 { |
|
332 SECStatus rv; |
|
333 secuPWData pwdata, newpwdata; |
|
334 char *oldpw = NULL, *newpw = NULL; |
|
335 |
|
336 if (oldPass) { |
|
337 pwdata.source = PW_PLAINTEXT; |
|
338 pwdata.data = oldPass; |
|
339 } else if (oldPwFile) { |
|
340 pwdata.source = PW_FROMFILE; |
|
341 pwdata.data = oldPwFile; |
|
342 } else { |
|
343 pwdata.source = PW_NONE; |
|
344 pwdata.data = NULL; |
|
345 } |
|
346 |
|
347 if (newPass) { |
|
348 newpwdata.source = PW_PLAINTEXT; |
|
349 newpwdata.data = newPass; |
|
350 } else if (newPwFile) { |
|
351 newpwdata.source = PW_FROMFILE; |
|
352 newpwdata.data = newPwFile; |
|
353 } else { |
|
354 newpwdata.source = PW_NONE; |
|
355 newpwdata.data = NULL; |
|
356 } |
|
357 |
|
358 if (PK11_NeedUserInit(slot)) { |
|
359 newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata); |
|
360 rv = PK11_InitPin(slot, (char*)NULL, newpw); |
|
361 goto done; |
|
362 } |
|
363 |
|
364 for (;;) { |
|
365 oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata); |
|
366 |
|
367 if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) { |
|
368 if (pwdata.source == PW_NONE) { |
|
369 PR_fprintf(PR_STDERR, "Invalid password. Try again.\n"); |
|
370 } else { |
|
371 PR_fprintf(PR_STDERR, "Invalid password.\n"); |
|
372 PORT_Memset(oldpw, 0, PL_strlen(oldpw)); |
|
373 PORT_Free(oldpw); |
|
374 return SECFailure; |
|
375 } |
|
376 } else |
|
377 break; |
|
378 |
|
379 PORT_Free(oldpw); |
|
380 } |
|
381 |
|
382 newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata); |
|
383 |
|
384 if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) { |
|
385 PR_fprintf(PR_STDERR, "Failed to change password.\n"); |
|
386 return SECFailure; |
|
387 } |
|
388 |
|
389 PORT_Memset(oldpw, 0, PL_strlen(oldpw)); |
|
390 PORT_Free(oldpw); |
|
391 |
|
392 PR_fprintf(PR_STDOUT, "Password changed successfully.\n"); |
|
393 |
|
394 done: |
|
395 PORT_Memset(newpw, 0, PL_strlen(newpw)); |
|
396 PORT_Free(newpw); |
|
397 return SECSuccess; |
|
398 } |
|
399 |
|
400 struct matchobj { |
|
401 SECItem index; |
|
402 char *nname; |
|
403 PRBool found; |
|
404 }; |
|
405 |
|
406 char * |
|
407 SECU_DefaultSSLDir(void) |
|
408 { |
|
409 char *dir; |
|
410 static char sslDir[1000]; |
|
411 |
|
412 dir = PR_GetEnv("SSL_DIR"); |
|
413 if (!dir) |
|
414 return NULL; |
|
415 |
|
416 sprintf(sslDir, "%s", dir); |
|
417 |
|
418 if (sslDir[strlen(sslDir)-1] == '/') |
|
419 sslDir[strlen(sslDir)-1] = 0; |
|
420 |
|
421 return sslDir; |
|
422 } |
|
423 |
|
424 char * |
|
425 SECU_AppendFilenameToDir(char *dir, char *filename) |
|
426 { |
|
427 static char path[1000]; |
|
428 |
|
429 if (dir[strlen(dir)-1] == '/') |
|
430 sprintf(path, "%s%s", dir, filename); |
|
431 else |
|
432 sprintf(path, "%s/%s", dir, filename); |
|
433 return path; |
|
434 } |
|
435 |
|
436 char * |
|
437 SECU_ConfigDirectory(const char* base) |
|
438 { |
|
439 static PRBool initted = PR_FALSE; |
|
440 const char *dir = ".netscape"; |
|
441 char *home; |
|
442 static char buf[1000]; |
|
443 |
|
444 if (initted) return buf; |
|
445 |
|
446 |
|
447 if (base == NULL || *base == 0) { |
|
448 home = PR_GetEnv("HOME"); |
|
449 if (!home) home = ""; |
|
450 |
|
451 if (*home && home[strlen(home) - 1] == '/') |
|
452 sprintf (buf, "%.900s%s", home, dir); |
|
453 else |
|
454 sprintf (buf, "%.900s/%s", home, dir); |
|
455 } else { |
|
456 sprintf(buf, "%.900s", base); |
|
457 if (buf[strlen(buf) - 1] == '/') |
|
458 buf[strlen(buf) - 1] = 0; |
|
459 } |
|
460 |
|
461 |
|
462 initted = PR_TRUE; |
|
463 return buf; |
|
464 } |
|
465 |
|
466 /*Turn off SSL for now */ |
|
467 /* This gets called by SSL when server wants our cert & key */ |
|
468 int |
|
469 SECU_GetClientAuthData(void *arg, PRFileDesc *fd, |
|
470 struct CERTDistNamesStr *caNames, |
|
471 struct CERTCertificateStr **pRetCert, |
|
472 struct SECKEYPrivateKeyStr **pRetKey) |
|
473 { |
|
474 SECKEYPrivateKey *key; |
|
475 CERTCertificate *cert; |
|
476 int errsave; |
|
477 |
|
478 if (arg == NULL) { |
|
479 fprintf(stderr, "no key/cert name specified for client auth\n"); |
|
480 return -1; |
|
481 } |
|
482 cert = PK11_FindCertFromNickname(arg, NULL); |
|
483 errsave = PORT_GetError(); |
|
484 if (!cert) { |
|
485 if (errsave == SEC_ERROR_BAD_PASSWORD) |
|
486 fprintf(stderr, "Bad password\n"); |
|
487 else if (errsave > 0) |
|
488 fprintf(stderr, "Unable to read cert (error %d)\n", errsave); |
|
489 else if (errsave == SEC_ERROR_BAD_DATABASE) |
|
490 fprintf(stderr, "Unable to get cert from database (%d)\n", errsave); |
|
491 else |
|
492 fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave); |
|
493 return -1; |
|
494 } |
|
495 |
|
496 key = PK11_FindKeyByAnyCert(arg,NULL); |
|
497 if (!key) { |
|
498 fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError()); |
|
499 return -1; |
|
500 } |
|
501 |
|
502 |
|
503 *pRetCert = cert; |
|
504 *pRetKey = key; |
|
505 |
|
506 return 0; |
|
507 } |
|
508 |
|
509 SECStatus |
|
510 SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii, |
|
511 PRBool warnOnPrivateKeyInAsciiFile) |
|
512 { |
|
513 SECStatus rv; |
|
514 if (ascii) { |
|
515 /* First convert ascii to binary */ |
|
516 SECItem filedata; |
|
517 char *asc, *body; |
|
518 |
|
519 /* Read in ascii data */ |
|
520 rv = SECU_FileToItem(&filedata, inFile); |
|
521 if (rv != SECSuccess) |
|
522 return rv; |
|
523 asc = (char *)filedata.data; |
|
524 if (!asc) { |
|
525 fprintf(stderr, "unable to read data from input file\n"); |
|
526 return SECFailure; |
|
527 } |
|
528 |
|
529 if (warnOnPrivateKeyInAsciiFile && strstr(asc, "PRIVATE KEY")) { |
|
530 fprintf(stderr, "Warning: ignoring private key. Consider to use " |
|
531 "pk12util.\n"); |
|
532 } |
|
533 |
|
534 /* check for headers and trailers and remove them */ |
|
535 if ((body = strstr(asc, "-----BEGIN")) != NULL) { |
|
536 char *trailer = NULL; |
|
537 asc = body; |
|
538 body = PORT_Strchr(body, '\n'); |
|
539 if (!body) |
|
540 body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */ |
|
541 if (body) |
|
542 trailer = strstr(++body, "-----END"); |
|
543 if (trailer != NULL) { |
|
544 *trailer = '\0'; |
|
545 } else { |
|
546 fprintf(stderr, "input has header but no trailer\n"); |
|
547 PORT_Free(filedata.data); |
|
548 return SECFailure; |
|
549 } |
|
550 } else { |
|
551 /* need one additional byte for zero terminator */ |
|
552 rv = SECITEM_ReallocItemV2(NULL, &filedata, filedata.len+1); |
|
553 if (rv != SECSuccess) { |
|
554 PORT_Free(filedata.data); |
|
555 return rv; |
|
556 } |
|
557 body = (char*)filedata.data; |
|
558 body[filedata.len-1] = '\0'; |
|
559 } |
|
560 |
|
561 /* Convert to binary */ |
|
562 rv = ATOB_ConvertAsciiToItem(der, body); |
|
563 if (rv != SECSuccess) { |
|
564 fprintf(stderr, "error converting ascii to binary (%s)\n", |
|
565 SECU_Strerror(PORT_GetError())); |
|
566 PORT_Free(filedata.data); |
|
567 return SECFailure; |
|
568 } |
|
569 |
|
570 PORT_Free(filedata.data); |
|
571 } else { |
|
572 /* Read in binary der */ |
|
573 rv = SECU_FileToItem(der, inFile); |
|
574 if (rv != SECSuccess) { |
|
575 fprintf(stderr, "error converting der (%s)\n", |
|
576 SECU_Strerror(PORT_GetError())); |
|
577 return SECFailure; |
|
578 } |
|
579 } |
|
580 return SECSuccess; |
|
581 } |
|
582 |
|
583 #define INDENT_MULT 4 |
|
584 |
|
585 SECStatus |
|
586 SECU_StripTagAndLength(SECItem *i) |
|
587 { |
|
588 unsigned int start; |
|
589 |
|
590 if (!i || !i->data || i->len < 2) { /* must be at least tag and length */ |
|
591 return SECFailure; |
|
592 } |
|
593 start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2); |
|
594 if (i->len < start) { |
|
595 return SECFailure; |
|
596 } |
|
597 i->data += start; |
|
598 i->len -= start; |
|
599 return SECSuccess; |
|
600 } |
|
601 |
|
602 |
|
603 |
|
604 static void |
|
605 secu_PrintRawStringQuotesOptional(FILE *out, SECItem *si, const char *m, |
|
606 int level, PRBool quotes) |
|
607 { |
|
608 int column; |
|
609 unsigned int i; |
|
610 |
|
611 if ( m ) { |
|
612 SECU_Indent(out, level); fprintf(out, "%s: ", m); |
|
613 column = (level * INDENT_MULT) + strlen(m) + 2; |
|
614 level++; |
|
615 } else { |
|
616 SECU_Indent(out, level); |
|
617 column = level*INDENT_MULT; |
|
618 } |
|
619 if (quotes) { |
|
620 fprintf(out, "\""); column++; |
|
621 } |
|
622 |
|
623 for (i = 0; i < si->len; i++) { |
|
624 unsigned char val = si->data[i]; |
|
625 unsigned char c; |
|
626 if (SECU_GetWrapEnabled() && column > 76) { |
|
627 SECU_Newline(out); |
|
628 SECU_Indent(out, level); column = level*INDENT_MULT; |
|
629 } |
|
630 |
|
631 if (utf8DisplayEnabled) { |
|
632 if (val < 32) |
|
633 c = '.'; |
|
634 else |
|
635 c = val; |
|
636 } else { |
|
637 c = printable[val]; |
|
638 } |
|
639 fprintf(out,"%c", c); |
|
640 column++; |
|
641 } |
|
642 |
|
643 if (quotes) { |
|
644 fprintf(out, "\""); column++; |
|
645 } |
|
646 if (SECU_GetWrapEnabled() && |
|
647 (column != level*INDENT_MULT || column > 76)) { |
|
648 SECU_Newline(out); |
|
649 } |
|
650 } |
|
651 |
|
652 static void |
|
653 secu_PrintRawString(FILE *out, SECItem *si, const char *m, int level) |
|
654 { |
|
655 secu_PrintRawStringQuotesOptional(out, si, m, level, PR_TRUE); |
|
656 } |
|
657 |
|
658 void |
|
659 SECU_PrintString(FILE *out, const SECItem *si, const char *m, int level) |
|
660 { |
|
661 SECItem my = *si; |
|
662 |
|
663 if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len) |
|
664 return; |
|
665 secu_PrintRawString(out, &my, m, level); |
|
666 } |
|
667 |
|
668 /* print an unencoded boolean */ |
|
669 static void |
|
670 secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level) |
|
671 { |
|
672 int val = 0; |
|
673 |
|
674 if ( i->data && i->len ) { |
|
675 val = i->data[0]; |
|
676 } |
|
677 |
|
678 if (!m) { |
|
679 m = "Boolean"; |
|
680 } |
|
681 SECU_Indent(out, level); |
|
682 fprintf(out, "%s: %s\n", m, (val ? "True" : "False")); |
|
683 } |
|
684 |
|
685 /* |
|
686 * Format and print "time". If the tag message "m" is not NULL, |
|
687 * do indent formatting based on "level" and add a newline afterward; |
|
688 * otherwise just print the formatted time string only. |
|
689 */ |
|
690 static void |
|
691 secu_PrintTime(FILE *out, const PRTime time, const char *m, int level) |
|
692 { |
|
693 PRExplodedTime printableTime; |
|
694 char *timeString; |
|
695 |
|
696 /* Convert to local time */ |
|
697 PR_ExplodeTime(time, PR_GMTParameters, &printableTime); |
|
698 |
|
699 timeString = PORT_Alloc(256); |
|
700 if (timeString == NULL) |
|
701 return; |
|
702 |
|
703 if (m != NULL) { |
|
704 SECU_Indent(out, level); |
|
705 fprintf(out, "%s: ", m); |
|
706 } |
|
707 |
|
708 if (PR_FormatTime(timeString, 256, "%a %b %d %H:%M:%S %Y", &printableTime)) { |
|
709 fputs(timeString, out); |
|
710 } |
|
711 |
|
712 if (m != NULL) |
|
713 fprintf(out, "\n"); |
|
714 |
|
715 PORT_Free(timeString); |
|
716 } |
|
717 |
|
718 /* |
|
719 * Format and print the UTC Time "t". If the tag message "m" is not NULL, |
|
720 * do indent formatting based on "level" and add a newline afterward; |
|
721 * otherwise just print the formatted time string only. |
|
722 */ |
|
723 void |
|
724 SECU_PrintUTCTime(FILE *out, const SECItem *t, const char *m, int level) |
|
725 { |
|
726 PRTime time; |
|
727 SECStatus rv; |
|
728 |
|
729 rv = DER_UTCTimeToTime(&time, t); |
|
730 if (rv != SECSuccess) |
|
731 return; |
|
732 |
|
733 secu_PrintTime(out, time, m, level); |
|
734 } |
|
735 |
|
736 /* |
|
737 * Format and print the Generalized Time "t". If the tag message "m" |
|
738 * is not NULL, * do indent formatting based on "level" and add a newline |
|
739 * afterward; otherwise just print the formatted time string only. |
|
740 */ |
|
741 void |
|
742 SECU_PrintGeneralizedTime(FILE *out, const SECItem *t, const char *m, int level) |
|
743 { |
|
744 PRTime time; |
|
745 SECStatus rv; |
|
746 |
|
747 |
|
748 rv = DER_GeneralizedTimeToTime(&time, t); |
|
749 if (rv != SECSuccess) |
|
750 return; |
|
751 |
|
752 secu_PrintTime(out, time, m, level); |
|
753 } |
|
754 |
|
755 /* |
|
756 * Format and print the UTC or Generalized Time "t". If the tag message |
|
757 * "m" is not NULL, do indent formatting based on "level" and add a newline |
|
758 * afterward; otherwise just print the formatted time string only. |
|
759 */ |
|
760 void |
|
761 SECU_PrintTimeChoice(FILE *out, const SECItem *t, const char *m, int level) |
|
762 { |
|
763 switch (t->type) { |
|
764 case siUTCTime: |
|
765 SECU_PrintUTCTime(out, t, m, level); |
|
766 break; |
|
767 |
|
768 case siGeneralizedTime: |
|
769 SECU_PrintGeneralizedTime(out, t, m, level); |
|
770 break; |
|
771 |
|
772 default: |
|
773 PORT_Assert(0); |
|
774 break; |
|
775 } |
|
776 } |
|
777 |
|
778 |
|
779 /* This prints a SET or SEQUENCE */ |
|
780 static void |
|
781 SECU_PrintSet(FILE *out, const SECItem *t, const char *m, int level) |
|
782 { |
|
783 int type = t->data[0] & SEC_ASN1_TAGNUM_MASK; |
|
784 int constructed = t->data[0] & SEC_ASN1_CONSTRUCTED; |
|
785 const char * label; |
|
786 SECItem my = *t; |
|
787 |
|
788 if (!constructed) { |
|
789 SECU_PrintAsHex(out, t, m, level); |
|
790 return; |
|
791 } |
|
792 if (SECSuccess != SECU_StripTagAndLength(&my)) |
|
793 return; |
|
794 |
|
795 SECU_Indent(out, level); |
|
796 if (m) { |
|
797 fprintf(out, "%s: ", m); |
|
798 } |
|
799 |
|
800 if (type == SEC_ASN1_SET) |
|
801 label = "Set "; |
|
802 else if (type == SEC_ASN1_SEQUENCE) |
|
803 label = "Sequence "; |
|
804 else |
|
805 label = ""; |
|
806 fprintf(out,"%s{\n", label); /* } */ |
|
807 |
|
808 while (my.len >= 2) { |
|
809 SECItem tmp = my; |
|
810 |
|
811 if (tmp.data[1] & 0x80) { |
|
812 unsigned int i; |
|
813 unsigned int lenlen = tmp.data[1] & 0x7f; |
|
814 if (lenlen > sizeof tmp.len) |
|
815 break; |
|
816 tmp.len = 0; |
|
817 for (i=0; i < lenlen; i++) { |
|
818 tmp.len = (tmp.len << 8) | tmp.data[2+i]; |
|
819 } |
|
820 tmp.len += lenlen + 2; |
|
821 } else { |
|
822 tmp.len = tmp.data[1] + 2; |
|
823 } |
|
824 if (tmp.len > my.len) { |
|
825 tmp.len = my.len; |
|
826 } |
|
827 my.data += tmp.len; |
|
828 my.len -= tmp.len; |
|
829 SECU_PrintAny(out, &tmp, NULL, level + 1); |
|
830 } |
|
831 SECU_Indent(out, level); fprintf(out, /* { */ "}\n"); |
|
832 } |
|
833 |
|
834 static void |
|
835 secu_PrintContextSpecific(FILE *out, const SECItem *i, const char *m, int level) |
|
836 { |
|
837 int type = i->data[0] & SEC_ASN1_TAGNUM_MASK; |
|
838 int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED; |
|
839 SECItem tmp; |
|
840 |
|
841 if (constructed) { |
|
842 char * m2; |
|
843 if (!m) |
|
844 m2 = PR_smprintf("[%d]", type); |
|
845 else |
|
846 m2 = PR_smprintf("%s: [%d]", m, type); |
|
847 if (m2) { |
|
848 SECU_PrintSet(out, i, m2, level); |
|
849 PR_smprintf_free(m2); |
|
850 } |
|
851 return; |
|
852 } |
|
853 |
|
854 SECU_Indent(out, level); |
|
855 if (m) { |
|
856 fprintf(out, "%s: ", m); |
|
857 } |
|
858 fprintf(out,"[%d]\n", type); |
|
859 |
|
860 tmp = *i; |
|
861 if (SECSuccess == SECU_StripTagAndLength(&tmp)) |
|
862 SECU_PrintAsHex(out, &tmp, m, level+1); |
|
863 } |
|
864 |
|
865 static void |
|
866 secu_PrintOctetString(FILE *out, const SECItem *i, const char *m, int level) |
|
867 { |
|
868 SECItem tmp = *i; |
|
869 if (SECSuccess == SECU_StripTagAndLength(&tmp)) |
|
870 SECU_PrintAsHex(out, &tmp, m, level); |
|
871 } |
|
872 |
|
873 static void |
|
874 secu_PrintBitString(FILE *out, const SECItem *i, const char *m, int level) |
|
875 { |
|
876 int unused_bits; |
|
877 SECItem tmp = *i; |
|
878 |
|
879 if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2) |
|
880 return; |
|
881 |
|
882 unused_bits = *tmp.data++; |
|
883 tmp.len--; |
|
884 |
|
885 SECU_PrintAsHex(out, &tmp, m, level); |
|
886 if (unused_bits) { |
|
887 SECU_Indent(out, level + 1); |
|
888 fprintf(out, "(%d least significant bits unused)\n", unused_bits); |
|
889 } |
|
890 } |
|
891 |
|
892 /* in a decoded bit string, the len member is a bit length. */ |
|
893 static void |
|
894 secu_PrintDecodedBitString(FILE *out, const SECItem *i, const char *m, int level) |
|
895 { |
|
896 int unused_bits; |
|
897 SECItem tmp = *i; |
|
898 |
|
899 |
|
900 unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0; |
|
901 DER_ConvertBitString(&tmp); /* convert length to byte length */ |
|
902 |
|
903 SECU_PrintAsHex(out, &tmp, m, level); |
|
904 if (unused_bits) { |
|
905 SECU_Indent(out, level + 1); |
|
906 fprintf(out, "(%d least significant bits unused)\n", unused_bits); |
|
907 } |
|
908 } |
|
909 |
|
910 |
|
911 /* Print a DER encoded Boolean */ |
|
912 void |
|
913 SECU_PrintEncodedBoolean(FILE *out, const SECItem *i, const char *m, int level) |
|
914 { |
|
915 SECItem my = *i; |
|
916 if (SECSuccess == SECU_StripTagAndLength(&my)) |
|
917 secu_PrintBoolean(out, &my, m, level); |
|
918 } |
|
919 |
|
920 /* Print a DER encoded integer */ |
|
921 void |
|
922 SECU_PrintEncodedInteger(FILE *out, const SECItem *i, const char *m, int level) |
|
923 { |
|
924 SECItem my = *i; |
|
925 if (SECSuccess == SECU_StripTagAndLength(&my)) |
|
926 SECU_PrintInteger(out, &my, m, level); |
|
927 } |
|
928 |
|
929 /* Print a DER encoded OID */ |
|
930 void |
|
931 SECU_PrintEncodedObjectID(FILE *out, const SECItem *i, const char *m, int level) |
|
932 { |
|
933 SECItem my = *i; |
|
934 if (SECSuccess == SECU_StripTagAndLength(&my)) |
|
935 SECU_PrintObjectID(out, &my, m, level); |
|
936 } |
|
937 |
|
938 static void |
|
939 secu_PrintBMPString(FILE *out, const SECItem *i, const char *m, int level) |
|
940 { |
|
941 unsigned char * s; |
|
942 unsigned char * d; |
|
943 int len; |
|
944 SECItem tmp = {0, 0, 0}; |
|
945 SECItem my = *i; |
|
946 |
|
947 if (SECSuccess != SECU_StripTagAndLength(&my)) |
|
948 goto loser; |
|
949 if (my.len % 2) |
|
950 goto loser; |
|
951 len = (int)(my.len / 2); |
|
952 tmp.data = (unsigned char *)PORT_Alloc(len); |
|
953 if (!tmp.data) |
|
954 goto loser; |
|
955 tmp.len = len; |
|
956 for (s = my.data, d = tmp.data ; len > 0; len--) { |
|
957 PRUint32 bmpChar = (s[0] << 8) | s[1]; s += 2; |
|
958 if (!isprint(bmpChar)) |
|
959 goto loser; |
|
960 *d++ = (unsigned char)bmpChar; |
|
961 } |
|
962 secu_PrintRawString(out, &tmp, m, level); |
|
963 PORT_Free(tmp.data); |
|
964 return; |
|
965 |
|
966 loser: |
|
967 SECU_PrintAsHex(out, i, m, level); |
|
968 if (tmp.data) |
|
969 PORT_Free(tmp.data); |
|
970 } |
|
971 |
|
972 static void |
|
973 secu_PrintUniversalString(FILE *out, const SECItem *i, const char *m, int level) |
|
974 { |
|
975 unsigned char * s; |
|
976 unsigned char * d; |
|
977 int len; |
|
978 SECItem tmp = {0, 0, 0}; |
|
979 SECItem my = *i; |
|
980 |
|
981 if (SECSuccess != SECU_StripTagAndLength(&my)) |
|
982 goto loser; |
|
983 if (my.len % 4) |
|
984 goto loser; |
|
985 len = (int)(my.len / 4); |
|
986 tmp.data = (unsigned char *)PORT_Alloc(len); |
|
987 if (!tmp.data) |
|
988 goto loser; |
|
989 tmp.len = len; |
|
990 for (s = my.data, d = tmp.data ; len > 0; len--) { |
|
991 PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; |
|
992 s += 4; |
|
993 if (!isprint(bmpChar)) |
|
994 goto loser; |
|
995 *d++ = (unsigned char)bmpChar; |
|
996 } |
|
997 secu_PrintRawString(out, &tmp, m, level); |
|
998 PORT_Free(tmp.data); |
|
999 return; |
|
1000 |
|
1001 loser: |
|
1002 SECU_PrintAsHex(out, i, m, level); |
|
1003 if (tmp.data) |
|
1004 PORT_Free(tmp.data); |
|
1005 } |
|
1006 |
|
1007 static void |
|
1008 secu_PrintUniversal(FILE *out, const SECItem *i, const char *m, int level) |
|
1009 { |
|
1010 switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) { |
|
1011 case SEC_ASN1_ENUMERATED: |
|
1012 case SEC_ASN1_INTEGER: |
|
1013 SECU_PrintEncodedInteger(out, i, m, level); |
|
1014 break; |
|
1015 case SEC_ASN1_OBJECT_ID: |
|
1016 SECU_PrintEncodedObjectID(out, i, m, level); |
|
1017 break; |
|
1018 case SEC_ASN1_BOOLEAN: |
|
1019 SECU_PrintEncodedBoolean(out, i, m, level); |
|
1020 break; |
|
1021 case SEC_ASN1_UTF8_STRING: |
|
1022 case SEC_ASN1_PRINTABLE_STRING: |
|
1023 case SEC_ASN1_VISIBLE_STRING: |
|
1024 case SEC_ASN1_IA5_STRING: |
|
1025 case SEC_ASN1_T61_STRING: |
|
1026 SECU_PrintString(out, i, m, level); |
|
1027 break; |
|
1028 case SEC_ASN1_GENERALIZED_TIME: |
|
1029 SECU_PrintGeneralizedTime(out, i, m, level); |
|
1030 break; |
|
1031 case SEC_ASN1_UTC_TIME: |
|
1032 SECU_PrintUTCTime(out, i, m, level); |
|
1033 break; |
|
1034 case SEC_ASN1_NULL: |
|
1035 SECU_Indent(out, level); |
|
1036 if (m && m[0]) |
|
1037 fprintf(out, "%s: NULL\n", m); |
|
1038 else |
|
1039 fprintf(out, "NULL\n"); |
|
1040 break; |
|
1041 case SEC_ASN1_SET: |
|
1042 case SEC_ASN1_SEQUENCE: |
|
1043 SECU_PrintSet(out, i, m, level); |
|
1044 break; |
|
1045 case SEC_ASN1_OCTET_STRING: |
|
1046 secu_PrintOctetString(out, i, m, level); |
|
1047 break; |
|
1048 case SEC_ASN1_BIT_STRING: |
|
1049 secu_PrintBitString(out, i, m, level); |
|
1050 break; |
|
1051 case SEC_ASN1_BMP_STRING: |
|
1052 secu_PrintBMPString(out, i, m, level); |
|
1053 break; |
|
1054 case SEC_ASN1_UNIVERSAL_STRING: |
|
1055 secu_PrintUniversalString(out, i, m, level); |
|
1056 break; |
|
1057 default: |
|
1058 SECU_PrintAsHex(out, i, m, level); |
|
1059 break; |
|
1060 } |
|
1061 } |
|
1062 |
|
1063 void |
|
1064 SECU_PrintAny(FILE *out, const SECItem *i, const char *m, int level) |
|
1065 { |
|
1066 if ( i && i->len && i->data ) { |
|
1067 switch (i->data[0] & SEC_ASN1_CLASS_MASK) { |
|
1068 case SEC_ASN1_CONTEXT_SPECIFIC: |
|
1069 secu_PrintContextSpecific(out, i, m, level); |
|
1070 break; |
|
1071 case SEC_ASN1_UNIVERSAL: |
|
1072 secu_PrintUniversal(out, i, m, level); |
|
1073 break; |
|
1074 default: |
|
1075 SECU_PrintAsHex(out, i, m, level); |
|
1076 break; |
|
1077 } |
|
1078 } |
|
1079 } |
|
1080 |
|
1081 static int |
|
1082 secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level) |
|
1083 { |
|
1084 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
1085 SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level+1); |
|
1086 SECU_PrintTimeChoice(out, &v->notAfter, "Not After ", level+1); |
|
1087 return 0; |
|
1088 } |
|
1089 |
|
1090 /* This function does NOT expect a DER type and length. */ |
|
1091 SECOidTag |
|
1092 SECU_PrintObjectID(FILE *out, const SECItem *oid, const char *m, int level) |
|
1093 { |
|
1094 SECOidData *oiddata; |
|
1095 char * oidString = NULL; |
|
1096 |
|
1097 oiddata = SECOID_FindOID(oid); |
|
1098 if (oiddata != NULL) { |
|
1099 const char *name = oiddata->desc; |
|
1100 SECU_Indent(out, level); |
|
1101 if (m != NULL) |
|
1102 fprintf(out, "%s: ", m); |
|
1103 fprintf(out, "%s\n", name); |
|
1104 return oiddata->offset; |
|
1105 } |
|
1106 oidString = CERT_GetOidString(oid); |
|
1107 if (oidString) { |
|
1108 SECU_Indent(out, level); |
|
1109 if (m != NULL) |
|
1110 fprintf(out, "%s: ", m); |
|
1111 fprintf(out, "%s\n", oidString); |
|
1112 PR_smprintf_free(oidString); |
|
1113 return SEC_OID_UNKNOWN; |
|
1114 } |
|
1115 SECU_PrintAsHex(out, oid, m, level); |
|
1116 return SEC_OID_UNKNOWN; |
|
1117 } |
|
1118 |
|
1119 typedef struct secuPBEParamsStr { |
|
1120 SECItem salt; |
|
1121 SECItem iterationCount; |
|
1122 SECItem keyLength; |
|
1123 SECAlgorithmID cipherAlg; |
|
1124 SECAlgorithmID kdfAlg; |
|
1125 } secuPBEParams; |
|
1126 |
|
1127 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
|
1128 |
|
1129 /* SECOID_PKCS5_PBKDF2 */ |
|
1130 const SEC_ASN1Template secuKDF2Params[] = |
|
1131 { |
|
1132 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) }, |
|
1133 { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) }, |
|
1134 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) }, |
|
1135 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, keyLength) }, |
|
1136 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg), |
|
1137 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
|
1138 { 0 } |
|
1139 }; |
|
1140 |
|
1141 /* PKCS5v1 & PKCS12 */ |
|
1142 const SEC_ASN1Template secuPBEParamsTemp[] = |
|
1143 { |
|
1144 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) }, |
|
1145 { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) }, |
|
1146 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) }, |
|
1147 { 0 } |
|
1148 }; |
|
1149 |
|
1150 /* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */ |
|
1151 const SEC_ASN1Template secuPBEV2Params[] = |
|
1152 { |
|
1153 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams)}, |
|
1154 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg), |
|
1155 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
|
1156 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, cipherAlg), |
|
1157 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
|
1158 { 0 } |
|
1159 }; |
|
1160 |
|
1161 void |
|
1162 secu_PrintRSAPSSParams(FILE *out, SECItem *value, char *m, int level) |
|
1163 { |
|
1164 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1165 SECStatus rv; |
|
1166 SECKEYRSAPSSParams param; |
|
1167 SECAlgorithmID maskHashAlg; |
|
1168 |
|
1169 if (m) { |
|
1170 SECU_Indent(out, level); |
|
1171 fprintf (out, "%s:\n", m); |
|
1172 } |
|
1173 |
|
1174 if (!pool) { |
|
1175 SECU_Indent(out, level); |
|
1176 fprintf(out, "Out of memory\n"); |
|
1177 return; |
|
1178 } |
|
1179 |
|
1180 PORT_Memset(¶m, 0, sizeof param); |
|
1181 |
|
1182 rv = SEC_QuickDERDecodeItem(pool, ¶m, |
|
1183 SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate), |
|
1184 value); |
|
1185 if (rv == SECSuccess) { |
|
1186 if (!param.hashAlg) { |
|
1187 SECU_Indent(out, level+1); |
|
1188 fprintf(out, "Hash algorithm: default, SHA-1\n"); |
|
1189 } else { |
|
1190 SECU_PrintObjectID(out, ¶m.hashAlg->algorithm, |
|
1191 "Hash algorithm", level+1); |
|
1192 } |
|
1193 if (!param.maskAlg) { |
|
1194 SECU_Indent(out, level+1); |
|
1195 fprintf(out, "Mask algorithm: default, MGF1\n"); |
|
1196 SECU_Indent(out, level+1); |
|
1197 fprintf(out, "Mask hash algorithm: default, SHA-1\n"); |
|
1198 } else { |
|
1199 SECU_PrintObjectID(out, ¶m.maskAlg->algorithm, |
|
1200 "Mask algorithm", level+1); |
|
1201 rv = SEC_QuickDERDecodeItem(pool, &maskHashAlg, |
|
1202 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), |
|
1203 ¶m.maskAlg->parameters); |
|
1204 if (rv == SECSuccess) { |
|
1205 SECU_PrintObjectID(out, &maskHashAlg.algorithm, |
|
1206 "Mask hash algorithm", level+1); |
|
1207 } else { |
|
1208 SECU_Indent(out, level+1); |
|
1209 fprintf(out, "Invalid mask generation algorithm parameters\n"); |
|
1210 } |
|
1211 } |
|
1212 if (!param.saltLength.data) { |
|
1213 SECU_Indent(out, level+1); |
|
1214 fprintf(out, "Salt length: default, %i (0x%2X)\n", 20, 20); |
|
1215 } else { |
|
1216 SECU_PrintInteger(out, ¶m.saltLength, "Salt Length", level+1); |
|
1217 } |
|
1218 } else { |
|
1219 SECU_Indent(out, level+1); |
|
1220 fprintf(out, "Invalid RSA-PSS parameters\n"); |
|
1221 } |
|
1222 PORT_FreeArena(pool, PR_FALSE); |
|
1223 } |
|
1224 |
|
1225 void |
|
1226 secu_PrintKDF2Params(FILE *out, SECItem *value, char *m, int level) |
|
1227 { |
|
1228 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1229 SECStatus rv; |
|
1230 secuPBEParams param; |
|
1231 |
|
1232 if (m) { |
|
1233 SECU_Indent(out, level); |
|
1234 fprintf (out, "%s:\n", m); |
|
1235 } |
|
1236 |
|
1237 if (!pool) { |
|
1238 SECU_Indent(out, level); |
|
1239 fprintf(out, "Out of memory\n"); |
|
1240 return; |
|
1241 } |
|
1242 |
|
1243 PORT_Memset(¶m, 0, sizeof param); |
|
1244 rv = SEC_QuickDERDecodeItem(pool, ¶m, secuKDF2Params, value); |
|
1245 if (rv == SECSuccess) { |
|
1246 SECU_PrintAsHex(out, ¶m.salt, "Salt", level+1); |
|
1247 SECU_PrintInteger(out, ¶m.iterationCount, "Iteration Count", |
|
1248 level+1); |
|
1249 SECU_PrintInteger(out, ¶m.keyLength, "Key Length", level+1); |
|
1250 SECU_PrintAlgorithmID(out, ¶m.kdfAlg, "KDF algorithm", level+1); |
|
1251 } |
|
1252 PORT_FreeArena(pool, PR_FALSE); |
|
1253 } |
|
1254 |
|
1255 void |
|
1256 secu_PrintPKCS5V2Params(FILE *out, SECItem *value, char *m, int level) |
|
1257 { |
|
1258 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1259 SECStatus rv; |
|
1260 secuPBEParams param; |
|
1261 |
|
1262 if (m) { |
|
1263 SECU_Indent(out, level); |
|
1264 fprintf (out, "%s:\n", m); |
|
1265 } |
|
1266 |
|
1267 if (!pool) { |
|
1268 SECU_Indent(out, level); |
|
1269 fprintf(out, "Out of memory\n"); |
|
1270 return; |
|
1271 } |
|
1272 |
|
1273 PORT_Memset(¶m, 0, sizeof param); |
|
1274 rv = SEC_QuickDERDecodeItem(pool, ¶m, secuPBEV2Params, value); |
|
1275 if (rv == SECSuccess) { |
|
1276 SECU_PrintAlgorithmID(out, ¶m.kdfAlg, "KDF", level+1); |
|
1277 SECU_PrintAlgorithmID(out, ¶m.cipherAlg, "Cipher", level+1); |
|
1278 } |
|
1279 PORT_FreeArena(pool, PR_FALSE); |
|
1280 } |
|
1281 |
|
1282 void |
|
1283 secu_PrintPBEParams(FILE *out, SECItem *value, char *m, int level) |
|
1284 { |
|
1285 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1286 SECStatus rv; |
|
1287 secuPBEParams param; |
|
1288 |
|
1289 if (m) { |
|
1290 SECU_Indent(out, level); |
|
1291 fprintf (out, "%s:\n", m); |
|
1292 } |
|
1293 |
|
1294 if (!pool) { |
|
1295 SECU_Indent(out, level); |
|
1296 fprintf(out, "Out of memory\n"); |
|
1297 return; |
|
1298 } |
|
1299 |
|
1300 PORT_Memset(¶m, 0, sizeof(secuPBEParams)); |
|
1301 rv = SEC_QuickDERDecodeItem(pool, ¶m, secuPBEParamsTemp, value); |
|
1302 if (rv == SECSuccess) { |
|
1303 SECU_PrintAsHex(out, ¶m.salt, "Salt", level+1); |
|
1304 SECU_PrintInteger(out, ¶m.iterationCount, "Iteration Count", |
|
1305 level+1); |
|
1306 } |
|
1307 PORT_FreeArena(pool, PR_FALSE); |
|
1308 } |
|
1309 |
|
1310 /* This function does NOT expect a DER type and length. */ |
|
1311 void |
|
1312 SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level) |
|
1313 { |
|
1314 SECOidTag algtag; |
|
1315 SECU_PrintObjectID(out, &a->algorithm, m, level); |
|
1316 |
|
1317 algtag = SECOID_GetAlgorithmTag(a); |
|
1318 if (SEC_PKCS5IsAlgorithmPBEAlgTag(algtag)) { |
|
1319 switch (algtag) { |
|
1320 case SEC_OID_PKCS5_PBKDF2: |
|
1321 secu_PrintKDF2Params(out, &a->parameters, "Parameters", level+1); |
|
1322 break; |
|
1323 case SEC_OID_PKCS5_PBES2: |
|
1324 secu_PrintPKCS5V2Params(out, &a->parameters, "Encryption", level+1); |
|
1325 break; |
|
1326 case SEC_OID_PKCS5_PBMAC1: |
|
1327 secu_PrintPKCS5V2Params(out, &a->parameters, "MAC", level+1); |
|
1328 break; |
|
1329 default: |
|
1330 secu_PrintPBEParams(out, &a->parameters, "Parameters", level+1); |
|
1331 break; |
|
1332 } |
|
1333 return; |
|
1334 } |
|
1335 |
|
1336 if (algtag == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { |
|
1337 secu_PrintRSAPSSParams(out, &a->parameters, "Parameters", level+1); |
|
1338 return; |
|
1339 } |
|
1340 |
|
1341 if (a->parameters.len == 0 |
|
1342 || (a->parameters.len == 2 |
|
1343 && PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) { |
|
1344 /* No arguments or NULL argument */ |
|
1345 } else { |
|
1346 /* Print args to algorithm */ |
|
1347 SECU_PrintAsHex(out, &a->parameters, "Args", level+1); |
|
1348 } |
|
1349 } |
|
1350 |
|
1351 static void |
|
1352 secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level) |
|
1353 { |
|
1354 SECItem *value; |
|
1355 int i; |
|
1356 char om[100]; |
|
1357 |
|
1358 if (m) { |
|
1359 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
1360 } |
|
1361 |
|
1362 /* |
|
1363 * Should make this smarter; look at the type field and then decode |
|
1364 * and print the value(s) appropriately! |
|
1365 */ |
|
1366 SECU_PrintObjectID(out, &(attr->type), "Type", level+1); |
|
1367 if (attr->values != NULL) { |
|
1368 i = 0; |
|
1369 while ((value = attr->values[i++]) != NULL) { |
|
1370 sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : ""); |
|
1371 if (attr->encoded || attr->typeTag == NULL) { |
|
1372 SECU_PrintAny(out, value, om, level+1); |
|
1373 } else { |
|
1374 switch (attr->typeTag->offset) { |
|
1375 default: |
|
1376 SECU_PrintAsHex(out, value, om, level+1); |
|
1377 break; |
|
1378 case SEC_OID_PKCS9_CONTENT_TYPE: |
|
1379 SECU_PrintObjectID(out, value, om, level+1); |
|
1380 break; |
|
1381 case SEC_OID_PKCS9_SIGNING_TIME: |
|
1382 SECU_PrintTimeChoice(out, value, om, level+1); |
|
1383 break; |
|
1384 } |
|
1385 } |
|
1386 } |
|
1387 } |
|
1388 } |
|
1389 |
|
1390 #ifndef NSS_DISABLE_ECC |
|
1391 static void |
|
1392 secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) |
|
1393 { |
|
1394 SECItem curveOID = { siBuffer, NULL, 0}; |
|
1395 |
|
1396 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
1397 SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level+1); |
|
1398 /* For named curves, the DEREncodedParams field contains an |
|
1399 * ASN Object ID (0x06 is SEC_ASN1_OBJECT_ID). |
|
1400 */ |
|
1401 if ((pk->u.ec.DEREncodedParams.len > 2) && |
|
1402 (pk->u.ec.DEREncodedParams.data[0] == 0x06)) { |
|
1403 curveOID.len = pk->u.ec.DEREncodedParams.data[1]; |
|
1404 curveOID.data = pk->u.ec.DEREncodedParams.data + 2; |
|
1405 SECU_PrintObjectID(out, &curveOID, "Curve", level +1); |
|
1406 } |
|
1407 } |
|
1408 #endif /* NSS_DISABLE_ECC */ |
|
1409 |
|
1410 void |
|
1411 SECU_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) |
|
1412 { |
|
1413 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
1414 SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1); |
|
1415 SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1); |
|
1416 if (pk->u.rsa.publicExponent.len == 1 && |
|
1417 pk->u.rsa.publicExponent.data[0] == 1) { |
|
1418 SECU_Indent(out, level +1); fprintf(out, "Error: INVALID RSA KEY!\n"); |
|
1419 } |
|
1420 } |
|
1421 |
|
1422 void |
|
1423 SECU_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) |
|
1424 { |
|
1425 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
1426 SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level+1); |
|
1427 SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level+1); |
|
1428 SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level+1); |
|
1429 SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level+1); |
|
1430 } |
|
1431 |
|
1432 static void |
|
1433 secu_PrintSubjectPublicKeyInfo(FILE *out, PLArenaPool *arena, |
|
1434 CERTSubjectPublicKeyInfo *i, char *msg, int level) |
|
1435 { |
|
1436 SECKEYPublicKey *pk; |
|
1437 |
|
1438 SECU_Indent(out, level); fprintf(out, "%s:\n", msg); |
|
1439 SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level+1); |
|
1440 |
|
1441 pk = SECKEY_ExtractPublicKey(i); |
|
1442 if (pk) { |
|
1443 switch (pk->keyType) { |
|
1444 case rsaKey: |
|
1445 SECU_PrintRSAPublicKey(out, pk, "RSA Public Key", level +1); |
|
1446 break; |
|
1447 |
|
1448 case dsaKey: |
|
1449 SECU_PrintDSAPublicKey(out, pk, "DSA Public Key", level +1); |
|
1450 break; |
|
1451 |
|
1452 #ifndef NSS_DISABLE_ECC |
|
1453 case ecKey: |
|
1454 secu_PrintECPublicKey(out, pk, "EC Public Key", level +1); |
|
1455 break; |
|
1456 #endif |
|
1457 |
|
1458 case dhKey: |
|
1459 case fortezzaKey: |
|
1460 case keaKey: |
|
1461 SECU_Indent(out, level); |
|
1462 fprintf(out, "unable to format this SPKI algorithm type\n"); |
|
1463 goto loser; |
|
1464 default: |
|
1465 SECU_Indent(out, level); |
|
1466 fprintf(out, "unknown SPKI algorithm type\n"); |
|
1467 goto loser; |
|
1468 } |
|
1469 PORT_FreeArena(pk->arena, PR_FALSE); |
|
1470 } else { |
|
1471 SECU_PrintErrMsg(out, level, "Error", "Parsing public key"); |
|
1472 loser: |
|
1473 if (i->subjectPublicKey.data) { |
|
1474 SECU_PrintAny(out, &i->subjectPublicKey, "Raw", level); |
|
1475 } |
|
1476 } |
|
1477 } |
|
1478 |
|
1479 static void |
|
1480 printStringWithoutCRLF(FILE *out, const char *str) |
|
1481 { |
|
1482 const char *c = str; |
|
1483 while (*c) { |
|
1484 if (*c != '\r' && *c != '\n') { |
|
1485 fputc(*c, out); |
|
1486 } |
|
1487 ++c; |
|
1488 } |
|
1489 } |
|
1490 |
|
1491 int |
|
1492 SECU_PrintDumpDerIssuerAndSerial(FILE *out, SECItem *der, char *m, |
|
1493 int level) |
|
1494 { |
|
1495 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1496 CERTCertificate *c; |
|
1497 int rv = SEC_ERROR_NO_MEMORY; |
|
1498 char *derIssuerB64; |
|
1499 char *derSerialB64; |
|
1500 |
|
1501 if (!arena) |
|
1502 return rv; |
|
1503 |
|
1504 /* Decode certificate */ |
|
1505 c = PORT_ArenaZNew(arena, CERTCertificate); |
|
1506 if (!c) |
|
1507 goto loser; |
|
1508 c->arena = arena; |
|
1509 rv = SEC_ASN1DecodeItem(arena, c, |
|
1510 SEC_ASN1_GET(CERT_CertificateTemplate), der); |
|
1511 if (rv) { |
|
1512 SECU_PrintErrMsg(out, 0, "Error", "Parsing extension"); |
|
1513 goto loser; |
|
1514 } |
|
1515 |
|
1516 SECU_PrintName(out, &c->subject, "Subject", 0); |
|
1517 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ |
|
1518 SECU_Newline(out); |
|
1519 SECU_PrintName(out, &c->issuer, "Issuer", 0); |
|
1520 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ |
|
1521 SECU_Newline(out); |
|
1522 SECU_PrintInteger(out, &c->serialNumber, "Serial Number", 0); |
|
1523 |
|
1524 derIssuerB64 = BTOA_ConvertItemToAscii(&c->derIssuer); |
|
1525 derSerialB64 = BTOA_ConvertItemToAscii(&c->serialNumber); |
|
1526 |
|
1527 fprintf(out, "Issuer DER Base64:\n"); |
|
1528 if (SECU_GetWrapEnabled()) { |
|
1529 fprintf(out, "%s\n", derIssuerB64); |
|
1530 } else { |
|
1531 printStringWithoutCRLF(out, derIssuerB64); |
|
1532 fputs("\n", out); |
|
1533 } |
|
1534 |
|
1535 fprintf(out, "Serial DER Base64:\n"); |
|
1536 if (SECU_GetWrapEnabled()) { |
|
1537 fprintf(out, "%s\n", derSerialB64); |
|
1538 } else { |
|
1539 printStringWithoutCRLF(out, derSerialB64); |
|
1540 fputs("\n", out); |
|
1541 } |
|
1542 |
|
1543 PORT_Free(derIssuerB64); |
|
1544 PORT_Free(derSerialB64); |
|
1545 |
|
1546 fprintf(out, "Serial DER as C source: \n{ %d, \"", c->serialNumber.len); |
|
1547 |
|
1548 { |
|
1549 int i; |
|
1550 for (i=0; i < c->serialNumber.len; ++i) { |
|
1551 unsigned char *chardata = (unsigned char*)(c->serialNumber.data); |
|
1552 unsigned char c = *(chardata + i); |
|
1553 |
|
1554 fprintf(out, "\\x%02x", c); |
|
1555 } |
|
1556 fprintf(out, "\" }\n"); |
|
1557 } |
|
1558 |
|
1559 loser: |
|
1560 PORT_FreeArena(arena, PR_FALSE); |
|
1561 return rv; |
|
1562 } |
|
1563 |
|
1564 static SECStatus |
|
1565 secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level) |
|
1566 { |
|
1567 SECItem decodedValue; |
|
1568 SECStatus rv; |
|
1569 PRTime invalidTime; |
|
1570 char *formattedTime = NULL; |
|
1571 |
|
1572 decodedValue.data = NULL; |
|
1573 rv = SEC_ASN1DecodeItem (NULL, &decodedValue, |
|
1574 SEC_ASN1_GET(SEC_GeneralizedTimeTemplate), |
|
1575 value); |
|
1576 if (rv == SECSuccess) { |
|
1577 rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue); |
|
1578 if (rv == SECSuccess) { |
|
1579 formattedTime = CERT_GenTime2FormattedAscii |
|
1580 (invalidTime, "%a %b %d %H:%M:%S %Y"); |
|
1581 SECU_Indent(out, level +1); |
|
1582 fprintf (out, "%s: %s\n", msg, formattedTime); |
|
1583 PORT_Free (formattedTime); |
|
1584 } |
|
1585 } |
|
1586 PORT_Free (decodedValue.data); |
|
1587 return (rv); |
|
1588 } |
|
1589 |
|
1590 static SECStatus |
|
1591 PrintExtKeyUsageExtension (FILE *out, SECItem *value, char *msg, int level) |
|
1592 { |
|
1593 CERTOidSequence *os; |
|
1594 SECItem **op; |
|
1595 |
|
1596 os = CERT_DecodeOidSequence(value); |
|
1597 if( (CERTOidSequence *)NULL == os ) { |
|
1598 return SECFailure; |
|
1599 } |
|
1600 |
|
1601 for( op = os->oids; *op; op++ ) { |
|
1602 SECU_PrintObjectID(out, *op, msg, level + 1); |
|
1603 } |
|
1604 CERT_DestroyOidSequence(os); |
|
1605 return SECSuccess; |
|
1606 } |
|
1607 |
|
1608 static SECStatus |
|
1609 secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) { |
|
1610 CERTBasicConstraints constraints; |
|
1611 SECStatus rv; |
|
1612 |
|
1613 SECU_Indent(out, level); |
|
1614 if (msg) { |
|
1615 fprintf(out,"%s: ",msg); |
|
1616 } |
|
1617 rv = CERT_DecodeBasicConstraintValue(&constraints,value); |
|
1618 if (rv == SECSuccess && constraints.isCA) { |
|
1619 if (constraints.pathLenConstraint >= 0) { |
|
1620 fprintf(out,"Is a CA with a maximum path length of %d.\n", |
|
1621 constraints.pathLenConstraint); |
|
1622 } else { |
|
1623 fprintf(out,"Is a CA with no maximum path length.\n"); |
|
1624 } |
|
1625 } else { |
|
1626 fprintf(out,"Is not a CA.\n"); |
|
1627 } |
|
1628 return SECSuccess; |
|
1629 } |
|
1630 |
|
1631 static const char * const nsTypeBits[] = { |
|
1632 "SSL Client", |
|
1633 "SSL Server", |
|
1634 "S/MIME", |
|
1635 "Object Signing", |
|
1636 "Reserved", |
|
1637 "SSL CA", |
|
1638 "S/MIME CA", |
|
1639 "ObjectSigning CA" |
|
1640 }; |
|
1641 |
|
1642 /* NSCertType is merely a bit string whose bits are displayed symbolically */ |
|
1643 static SECStatus |
|
1644 secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) |
|
1645 { |
|
1646 int unused; |
|
1647 int NS_Type; |
|
1648 int i; |
|
1649 int found = 0; |
|
1650 SECItem my = *value; |
|
1651 |
|
1652 if ((my.data[0] != SEC_ASN1_BIT_STRING) || |
|
1653 SECSuccess != SECU_StripTagAndLength(&my)) { |
|
1654 SECU_PrintAny(out, value, "Data", level); |
|
1655 return SECSuccess; |
|
1656 } |
|
1657 |
|
1658 unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0; |
|
1659 NS_Type = my.data[1] & (0xff << unused); |
|
1660 |
|
1661 |
|
1662 SECU_Indent(out, level); |
|
1663 if (msg) { |
|
1664 fprintf(out,"%s: ",msg); |
|
1665 } else { |
|
1666 fprintf(out,"Netscape Certificate Type: "); |
|
1667 } |
|
1668 for (i=0; i < 8; i++) { |
|
1669 if ( (0x80 >> i) & NS_Type) { |
|
1670 fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]); |
|
1671 found = 1; |
|
1672 } |
|
1673 } |
|
1674 fprintf(out, (found ? ">\n" : "none\n")); |
|
1675 return SECSuccess; |
|
1676 } |
|
1677 |
|
1678 static const char * const usageBits[] = { |
|
1679 "Digital Signature", /* 0x80 */ |
|
1680 "Non-Repudiation", /* 0x40 */ |
|
1681 "Key Encipherment", /* 0x20 */ |
|
1682 "Data Encipherment", /* 0x10 */ |
|
1683 "Key Agreement", /* 0x08 */ |
|
1684 "Certificate Signing", /* 0x04 */ |
|
1685 "CRL Signing", /* 0x02 */ |
|
1686 "Encipher Only", /* 0x01 */ |
|
1687 "Decipher Only", /* 0x0080 */ |
|
1688 NULL |
|
1689 }; |
|
1690 |
|
1691 /* X509KeyUsage is merely a bit string whose bits are displayed symbolically */ |
|
1692 static void |
|
1693 secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level) |
|
1694 { |
|
1695 int unused; |
|
1696 int usage; |
|
1697 int i; |
|
1698 int found = 0; |
|
1699 SECItem my = *value; |
|
1700 |
|
1701 if ((my.data[0] != SEC_ASN1_BIT_STRING) || |
|
1702 SECSuccess != SECU_StripTagAndLength(&my)) { |
|
1703 SECU_PrintAny(out, value, "Data", level); |
|
1704 return; |
|
1705 } |
|
1706 |
|
1707 unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0; |
|
1708 usage = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8 |
|
1709 : (my.data[1] << 8) | |
|
1710 (my.data[2] & (0xff << unused)); |
|
1711 |
|
1712 SECU_Indent(out, level); |
|
1713 fprintf(out, "Usages: "); |
|
1714 for (i=0; usageBits[i]; i++) { |
|
1715 if ( (0x8000 >> i) & usage) { |
|
1716 if (found) |
|
1717 SECU_Indent(out, level + 2); |
|
1718 fprintf(out, "%s\n", usageBits[i]); |
|
1719 found = 1; |
|
1720 } |
|
1721 } |
|
1722 if (!found) { |
|
1723 fprintf(out, "(none)\n"); |
|
1724 } |
|
1725 } |
|
1726 |
|
1727 static void |
|
1728 secu_PrintIPAddress(FILE *out, SECItem *value, char *msg, int level) |
|
1729 { |
|
1730 PRStatus st; |
|
1731 PRNetAddr addr; |
|
1732 char addrBuf[80]; |
|
1733 |
|
1734 memset(&addr, 0, sizeof addr); |
|
1735 if (value->len == 4) { |
|
1736 addr.inet.family = PR_AF_INET; |
|
1737 memcpy(&addr.inet.ip, value->data, value->len); |
|
1738 } else if (value->len == 16) { |
|
1739 addr.ipv6.family = PR_AF_INET6; |
|
1740 memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len); |
|
1741 if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { |
|
1742 /* convert to IPv4. */ |
|
1743 addr.inet.family = PR_AF_INET; |
|
1744 memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4); |
|
1745 memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad); |
|
1746 } |
|
1747 } else { |
|
1748 goto loser; |
|
1749 } |
|
1750 |
|
1751 st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf); |
|
1752 if (st == PR_SUCCESS) { |
|
1753 SECU_Indent(out, level); |
|
1754 fprintf(out, "%s: %s\n", msg, addrBuf); |
|
1755 } else { |
|
1756 loser: |
|
1757 SECU_PrintAsHex(out, value, msg, level); |
|
1758 } |
|
1759 } |
|
1760 |
|
1761 |
|
1762 static void |
|
1763 secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, char *msg, int level) |
|
1764 { |
|
1765 char label[40]; |
|
1766 if (msg && msg[0]) { |
|
1767 SECU_Indent(out, level++); fprintf(out, "%s: \n", msg); |
|
1768 } |
|
1769 switch (gname->type) { |
|
1770 case certOtherName : |
|
1771 SECU_PrintAny( out, &gname->name.OthName.name, "Other Name", level); |
|
1772 SECU_PrintObjectID(out, &gname->name.OthName.oid, "OID", level+1); |
|
1773 break; |
|
1774 case certDirectoryName : |
|
1775 SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level); |
|
1776 break; |
|
1777 case certRFC822Name : |
|
1778 secu_PrintRawString( out, &gname->name.other, "RFC822 Name", level); |
|
1779 break; |
|
1780 case certDNSName : |
|
1781 secu_PrintRawString( out, &gname->name.other, "DNS name", level); |
|
1782 break; |
|
1783 case certURI : |
|
1784 secu_PrintRawString( out, &gname->name.other, "URI", level); |
|
1785 break; |
|
1786 case certIPAddress : |
|
1787 secu_PrintIPAddress(out, &gname->name.other, "IP Address", level); |
|
1788 break; |
|
1789 case certRegisterID : |
|
1790 SECU_PrintObjectID( out, &gname->name.other, "Registered ID", level); |
|
1791 break; |
|
1792 case certX400Address : |
|
1793 SECU_PrintAny( out, &gname->name.other, "X400 Address", level); |
|
1794 break; |
|
1795 case certEDIPartyName : |
|
1796 SECU_PrintAny( out, &gname->name.other, "EDI Party", level); |
|
1797 break; |
|
1798 default: |
|
1799 PR_snprintf(label, sizeof label, "unknown type [%d]", |
|
1800 (int)gname->type - 1); |
|
1801 SECU_PrintAsHex(out, &gname->name.other, label, level); |
|
1802 break; |
|
1803 } |
|
1804 } |
|
1805 |
|
1806 static void |
|
1807 secu_PrintGeneralNames(FILE *out, CERTGeneralName *gname, char *msg, int level) |
|
1808 { |
|
1809 CERTGeneralName *name = gname; |
|
1810 do { |
|
1811 secu_PrintGeneralName(out, name, msg, level); |
|
1812 name = CERT_GetNextGeneralName(name); |
|
1813 } while (name && name != gname); |
|
1814 } |
|
1815 |
|
1816 |
|
1817 static void |
|
1818 secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level) |
|
1819 { |
|
1820 CERTAuthKeyID *kid = NULL; |
|
1821 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1822 |
|
1823 if (!pool) { |
|
1824 SECU_PrintError("Error", "Allocating new ArenaPool"); |
|
1825 return; |
|
1826 } |
|
1827 kid = CERT_DecodeAuthKeyID(pool, value); |
|
1828 if (!kid) { |
|
1829 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); |
|
1830 SECU_PrintAny(out, value, "Data", level); |
|
1831 } else { |
|
1832 int keyIDPresent = (kid->keyID.data && kid->keyID.len); |
|
1833 int issuerPresent = kid->authCertIssuer != NULL; |
|
1834 int snPresent = (kid->authCertSerialNumber.data && |
|
1835 kid->authCertSerialNumber.len); |
|
1836 |
|
1837 if (keyIDPresent) |
|
1838 SECU_PrintAsHex(out, &kid->keyID, "Key ID", level); |
|
1839 if (issuerPresent) |
|
1840 secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level); |
|
1841 if (snPresent) |
|
1842 SECU_PrintInteger(out, &kid->authCertSerialNumber, |
|
1843 "Serial Number", level); |
|
1844 } |
|
1845 PORT_FreeArena(pool, PR_FALSE); |
|
1846 } |
|
1847 |
|
1848 |
|
1849 static void |
|
1850 secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level) |
|
1851 { |
|
1852 CERTGeneralName * nameList; |
|
1853 CERTGeneralName * current; |
|
1854 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1855 |
|
1856 if (!pool) { |
|
1857 SECU_PrintError("Error", "Allocating new ArenaPool"); |
|
1858 return; |
|
1859 } |
|
1860 nameList = current = CERT_DecodeAltNameExtension(pool, value); |
|
1861 if (!current) { |
|
1862 if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) { |
|
1863 /* Decoder found empty sequence, which is invalid. */ |
|
1864 PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
1865 } |
|
1866 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); |
|
1867 SECU_PrintAny(out, value, "Data", level); |
|
1868 } else { |
|
1869 do { |
|
1870 secu_PrintGeneralName(out, current, msg, level); |
|
1871 current = CERT_GetNextGeneralName(current); |
|
1872 } while (current != nameList); |
|
1873 } |
|
1874 PORT_FreeArena(pool, PR_FALSE); |
|
1875 } |
|
1876 |
|
1877 static void |
|
1878 secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level) |
|
1879 { |
|
1880 CERTCrlDistributionPoints * dPoints; |
|
1881 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1882 |
|
1883 if (!pool) { |
|
1884 SECU_PrintError("Error", "Allocating new ArenaPool"); |
|
1885 return; |
|
1886 } |
|
1887 dPoints = CERT_DecodeCRLDistributionPoints(pool, value); |
|
1888 if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) { |
|
1889 CRLDistributionPoint ** pPoints = dPoints->distPoints; |
|
1890 CRLDistributionPoint * pPoint; |
|
1891 while (NULL != (pPoint = *pPoints++)) { |
|
1892 SECU_Indent(out, level); fputs("Distribution point:\n", out); |
|
1893 if (pPoint->distPointType == generalName && |
|
1894 pPoint->distPoint.fullName != NULL) { |
|
1895 secu_PrintGeneralNames(out, pPoint->distPoint.fullName, NULL, |
|
1896 level + 1); |
|
1897 } else if (pPoint->distPointType == relativeDistinguishedName && |
|
1898 pPoint->distPoint.relativeName.avas) { |
|
1899 SECU_PrintRDN(out, &pPoint->distPoint.relativeName, "RDN", |
|
1900 level + 1); |
|
1901 } else if (pPoint->derDistPoint.data) { |
|
1902 SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level + 1); |
|
1903 } |
|
1904 if (pPoint->reasons.data) { |
|
1905 secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons", |
|
1906 level + 1); |
|
1907 } |
|
1908 if (pPoint->crlIssuer) { |
|
1909 secu_PrintGeneralName(out, pPoint->crlIssuer, "CRL issuer", |
|
1910 level + 1); |
|
1911 } |
|
1912 } |
|
1913 } else { |
|
1914 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); |
|
1915 SECU_PrintAny(out, value, "Data", level); |
|
1916 } |
|
1917 PORT_FreeArena(pool, PR_FALSE); |
|
1918 } |
|
1919 |
|
1920 |
|
1921 static void |
|
1922 secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value, |
|
1923 char *msg, int level) |
|
1924 { |
|
1925 CERTNameConstraint *head = value; |
|
1926 SECU_Indent(out, level); fprintf(out, "%s Subtree:\n", msg); |
|
1927 level++; |
|
1928 do { |
|
1929 secu_PrintGeneralName(out, &value->name, NULL, level); |
|
1930 if (value->min.data) |
|
1931 SECU_PrintInteger(out, &value->min, "Minimum", level+1); |
|
1932 if (value->max.data) |
|
1933 SECU_PrintInteger(out, &value->max, "Maximum", level+1); |
|
1934 value = CERT_GetNextNameConstraint(value); |
|
1935 } while (value != head); |
|
1936 } |
|
1937 |
|
1938 static void |
|
1939 secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, char *msg, int level) |
|
1940 { |
|
1941 CERTNameConstraints * cnstrnts; |
|
1942 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1943 |
|
1944 if (!pool) { |
|
1945 SECU_PrintError("Error", "Allocating new ArenaPool"); |
|
1946 return; |
|
1947 } |
|
1948 cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value); |
|
1949 if (!cnstrnts) { |
|
1950 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); |
|
1951 SECU_PrintAny(out, value, "Raw", level); |
|
1952 } else { |
|
1953 if (cnstrnts->permited) |
|
1954 secu_PrintNameConstraintSubtree(out, cnstrnts->permited, |
|
1955 "Permitted", level); |
|
1956 if (cnstrnts->excluded) |
|
1957 secu_PrintNameConstraintSubtree(out, cnstrnts->excluded, |
|
1958 "Excluded", level); |
|
1959 } |
|
1960 PORT_FreeArena(pool, PR_FALSE); |
|
1961 } |
|
1962 |
|
1963 |
|
1964 static void |
|
1965 secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level) |
|
1966 { |
|
1967 CERTAuthInfoAccess **infos = NULL; |
|
1968 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
1969 |
|
1970 if (!pool) { |
|
1971 SECU_PrintError("Error", "Allocating new ArenaPool"); |
|
1972 return; |
|
1973 } |
|
1974 infos = CERT_DecodeAuthInfoAccessExtension(pool, value); |
|
1975 if (!infos) { |
|
1976 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); |
|
1977 SECU_PrintAny(out, value, "Raw", level); |
|
1978 } else { |
|
1979 CERTAuthInfoAccess *info; |
|
1980 while (NULL != (info = *infos++)) { |
|
1981 if (info->method.data) { |
|
1982 SECU_PrintObjectID(out, &info->method, "Method", level); |
|
1983 } else { |
|
1984 SECU_Indent(out,level); |
|
1985 fprintf(out, "Error: missing method\n"); |
|
1986 } |
|
1987 if (info->location) { |
|
1988 secu_PrintGeneralName(out, info->location, "Location", level); |
|
1989 } else { |
|
1990 SECU_PrintAny(out, &info->derLocation, "Location", level); |
|
1991 } |
|
1992 } |
|
1993 } |
|
1994 PORT_FreeArena(pool, PR_FALSE); |
|
1995 } |
|
1996 |
|
1997 |
|
1998 void |
|
1999 SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, |
|
2000 char *msg, int level) |
|
2001 { |
|
2002 SECOidTag oidTag; |
|
2003 |
|
2004 if ( extensions ) { |
|
2005 if (msg && *msg) { |
|
2006 SECU_Indent(out, level++); fprintf(out, "%s:\n", msg); |
|
2007 } |
|
2008 |
|
2009 while ( *extensions ) { |
|
2010 SECItem *tmpitem; |
|
2011 |
|
2012 tmpitem = &(*extensions)->id; |
|
2013 SECU_PrintObjectID(out, tmpitem, "Name", level); |
|
2014 |
|
2015 tmpitem = &(*extensions)->critical; |
|
2016 if ( tmpitem->len ) { |
|
2017 secu_PrintBoolean(out, tmpitem, "Critical", level); |
|
2018 } |
|
2019 |
|
2020 oidTag = SECOID_FindOIDTag (&((*extensions)->id)); |
|
2021 tmpitem = &((*extensions)->value); |
|
2022 |
|
2023 switch (oidTag) { |
|
2024 case SEC_OID_X509_INVALID_DATE: |
|
2025 case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME: |
|
2026 secu_PrintX509InvalidDate(out, tmpitem, "Date", level ); |
|
2027 break; |
|
2028 case SEC_OID_X509_CERTIFICATE_POLICIES: |
|
2029 SECU_PrintPolicy(out, tmpitem, "Data", level ); |
|
2030 break; |
|
2031 case SEC_OID_NS_CERT_EXT_BASE_URL: |
|
2032 case SEC_OID_NS_CERT_EXT_REVOCATION_URL: |
|
2033 case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: |
|
2034 case SEC_OID_NS_CERT_EXT_CA_CRL_URL: |
|
2035 case SEC_OID_NS_CERT_EXT_CA_CERT_URL: |
|
2036 case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: |
|
2037 case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: |
|
2038 case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL: |
|
2039 case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: |
|
2040 case SEC_OID_OCSP_RESPONDER: |
|
2041 SECU_PrintString(out,tmpitem, "URL", level); |
|
2042 break; |
|
2043 case SEC_OID_NS_CERT_EXT_COMMENT: |
|
2044 SECU_PrintString(out,tmpitem, "Comment", level); |
|
2045 break; |
|
2046 case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: |
|
2047 SECU_PrintString(out,tmpitem, "ServerName", level); |
|
2048 break; |
|
2049 case SEC_OID_NS_CERT_EXT_CERT_TYPE: |
|
2050 secu_PrintNSCertType(out,tmpitem,"Data",level); |
|
2051 break; |
|
2052 case SEC_OID_X509_BASIC_CONSTRAINTS: |
|
2053 secu_PrintBasicConstraints(out,tmpitem,"Data",level); |
|
2054 break; |
|
2055 case SEC_OID_X509_EXT_KEY_USAGE: |
|
2056 PrintExtKeyUsageExtension(out, tmpitem, NULL, level); |
|
2057 break; |
|
2058 case SEC_OID_X509_KEY_USAGE: |
|
2059 secu_PrintX509KeyUsage(out, tmpitem, NULL, level ); |
|
2060 break; |
|
2061 case SEC_OID_X509_AUTH_KEY_ID: |
|
2062 secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level ); |
|
2063 break; |
|
2064 case SEC_OID_X509_SUBJECT_ALT_NAME: |
|
2065 case SEC_OID_X509_ISSUER_ALT_NAME: |
|
2066 secu_PrintAltNameExtension(out, tmpitem, NULL, level ); |
|
2067 break; |
|
2068 case SEC_OID_X509_CRL_DIST_POINTS: |
|
2069 secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level ); |
|
2070 break; |
|
2071 case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD: |
|
2072 SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL, |
|
2073 level ); |
|
2074 break; |
|
2075 case SEC_OID_X509_NAME_CONSTRAINTS: |
|
2076 secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level); |
|
2077 break; |
|
2078 case SEC_OID_X509_AUTH_INFO_ACCESS: |
|
2079 secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level); |
|
2080 break; |
|
2081 |
|
2082 case SEC_OID_X509_CRL_NUMBER: |
|
2083 case SEC_OID_X509_REASON_CODE: |
|
2084 |
|
2085 /* PKIX OIDs */ |
|
2086 case SEC_OID_PKIX_OCSP: |
|
2087 case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: |
|
2088 case SEC_OID_PKIX_OCSP_NONCE: |
|
2089 case SEC_OID_PKIX_OCSP_CRL: |
|
2090 case SEC_OID_PKIX_OCSP_RESPONSE: |
|
2091 case SEC_OID_PKIX_OCSP_NO_CHECK: |
|
2092 case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF: |
|
2093 case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR: |
|
2094 case SEC_OID_PKIX_REGCTRL_REGTOKEN: |
|
2095 case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR: |
|
2096 case SEC_OID_PKIX_REGCTRL_PKIPUBINFO: |
|
2097 case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: |
|
2098 case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID: |
|
2099 case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY: |
|
2100 case SEC_OID_PKIX_REGINFO_UTF8_PAIRS: |
|
2101 case SEC_OID_PKIX_REGINFO_CERT_REQUEST: |
|
2102 |
|
2103 /* Netscape extension OIDs. */ |
|
2104 case SEC_OID_NS_CERT_EXT_NETSCAPE_OK: |
|
2105 case SEC_OID_NS_CERT_EXT_ISSUER_LOGO: |
|
2106 case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO: |
|
2107 case SEC_OID_NS_CERT_EXT_ENTITY_LOGO: |
|
2108 case SEC_OID_NS_CERT_EXT_USER_PICTURE: |
|
2109 |
|
2110 /* x.509 v3 Extensions */ |
|
2111 case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: |
|
2112 case SEC_OID_X509_SUBJECT_KEY_ID: |
|
2113 case SEC_OID_X509_POLICY_MAPPINGS: |
|
2114 case SEC_OID_X509_POLICY_CONSTRAINTS: |
|
2115 |
|
2116 |
|
2117 default: |
|
2118 SECU_PrintAny(out, tmpitem, "Data", level); |
|
2119 break; |
|
2120 } |
|
2121 |
|
2122 SECU_Newline(out); |
|
2123 extensions++; |
|
2124 } |
|
2125 } |
|
2126 } |
|
2127 |
|
2128 /* An RDN is a subset of a DirectoryName, and we already know how to |
|
2129 * print those, so make a directory name out of the RDN, and print it. |
|
2130 */ |
|
2131 void |
|
2132 SECU_PrintRDN(FILE *out, CERTRDN *rdn, const char *msg, int level) |
|
2133 { |
|
2134 CERTName name; |
|
2135 CERTRDN *rdns[2]; |
|
2136 |
|
2137 name.arena = NULL; |
|
2138 name.rdns = rdns; |
|
2139 rdns[0] = rdn; |
|
2140 rdns[1] = NULL; |
|
2141 SECU_PrintName(out, &name, msg, level); |
|
2142 } |
|
2143 |
|
2144 void |
|
2145 SECU_PrintNameQuotesOptional(FILE *out, CERTName *name, const char *msg, |
|
2146 int level, PRBool quotes) |
|
2147 { |
|
2148 char *nameStr = NULL; |
|
2149 char *str; |
|
2150 SECItem my; |
|
2151 |
|
2152 if (!name) { |
|
2153 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
2154 return; |
|
2155 } |
|
2156 if (!name->rdns || !name->rdns[0]) { |
|
2157 str = "(empty)"; |
|
2158 } else { |
|
2159 str = nameStr = CERT_NameToAscii(name); |
|
2160 } |
|
2161 if (!str) { |
|
2162 str = "!Invalid AVA!"; |
|
2163 } |
|
2164 my.data = (unsigned char *)str; |
|
2165 my.len = PORT_Strlen(str); |
|
2166 #if 1 |
|
2167 secu_PrintRawStringQuotesOptional(out, &my, msg, level, quotes); |
|
2168 #else |
|
2169 SECU_Indent(out, level); fprintf(out, "%s: ", msg); |
|
2170 fprintf(out, str); |
|
2171 SECU_Newline(out); |
|
2172 #endif |
|
2173 PORT_Free(nameStr); |
|
2174 } |
|
2175 |
|
2176 void |
|
2177 SECU_PrintName(FILE *out, CERTName *name, const char *msg, int level) |
|
2178 { |
|
2179 SECU_PrintNameQuotesOptional(out, name, msg, level, PR_TRUE); |
|
2180 } |
|
2181 |
|
2182 void |
|
2183 printflags(char *trusts, unsigned int flags) |
|
2184 { |
|
2185 if (flags & CERTDB_VALID_CA) |
|
2186 if (!(flags & CERTDB_TRUSTED_CA) && |
|
2187 !(flags & CERTDB_TRUSTED_CLIENT_CA)) |
|
2188 PORT_Strcat(trusts, "c"); |
|
2189 if (flags & CERTDB_TERMINAL_RECORD) |
|
2190 if (!(flags & CERTDB_TRUSTED)) |
|
2191 PORT_Strcat(trusts, "p"); |
|
2192 if (flags & CERTDB_TRUSTED_CA) |
|
2193 PORT_Strcat(trusts, "C"); |
|
2194 if (flags & CERTDB_TRUSTED_CLIENT_CA) |
|
2195 PORT_Strcat(trusts, "T"); |
|
2196 if (flags & CERTDB_TRUSTED) |
|
2197 PORT_Strcat(trusts, "P"); |
|
2198 if (flags & CERTDB_USER) |
|
2199 PORT_Strcat(trusts, "u"); |
|
2200 if (flags & CERTDB_SEND_WARN) |
|
2201 PORT_Strcat(trusts, "w"); |
|
2202 if (flags & CERTDB_INVISIBLE_CA) |
|
2203 PORT_Strcat(trusts, "I"); |
|
2204 if (flags & CERTDB_GOVT_APPROVED_CA) |
|
2205 PORT_Strcat(trusts, "G"); |
|
2206 return; |
|
2207 } |
|
2208 |
|
2209 /* callback for listing certs through pkcs11 */ |
|
2210 SECStatus |
|
2211 SECU_PrintCertNickname(CERTCertListNode *node, void *data) |
|
2212 { |
|
2213 CERTCertTrust trust; |
|
2214 CERTCertificate* cert; |
|
2215 FILE *out; |
|
2216 char trusts[30]; |
|
2217 char *name; |
|
2218 |
|
2219 cert = node->cert; |
|
2220 |
|
2221 PORT_Memset (trusts, 0, sizeof (trusts)); |
|
2222 out = (FILE *)data; |
|
2223 |
|
2224 name = node->appData; |
|
2225 if (!name || !name[0]) { |
|
2226 name = cert->nickname; |
|
2227 } |
|
2228 if (!name || !name[0]) { |
|
2229 name = cert->emailAddr; |
|
2230 } |
|
2231 if (!name || !name[0]) { |
|
2232 name = "(NULL)"; |
|
2233 } |
|
2234 |
|
2235 if (CERT_GetCertTrust(cert, &trust) == SECSuccess) { |
|
2236 printflags(trusts, trust.sslFlags); |
|
2237 PORT_Strcat(trusts, ","); |
|
2238 printflags(trusts, trust.emailFlags); |
|
2239 PORT_Strcat(trusts, ","); |
|
2240 printflags(trusts, trust.objectSigningFlags); |
|
2241 } else { |
|
2242 PORT_Memcpy(trusts,",,",3); |
|
2243 } |
|
2244 fprintf(out, "%-60s %-5s\n", name, trusts); |
|
2245 |
|
2246 return (SECSuccess); |
|
2247 } |
|
2248 |
|
2249 int |
|
2250 SECU_DecodeAndPrintExtensions(FILE *out, SECItem *any, char *m, int level) |
|
2251 { |
|
2252 CERTCertExtension **extensions = NULL; |
|
2253 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
2254 int rv = 0; |
|
2255 |
|
2256 if (!arena) |
|
2257 return SEC_ERROR_NO_MEMORY; |
|
2258 |
|
2259 rv = SEC_QuickDERDecodeItem(arena, &extensions, |
|
2260 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), any); |
|
2261 if (!rv) |
|
2262 SECU_PrintExtensions(out, extensions, m, level); |
|
2263 else |
|
2264 SECU_PrintAny(out, any, m, level); |
|
2265 PORT_FreeArena(arena, PR_FALSE); |
|
2266 return rv; |
|
2267 } |
|
2268 |
|
2269 /* print a decoded SET OF or SEQUENCE OF Extensions */ |
|
2270 int |
|
2271 SECU_PrintSetOfExtensions(FILE *out, SECItem **any, char *m, int level) |
|
2272 { |
|
2273 int rv = 0; |
|
2274 if (m && *m) { |
|
2275 SECU_Indent(out, level++); fprintf(out, "%s:\n", m); |
|
2276 } |
|
2277 while (any && any[0]) { |
|
2278 rv |= SECU_DecodeAndPrintExtensions(out, any[0], "", level); |
|
2279 any++; |
|
2280 } |
|
2281 return rv; |
|
2282 } |
|
2283 |
|
2284 /* print a decoded SET OF or SEQUENCE OF "ANY" */ |
|
2285 int |
|
2286 SECU_PrintSetOfAny(FILE *out, SECItem **any, char *m, int level) |
|
2287 { |
|
2288 int rv = 0; |
|
2289 if (m && *m) { |
|
2290 SECU_Indent(out, level++); fprintf(out, "%s:\n", m); |
|
2291 } |
|
2292 while (any && any[0]) { |
|
2293 SECU_PrintAny(out, any[0], "", level); |
|
2294 any++; |
|
2295 } |
|
2296 return rv; |
|
2297 } |
|
2298 |
|
2299 int |
|
2300 SECU_PrintCertAttribute(FILE *out, CERTAttribute *attr, char *m, int level) |
|
2301 { |
|
2302 int rv = 0; |
|
2303 SECOidTag tag; |
|
2304 tag = SECU_PrintObjectID(out, &attr->attrType, "Attribute Type", level); |
|
2305 if (tag == SEC_OID_PKCS9_EXTENSION_REQUEST) { |
|
2306 rv = SECU_PrintSetOfExtensions(out, attr->attrValue, "Extensions", level); |
|
2307 } else { |
|
2308 rv = SECU_PrintSetOfAny(out, attr->attrValue, "Attribute Values", level); |
|
2309 } |
|
2310 return rv; |
|
2311 } |
|
2312 |
|
2313 int |
|
2314 SECU_PrintCertAttributes(FILE *out, CERTAttribute **attrs, char *m, int level) |
|
2315 { |
|
2316 int rv = 0; |
|
2317 while (attrs[0]) { |
|
2318 rv |= SECU_PrintCertAttribute(out, attrs[0], m, level+1); |
|
2319 attrs++; |
|
2320 } |
|
2321 return rv; |
|
2322 } |
|
2323 |
|
2324 int /* sometimes a PRErrorCode, other times a SECStatus. Sigh. */ |
|
2325 SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, int level) |
|
2326 { |
|
2327 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
2328 CERTCertificateRequest *cr; |
|
2329 int rv = SEC_ERROR_NO_MEMORY; |
|
2330 |
|
2331 if (!arena) |
|
2332 return rv; |
|
2333 |
|
2334 /* Decode certificate request */ |
|
2335 cr = PORT_ArenaZNew(arena, CERTCertificateRequest); |
|
2336 if (!cr) |
|
2337 goto loser; |
|
2338 cr->arena = arena; |
|
2339 rv = SEC_QuickDERDecodeItem(arena, cr, |
|
2340 SEC_ASN1_GET(CERT_CertificateRequestTemplate), der); |
|
2341 if (rv) |
|
2342 goto loser; |
|
2343 |
|
2344 /* Pretty print it out */ |
|
2345 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2346 SECU_PrintInteger(out, &cr->version, "Version", level+1); |
|
2347 SECU_PrintName(out, &cr->subject, "Subject", level+1); |
|
2348 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ |
|
2349 SECU_Newline(out); |
|
2350 secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo, |
|
2351 "Subject Public Key Info", level+1); |
|
2352 if (cr->attributes) |
|
2353 SECU_PrintCertAttributes(out, cr->attributes, "Attributes", level+1); |
|
2354 rv = 0; |
|
2355 loser: |
|
2356 PORT_FreeArena(arena, PR_FALSE); |
|
2357 return rv; |
|
2358 } |
|
2359 |
|
2360 int |
|
2361 SECU_PrintCertificate(FILE *out, const SECItem *der, const char *m, int level) |
|
2362 { |
|
2363 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
2364 CERTCertificate *c; |
|
2365 int rv = SEC_ERROR_NO_MEMORY; |
|
2366 int iv; |
|
2367 |
|
2368 if (!arena) |
|
2369 return rv; |
|
2370 |
|
2371 /* Decode certificate */ |
|
2372 c = PORT_ArenaZNew(arena, CERTCertificate); |
|
2373 if (!c) |
|
2374 goto loser; |
|
2375 c->arena = arena; |
|
2376 rv = SEC_ASN1DecodeItem(arena, c, |
|
2377 SEC_ASN1_GET(CERT_CertificateTemplate), der); |
|
2378 if (rv) { |
|
2379 SECU_Indent(out, level); |
|
2380 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); |
|
2381 SECU_PrintAny(out, der, "Raw", level); |
|
2382 goto loser; |
|
2383 } |
|
2384 /* Pretty print it out */ |
|
2385 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2386 iv = c->version.len ? DER_GetInteger(&c->version) : 0; /* version is optional */ |
|
2387 SECU_Indent(out, level+1); fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); |
|
2388 |
|
2389 SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level+1); |
|
2390 SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level+1); |
|
2391 SECU_PrintName(out, &c->issuer, "Issuer", level+1); |
|
2392 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ |
|
2393 SECU_Newline(out); |
|
2394 secu_PrintValidity(out, &c->validity, "Validity", level+1); |
|
2395 SECU_PrintName(out, &c->subject, "Subject", level+1); |
|
2396 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ |
|
2397 SECU_Newline(out); |
|
2398 secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, |
|
2399 "Subject Public Key Info", level+1); |
|
2400 if (c->issuerID.data) |
|
2401 secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level+1); |
|
2402 if (c->subjectID.data) |
|
2403 secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level+1); |
|
2404 SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1); |
|
2405 loser: |
|
2406 PORT_FreeArena(arena, PR_FALSE); |
|
2407 return rv; |
|
2408 } |
|
2409 |
|
2410 int |
|
2411 SECU_PrintSubjectPublicKeyInfo(FILE *out, SECItem *der, char *m, int level) |
|
2412 { |
|
2413 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
2414 int rv = SEC_ERROR_NO_MEMORY; |
|
2415 CERTSubjectPublicKeyInfo spki; |
|
2416 |
|
2417 if (!arena) |
|
2418 return rv; |
|
2419 |
|
2420 PORT_Memset(&spki, 0, sizeof spki); |
|
2421 rv = SEC_ASN1DecodeItem(arena, &spki, |
|
2422 SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate), |
|
2423 der); |
|
2424 if (!rv) { |
|
2425 if (m && *m) { |
|
2426 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2427 } |
|
2428 secu_PrintSubjectPublicKeyInfo(out, arena, &spki, |
|
2429 "Subject Public Key Info", level+1); |
|
2430 } |
|
2431 |
|
2432 PORT_FreeArena(arena, PR_FALSE); |
|
2433 return rv; |
|
2434 } |
|
2435 |
|
2436 #ifdef HAVE_EPV_TEMPLATE |
|
2437 int |
|
2438 SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level) |
|
2439 { |
|
2440 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
2441 SECKEYEncryptedPrivateKeyInfo key; |
|
2442 int rv = SEC_ERROR_NO_MEMORY; |
|
2443 |
|
2444 if (!arena) |
|
2445 return rv; |
|
2446 |
|
2447 PORT_Memset(&key, 0, sizeof(key)); |
|
2448 rv = SEC_ASN1DecodeItem(arena, &key, |
|
2449 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der); |
|
2450 if (rv) |
|
2451 goto loser; |
|
2452 |
|
2453 /* Pretty print it out */ |
|
2454 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2455 SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm", |
|
2456 level+1); |
|
2457 SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level+1); |
|
2458 loser: |
|
2459 PORT_FreeArena(arena, PR_TRUE); |
|
2460 return rv; |
|
2461 } |
|
2462 #endif |
|
2463 |
|
2464 int |
|
2465 SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level) |
|
2466 { |
|
2467 unsigned char fingerprint[SHA256_LENGTH]; |
|
2468 char *fpStr = NULL; |
|
2469 int err = PORT_GetError(); |
|
2470 SECStatus rv; |
|
2471 SECItem fpItem; |
|
2472 |
|
2473 /* Print SHA-256 fingerprint */ |
|
2474 memset(fingerprint, 0, sizeof fingerprint); |
|
2475 rv = PK11_HashBuf(SEC_OID_SHA256, fingerprint, derCert->data, derCert->len); |
|
2476 fpItem.data = fingerprint; |
|
2477 fpItem.len = SHA256_LENGTH; |
|
2478 fpStr = CERT_Hexify(&fpItem, 1); |
|
2479 SECU_Indent(out, level); fprintf(out, "%s (SHA-256):", m); |
|
2480 if (SECU_GetWrapEnabled()) { |
|
2481 fprintf(out, "\n"); |
|
2482 SECU_Indent(out, level+1); |
|
2483 } |
|
2484 else { |
|
2485 fprintf(out, " "); |
|
2486 } |
|
2487 fprintf(out, "%s\n", fpStr); |
|
2488 PORT_Free(fpStr); |
|
2489 fpStr = NULL; |
|
2490 if (rv != SECSuccess && !err) |
|
2491 err = PORT_GetError(); |
|
2492 |
|
2493 /* print SHA1 fingerprint */ |
|
2494 memset(fingerprint, 0, sizeof fingerprint); |
|
2495 rv = PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len); |
|
2496 fpItem.data = fingerprint; |
|
2497 fpItem.len = SHA1_LENGTH; |
|
2498 fpStr = CERT_Hexify(&fpItem, 1); |
|
2499 SECU_Indent(out, level); fprintf(out, "%s (SHA1):", m); |
|
2500 if (SECU_GetWrapEnabled()) { |
|
2501 fprintf(out, "\n"); |
|
2502 SECU_Indent(out, level+1); |
|
2503 } |
|
2504 else { |
|
2505 fprintf(out, " "); |
|
2506 } |
|
2507 fprintf(out, "%s\n", fpStr); |
|
2508 PORT_Free(fpStr); |
|
2509 if (SECU_GetWrapEnabled()) |
|
2510 fprintf(out, "\n"); |
|
2511 |
|
2512 if (err) |
|
2513 PORT_SetError(err); |
|
2514 if (err || rv != SECSuccess) |
|
2515 return SECFailure; |
|
2516 |
|
2517 return 0; |
|
2518 } |
|
2519 |
|
2520 /* |
|
2521 ** PKCS7 Support |
|
2522 */ |
|
2523 |
|
2524 /* forward declaration */ |
|
2525 static int |
|
2526 secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *, int); |
|
2527 |
|
2528 /* |
|
2529 ** secu_PrintPKCS7EncContent |
|
2530 ** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it) |
|
2531 */ |
|
2532 static void |
|
2533 secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src, |
|
2534 char *m, int level) |
|
2535 { |
|
2536 if (src->contentTypeTag == NULL) |
|
2537 src->contentTypeTag = SECOID_FindOID(&(src->contentType)); |
|
2538 |
|
2539 SECU_Indent(out, level); |
|
2540 fprintf(out, "%s:\n", m); |
|
2541 SECU_Indent(out, level + 1); |
|
2542 fprintf(out, "Content Type: %s\n", |
|
2543 (src->contentTypeTag != NULL) ? src->contentTypeTag->desc |
|
2544 : "Unknown"); |
|
2545 SECU_PrintAlgorithmID(out, &(src->contentEncAlg), |
|
2546 "Content Encryption Algorithm", level+1); |
|
2547 SECU_PrintAsHex(out, &(src->encContent), |
|
2548 "Encrypted Content", level+1); |
|
2549 } |
|
2550 |
|
2551 /* |
|
2552 ** secu_PrintRecipientInfo |
|
2553 ** Prints a PKCS7RecipientInfo type |
|
2554 */ |
|
2555 static void |
|
2556 secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m, |
|
2557 int level) |
|
2558 { |
|
2559 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2560 SECU_PrintInteger(out, &(info->version), "Version", level + 1); |
|
2561 |
|
2562 SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", |
|
2563 level + 1); |
|
2564 SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), |
|
2565 "Serial Number", level + 1); |
|
2566 |
|
2567 /* Parse and display encrypted key */ |
|
2568 SECU_PrintAlgorithmID(out, &(info->keyEncAlg), |
|
2569 "Key Encryption Algorithm", level + 1); |
|
2570 SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1); |
|
2571 } |
|
2572 |
|
2573 /* |
|
2574 ** secu_PrintSignerInfo |
|
2575 ** Prints a PKCS7SingerInfo type |
|
2576 */ |
|
2577 static void |
|
2578 secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level) |
|
2579 { |
|
2580 SEC_PKCS7Attribute *attr; |
|
2581 int iv; |
|
2582 char om[100]; |
|
2583 |
|
2584 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2585 SECU_PrintInteger(out, &(info->version), "Version", level + 1); |
|
2586 |
|
2587 SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", |
|
2588 level + 1); |
|
2589 SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), |
|
2590 "Serial Number", level + 1); |
|
2591 |
|
2592 SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm", |
|
2593 level + 1); |
|
2594 |
|
2595 if (info->authAttr != NULL) { |
|
2596 SECU_Indent(out, level + 1); |
|
2597 fprintf(out, "Authenticated Attributes:\n"); |
|
2598 iv = 0; |
|
2599 while ((attr = info->authAttr[iv++]) != NULL) { |
|
2600 sprintf(om, "Attribute (%d)", iv); |
|
2601 secu_PrintAttribute(out, attr, om, level + 2); |
|
2602 } |
|
2603 } |
|
2604 |
|
2605 /* Parse and display signature */ |
|
2606 SECU_PrintAlgorithmID(out, &(info->digestEncAlg), |
|
2607 "Digest Encryption Algorithm", level + 1); |
|
2608 SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1); |
|
2609 |
|
2610 if (info->unAuthAttr != NULL) { |
|
2611 SECU_Indent(out, level + 1); |
|
2612 fprintf(out, "Unauthenticated Attributes:\n"); |
|
2613 iv = 0; |
|
2614 while ((attr = info->unAuthAttr[iv++]) != NULL) { |
|
2615 sprintf(om, "Attribute (%x)", iv); |
|
2616 secu_PrintAttribute(out, attr, om, level + 2); |
|
2617 } |
|
2618 } |
|
2619 } |
|
2620 |
|
2621 /* callers of this function must make sure that the CERTSignedCrl |
|
2622 from which they are extracting the CERTCrl has been fully-decoded. |
|
2623 Otherwise it will not have the entries even though the CRL may have |
|
2624 some */ |
|
2625 |
|
2626 void |
|
2627 SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level) |
|
2628 { |
|
2629 CERTCrlEntry *entry; |
|
2630 int iv; |
|
2631 char om[100]; |
|
2632 |
|
2633 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2634 /* version is optional */ |
|
2635 iv = crl->version.len ? DER_GetInteger(&crl->version) : 0; |
|
2636 SECU_Indent(out, level+1); |
|
2637 fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); |
|
2638 SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm", |
|
2639 level + 1); |
|
2640 SECU_PrintName(out, &(crl->name), "Issuer", level + 1); |
|
2641 SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1); |
|
2642 if (crl->nextUpdate.data && crl->nextUpdate.len) /* is optional */ |
|
2643 SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1); |
|
2644 |
|
2645 if (crl->entries != NULL) { |
|
2646 iv = 0; |
|
2647 while ((entry = crl->entries[iv++]) != NULL) { |
|
2648 sprintf(om, "Entry %d (0x%x):\n", iv, iv); |
|
2649 SECU_Indent(out, level + 1); fputs(om, out); |
|
2650 SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number", |
|
2651 level + 2); |
|
2652 SECU_PrintTimeChoice(out, &(entry->revocationDate), |
|
2653 "Revocation Date", level + 2); |
|
2654 SECU_PrintExtensions(out, entry->extensions, |
|
2655 "Entry Extensions", level + 2); |
|
2656 } |
|
2657 } |
|
2658 SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1); |
|
2659 } |
|
2660 |
|
2661 /* |
|
2662 ** secu_PrintPKCS7Signed |
|
2663 ** Pretty print a PKCS7 signed data type (up to version 1). |
|
2664 */ |
|
2665 static int |
|
2666 secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src, |
|
2667 const char *m, int level) |
|
2668 { |
|
2669 SECAlgorithmID *digAlg; /* digest algorithms */ |
|
2670 SECItem *aCert; /* certificate */ |
|
2671 CERTSignedCrl *aCrl; /* certificate revocation list */ |
|
2672 SEC_PKCS7SignerInfo *sigInfo; /* signer information */ |
|
2673 int rv, iv; |
|
2674 char om[100]; |
|
2675 |
|
2676 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2677 SECU_PrintInteger(out, &(src->version), "Version", level + 1); |
|
2678 |
|
2679 /* Parse and list digest algorithms (if any) */ |
|
2680 if (src->digestAlgorithms != NULL) { |
|
2681 SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); |
|
2682 iv = 0; |
|
2683 while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { |
|
2684 sprintf(om, "Digest Algorithm (%x)", iv); |
|
2685 SECU_PrintAlgorithmID(out, digAlg, om, level + 2); |
|
2686 } |
|
2687 } |
|
2688 |
|
2689 /* Now for the content */ |
|
2690 rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo), |
|
2691 "Content Information", level + 1); |
|
2692 if (rv != 0) |
|
2693 return rv; |
|
2694 |
|
2695 /* Parse and list certificates (if any) */ |
|
2696 if (src->rawCerts != NULL) { |
|
2697 SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); |
|
2698 iv = 0; |
|
2699 while ((aCert = src->rawCerts[iv++]) != NULL) { |
|
2700 sprintf(om, "Certificate (%x)", iv); |
|
2701 rv = SECU_PrintSignedData(out, aCert, om, level + 2, |
|
2702 SECU_PrintCertificate); |
|
2703 if (rv) |
|
2704 return rv; |
|
2705 } |
|
2706 } |
|
2707 |
|
2708 /* Parse and list CRL's (if any) */ |
|
2709 if (src->crls != NULL) { |
|
2710 SECU_Indent(out, level + 1); |
|
2711 fprintf(out, "Signed Revocation Lists:\n"); |
|
2712 iv = 0; |
|
2713 while ((aCrl = src->crls[iv++]) != NULL) { |
|
2714 sprintf(om, "Signed Revocation List (%x)", iv); |
|
2715 SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); |
|
2716 SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, |
|
2717 "Signature Algorithm", level+3); |
|
2718 DER_ConvertBitString(&aCrl->signatureWrap.signature); |
|
2719 SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", |
|
2720 level+3); |
|
2721 SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", |
|
2722 level + 3); |
|
2723 } |
|
2724 } |
|
2725 |
|
2726 /* Parse and list signatures (if any) */ |
|
2727 if (src->signerInfos != NULL) { |
|
2728 SECU_Indent(out, level + 1); |
|
2729 fprintf(out, "Signer Information List:\n"); |
|
2730 iv = 0; |
|
2731 while ((sigInfo = src->signerInfos[iv++]) != NULL) { |
|
2732 sprintf(om, "Signer Information (%x)", iv); |
|
2733 secu_PrintSignerInfo(out, sigInfo, om, level + 2); |
|
2734 } |
|
2735 } |
|
2736 |
|
2737 return 0; |
|
2738 } |
|
2739 |
|
2740 /* |
|
2741 ** secu_PrintPKCS7Enveloped |
|
2742 ** Pretty print a PKCS7 enveloped data type (up to version 1). |
|
2743 */ |
|
2744 static void |
|
2745 secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src, |
|
2746 const char *m, int level) |
|
2747 { |
|
2748 SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */ |
|
2749 int iv; |
|
2750 char om[100]; |
|
2751 |
|
2752 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2753 SECU_PrintInteger(out, &(src->version), "Version", level + 1); |
|
2754 |
|
2755 /* Parse and list recipients (this is not optional) */ |
|
2756 if (src->recipientInfos != NULL) { |
|
2757 SECU_Indent(out, level + 1); |
|
2758 fprintf(out, "Recipient Information List:\n"); |
|
2759 iv = 0; |
|
2760 while ((recInfo = src->recipientInfos[iv++]) != NULL) { |
|
2761 sprintf(om, "Recipient Information (%x)", iv); |
|
2762 secu_PrintRecipientInfo(out, recInfo, om, level + 2); |
|
2763 } |
|
2764 } |
|
2765 |
|
2766 secu_PrintPKCS7EncContent(out, &src->encContentInfo, |
|
2767 "Encrypted Content Information", level + 1); |
|
2768 } |
|
2769 |
|
2770 /* |
|
2771 ** secu_PrintPKCS7SignedEnveloped |
|
2772 ** Pretty print a PKCS7 singed and enveloped data type (up to version 1). |
|
2773 */ |
|
2774 static int |
|
2775 secu_PrintPKCS7SignedAndEnveloped(FILE *out, |
|
2776 SEC_PKCS7SignedAndEnvelopedData *src, |
|
2777 const char *m, int level) |
|
2778 { |
|
2779 SECAlgorithmID *digAlg; /* pointer for digest algorithms */ |
|
2780 SECItem *aCert; /* pointer for certificate */ |
|
2781 CERTSignedCrl *aCrl; /* pointer for certificate revocation list */ |
|
2782 SEC_PKCS7SignerInfo *sigInfo; /* pointer for signer information */ |
|
2783 SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */ |
|
2784 int rv, iv; |
|
2785 char om[100]; |
|
2786 |
|
2787 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2788 SECU_PrintInteger(out, &(src->version), "Version", level + 1); |
|
2789 |
|
2790 /* Parse and list recipients (this is not optional) */ |
|
2791 if (src->recipientInfos != NULL) { |
|
2792 SECU_Indent(out, level + 1); |
|
2793 fprintf(out, "Recipient Information List:\n"); |
|
2794 iv = 0; |
|
2795 while ((recInfo = src->recipientInfos[iv++]) != NULL) { |
|
2796 sprintf(om, "Recipient Information (%x)", iv); |
|
2797 secu_PrintRecipientInfo(out, recInfo, om, level + 2); |
|
2798 } |
|
2799 } |
|
2800 |
|
2801 /* Parse and list digest algorithms (if any) */ |
|
2802 if (src->digestAlgorithms != NULL) { |
|
2803 SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); |
|
2804 iv = 0; |
|
2805 while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { |
|
2806 sprintf(om, "Digest Algorithm (%x)", iv); |
|
2807 SECU_PrintAlgorithmID(out, digAlg, om, level + 2); |
|
2808 } |
|
2809 } |
|
2810 |
|
2811 secu_PrintPKCS7EncContent(out, &src->encContentInfo, |
|
2812 "Encrypted Content Information", level + 1); |
|
2813 |
|
2814 /* Parse and list certificates (if any) */ |
|
2815 if (src->rawCerts != NULL) { |
|
2816 SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); |
|
2817 iv = 0; |
|
2818 while ((aCert = src->rawCerts[iv++]) != NULL) { |
|
2819 sprintf(om, "Certificate (%x)", iv); |
|
2820 rv = SECU_PrintSignedData(out, aCert, om, level + 2, |
|
2821 SECU_PrintCertificate); |
|
2822 if (rv) |
|
2823 return rv; |
|
2824 } |
|
2825 } |
|
2826 |
|
2827 /* Parse and list CRL's (if any) */ |
|
2828 if (src->crls != NULL) { |
|
2829 SECU_Indent(out, level + 1); |
|
2830 fprintf(out, "Signed Revocation Lists:\n"); |
|
2831 iv = 0; |
|
2832 while ((aCrl = src->crls[iv++]) != NULL) { |
|
2833 sprintf(om, "Signed Revocation List (%x)", iv); |
|
2834 SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); |
|
2835 SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, |
|
2836 "Signature Algorithm", level+3); |
|
2837 DER_ConvertBitString(&aCrl->signatureWrap.signature); |
|
2838 SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", |
|
2839 level+3); |
|
2840 SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", |
|
2841 level + 3); |
|
2842 } |
|
2843 } |
|
2844 |
|
2845 /* Parse and list signatures (if any) */ |
|
2846 if (src->signerInfos != NULL) { |
|
2847 SECU_Indent(out, level + 1); |
|
2848 fprintf(out, "Signer Information List:\n"); |
|
2849 iv = 0; |
|
2850 while ((sigInfo = src->signerInfos[iv++]) != NULL) { |
|
2851 sprintf(om, "Signer Information (%x)", iv); |
|
2852 secu_PrintSignerInfo(out, sigInfo, om, level + 2); |
|
2853 } |
|
2854 } |
|
2855 |
|
2856 return 0; |
|
2857 } |
|
2858 |
|
2859 int |
|
2860 SECU_PrintCrl (FILE *out, SECItem *der, char *m, int level) |
|
2861 { |
|
2862 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
2863 CERTCrl *c = NULL; |
|
2864 int rv = SEC_ERROR_NO_MEMORY; |
|
2865 |
|
2866 if (!arena) |
|
2867 return rv; |
|
2868 do { |
|
2869 /* Decode CRL */ |
|
2870 c = PORT_ArenaZNew(arena, CERTCrl); |
|
2871 if (!c) |
|
2872 break; |
|
2873 |
|
2874 rv = SEC_QuickDERDecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der); |
|
2875 if (rv != SECSuccess) |
|
2876 break; |
|
2877 SECU_PrintCRLInfo (out, c, m, level); |
|
2878 } while (0); |
|
2879 PORT_FreeArena (arena, PR_FALSE); |
|
2880 return rv; |
|
2881 } |
|
2882 |
|
2883 |
|
2884 /* |
|
2885 ** secu_PrintPKCS7Encrypted |
|
2886 ** Pretty print a PKCS7 encrypted data type (up to version 1). |
|
2887 */ |
|
2888 static void |
|
2889 secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src, |
|
2890 const char *m, int level) |
|
2891 { |
|
2892 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2893 SECU_PrintInteger(out, &(src->version), "Version", level + 1); |
|
2894 |
|
2895 secu_PrintPKCS7EncContent(out, &src->encContentInfo, |
|
2896 "Encrypted Content Information", level + 1); |
|
2897 } |
|
2898 |
|
2899 /* |
|
2900 ** secu_PrintPKCS7Digested |
|
2901 ** Pretty print a PKCS7 digested data type (up to version 1). |
|
2902 */ |
|
2903 static void |
|
2904 secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src, |
|
2905 const char *m, int level) |
|
2906 { |
|
2907 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2908 SECU_PrintInteger(out, &(src->version), "Version", level + 1); |
|
2909 |
|
2910 SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm", |
|
2911 level + 1); |
|
2912 secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information", |
|
2913 level + 1); |
|
2914 SECU_PrintAsHex(out, &src->digest, "Digest", level + 1); |
|
2915 } |
|
2916 |
|
2917 /* |
|
2918 ** secu_PrintPKCS7ContentInfo |
|
2919 ** Takes a SEC_PKCS7ContentInfo type and sends the contents to the |
|
2920 ** appropriate function |
|
2921 */ |
|
2922 static int |
|
2923 secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src, |
|
2924 char *m, int level) |
|
2925 { |
|
2926 const char *desc; |
|
2927 SECOidTag kind; |
|
2928 int rv; |
|
2929 |
|
2930 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
2931 level++; |
|
2932 |
|
2933 if (src->contentTypeTag == NULL) |
|
2934 src->contentTypeTag = SECOID_FindOID(&(src->contentType)); |
|
2935 |
|
2936 if (src->contentTypeTag == NULL) { |
|
2937 desc = "Unknown"; |
|
2938 kind = SEC_OID_PKCS7_DATA; |
|
2939 } else { |
|
2940 desc = src->contentTypeTag->desc; |
|
2941 kind = src->contentTypeTag->offset; |
|
2942 } |
|
2943 |
|
2944 if (src->content.data == NULL) { |
|
2945 SECU_Indent(out, level); fprintf(out, "%s:\n", desc); |
|
2946 level++; |
|
2947 SECU_Indent(out, level); fprintf(out, "<no content>\n"); |
|
2948 return 0; |
|
2949 } |
|
2950 |
|
2951 rv = 0; |
|
2952 switch (kind) { |
|
2953 case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */ |
|
2954 rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level); |
|
2955 break; |
|
2956 |
|
2957 case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */ |
|
2958 secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level); |
|
2959 break; |
|
2960 |
|
2961 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */ |
|
2962 rv = secu_PrintPKCS7SignedAndEnveloped(out, |
|
2963 src->content.signedAndEnvelopedData, |
|
2964 desc, level); |
|
2965 break; |
|
2966 |
|
2967 case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */ |
|
2968 secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level); |
|
2969 break; |
|
2970 |
|
2971 case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */ |
|
2972 secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level); |
|
2973 break; |
|
2974 |
|
2975 default: |
|
2976 SECU_PrintAsHex(out, src->content.data, desc, level); |
|
2977 break; |
|
2978 } |
|
2979 |
|
2980 return rv; |
|
2981 } |
|
2982 |
|
2983 /* |
|
2984 ** SECU_PrintPKCS7ContentInfo |
|
2985 ** Decode and print any major PKCS7 data type (up to version 1). |
|
2986 */ |
|
2987 int |
|
2988 SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level) |
|
2989 { |
|
2990 SEC_PKCS7ContentInfo *cinfo; |
|
2991 int rv; |
|
2992 |
|
2993 cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
|
2994 if (cinfo != NULL) { |
|
2995 /* Send it to recursive parsing and printing module */ |
|
2996 rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level); |
|
2997 SEC_PKCS7DestroyContentInfo(cinfo); |
|
2998 } else { |
|
2999 rv = -1; |
|
3000 } |
|
3001 |
|
3002 return rv; |
|
3003 } |
|
3004 |
|
3005 /* |
|
3006 ** End of PKCS7 functions |
|
3007 */ |
|
3008 |
|
3009 void |
|
3010 printFlags(FILE *out, unsigned int flags, int level) |
|
3011 { |
|
3012 if ( flags & CERTDB_TERMINAL_RECORD ) { |
|
3013 SECU_Indent(out, level); fprintf(out, "Terminal Record\n"); |
|
3014 } |
|
3015 if ( flags & CERTDB_TRUSTED ) { |
|
3016 SECU_Indent(out, level); fprintf(out, "Trusted\n"); |
|
3017 } |
|
3018 if ( flags & CERTDB_SEND_WARN ) { |
|
3019 SECU_Indent(out, level); fprintf(out, "Warn When Sending\n"); |
|
3020 } |
|
3021 if ( flags & CERTDB_VALID_CA ) { |
|
3022 SECU_Indent(out, level); fprintf(out, "Valid CA\n"); |
|
3023 } |
|
3024 if ( flags & CERTDB_TRUSTED_CA ) { |
|
3025 SECU_Indent(out, level); fprintf(out, "Trusted CA\n"); |
|
3026 } |
|
3027 if ( flags & CERTDB_NS_TRUSTED_CA ) { |
|
3028 SECU_Indent(out, level); fprintf(out, "Netscape Trusted CA\n"); |
|
3029 } |
|
3030 if ( flags & CERTDB_USER ) { |
|
3031 SECU_Indent(out, level); fprintf(out, "User\n"); |
|
3032 } |
|
3033 if ( flags & CERTDB_TRUSTED_CLIENT_CA ) { |
|
3034 SECU_Indent(out, level); fprintf(out, "Trusted Client CA\n"); |
|
3035 } |
|
3036 if ( flags & CERTDB_GOVT_APPROVED_CA ) { |
|
3037 SECU_Indent(out, level); fprintf(out, "Step-up\n"); |
|
3038 } |
|
3039 } |
|
3040 |
|
3041 void |
|
3042 SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level) |
|
3043 { |
|
3044 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
3045 SECU_Indent(out, level+1); fprintf(out, "SSL Flags:\n"); |
|
3046 printFlags(out, trust->sslFlags, level+2); |
|
3047 SECU_Indent(out, level+1); fprintf(out, "Email Flags:\n"); |
|
3048 printFlags(out, trust->emailFlags, level+2); |
|
3049 SECU_Indent(out, level+1); fprintf(out, "Object Signing Flags:\n"); |
|
3050 printFlags(out, trust->objectSigningFlags, level+2); |
|
3051 } |
|
3052 |
|
3053 int SECU_PrintDERName(FILE *out, SECItem *der, const char *m, int level) |
|
3054 { |
|
3055 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
3056 CERTName *name; |
|
3057 int rv = SEC_ERROR_NO_MEMORY; |
|
3058 |
|
3059 if (!arena) |
|
3060 return rv; |
|
3061 |
|
3062 name = PORT_ArenaZNew(arena, CERTName); |
|
3063 if (!name) |
|
3064 goto loser; |
|
3065 |
|
3066 rv = SEC_ASN1DecodeItem(arena, name, SEC_ASN1_GET(CERT_NameTemplate), der); |
|
3067 if (rv) |
|
3068 goto loser; |
|
3069 |
|
3070 SECU_PrintName(out, name, m, level); |
|
3071 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ |
|
3072 SECU_Newline(out); |
|
3073 loser: |
|
3074 PORT_FreeArena(arena, PR_FALSE); |
|
3075 return rv; |
|
3076 } |
|
3077 |
|
3078 typedef enum { |
|
3079 noSignature = 0, |
|
3080 withSignature = 1 |
|
3081 } SignatureOptionType; |
|
3082 |
|
3083 static int |
|
3084 secu_PrintSignedDataSigOpt(FILE *out, SECItem *der, const char *m, |
|
3085 int level, SECU_PPFunc inner, |
|
3086 SignatureOptionType withSignature) |
|
3087 { |
|
3088 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
3089 CERTSignedData *sd; |
|
3090 int rv = SEC_ERROR_NO_MEMORY; |
|
3091 |
|
3092 if (!arena) |
|
3093 return rv; |
|
3094 |
|
3095 /* Strip off the signature */ |
|
3096 sd = PORT_ArenaZNew(arena, CERTSignedData); |
|
3097 if (!sd) |
|
3098 goto loser; |
|
3099 |
|
3100 rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate), |
|
3101 der); |
|
3102 if (rv) |
|
3103 goto loser; |
|
3104 |
|
3105 if (m) { |
|
3106 SECU_Indent(out, level); fprintf(out, "%s:\n", m); |
|
3107 } else { |
|
3108 level -= 1; |
|
3109 } |
|
3110 rv = (*inner)(out, &sd->data, "Data", level+1); |
|
3111 |
|
3112 if (withSignature) { |
|
3113 SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm", |
|
3114 level+1); |
|
3115 DER_ConvertBitString(&sd->signature); |
|
3116 SECU_PrintAsHex(out, &sd->signature, "Signature", level+1); |
|
3117 } |
|
3118 SECU_PrintFingerprints(out, der, "Fingerprint", level+1); |
|
3119 loser: |
|
3120 PORT_FreeArena(arena, PR_FALSE); |
|
3121 return rv; |
|
3122 } |
|
3123 |
|
3124 int SECU_PrintSignedData(FILE *out, SECItem *der, const char *m, |
|
3125 int level, SECU_PPFunc inner) |
|
3126 { |
|
3127 return secu_PrintSignedDataSigOpt(out, der, m, level, inner, |
|
3128 withSignature); |
|
3129 } |
|
3130 |
|
3131 int SECU_PrintSignedContent(FILE *out, SECItem *der, char *m, |
|
3132 int level, SECU_PPFunc inner) |
|
3133 { |
|
3134 return secu_PrintSignedDataSigOpt(out, der, m, level, inner, |
|
3135 noSignature); |
|
3136 } |
|
3137 |
|
3138 SECStatus |
|
3139 SEC_PrintCertificateAndTrust(CERTCertificate *cert, |
|
3140 const char *label, |
|
3141 CERTCertTrust *trust) |
|
3142 { |
|
3143 SECStatus rv; |
|
3144 SECItem data; |
|
3145 CERTCertTrust certTrust; |
|
3146 |
|
3147 data.data = cert->derCert.data; |
|
3148 data.len = cert->derCert.len; |
|
3149 |
|
3150 rv = SECU_PrintSignedData(stdout, &data, label, 0, |
|
3151 SECU_PrintCertificate); |
|
3152 if (rv) { |
|
3153 return(SECFailure); |
|
3154 } |
|
3155 if (trust) { |
|
3156 SECU_PrintTrustFlags(stdout, trust, |
|
3157 "Certificate Trust Flags", 1); |
|
3158 } else if (CERT_GetCertTrust(cert, &certTrust) == SECSuccess) { |
|
3159 SECU_PrintTrustFlags(stdout, &certTrust, |
|
3160 "Certificate Trust Flags", 1); |
|
3161 } |
|
3162 |
|
3163 printf("\n"); |
|
3164 |
|
3165 return(SECSuccess); |
|
3166 } |
|
3167 |
|
3168 |
|
3169 static char * |
|
3170 bestCertName(CERTCertificate *cert) { |
|
3171 if (cert->nickname) { |
|
3172 return cert->nickname; |
|
3173 } |
|
3174 if (cert->emailAddr && cert->emailAddr[0]) { |
|
3175 return cert->emailAddr; |
|
3176 } |
|
3177 return cert->subjectName; |
|
3178 } |
|
3179 |
|
3180 void |
|
3181 SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle, |
|
3182 CERTCertificate *cert, PRBool checksig, |
|
3183 SECCertificateUsage certUsage, void *pinArg, PRBool verbose, |
|
3184 PRTime datetime) |
|
3185 { |
|
3186 CERTVerifyLog log; |
|
3187 CERTVerifyLogNode *node; |
|
3188 |
|
3189 PRErrorCode err = PORT_GetError(); |
|
3190 |
|
3191 log.arena = PORT_NewArena(512); |
|
3192 log.head = log.tail = NULL; |
|
3193 log.count = 0; |
|
3194 CERT_VerifyCertificate(handle, cert, checksig, certUsage, datetime, pinArg, &log, NULL); |
|
3195 |
|
3196 SECU_displayVerifyLog(outfile, &log, verbose); |
|
3197 |
|
3198 for (node = log.head; node; node = node->next) { |
|
3199 if (node->cert) |
|
3200 CERT_DestroyCertificate(node->cert); |
|
3201 } |
|
3202 PORT_FreeArena(log.arena, PR_FALSE); |
|
3203 |
|
3204 PORT_SetError(err); /* restore original error code */ |
|
3205 } |
|
3206 |
|
3207 void |
|
3208 SECU_displayVerifyLog(FILE *outfile, CERTVerifyLog *log, |
|
3209 PRBool verbose) |
|
3210 { |
|
3211 CERTVerifyLogNode *node = NULL; |
|
3212 unsigned int depth = (unsigned int)-1; |
|
3213 unsigned int flags = 0; |
|
3214 char * errstr = NULL; |
|
3215 |
|
3216 if (log->count > 0) { |
|
3217 fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n"); |
|
3218 for (node = log->head; node; node = node->next) { |
|
3219 if (depth != node->depth) { |
|
3220 depth = node->depth; |
|
3221 fprintf(outfile,"CERT %d. %s %s:\n", depth, |
|
3222 bestCertName(node->cert), |
|
3223 depth ? "[Certificate Authority]": ""); |
|
3224 if (verbose) { |
|
3225 const char * emailAddr; |
|
3226 emailAddr = CERT_GetFirstEmailAddress(node->cert); |
|
3227 if (emailAddr) { |
|
3228 fprintf(outfile,"Email Address(es): "); |
|
3229 do { |
|
3230 fprintf(outfile, "%s\n", emailAddr); |
|
3231 emailAddr = CERT_GetNextEmailAddress(node->cert, |
|
3232 emailAddr); |
|
3233 } while (emailAddr); |
|
3234 } |
|
3235 } |
|
3236 } |
|
3237 fprintf(outfile, " ERROR %ld: %s\n", node->error, |
|
3238 SECU_Strerror(node->error)); |
|
3239 errstr = NULL; |
|
3240 switch (node->error) { |
|
3241 case SEC_ERROR_INADEQUATE_KEY_USAGE: |
|
3242 flags = (unsigned int)node->arg; |
|
3243 switch (flags) { |
|
3244 case KU_DIGITAL_SIGNATURE: |
|
3245 errstr = "Cert cannot sign."; |
|
3246 break; |
|
3247 case KU_KEY_ENCIPHERMENT: |
|
3248 errstr = "Cert cannot encrypt."; |
|
3249 break; |
|
3250 case KU_KEY_CERT_SIGN: |
|
3251 errstr = "Cert cannot sign other certs."; |
|
3252 break; |
|
3253 default: |
|
3254 errstr = "[unknown usage]."; |
|
3255 break; |
|
3256 } |
|
3257 case SEC_ERROR_INADEQUATE_CERT_TYPE: |
|
3258 flags = (unsigned int)node->arg; |
|
3259 switch (flags) { |
|
3260 case NS_CERT_TYPE_SSL_CLIENT: |
|
3261 case NS_CERT_TYPE_SSL_SERVER: |
|
3262 errstr = "Cert cannot be used for SSL."; |
|
3263 break; |
|
3264 case NS_CERT_TYPE_SSL_CA: |
|
3265 errstr = "Cert cannot be used as an SSL CA."; |
|
3266 break; |
|
3267 case NS_CERT_TYPE_EMAIL: |
|
3268 errstr = "Cert cannot be used for SMIME."; |
|
3269 break; |
|
3270 case NS_CERT_TYPE_EMAIL_CA: |
|
3271 errstr = "Cert cannot be used as an SMIME CA."; |
|
3272 break; |
|
3273 case NS_CERT_TYPE_OBJECT_SIGNING: |
|
3274 errstr = "Cert cannot be used for object signing."; |
|
3275 break; |
|
3276 case NS_CERT_TYPE_OBJECT_SIGNING_CA: |
|
3277 errstr = "Cert cannot be used as an object signing CA."; |
|
3278 break; |
|
3279 default: |
|
3280 errstr = "[unknown usage]."; |
|
3281 break; |
|
3282 } |
|
3283 case SEC_ERROR_UNKNOWN_ISSUER: |
|
3284 case SEC_ERROR_UNTRUSTED_ISSUER: |
|
3285 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: |
|
3286 errstr = node->cert->issuerName; |
|
3287 break; |
|
3288 default: |
|
3289 break; |
|
3290 } |
|
3291 if (errstr) { |
|
3292 fprintf(stderr," %s\n",errstr); |
|
3293 } |
|
3294 } |
|
3295 } |
|
3296 } |
|
3297 |
|
3298 void |
|
3299 SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle, |
|
3300 CERTCertificate *cert, PRBool checksig, |
|
3301 SECCertificateUsage certUsage, void *pinArg, PRBool verbose) |
|
3302 { |
|
3303 SECU_printCertProblemsOnDate(outfile, handle, cert, checksig, |
|
3304 certUsage, pinArg, verbose, PR_Now()); |
|
3305 } |
|
3306 |
|
3307 SECStatus |
|
3308 SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile, |
|
3309 PRBool ascii, char *url) |
|
3310 { |
|
3311 PORT_Assert(derCrl != NULL); |
|
3312 if (!derCrl) { |
|
3313 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3314 return SECFailure; |
|
3315 } |
|
3316 |
|
3317 if (outFile != NULL) { |
|
3318 if (ascii) { |
|
3319 PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER, |
|
3320 BTOA_DataToAscii(derCrl->data, derCrl->len), |
|
3321 NS_CRL_TRAILER); |
|
3322 } else { |
|
3323 if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) { |
|
3324 return SECFailure; |
|
3325 } |
|
3326 } |
|
3327 } |
|
3328 if (slot) { |
|
3329 CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url, |
|
3330 SEC_CRL_TYPE, NULL, 0, NULL, 0); |
|
3331 if (newCrl != NULL) { |
|
3332 SEC_DestroyCrl(newCrl); |
|
3333 return SECSuccess; |
|
3334 } |
|
3335 return SECFailure; |
|
3336 } |
|
3337 if (!outFile && !slot) { |
|
3338 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3339 return SECFailure; |
|
3340 } |
|
3341 return SECSuccess; |
|
3342 } |
|
3343 |
|
3344 SECStatus |
|
3345 SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl, |
|
3346 SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode) |
|
3347 { |
|
3348 SECItem der; |
|
3349 SECKEYPrivateKey *caPrivateKey = NULL; |
|
3350 SECStatus rv; |
|
3351 PLArenaPool *arena; |
|
3352 SECOidTag algID; |
|
3353 void *dummy; |
|
3354 |
|
3355 PORT_Assert(issuer != NULL && signCrl != NULL); |
|
3356 if (!issuer || !signCrl) { |
|
3357 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3358 return SECFailure; |
|
3359 } |
|
3360 |
|
3361 arena = signCrl->arena; |
|
3362 |
|
3363 caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL); |
|
3364 if (caPrivateKey == NULL) { |
|
3365 *resCode = noKeyFound; |
|
3366 return SECFailure; |
|
3367 } |
|
3368 |
|
3369 algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag); |
|
3370 if (algID == SEC_OID_UNKNOWN) { |
|
3371 *resCode = noSignatureMatch; |
|
3372 rv = SECFailure; |
|
3373 goto done; |
|
3374 } |
|
3375 |
|
3376 if (!signCrl->crl.signatureAlg.parameters.data) { |
|
3377 rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0); |
|
3378 if (rv != SECSuccess) { |
|
3379 *resCode = failToEncode; |
|
3380 goto done; |
|
3381 } |
|
3382 } |
|
3383 |
|
3384 der.len = 0; |
|
3385 der.data = NULL; |
|
3386 dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl, |
|
3387 SEC_ASN1_GET(CERT_CrlTemplate)); |
|
3388 if (!dummy) { |
|
3389 *resCode = failToEncode; |
|
3390 rv = SECFailure; |
|
3391 goto done; |
|
3392 } |
|
3393 |
|
3394 rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap, |
|
3395 der.data, der.len, caPrivateKey, algID); |
|
3396 if (rv != SECSuccess) { |
|
3397 *resCode = failToSign; |
|
3398 goto done; |
|
3399 } |
|
3400 |
|
3401 signCrl->derCrl = PORT_ArenaZNew(arena, SECItem); |
|
3402 if (signCrl->derCrl == NULL) { |
|
3403 *resCode = noMem; |
|
3404 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
3405 rv = SECFailure; |
|
3406 goto done; |
|
3407 } |
|
3408 |
|
3409 signCrl->derCrl->len = 0; |
|
3410 signCrl->derCrl->data = NULL; |
|
3411 dummy = SEC_ASN1EncodeItem (arena, signCrl->derCrl, signCrl, |
|
3412 SEC_ASN1_GET(CERT_SignedCrlTemplate)); |
|
3413 if (!dummy) { |
|
3414 *resCode = failToEncode; |
|
3415 rv = SECFailure; |
|
3416 goto done; |
|
3417 } |
|
3418 |
|
3419 done: |
|
3420 if (caPrivateKey) { |
|
3421 SECKEY_DestroyPrivateKey(caPrivateKey); |
|
3422 } |
|
3423 return rv; |
|
3424 } |
|
3425 |
|
3426 |
|
3427 |
|
3428 SECStatus |
|
3429 SECU_CopyCRL(PLArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl) |
|
3430 { |
|
3431 void *dummy; |
|
3432 SECStatus rv = SECSuccess; |
|
3433 SECItem der; |
|
3434 |
|
3435 PORT_Assert(destArena && srcCrl && destCrl); |
|
3436 if (!destArena || !srcCrl || !destCrl) { |
|
3437 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3438 return SECFailure; |
|
3439 } |
|
3440 |
|
3441 der.len = 0; |
|
3442 der.data = NULL; |
|
3443 dummy = SEC_ASN1EncodeItem (destArena, &der, srcCrl, |
|
3444 SEC_ASN1_GET(CERT_CrlTemplate)); |
|
3445 if (!dummy) { |
|
3446 return SECFailure; |
|
3447 } |
|
3448 |
|
3449 rv = SEC_QuickDERDecodeItem(destArena, destCrl, |
|
3450 SEC_ASN1_GET(CERT_CrlTemplate), &der); |
|
3451 if (rv != SECSuccess) { |
|
3452 return SECFailure; |
|
3453 } |
|
3454 |
|
3455 destCrl->arena = destArena; |
|
3456 |
|
3457 return rv; |
|
3458 } |
|
3459 |
|
3460 SECStatus |
|
3461 SECU_DerSignDataCRL(PLArenaPool *arena, CERTSignedData *sd, |
|
3462 unsigned char *buf, int len, SECKEYPrivateKey *pk, |
|
3463 SECOidTag algID) |
|
3464 { |
|
3465 SECItem it; |
|
3466 SECStatus rv; |
|
3467 |
|
3468 it.data = 0; |
|
3469 |
|
3470 /* XXX We should probably have some asserts here to make sure the key type |
|
3471 * and algID match |
|
3472 */ |
|
3473 |
|
3474 /* Sign input buffer */ |
|
3475 rv = SEC_SignData(&it, buf, len, pk, algID); |
|
3476 if (rv) goto loser; |
|
3477 |
|
3478 /* Fill out SignedData object */ |
|
3479 PORT_Memset(sd, 0, sizeof(*sd)); |
|
3480 sd->data.data = buf; |
|
3481 sd->data.len = len; |
|
3482 sd->signature.data = it.data; |
|
3483 sd->signature.len = it.len << 3; /* convert to bit string */ |
|
3484 rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0); |
|
3485 if (rv) goto loser; |
|
3486 |
|
3487 return rv; |
|
3488 |
|
3489 loser: |
|
3490 PORT_Free(it.data); |
|
3491 return rv; |
|
3492 } |
|
3493 |
|
3494 #if 0 |
|
3495 |
|
3496 /* we need access to the private function cert_FindExtension for this code to work */ |
|
3497 |
|
3498 CERTAuthKeyID * |
|
3499 SECU_FindCRLAuthKeyIDExten (PLArenaPool *arena, CERTSignedCrl *scrl) |
|
3500 { |
|
3501 SECItem encodedExtenValue; |
|
3502 SECStatus rv; |
|
3503 CERTAuthKeyID *ret; |
|
3504 CERTCrl* crl; |
|
3505 |
|
3506 if (!scrl) { |
|
3507 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3508 return NULL; |
|
3509 } |
|
3510 |
|
3511 crl = &scrl->crl; |
|
3512 |
|
3513 encodedExtenValue.data = NULL; |
|
3514 encodedExtenValue.len = 0; |
|
3515 |
|
3516 rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID, |
|
3517 &encodedExtenValue); |
|
3518 if ( rv != SECSuccess ) { |
|
3519 return (NULL); |
|
3520 } |
|
3521 |
|
3522 ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue); |
|
3523 |
|
3524 PORT_Free(encodedExtenValue.data); |
|
3525 encodedExtenValue.data = NULL; |
|
3526 |
|
3527 return(ret); |
|
3528 } |
|
3529 |
|
3530 #endif |
|
3531 |
|
3532 /* |
|
3533 * Find the issuer of a Crl. Use the authorityKeyID if it exists. |
|
3534 */ |
|
3535 CERTCertificate * |
|
3536 SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem* subject, |
|
3537 CERTAuthKeyID* authorityKeyID, PRTime validTime) |
|
3538 { |
|
3539 CERTCertificate *issuerCert = NULL; |
|
3540 CERTCertList *certList = NULL; |
|
3541 CERTCertTrust trust; |
|
3542 |
|
3543 if (!subject) { |
|
3544 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3545 return NULL; |
|
3546 } |
|
3547 |
|
3548 certList = |
|
3549 CERT_CreateSubjectCertList(NULL, dbhandle, subject, |
|
3550 validTime, PR_TRUE); |
|
3551 if (certList) { |
|
3552 CERTCertListNode *node = CERT_LIST_HEAD(certList); |
|
3553 |
|
3554 /* XXX and authoritykeyid in the future */ |
|
3555 while ( ! CERT_LIST_END(node, certList) ) { |
|
3556 CERTCertificate *cert = node->cert; |
|
3557 /* check cert CERTCertTrust data is allocated, check cert |
|
3558 usage extension, check that cert has pkey in db. Select |
|
3559 the first (newest) user cert */ |
|
3560 if (CERT_GetCertTrust(cert, &trust) == SECSuccess && |
|
3561 CERT_CheckCertUsage(cert, KU_CRL_SIGN) == SECSuccess && |
|
3562 CERT_IsUserCert(cert)) { |
|
3563 |
|
3564 issuerCert = CERT_DupCertificate(cert); |
|
3565 break; |
|
3566 } |
|
3567 node = CERT_LIST_NEXT(node); |
|
3568 } |
|
3569 CERT_DestroyCertList(certList); |
|
3570 } |
|
3571 return(issuerCert); |
|
3572 } |
|
3573 |
|
3574 |
|
3575 /* Encodes and adds extensions to the CRL or CRL entries. */ |
|
3576 SECStatus |
|
3577 SECU_EncodeAndAddExtensionValue(PLArenaPool *arena, void *extHandle, |
|
3578 void *value, PRBool criticality, int extenType, |
|
3579 EXTEN_EXT_VALUE_ENCODER EncodeValueFn) |
|
3580 { |
|
3581 SECItem encodedValue; |
|
3582 SECStatus rv; |
|
3583 |
|
3584 encodedValue.data = NULL; |
|
3585 encodedValue.len = 0; |
|
3586 do { |
|
3587 rv = (*EncodeValueFn)(arena, value, &encodedValue); |
|
3588 if (rv != SECSuccess) |
|
3589 break; |
|
3590 |
|
3591 rv = CERT_AddExtension(extHandle, extenType, &encodedValue, |
|
3592 criticality, PR_TRUE); |
|
3593 if (rv != SECSuccess) |
|
3594 break; |
|
3595 } while (0); |
|
3596 |
|
3597 return (rv); |
|
3598 } |
|
3599 |
|
3600 CERTCertificate* |
|
3601 SECU_FindCertByNicknameOrFilename(CERTCertDBHandle *handle, |
|
3602 char *name, PRBool ascii, |
|
3603 void *pwarg) |
|
3604 { |
|
3605 CERTCertificate *the_cert; |
|
3606 the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name); |
|
3607 if (the_cert) { |
|
3608 return the_cert; |
|
3609 } |
|
3610 the_cert = PK11_FindCertFromNickname(name, pwarg); |
|
3611 if (!the_cert) { |
|
3612 /* Don't have a cert with name "name" in the DB. Try to |
|
3613 * open a file with such name and get the cert from there.*/ |
|
3614 SECStatus rv; |
|
3615 SECItem item = {0, NULL, 0}; |
|
3616 PRFileDesc* fd = PR_Open(name, PR_RDONLY, 0777); |
|
3617 if (!fd) { |
|
3618 return NULL; |
|
3619 } |
|
3620 rv = SECU_ReadDERFromFile(&item, fd, ascii, PR_FALSE); |
|
3621 PR_Close(fd); |
|
3622 if (rv != SECSuccess || !item.len) { |
|
3623 PORT_Free(item.data); |
|
3624 return NULL; |
|
3625 } |
|
3626 the_cert = CERT_NewTempCertificate(handle, &item, |
|
3627 NULL /* nickname */, |
|
3628 PR_FALSE /* isPerm */, |
|
3629 PR_TRUE /* copyDER */); |
|
3630 PORT_Free(item.data); |
|
3631 } |
|
3632 return the_cert; |
|
3633 } |
|
3634 |
|
3635 /* Convert a SSL/TLS protocol version string into the respective numeric value |
|
3636 * defined by the SSL_LIBRARY_VERSION_* constants, |
|
3637 * while accepting a flexible set of case-insensitive identifiers. |
|
3638 * |
|
3639 * Caller must specify bufLen, allowing the function to operate on substrings. |
|
3640 */ |
|
3641 static SECStatus |
|
3642 SECU_GetSSLVersionFromName(const char *buf, size_t bufLen, PRUint16 *version) |
|
3643 { |
|
3644 if (!buf || !version) { |
|
3645 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3646 return SECFailure; |
|
3647 } |
|
3648 |
|
3649 if (!PL_strncasecmp(buf, "ssl2", bufLen)) { |
|
3650 *version = SSL_LIBRARY_VERSION_2; |
|
3651 return SECSuccess; |
|
3652 } |
|
3653 if (!PL_strncasecmp(buf, "ssl3", bufLen)) { |
|
3654 *version = SSL_LIBRARY_VERSION_3_0; |
|
3655 return SECSuccess; |
|
3656 } |
|
3657 if (!PL_strncasecmp(buf, "tls1.0", bufLen)) { |
|
3658 *version = SSL_LIBRARY_VERSION_TLS_1_0; |
|
3659 return SECSuccess; |
|
3660 } |
|
3661 if (!PL_strncasecmp(buf, "tls1.1", bufLen)) { |
|
3662 *version = SSL_LIBRARY_VERSION_TLS_1_1; |
|
3663 return SECSuccess; |
|
3664 } |
|
3665 if (!PL_strncasecmp(buf, "tls1.2", bufLen)) { |
|
3666 *version = SSL_LIBRARY_VERSION_TLS_1_2; |
|
3667 return SECSuccess; |
|
3668 } |
|
3669 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3670 return SECFailure; |
|
3671 } |
|
3672 |
|
3673 SECStatus |
|
3674 SECU_ParseSSLVersionRangeString(const char *input, |
|
3675 const SSLVersionRange defaultVersionRange, |
|
3676 const PRBool defaultEnableSSL2, |
|
3677 SSLVersionRange *vrange, PRBool *enableSSL2) |
|
3678 { |
|
3679 const char *colonPos; |
|
3680 size_t colonIndex; |
|
3681 const char *maxStr; |
|
3682 |
|
3683 if (!input || !vrange || !enableSSL2) { |
|
3684 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3685 return SECFailure; |
|
3686 } |
|
3687 |
|
3688 if (!strcmp(input, ":")) { |
|
3689 /* special value, use default */ |
|
3690 *enableSSL2 = defaultEnableSSL2; |
|
3691 *vrange = defaultVersionRange; |
|
3692 return SECSuccess; |
|
3693 } |
|
3694 |
|
3695 colonPos = strchr(input, ':'); |
|
3696 if (!colonPos) { |
|
3697 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3698 return SECFailure; |
|
3699 } |
|
3700 |
|
3701 colonIndex = colonPos - input; |
|
3702 maxStr = colonPos + 1; |
|
3703 |
|
3704 if (!colonIndex) { |
|
3705 /* colon was first character, min version is empty */ |
|
3706 *enableSSL2 = defaultEnableSSL2; |
|
3707 vrange->min = defaultVersionRange.min; |
|
3708 } else { |
|
3709 PRUint16 version; |
|
3710 /* colonIndex is equivalent to the length of the min version substring */ |
|
3711 if (SECU_GetSSLVersionFromName(input, colonIndex, &version) != SECSuccess) { |
|
3712 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3713 return SECFailure; |
|
3714 } |
|
3715 |
|
3716 if (version == SSL_LIBRARY_VERSION_2) { |
|
3717 *enableSSL2 = PR_TRUE; |
|
3718 vrange->min = defaultVersionRange.min; |
|
3719 } else { |
|
3720 *enableSSL2 = PR_FALSE; |
|
3721 vrange->min = version; |
|
3722 } |
|
3723 } |
|
3724 |
|
3725 if (!*maxStr) { |
|
3726 vrange->max = defaultVersionRange.max; |
|
3727 } else { |
|
3728 PRUint16 version; |
|
3729 /* if max version is empty, then maxStr points to the string terminator */ |
|
3730 if (SECU_GetSSLVersionFromName(maxStr, strlen(maxStr), &version) |
|
3731 != SECSuccess) { |
|
3732 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3733 return SECFailure; |
|
3734 } |
|
3735 |
|
3736 if (version == SSL_LIBRARY_VERSION_2) { |
|
3737 /* consistency checking, require that min allows enableSSL2, too */ |
|
3738 if (!*enableSSL2) { |
|
3739 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
3740 return SECFailure; |
|
3741 } |
|
3742 /* we use 0 because SSL_LIBRARY_VERSION_NONE is private: */ |
|
3743 vrange->min = 0; |
|
3744 vrange->max = 0; |
|
3745 } else { |
|
3746 vrange->max = version; |
|
3747 } |
|
3748 } |
|
3749 |
|
3750 return SECSuccess; |
|
3751 } |