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