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