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