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(&param, 0, sizeof param);
1235 
1236     rv = SEC_QuickDERDecodeItem(pool, &param,
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, &param.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, &param.maskAlg->algorithm,
1254                                "Mask algorithm", level + 1);
1255             rv = SEC_QuickDERDecodeItem(pool, &maskHashAlg,
1256                                         SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
1257                                         &param.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, &param.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(&param, 0, sizeof param);
1298     rv = SEC_QuickDERDecodeItem(pool, &param, secuKDF2Params, value);
1299     if (rv == SECSuccess) {
1300         SECU_PrintAsHex(out, &param.salt, "Salt", level + 1);
1301         SECU_PrintInteger(out, &param.iterationCount, "Iteration Count",
1302                           level + 1);
1303         SECU_PrintInteger(out, &param.keyLength, "Key Length", level + 1);
1304         SECU_PrintAlgorithmID(out, &param.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(&param, 0, sizeof param);
1328     rv = SEC_QuickDERDecodeItem(pool, &param, secuPBEV2Params, value);
1329     if (rv == SECSuccess) {
1330         SECU_PrintAlgorithmID(out, &param.kdfAlg, "KDF", level + 1);
1331         SECU_PrintAlgorithmID(out, &param.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(&param, 0, sizeof(secuPBEParams));
1355     rv = SEC_QuickDERDecodeItem(pool, &param, secuPBEParamsTemp, value);
1356     if (rv == SECSuccess) {
1357         SECU_PrintAsHex(out, &param.salt, "Salt", level + 1);
1358         SECU_PrintInteger(out, &param.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