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