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