Import 1.9b4 NSS tag from cvs
[mozilla-nss.git] / security / nss / cmd / lib / secutil.c
blob1862f3b7d8d28ba2ac31df3c2503f77c05f28d35
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 ** secutil.c - various functions used by security stuff
42 #include "prtypes.h"
43 #include "prtime.h"
44 #include "prlong.h"
45 #include "prerror.h"
46 #include "prprf.h"
47 #include "plgetopt.h"
48 #include "prenv.h"
49 #include "prnetdb.h"
51 #include "cryptohi.h"
52 #include "secutil.h"
53 #include "secpkcs7.h"
54 #include "secpkcs5.h"
55 #include <stdarg.h>
56 #if !defined(_WIN32_WCE)
57 #include <sys/stat.h>
58 #include <errno.h>
59 #endif
61 #ifdef XP_UNIX
62 #include <unistd.h>
63 #endif
65 /* for SEC_TraverseNames */
66 #include "cert.h"
67 #include "certt.h"
68 #include "certdb.h"
70 /* #include "secmod.h" */
71 #include "pk11func.h"
72 #include "secoid.h"
74 static char consoleName[] = {
75 #ifdef XP_UNIX
76 #ifdef VMS
77 "TT"
78 #else
79 "/dev/tty"
80 #endif
81 #else
82 #ifdef XP_OS2
83 "\\DEV\\CON"
84 #else
85 "CON:"
86 #endif
87 #endif
91 char *
92 SECU_GetString(int16 error_number)
95 static char errString[80];
96 sprintf(errString, "Unknown error string (%d)", error_number);
97 return errString;
100 void
101 SECU_PrintErrMsg(FILE *out, int level, char *progName, char *msg, ...)
103 va_list args;
104 PRErrorCode err = PORT_GetError();
105 const char * errString = SECU_Strerror(err);
107 va_start(args, msg);
109 SECU_Indent(out, level);
110 fprintf(out, "%s: ", progName);
111 vfprintf(out, msg, args);
112 if (errString != NULL && PORT_Strlen(errString) > 0)
113 fprintf(out, ": %s\n", errString);
114 else
115 fprintf(out, ": error %d\n", (int)err);
117 va_end(args);
120 void
121 SECU_PrintError(char *progName, char *msg, ...)
123 va_list args;
124 PRErrorCode err = PORT_GetError();
125 const char * errString = SECU_Strerror(err);
127 va_start(args, msg);
129 fprintf(stderr, "%s: ", progName);
130 vfprintf(stderr, msg, args);
131 if (errString != NULL && PORT_Strlen(errString) > 0)
132 fprintf(stderr, ": %s\n", errString);
133 else
134 fprintf(stderr, ": error %d\n", (int)err);
136 va_end(args);
139 void
140 SECU_PrintSystemError(char *progName, char *msg, ...)
142 va_list args;
144 va_start(args, msg);
145 fprintf(stderr, "%s: ", progName);
146 vfprintf(stderr, msg, args);
147 #if defined(_WIN32_WCE)
148 fprintf(stderr, ": %d\n", PR_GetOSError());
149 #else
150 fprintf(stderr, ": %s\n", strerror(errno));
151 #endif
152 va_end(args);
155 static void
156 secu_ClearPassword(char *p)
158 if (p) {
159 PORT_Memset(p, 0, PORT_Strlen(p));
160 PORT_Free(p);
164 char *
165 SECU_GetPasswordString(void *arg, char *prompt)
167 #ifndef _WINDOWS
168 char *p = NULL;
169 FILE *input, *output;
171 /* open terminal */
172 input = fopen(consoleName, "r");
173 if (input == NULL) {
174 fprintf(stderr, "Error opening input terminal for read\n");
175 return NULL;
178 output = fopen(consoleName, "w");
179 if (output == NULL) {
180 fprintf(stderr, "Error opening output terminal for write\n");
181 return NULL;
184 p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword);
187 fclose(input);
188 fclose(output);
190 return p;
192 #else
193 /* Win32 version of above. opening the console may fail
194 on windows95, and certainly isn't necessary.. */
196 char *p = NULL;
198 p = SEC_GetPassword (stdin, stdout, prompt, SEC_BlindCheckPassword);
199 return p;
201 #endif
206 * p a s s w o r d _ h a r d c o d e
208 * A function to use the password passed in the -f(pwfile) argument
209 * of the command line.
210 * After use once, null it out otherwise PKCS11 calls us forever.?
213 char *
214 SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg)
216 unsigned char phrase[200];
217 PRFileDesc *fd;
218 PRInt32 nb;
219 char *pwFile = arg;
220 int i;
222 if (!pwFile)
223 return 0;
225 if (retry) {
226 return 0; /* no good retrying - the files contents will be the same */
229 fd = PR_Open(pwFile, PR_RDONLY, 0);
230 if (!fd) {
231 fprintf(stderr, "No password file \"%s\" exists.\n", pwFile);
232 return NULL;
235 nb = PR_Read(fd, phrase, sizeof(phrase));
237 PR_Close(fd);
238 /* handle the Windows EOL case */
239 i = 0;
240 while (phrase[i] != '\r' && phrase[i] != '\n' && i < nb) i++;
241 phrase[i] = '\0';
242 if (nb == 0) {
243 fprintf(stderr,"password file contains no data\n");
244 return NULL;
246 return (char*) PORT_Strdup((char*)phrase);
249 char *
250 SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg)
252 char prompt[255];
253 secuPWData *pwdata = (secuPWData *)arg;
254 secuPWData pwnull = { PW_NONE, 0 };
255 secuPWData pwxtrn = { PW_EXTERNAL, "external" };
256 char *pw;
258 if (pwdata == NULL)
259 pwdata = &pwnull;
261 if (PK11_ProtectedAuthenticationPath(slot)) {
262 pwdata = &pwxtrn;
264 if (retry && pwdata->source != PW_NONE) {
265 PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n");
266 return NULL;
269 switch (pwdata->source) {
270 case PW_NONE:
271 sprintf(prompt, "Enter Password or Pin for \"%s\":",
272 PK11_GetTokenName(slot));
273 return SECU_GetPasswordString(NULL, prompt);
274 case PW_FROMFILE:
275 /* Instead of opening and closing the file every time, get the pw
276 * once, then keep it in memory (duh).
278 pw = SECU_FilePasswd(slot, retry, pwdata->data);
279 pwdata->source = PW_PLAINTEXT;
280 pwdata->data = PL_strdup(pw);
281 /* it's already been dup'ed */
282 return pw;
283 case PW_EXTERNAL:
284 sprintf(prompt,
285 "Press Enter, then enter PIN for \"%s\" on external device.\n",
286 PK11_GetTokenName(slot));
287 (void) SECU_GetPasswordString(NULL, prompt);
288 /* Fall Through */
289 case PW_PLAINTEXT:
290 return PL_strdup(pwdata->data);
291 default:
292 break;
295 PR_fprintf(PR_STDERR, "Password check failed: No password found.\n");
296 return NULL;
299 char *
300 secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg)
302 char *p0 = NULL;
303 char *p1 = NULL;
304 FILE *input, *output;
305 secuPWData *pwdata = arg;
307 if (pwdata->source == PW_FROMFILE) {
308 return SECU_FilePasswd(slot, retry, pwdata->data);
310 if (pwdata->source == PW_PLAINTEXT) {
311 return PL_strdup(pwdata->data);
314 /* PW_NONE - get it from tty */
315 /* open terminal */
316 #ifdef _WINDOWS
317 input = stdin;
318 #else
319 input = fopen(consoleName, "r");
320 #endif
321 if (input == NULL) {
322 PR_fprintf(PR_STDERR, "Error opening input terminal for read\n");
323 return NULL;
326 /* we have no password, so initialize database with one */
327 PR_fprintf(PR_STDERR,
328 "Enter a password which will be used to encrypt your keys.\n"
329 "The password should be at least 8 characters long,\n"
330 "and should contain at least one non-alphabetic character.\n\n");
332 output = fopen(consoleName, "w");
333 if (output == NULL) {
334 PR_fprintf(PR_STDERR, "Error opening output terminal for write\n");
335 return NULL;
339 for (;;) {
340 if (p0)
341 PORT_Free(p0);
342 p0 = SEC_GetPassword(input, output, "Enter new password: ",
343 SEC_BlindCheckPassword);
345 if (p1)
346 PORT_Free(p1);
347 p1 = SEC_GetPassword(input, output, "Re-enter password: ",
348 SEC_BlindCheckPassword);
349 if (p0 && p1 && !PORT_Strcmp(p0, p1)) {
350 break;
352 PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n");
355 /* clear out the duplicate password string */
356 secu_ClearPassword(p1);
358 fclose(input);
359 fclose(output);
361 return p0;
364 SECStatus
365 SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile)
367 return SECU_ChangePW2(slot, passwd, 0, pwFile, 0);
370 SECStatus
371 SECU_ChangePW2(PK11SlotInfo *slot, char *oldPass, char *newPass,
372 char *oldPwFile, char *newPwFile)
374 SECStatus rv;
375 secuPWData pwdata, newpwdata;
376 char *oldpw = NULL, *newpw = NULL;
378 if (oldPass) {
379 pwdata.source = PW_PLAINTEXT;
380 pwdata.data = oldPass;
381 } else if (oldPwFile) {
382 pwdata.source = PW_FROMFILE;
383 pwdata.data = oldPwFile;
384 } else {
385 pwdata.source = PW_NONE;
386 pwdata.data = NULL;
389 if (newPass) {
390 newpwdata.source = PW_PLAINTEXT;
391 newpwdata.data = newPass;
392 } else if (newPwFile) {
393 newpwdata.source = PW_FROMFILE;
394 newpwdata.data = newPwFile;
395 } else {
396 newpwdata.source = PW_NONE;
397 newpwdata.data = NULL;
400 if (PK11_NeedUserInit(slot)) {
401 newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata);
402 rv = PK11_InitPin(slot, (char*)NULL, newpw);
403 goto done;
406 for (;;) {
407 oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata);
409 if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) {
410 if (pwdata.source == PW_NONE) {
411 PR_fprintf(PR_STDERR, "Invalid password. Try again.\n");
412 } else {
413 PR_fprintf(PR_STDERR, "Invalid password.\n");
414 PORT_Memset(oldpw, 0, PL_strlen(oldpw));
415 PORT_Free(oldpw);
416 return SECFailure;
418 } else
419 break;
421 PORT_Free(oldpw);
424 newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata);
426 if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) {
427 PR_fprintf(PR_STDERR, "Failed to change password.\n");
428 return SECFailure;
431 PORT_Memset(oldpw, 0, PL_strlen(oldpw));
432 PORT_Free(oldpw);
434 PR_fprintf(PR_STDOUT, "Password changed successfully.\n");
436 done:
437 PORT_Memset(newpw, 0, PL_strlen(newpw));
438 PORT_Free(newpw);
439 return SECSuccess;
442 struct matchobj {
443 SECItem index;
444 char *nname;
445 PRBool found;
448 char *
449 SECU_DefaultSSLDir(void)
451 char *dir;
452 static char sslDir[1000];
454 dir = PR_GetEnv("SSL_DIR");
455 if (!dir)
456 return NULL;
458 sprintf(sslDir, "%s", dir);
460 if (sslDir[strlen(sslDir)-1] == '/')
461 sslDir[strlen(sslDir)-1] = 0;
463 return sslDir;
466 char *
467 SECU_AppendFilenameToDir(char *dir, char *filename)
469 static char path[1000];
471 if (dir[strlen(dir)-1] == '/')
472 sprintf(path, "%s%s", dir, filename);
473 else
474 sprintf(path, "%s/%s", dir, filename);
475 return path;
478 char *
479 SECU_ConfigDirectory(const char* base)
481 static PRBool initted = PR_FALSE;
482 const char *dir = ".netscape";
483 char *home;
484 static char buf[1000];
486 if (initted) return buf;
489 if (base == NULL || *base == 0) {
490 home = PR_GetEnv("HOME");
491 if (!home) home = "";
493 if (*home && home[strlen(home) - 1] == '/')
494 sprintf (buf, "%.900s%s", home, dir);
495 else
496 sprintf (buf, "%.900s/%s", home, dir);
497 } else {
498 sprintf(buf, "%.900s", base);
499 if (buf[strlen(buf) - 1] == '/')
500 buf[strlen(buf) - 1] = 0;
504 initted = PR_TRUE;
505 return buf;
508 /*Turn off SSL for now */
509 /* This gets called by SSL when server wants our cert & key */
511 SECU_GetClientAuthData(void *arg, PRFileDesc *fd,
512 struct CERTDistNamesStr *caNames,
513 struct CERTCertificateStr **pRetCert,
514 struct SECKEYPrivateKeyStr **pRetKey)
516 SECKEYPrivateKey *key;
517 CERTCertificate *cert;
518 int errsave;
520 if (arg == NULL) {
521 fprintf(stderr, "no key/cert name specified for client auth\n");
522 return -1;
524 cert = PK11_FindCertFromNickname(arg, NULL);
525 errsave = PORT_GetError();
526 if (!cert) {
527 if (errsave == SEC_ERROR_BAD_PASSWORD)
528 fprintf(stderr, "Bad password\n");
529 else if (errsave > 0)
530 fprintf(stderr, "Unable to read cert (error %d)\n", errsave);
531 else if (errsave == SEC_ERROR_BAD_DATABASE)
532 fprintf(stderr, "Unable to get cert from database (%d)\n", errsave);
533 else
534 fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave);
535 return -1;
538 key = PK11_FindKeyByAnyCert(arg,NULL);
539 if (!key) {
540 fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError());
541 return -1;
545 *pRetCert = cert;
546 *pRetKey = key;
548 return 0;
551 SECStatus
552 secu_StdinToItem(SECItem *dst)
554 unsigned char buf[1000];
555 PRInt32 numBytes;
556 PRBool notDone = PR_TRUE;
558 dst->len = 0;
559 dst->data = NULL;
561 while (notDone) {
562 numBytes = PR_Read(PR_STDIN, buf, sizeof(buf));
564 if (numBytes < 0) {
565 return SECFailure;
568 if (numBytes == 0)
569 break;
571 if (dst->data) {
572 unsigned char * p = dst->data;
573 dst->data = (unsigned char*)PORT_Realloc(p, dst->len + numBytes);
574 if (!dst->data) {
575 PORT_Free(p);
577 } else {
578 dst->data = (unsigned char*)PORT_Alloc(numBytes);
580 if (!dst->data) {
581 return SECFailure;
583 PORT_Memcpy(dst->data + dst->len, buf, numBytes);
584 dst->len += numBytes;
587 return SECSuccess;
590 SECStatus
591 SECU_FileToItem(SECItem *dst, PRFileDesc *src)
593 PRFileInfo info;
594 PRInt32 numBytes;
595 PRStatus prStatus;
597 if (src == PR_STDIN)
598 return secu_StdinToItem(dst);
600 prStatus = PR_GetOpenFileInfo(src, &info);
602 if (prStatus != PR_SUCCESS) {
603 PORT_SetError(SEC_ERROR_IO);
604 return SECFailure;
607 /* XXX workaround for 3.1, not all utils zero dst before sending */
608 dst->data = 0;
609 if (!SECITEM_AllocItem(NULL, dst, info.size))
610 goto loser;
612 numBytes = PR_Read(src, dst->data, info.size);
613 if (numBytes != info.size) {
614 PORT_SetError(SEC_ERROR_IO);
615 goto loser;
618 return SECSuccess;
619 loser:
620 SECITEM_FreeItem(dst, PR_FALSE);
621 dst->data = NULL;
622 return SECFailure;
625 SECStatus
626 SECU_TextFileToItem(SECItem *dst, PRFileDesc *src)
628 PRFileInfo info;
629 PRInt32 numBytes;
630 PRStatus prStatus;
631 unsigned char *buf;
633 if (src == PR_STDIN)
634 return secu_StdinToItem(dst);
636 prStatus = PR_GetOpenFileInfo(src, &info);
638 if (prStatus != PR_SUCCESS) {
639 PORT_SetError(SEC_ERROR_IO);
640 return SECFailure;
643 buf = (unsigned char*)PORT_Alloc(info.size);
644 if (!buf)
645 return SECFailure;
647 numBytes = PR_Read(src, buf, info.size);
648 if (numBytes != info.size) {
649 PORT_SetError(SEC_ERROR_IO);
650 goto loser;
653 if (buf[numBytes-1] == '\n') numBytes--;
654 #ifdef _WINDOWS
655 if (buf[numBytes-1] == '\r') numBytes--;
656 #endif
658 /* XXX workaround for 3.1, not all utils zero dst before sending */
659 dst->data = 0;
660 if (!SECITEM_AllocItem(NULL, dst, numBytes))
661 goto loser;
663 memcpy(dst->data, buf, numBytes);
665 PORT_Free(buf);
666 return SECSuccess;
667 loser:
668 PORT_Free(buf);
669 return SECFailure;
672 SECStatus
673 SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii)
675 SECStatus rv;
676 if (ascii) {
677 /* First convert ascii to binary */
678 SECItem filedata;
679 char *asc, *body;
681 /* Read in ascii data */
682 rv = SECU_FileToItem(&filedata, inFile);
683 asc = (char *)filedata.data;
684 if (!asc) {
685 fprintf(stderr, "unable to read data from input file\n");
686 return SECFailure;
689 /* check for headers and trailers and remove them */
690 if ((body = strstr(asc, "-----BEGIN")) != NULL) {
691 char *trailer = NULL;
692 asc = body;
693 body = PORT_Strchr(body, '\n');
694 if (!body)
695 body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
696 if (body)
697 trailer = strstr(++body, "-----END");
698 if (trailer != NULL) {
699 *trailer = '\0';
700 } else {
701 fprintf(stderr, "input has header but no trailer\n");
702 PORT_Free(filedata.data);
703 return SECFailure;
705 } else {
706 body = asc;
709 /* Convert to binary */
710 rv = ATOB_ConvertAsciiToItem(der, body);
711 if (rv) {
712 fprintf(stderr, "error converting ascii to binary (%s)\n",
713 SECU_Strerror(PORT_GetError()));
714 PORT_Free(filedata.data);
715 return SECFailure;
718 PORT_Free(filedata.data);
719 } else {
720 /* Read in binary der */
721 rv = SECU_FileToItem(der, inFile);
722 if (rv) {
723 fprintf(stderr, "error converting der (%s)\n",
724 SECU_Strerror(PORT_GetError()));
725 return SECFailure;
728 return SECSuccess;
731 #define INDENT_MULT 4
732 void
733 SECU_Indent(FILE *out, int level)
735 int i;
737 for (i = 0; i < level; i++) {
738 fprintf(out, " ");
742 static void secu_Newline(FILE *out)
744 fprintf(out, "\n");
747 void
748 SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level)
750 unsigned i;
751 int column;
752 PRBool isString = PR_TRUE;
753 PRBool isWhiteSpace = PR_TRUE;
754 PRBool printedHex = PR_FALSE;
755 unsigned int limit = 15;
757 if ( m ) {
758 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
759 level++;
762 SECU_Indent(out, level); column = level*INDENT_MULT;
763 if (!data->len) {
764 fprintf(out, "(empty)\n");
765 return;
767 /* take a pass to see if it's all printable. */
768 for (i = 0; i < data->len; i++) {
769 unsigned char val = data->data[i];
770 if (!val || !isprint(val)) {
771 isString = PR_FALSE;
772 break;
774 if (isWhiteSpace && !isspace(val)) {
775 isWhiteSpace = PR_FALSE;
779 /* Short values, such as bit strings (which are printed with this
780 ** function) often look like strings, but we want to see the bits.
781 ** so this test assures that short values will be printed in hex,
782 ** perhaps in addition to being printed as strings.
783 ** The threshold size (4 bytes) is arbitrary.
785 if (!isString || data->len <= 4) {
786 for (i = 0; i < data->len; i++) {
787 if (i != data->len - 1) {
788 fprintf(out, "%02x:", data->data[i]);
789 column += 3;
790 } else {
791 fprintf(out, "%02x", data->data[i]);
792 column += 2;
793 break;
795 if (column > 76 || (i % 16 == limit)) {
796 secu_Newline(out);
797 SECU_Indent(out, level);
798 column = level*INDENT_MULT;
799 limit = i % 16;
802 printedHex = PR_TRUE;
804 if (isString && !isWhiteSpace) {
805 if (printedHex != PR_FALSE) {
806 secu_Newline(out);
807 SECU_Indent(out, level); column = level*INDENT_MULT;
809 for (i = 0; i < data->len; i++) {
810 unsigned char val = data->data[i];
812 if (val) {
813 fprintf(out,"%c",val);
814 column++;
815 } else {
816 column = 77;
818 if (column > 76) {
819 secu_Newline(out);
820 SECU_Indent(out, level); column = level*INDENT_MULT;
825 if (column != level*INDENT_MULT) {
826 secu_Newline(out);
830 static const char *hex = "0123456789abcdef";
832 static const char printable[257] = {
833 "................" /* 0x */
834 "................" /* 1x */
835 " !\"#$%&'()*+,-./" /* 2x */
836 "0123456789:;<=>?" /* 3x */
837 "@ABCDEFGHIJKLMNO" /* 4x */
838 "PQRSTUVWXYZ[\\]^_" /* 5x */
839 "`abcdefghijklmno" /* 6x */
840 "pqrstuvwxyz{|}~." /* 7x */
841 "................" /* 8x */
842 "................" /* 9x */
843 "................" /* ax */
844 "................" /* bx */
845 "................" /* cx */
846 "................" /* dx */
847 "................" /* ex */
848 "................" /* fx */
851 void
852 SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len)
854 const unsigned char *cp = (const unsigned char *)vp;
855 char buf[80];
856 char *bp;
857 char *ap;
859 fprintf(out, "%s [Len: %d]\n", msg, len);
860 memset(buf, ' ', sizeof buf);
861 bp = buf;
862 ap = buf + 50;
863 while (--len >= 0) {
864 unsigned char ch = *cp++;
865 *bp++ = hex[(ch >> 4) & 0xf];
866 *bp++ = hex[ch & 0xf];
867 *bp++ = ' ';
868 *ap++ = printable[ch];
869 if (ap - buf >= 66) {
870 *ap = 0;
871 fprintf(out, " %s\n", buf);
872 memset(buf, ' ', sizeof buf);
873 bp = buf;
874 ap = buf + 50;
877 if (bp > buf) {
878 *ap = 0;
879 fprintf(out, " %s\n", buf);
883 SECStatus
884 SECU_StripTagAndLength(SECItem *i)
886 unsigned int start;
888 if (!i || !i->data || i->len < 2) { /* must be at least tag and length */
889 return SECFailure;
891 start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2);
892 if (i->len < start) {
893 return SECFailure;
895 i->data += start;
896 i->len -= start;
897 return SECSuccess;
901 /* This expents i->data[0] to be the MSB of the integer.
902 ** if you want to print a DER-encoded integer (with the tag and length)
903 ** call SECU_PrintEncodedInteger();
905 void
906 SECU_PrintInteger(FILE *out, SECItem *i, char *m, int level)
908 int iv;
910 if (!i || !i->len || !i->data) {
911 SECU_Indent(out, level);
912 if (m) {
913 fprintf(out, "%s: (null)\n", m);
914 } else {
915 fprintf(out, "(null)\n");
917 } else if (i->len > 4) {
918 SECU_PrintAsHex(out, i, m, level);
919 } else {
920 if (i->type == siUnsignedInteger && *i->data & 0x80) {
921 /* Make sure i->data has zero in the highest bite
922 * if i->data is an unsigned integer */
923 SECItem tmpI;
924 char data[] = {0, 0, 0, 0, 0};
926 PORT_Memcpy(data + 1, i->data, i->len);
927 tmpI.len = i->len + 1;
928 tmpI.data = (void*)data;
930 iv = DER_GetInteger(&tmpI);
931 } else {
932 iv = DER_GetInteger(i);
934 SECU_Indent(out, level);
935 if (m) {
936 fprintf(out, "%s: %d (0x%x)\n", m, iv, iv);
937 } else {
938 fprintf(out, "%d (0x%x)\n", iv, iv);
943 static void
944 secu_PrintRawString(FILE *out, SECItem *si, char *m, int level)
946 int column;
947 unsigned int i;
949 if ( m ) {
950 SECU_Indent(out, level); fprintf(out, "%s: ", m);
951 column = (level * INDENT_MULT) + strlen(m) + 2;
952 level++;
953 } else {
954 SECU_Indent(out, level);
955 column = level*INDENT_MULT;
957 fprintf(out, "\""); column++;
959 for (i = 0; i < si->len; i++) {
960 unsigned char val = si->data[i];
961 if (column > 76) {
962 secu_Newline(out);
963 SECU_Indent(out, level); column = level*INDENT_MULT;
966 fprintf(out,"%c", printable[val]); column++;
969 fprintf(out, "\""); column++;
970 if (column != level*INDENT_MULT || column > 76) {
971 secu_Newline(out);
975 void
976 SECU_PrintString(FILE *out, SECItem *si, char *m, int level)
978 SECItem my = *si;
980 if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len)
981 return;
982 secu_PrintRawString(out, &my, m, level);
985 /* print an unencoded boolean */
986 static void
987 secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level)
989 int val = 0;
991 if ( i->data && i->len ) {
992 val = i->data[0];
995 if (!m) {
996 m = "Boolean";
998 SECU_Indent(out, level);
999 fprintf(out, "%s: %s\n", m, (val ? "True" : "False"));
1003 * Format and print "time". If the tag message "m" is not NULL,
1004 * do indent formatting based on "level" and add a newline afterward;
1005 * otherwise just print the formatted time string only.
1007 static void
1008 secu_PrintTime(FILE *out, int64 time, char *m, int level)
1010 PRExplodedTime printableTime;
1011 char *timeString;
1013 /* Convert to local time */
1014 PR_ExplodeTime(time, PR_GMTParameters, &printableTime);
1016 timeString = PORT_Alloc(100);
1017 if (timeString == NULL)
1018 return;
1020 if (m != NULL) {
1021 SECU_Indent(out, level);
1022 fprintf(out, "%s: ", m);
1025 PR_FormatTime(timeString, 100, "%a %b %d %H:%M:%S %Y", &printableTime);
1026 fprintf(out, timeString);
1028 if (m != NULL)
1029 fprintf(out, "\n");
1031 PORT_Free(timeString);
1035 * Format and print the UTC Time "t". If the tag message "m" is not NULL,
1036 * do indent formatting based on "level" and add a newline afterward;
1037 * otherwise just print the formatted time string only.
1039 void
1040 SECU_PrintUTCTime(FILE *out, SECItem *t, char *m, int level)
1042 int64 time;
1043 SECStatus rv;
1045 rv = DER_UTCTimeToTime(&time, t);
1046 if (rv != SECSuccess)
1047 return;
1049 secu_PrintTime(out, time, m, level);
1053 * Format and print the Generalized Time "t". If the tag message "m"
1054 * is not NULL, * do indent formatting based on "level" and add a newline
1055 * afterward; otherwise just print the formatted time string only.
1057 void
1058 SECU_PrintGeneralizedTime(FILE *out, SECItem *t, char *m, int level)
1060 int64 time;
1061 SECStatus rv;
1064 rv = DER_GeneralizedTimeToTime(&time, t);
1065 if (rv != SECSuccess)
1066 return;
1068 secu_PrintTime(out, time, m, level);
1072 * Format and print the UTC or Generalized Time "t". If the tag message
1073 * "m" is not NULL, do indent formatting based on "level" and add a newline
1074 * afterward; otherwise just print the formatted time string only.
1076 void
1077 SECU_PrintTimeChoice(FILE *out, SECItem *t, char *m, int level)
1079 switch (t->type) {
1080 case siUTCTime:
1081 SECU_PrintUTCTime(out, t, m, level);
1082 break;
1084 case siGeneralizedTime:
1085 SECU_PrintGeneralizedTime(out, t, m, level);
1086 break;
1088 default:
1089 PORT_Assert(0);
1090 break;
1095 /* This prints a SET or SEQUENCE */
1096 void
1097 SECU_PrintSet(FILE *out, SECItem *t, char *m, int level)
1099 int type = t->data[0] & SEC_ASN1_TAGNUM_MASK;
1100 int constructed = t->data[0] & SEC_ASN1_CONSTRUCTED;
1101 const char * label;
1102 SECItem my = *t;
1104 if (!constructed) {
1105 SECU_PrintAsHex(out, t, m, level);
1106 return;
1108 if (SECSuccess != SECU_StripTagAndLength(&my))
1109 return;
1111 SECU_Indent(out, level);
1112 if (m) {
1113 fprintf(out, "%s: ", m);
1116 if (type == SEC_ASN1_SET)
1117 label = "Set ";
1118 else if (type == SEC_ASN1_SEQUENCE)
1119 label = "Sequence ";
1120 else
1121 label = "";
1122 fprintf(out,"%s{\n", label); /* } */
1124 while (my.len >= 2) {
1125 SECItem tmp = my;
1127 if (tmp.data[1] & 0x80) {
1128 unsigned int i;
1129 unsigned int lenlen = tmp.data[1] & 0x7f;
1130 if (lenlen > sizeof tmp.len)
1131 break;
1132 tmp.len = 0;
1133 for (i=0; i < lenlen; i++) {
1134 tmp.len = (tmp.len << 8) | tmp.data[2+i];
1136 tmp.len += lenlen + 2;
1137 } else {
1138 tmp.len = tmp.data[1] + 2;
1140 if (tmp.len > my.len) {
1141 tmp.len = my.len;
1143 my.data += tmp.len;
1144 my.len -= tmp.len;
1145 SECU_PrintAny(out, &tmp, NULL, level + 1);
1147 SECU_Indent(out, level); fprintf(out, /* { */ "}\n");
1150 static void
1151 secu_PrintContextSpecific(FILE *out, SECItem *i, char *m, int level)
1153 int type = i->data[0] & SEC_ASN1_TAGNUM_MASK;
1154 int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED;
1155 SECItem tmp;
1157 if (constructed) {
1158 char * m2;
1159 if (!m)
1160 m2 = PR_smprintf("[%d]", type);
1161 else
1162 m2 = PR_smprintf("%s: [%d]", m, type);
1163 if (m2) {
1164 SECU_PrintSet(out, i, m2, level);
1165 PR_smprintf_free(m2);
1167 return;
1170 SECU_Indent(out, level);
1171 if (m) {
1172 fprintf(out, "%s: ", m);
1174 fprintf(out,"[%d]\n", type);
1176 tmp = *i;
1177 if (SECSuccess == SECU_StripTagAndLength(&tmp))
1178 SECU_PrintAsHex(out, &tmp, m, level+1);
1181 static void
1182 secu_PrintOctetString(FILE *out, SECItem *i, char *m, int level)
1184 SECItem tmp = *i;
1185 if (SECSuccess == SECU_StripTagAndLength(&tmp))
1186 SECU_PrintAsHex(out, &tmp, m, level);
1189 static void
1190 secu_PrintBitString(FILE *out, SECItem *i, char *m, int level)
1192 int unused_bits;
1193 SECItem tmp = *i;
1195 if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2)
1196 return;
1198 unused_bits = *tmp.data++;
1199 tmp.len--;
1201 SECU_PrintAsHex(out, &tmp, m, level);
1202 if (unused_bits) {
1203 SECU_Indent(out, level + 1);
1204 fprintf(out, "(%d least significant bits unused)\n", unused_bits);
1208 /* in a decoded bit string, the len member is a bit length. */
1209 static void
1210 secu_PrintDecodedBitString(FILE *out, SECItem *i, char *m, int level)
1212 int unused_bits;
1213 SECItem tmp = *i;
1216 unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0;
1217 DER_ConvertBitString(&tmp); /* convert length to byte length */
1219 SECU_PrintAsHex(out, &tmp, m, level);
1220 if (unused_bits) {
1221 SECU_Indent(out, level + 1);
1222 fprintf(out, "(%d least significant bits unused)\n", unused_bits);
1227 /* Print a DER encoded Boolean */
1228 void
1229 SECU_PrintEncodedBoolean(FILE *out, SECItem *i, char *m, int level)
1231 SECItem my = *i;
1232 if (SECSuccess == SECU_StripTagAndLength(&my))
1233 secu_PrintBoolean(out, &my, m, level);
1236 /* Print a DER encoded integer */
1237 void
1238 SECU_PrintEncodedInteger(FILE *out, SECItem *i, char *m, int level)
1240 SECItem my = *i;
1241 if (SECSuccess == SECU_StripTagAndLength(&my))
1242 SECU_PrintInteger(out, &my, m, level);
1245 /* Print a DER encoded OID */
1246 void
1247 SECU_PrintEncodedObjectID(FILE *out, SECItem *i, char *m, int level)
1249 SECItem my = *i;
1250 if (SECSuccess == SECU_StripTagAndLength(&my))
1251 SECU_PrintObjectID(out, &my, m, level);
1254 static void
1255 secu_PrintBMPString(FILE *out, SECItem *i, char *m, int level)
1257 unsigned char * s;
1258 unsigned char * d;
1259 int len;
1260 SECItem tmp = {0, 0, 0};
1261 SECItem my = *i;
1263 if (SECSuccess != SECU_StripTagAndLength(&my))
1264 goto loser;
1265 if (my.len % 2)
1266 goto loser;
1267 len = (int)(my.len / 2);
1268 tmp.data = (unsigned char *)PORT_Alloc(len);
1269 if (!tmp.data)
1270 goto loser;
1271 tmp.len = len;
1272 for (s = my.data, d = tmp.data ; len > 0; len--) {
1273 PRUint32 bmpChar = (s[0] << 8) | s[1]; s += 2;
1274 if (!isprint(bmpChar))
1275 goto loser;
1276 *d++ = (unsigned char)bmpChar;
1278 secu_PrintRawString(out, &tmp, m, level);
1279 PORT_Free(tmp.data);
1280 return;
1282 loser:
1283 SECU_PrintAsHex(out, i, m, level);
1284 if (tmp.data)
1285 PORT_Free(tmp.data);
1288 static void
1289 secu_PrintUniversalString(FILE *out, SECItem *i, char *m, int level)
1291 unsigned char * s;
1292 unsigned char * d;
1293 int len;
1294 SECItem tmp = {0, 0, 0};
1295 SECItem my = *i;
1297 if (SECSuccess != SECU_StripTagAndLength(&my))
1298 goto loser;
1299 if (my.len % 4)
1300 goto loser;
1301 len = (int)(my.len / 4);
1302 tmp.data = (unsigned char *)PORT_Alloc(len);
1303 if (!tmp.data)
1304 goto loser;
1305 tmp.len = len;
1306 for (s = my.data, d = tmp.data ; len > 0; len--) {
1307 PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
1308 s += 4;
1309 if (!isprint(bmpChar))
1310 goto loser;
1311 *d++ = (unsigned char)bmpChar;
1313 secu_PrintRawString(out, &tmp, m, level);
1314 PORT_Free(tmp.data);
1315 return;
1317 loser:
1318 SECU_PrintAsHex(out, i, m, level);
1319 if (tmp.data)
1320 PORT_Free(tmp.data);
1323 static void
1324 secu_PrintUniversal(FILE *out, SECItem *i, char *m, int level)
1326 switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) {
1327 case SEC_ASN1_ENUMERATED:
1328 case SEC_ASN1_INTEGER:
1329 SECU_PrintEncodedInteger(out, i, m, level);
1330 break;
1331 case SEC_ASN1_OBJECT_ID:
1332 SECU_PrintEncodedObjectID(out, i, m, level);
1333 break;
1334 case SEC_ASN1_BOOLEAN:
1335 SECU_PrintEncodedBoolean(out, i, m, level);
1336 break;
1337 case SEC_ASN1_UTF8_STRING:
1338 case SEC_ASN1_PRINTABLE_STRING:
1339 case SEC_ASN1_VISIBLE_STRING:
1340 case SEC_ASN1_IA5_STRING:
1341 case SEC_ASN1_T61_STRING:
1342 SECU_PrintString(out, i, m, level);
1343 break;
1344 case SEC_ASN1_GENERALIZED_TIME:
1345 SECU_PrintGeneralizedTime(out, i, m, level);
1346 break;
1347 case SEC_ASN1_UTC_TIME:
1348 SECU_PrintUTCTime(out, i, m, level);
1349 break;
1350 case SEC_ASN1_NULL:
1351 SECU_Indent(out, level);
1352 if (m && m[0])
1353 fprintf(out, "%s: NULL\n", m);
1354 else
1355 fprintf(out, "NULL\n");
1356 break;
1357 case SEC_ASN1_SET:
1358 case SEC_ASN1_SEQUENCE:
1359 SECU_PrintSet(out, i, m, level);
1360 break;
1361 case SEC_ASN1_OCTET_STRING:
1362 secu_PrintOctetString(out, i, m, level);
1363 break;
1364 case SEC_ASN1_BIT_STRING:
1365 secu_PrintBitString(out, i, m, level);
1366 break;
1367 case SEC_ASN1_BMP_STRING:
1368 secu_PrintBMPString(out, i, m, level);
1369 break;
1370 case SEC_ASN1_UNIVERSAL_STRING:
1371 secu_PrintUniversalString(out, i, m, level);
1372 break;
1373 default:
1374 SECU_PrintAsHex(out, i, m, level);
1375 break;
1379 void
1380 SECU_PrintAny(FILE *out, SECItem *i, char *m, int level)
1382 if ( i && i->len && i->data ) {
1383 switch (i->data[0] & SEC_ASN1_CLASS_MASK) {
1384 case SEC_ASN1_CONTEXT_SPECIFIC:
1385 secu_PrintContextSpecific(out, i, m, level);
1386 break;
1387 case SEC_ASN1_UNIVERSAL:
1388 secu_PrintUniversal(out, i, m, level);
1389 break;
1390 default:
1391 SECU_PrintAsHex(out, i, m, level);
1392 break;
1397 static int
1398 secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level)
1400 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
1401 SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level+1);
1402 SECU_PrintTimeChoice(out, &v->notAfter, "Not After ", level+1);
1403 return 0;
1406 /* This function does NOT expect a DER type and length. */
1407 SECOidTag
1408 SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level)
1410 SECOidData *oiddata;
1411 char * oidString = NULL;
1413 oiddata = SECOID_FindOID(oid);
1414 if (oiddata != NULL) {
1415 const char *name = oiddata->desc;
1416 SECU_Indent(out, level);
1417 if (m != NULL)
1418 fprintf(out, "%s: ", m);
1419 fprintf(out, "%s\n", name);
1420 return oiddata->offset;
1422 oidString = CERT_GetOidString(oid);
1423 if (oidString) {
1424 SECU_Indent(out, level);
1425 if (m != NULL)
1426 fprintf(out, "%s: ", m);
1427 fprintf(out, "%s\n", oidString);
1428 PR_smprintf_free(oidString);
1429 return SEC_OID_UNKNOWN;
1431 SECU_PrintAsHex(out, oid, m, level);
1432 return SEC_OID_UNKNOWN;
1435 typedef struct secuPBEParamsStr {
1436 SECItem salt;
1437 SECItem iterationCount;
1438 SECItem keyLength;
1439 SECAlgorithmID cipherAlg;
1440 SECAlgorithmID kdfAlg;
1441 } secuPBEParams;
1443 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate);
1445 /* SECOID_PKCS5_PBKDF2 */
1446 const SEC_ASN1Template secuKDF2Params[] =
1448 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) },
1449 { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) },
1450 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) },
1451 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, keyLength) },
1452 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg),
1453 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1454 { 0 }
1457 /* PKCS5v1 & PKCS12 */
1458 const SEC_ASN1Template secuPBEParamsTemp[] =
1460 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) },
1461 { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) },
1462 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) },
1463 { 0 }
1466 /* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */
1467 const SEC_ASN1Template secuPBEV2Params[] =
1469 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams)},
1470 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg),
1471 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1472 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, cipherAlg),
1473 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
1474 { 0 }
1477 void
1478 secu_PrintKDF2Params(FILE *out, SECItem *value, char *m, int level)
1480 PRArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1481 SECStatus rv;
1482 secuPBEParams param;
1484 if (m) {
1485 SECU_Indent(out, level);
1486 fprintf (out, "%s:\n", m);
1489 if (!pool) {
1490 SECU_Indent(out, level);
1491 fprintf(out, "Out of memory\n");
1492 return;
1495 PORT_Memset(&param, 0, sizeof param);
1496 rv = SEC_QuickDERDecodeItem(pool, &param, secuKDF2Params, value);
1497 if (rv == SECSuccess) {
1498 SECU_PrintAsHex(out, &param.salt, "Salt", level+1);
1499 SECU_PrintInteger(out, &param.iterationCount, "Iteration Count",
1500 level+1);
1501 SECU_PrintInteger(out, &param.keyLength, "Key Length", level+1);
1502 SECU_PrintAlgorithmID(out, &param.kdfAlg, "KDF algorithm", level+1);
1504 PORT_FreeArena(pool, PR_FALSE);
1507 void
1508 secu_PrintPKCS5V2Params(FILE *out, SECItem *value, char *m, int level)
1510 PRArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1511 SECStatus rv;
1512 secuPBEParams param;
1514 if (m) {
1515 SECU_Indent(out, level);
1516 fprintf (out, "%s:\n", m);
1519 if (!pool) {
1520 SECU_Indent(out, level);
1521 fprintf(out, "Out of memory\n");
1522 return;
1525 PORT_Memset(&param, 0, sizeof param);
1526 rv = SEC_QuickDERDecodeItem(pool, &param, secuPBEV2Params, value);
1527 if (rv == SECSuccess) {
1528 SECU_PrintAlgorithmID(out, &param.kdfAlg, "KDF", level+1);
1529 SECU_PrintAlgorithmID(out, &param.cipherAlg, "Cipher", level+1);
1531 PORT_FreeArena(pool, PR_FALSE);
1534 void
1535 secu_PrintPBEParams(FILE *out, SECItem *value, char *m, int level)
1537 PRArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1538 SECStatus rv;
1539 secuPBEParams param;
1541 if (m) {
1542 SECU_Indent(out, level);
1543 fprintf (out, "%s:\n", m);
1546 if (!pool) {
1547 SECU_Indent(out, level);
1548 fprintf(out, "Out of memory\n");
1549 return;
1552 PORT_Memset(&param, 0, sizeof(secuPBEParams));
1553 rv = SEC_QuickDERDecodeItem(pool, &param, secuPBEParamsTemp, value);
1554 if (rv == SECSuccess) {
1555 SECU_PrintAsHex(out, &param.salt, "Salt", level+1);
1556 SECU_PrintInteger(out, &param.iterationCount, "Iteration Count",
1557 level+1);
1559 PORT_FreeArena(pool, PR_FALSE);
1562 /* This function does NOT expect a DER type and length. */
1563 void
1564 SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level)
1566 SECOidTag algtag;
1567 SECU_PrintObjectID(out, &a->algorithm, m, level);
1569 algtag = SECOID_GetAlgorithmTag(a);
1570 if (SEC_PKCS5IsAlgorithmPBEAlgTag(algtag)) {
1571 switch (algtag) {
1572 case SEC_OID_PKCS5_PBKDF2:
1573 secu_PrintKDF2Params(out, &a->parameters, "Parameters", level+1);
1574 break;
1575 case SEC_OID_PKCS5_PBES2:
1576 secu_PrintPKCS5V2Params(out, &a->parameters, "Encryption", level+1);
1577 break;
1578 case SEC_OID_PKCS5_PBMAC1:
1579 secu_PrintPKCS5V2Params(out, &a->parameters, "MAC", level+1);
1580 break;
1581 default:
1582 secu_PrintPBEParams(out, &a->parameters, "Parameters", level+1);
1583 break;
1585 return;
1589 if (a->parameters.len == 0
1590 || (a->parameters.len == 2
1591 && PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) {
1592 /* No arguments or NULL argument */
1593 } else {
1594 /* Print args to algorithm */
1595 SECU_PrintAsHex(out, &a->parameters, "Args", level+1);
1599 static void
1600 secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level)
1602 SECItem *value;
1603 int i;
1604 char om[100];
1606 if (m) {
1607 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
1611 * Should make this smarter; look at the type field and then decode
1612 * and print the value(s) appropriately!
1614 SECU_PrintObjectID(out, &(attr->type), "Type", level+1);
1615 if (attr->values != NULL) {
1616 i = 0;
1617 while ((value = attr->values[i++]) != NULL) {
1618 sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : "");
1619 if (attr->encoded || attr->typeTag == NULL) {
1620 SECU_PrintAny(out, value, om, level+1);
1621 } else {
1622 switch (attr->typeTag->offset) {
1623 default:
1624 SECU_PrintAsHex(out, value, om, level+1);
1625 break;
1626 case SEC_OID_PKCS9_CONTENT_TYPE:
1627 SECU_PrintObjectID(out, value, om, level+1);
1628 break;
1629 case SEC_OID_PKCS9_SIGNING_TIME:
1630 SECU_PrintTimeChoice(out, value, om, level+1);
1631 break;
1638 static void
1639 secu_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
1642 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
1643 SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1);
1644 SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1);
1645 if (pk->u.rsa.publicExponent.len == 1 &&
1646 pk->u.rsa.publicExponent.data[0] == 1) {
1647 SECU_Indent(out, level +1); fprintf(out, "Error: INVALID RSA KEY!\n");
1651 static void
1652 secu_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
1654 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
1655 SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level+1);
1656 SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level+1);
1657 SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level+1);
1658 SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level+1);
1661 #ifdef NSS_ENABLE_ECC
1662 static void
1663 secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
1665 SECItem curveOID = { siBuffer, NULL, 0};
1667 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
1668 SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level+1);
1669 /* For named curves, the DEREncodedParams field contains an
1670 * ASN Object ID (0x06 is SEC_ASN1_OBJECT_ID).
1672 if ((pk->u.ec.DEREncodedParams.len > 2) &&
1673 (pk->u.ec.DEREncodedParams.data[0] == 0x06)) {
1674 curveOID.len = pk->u.ec.DEREncodedParams.data[1];
1675 curveOID.data = pk->u.ec.DEREncodedParams.data + 2;
1676 SECU_PrintObjectID(out, &curveOID, "Curve", level +1);
1679 #endif /* NSS_ENABLE_ECC */
1681 static void
1682 secu_PrintSubjectPublicKeyInfo(FILE *out, PRArenaPool *arena,
1683 CERTSubjectPublicKeyInfo *i, char *msg, int level)
1685 SECKEYPublicKey *pk;
1687 SECU_Indent(out, level); fprintf(out, "%s:\n", msg);
1688 SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level+1);
1690 pk = SECKEY_ExtractPublicKey(i);
1691 if (pk) {
1692 switch (pk->keyType) {
1693 case rsaKey:
1694 secu_PrintRSAPublicKey(out, pk, "RSA Public Key", level +1);
1695 break;
1697 case dsaKey:
1698 secu_PrintDSAPublicKey(out, pk, "DSA Public Key", level +1);
1699 break;
1701 #ifdef NSS_ENABLE_ECC
1702 case ecKey:
1703 secu_PrintECPublicKey(out, pk, "EC Public Key", level +1);
1704 break;
1705 #endif
1707 case dhKey:
1708 case fortezzaKey:
1709 case keaKey:
1710 SECU_Indent(out, level);
1711 fprintf(out, "unable to format this SPKI algorithm type\n");
1712 goto loser;
1713 default:
1714 SECU_Indent(out, level);
1715 fprintf(out, "unknown SPKI algorithm type\n");
1716 goto loser;
1718 PORT_FreeArena(pk->arena, PR_FALSE);
1719 } else {
1720 SECU_PrintErrMsg(out, level, "Error", "Parsing public key");
1721 loser:
1722 if (i->subjectPublicKey.data) {
1723 SECU_PrintAny(out, &i->subjectPublicKey, "Raw", level);
1728 static SECStatus
1729 secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level)
1731 SECItem decodedValue;
1732 SECStatus rv;
1733 int64 invalidTime;
1734 char *formattedTime = NULL;
1736 decodedValue.data = NULL;
1737 rv = SEC_ASN1DecodeItem (NULL, &decodedValue,
1738 SEC_ASN1_GET(SEC_GeneralizedTimeTemplate),
1739 value);
1740 if (rv == SECSuccess) {
1741 rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue);
1742 if (rv == SECSuccess) {
1743 formattedTime = CERT_GenTime2FormattedAscii
1744 (invalidTime, "%a %b %d %H:%M:%S %Y");
1745 SECU_Indent(out, level +1);
1746 fprintf (out, "%s: %s\n", msg, formattedTime);
1747 PORT_Free (formattedTime);
1750 PORT_Free (decodedValue.data);
1751 return (rv);
1754 static SECStatus
1755 PrintExtKeyUsageExtension (FILE *out, SECItem *value, char *msg, int level)
1757 CERTOidSequence *os;
1758 SECItem **op;
1760 os = CERT_DecodeOidSequence(value);
1761 if( (CERTOidSequence *)NULL == os ) {
1762 return SECFailure;
1765 for( op = os->oids; *op; op++ ) {
1766 SECU_PrintObjectID(out, *op, msg, level + 1);
1768 CERT_DestroyOidSequence(os);
1769 return SECSuccess;
1772 static SECStatus
1773 secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) {
1774 CERTBasicConstraints constraints;
1775 SECStatus rv;
1777 SECU_Indent(out, level);
1778 if (msg) {
1779 fprintf(out,"%s: ",msg);
1781 rv = CERT_DecodeBasicConstraintValue(&constraints,value);
1782 if (rv == SECSuccess && constraints.isCA) {
1783 if (constraints.pathLenConstraint >= 0) {
1784 fprintf(out,"Is a CA with a maximum path length of %d.\n",
1785 constraints.pathLenConstraint);
1786 } else {
1787 fprintf(out,"Is a CA with no maximum path length.\n");
1789 } else {
1790 fprintf(out,"Is not a CA.\n");
1792 return SECSuccess;
1795 static const char * const nsTypeBits[] = {
1796 "SSL Client",
1797 "SSL Server",
1798 "S/MIME",
1799 "Object Signing",
1800 "Reserved",
1801 "SSL CA",
1802 "S/MIME CA",
1803 "ObjectSigning CA"
1806 /* NSCertType is merely a bit string whose bits are displayed symbolically */
1807 static SECStatus
1808 secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level)
1810 int unused;
1811 int NS_Type;
1812 int i;
1813 int found = 0;
1814 SECItem my = *value;
1816 if ((my.data[0] != SEC_ASN1_BIT_STRING) ||
1817 SECSuccess != SECU_StripTagAndLength(&my)) {
1818 SECU_PrintAny(out, value, "Data", level);
1819 return SECSuccess;
1822 unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0;
1823 NS_Type = my.data[1] & (0xff << unused);
1826 SECU_Indent(out, level);
1827 if (msg) {
1828 fprintf(out,"%s: ",msg);
1829 } else {
1830 fprintf(out,"Netscape Certificate Type: ");
1832 for (i=0; i < 8; i++) {
1833 if ( (0x80 >> i) & NS_Type) {
1834 fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]);
1835 found = 1;
1838 fprintf(out, (found ? ">\n" : "none\n"));
1839 return SECSuccess;
1842 static const char * const usageBits[] = {
1843 "Digital Signature", /* 0x80 */
1844 "Non-Repudiation", /* 0x40 */
1845 "Key Encipherment", /* 0x20 */
1846 "Data Encipherment", /* 0x10 */
1847 "Key Agreement", /* 0x08 */
1848 "Certificate Signing", /* 0x04 */
1849 "CRL Signing", /* 0x02 */
1850 "Encipher Only", /* 0x01 */
1851 "Decipher Only", /* 0x0080 */
1852 NULL
1855 /* X509KeyUsage is merely a bit string whose bits are displayed symbolically */
1856 static void
1857 secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level)
1859 int unused;
1860 int usage;
1861 int i;
1862 int found = 0;
1863 SECItem my = *value;
1865 if ((my.data[0] != SEC_ASN1_BIT_STRING) ||
1866 SECSuccess != SECU_StripTagAndLength(&my)) {
1867 SECU_PrintAny(out, value, "Data", level);
1868 return;
1871 unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0;
1872 usage = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8
1873 : (my.data[1] << 8) |
1874 (my.data[2] & (0xff << unused));
1876 SECU_Indent(out, level);
1877 fprintf(out, "Usages: ");
1878 for (i=0; usageBits[i]; i++) {
1879 if ( (0x8000 >> i) & usage) {
1880 if (found)
1881 SECU_Indent(out, level + 2);
1882 fprintf(out, "%s\n", usageBits[i]);
1883 found = 1;
1886 if (!found) {
1887 fprintf(out, "(none)\n");
1891 static void
1892 secu_PrintIPAddress(FILE *out, SECItem *value, char *msg, int level)
1894 PRStatus st;
1895 PRNetAddr addr;
1896 char addrBuf[80];
1898 memset(&addr, 0, sizeof addr);
1899 if (value->len == 4) {
1900 addr.inet.family = PR_AF_INET;
1901 memcpy(&addr.inet.ip, value->data, value->len);
1902 } else if (value->len == 16) {
1903 addr.ipv6.family = PR_AF_INET6;
1904 memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len);
1905 if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) {
1906 /* convert to IPv4. */
1907 addr.inet.family = PR_AF_INET;
1908 memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4);
1909 memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad);
1911 } else {
1912 goto loser;
1915 st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf);
1916 if (st == PR_SUCCESS) {
1917 SECU_Indent(out, level);
1918 fprintf(out, "%s: %s\n", msg, addrBuf);
1919 } else {
1920 loser:
1921 SECU_PrintAsHex(out, value, msg, level);
1926 static void
1927 secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, char *msg, int level)
1929 char label[40];
1930 if (msg && msg[0]) {
1931 SECU_Indent(out, level++); fprintf(out, "%s: \n", msg);
1933 switch (gname->type) {
1934 case certOtherName :
1935 SECU_PrintAny( out, &gname->name.OthName.name, "Other Name", level);
1936 SECU_PrintObjectID(out, &gname->name.OthName.oid, "OID", level+1);
1937 break;
1938 case certDirectoryName :
1939 SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level);
1940 break;
1941 case certRFC822Name :
1942 secu_PrintRawString( out, &gname->name.other, "RFC822 Name", level);
1943 break;
1944 case certDNSName :
1945 secu_PrintRawString( out, &gname->name.other, "DNS name", level);
1946 break;
1947 case certURI :
1948 secu_PrintRawString( out, &gname->name.other, "URI", level);
1949 break;
1950 case certIPAddress :
1951 secu_PrintIPAddress(out, &gname->name.other, "IP Address", level);
1952 break;
1953 case certRegisterID :
1954 SECU_PrintObjectID( out, &gname->name.other, "Registered ID", level);
1955 break;
1956 case certX400Address :
1957 SECU_PrintAny( out, &gname->name.other, "X400 Address", level);
1958 break;
1959 case certEDIPartyName :
1960 SECU_PrintAny( out, &gname->name.other, "EDI Party", level);
1961 break;
1962 default:
1963 PR_snprintf(label, sizeof label, "unknown type [%d]",
1964 (int)gname->type - 1);
1965 SECU_PrintAsHex(out, &gname->name.other, label, level);
1966 break;
1970 static void
1971 secu_PrintGeneralNames(FILE *out, CERTGeneralName *gname, char *msg, int level)
1973 CERTGeneralName *name = gname;
1974 do {
1975 secu_PrintGeneralName(out, name, msg, level);
1976 name = CERT_GetNextGeneralName(name);
1977 } while (name && name != gname);
1981 static void
1982 secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level)
1984 CERTAuthKeyID *kid = NULL;
1985 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1987 if (!pool) {
1988 SECU_PrintError("Error", "Allocating new ArenaPool");
1989 return;
1991 kid = CERT_DecodeAuthKeyID(pool, value);
1992 if (!kid) {
1993 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
1994 SECU_PrintAny(out, value, "Data", level);
1995 } else {
1996 int keyIDPresent = (kid->keyID.data && kid->keyID.len);
1997 int issuerPresent = kid->authCertIssuer != NULL;
1998 int snPresent = (kid->authCertSerialNumber.data &&
1999 kid->authCertSerialNumber.len);
2001 if ((keyIDPresent && !issuerPresent && !snPresent) ||
2002 (!keyIDPresent && issuerPresent && snPresent)) {
2003 /* all is well */
2004 } else {
2005 SECU_Indent(out, level);
2006 fprintf(out,
2007 "Error: KeyID OR (Issuer AND Serial) must be present, not both.\n");
2009 if (keyIDPresent)
2010 SECU_PrintAsHex(out, &kid->keyID, "Key ID", level);
2011 if (issuerPresent)
2012 secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level);
2013 if (snPresent)
2014 SECU_PrintInteger(out, &kid->authCertSerialNumber,
2015 "Serial Number", level);
2017 PORT_FreeArena(pool, PR_FALSE);
2021 static void
2022 secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level)
2024 CERTGeneralName * nameList;
2025 CERTGeneralName * current;
2026 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2028 if (!pool) {
2029 SECU_PrintError("Error", "Allocating new ArenaPool");
2030 return;
2032 nameList = current = CERT_DecodeAltNameExtension(pool, value);
2033 if (!current) {
2034 if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
2035 /* Decoder found empty sequence, which is invalid. */
2036 PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
2038 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
2039 SECU_PrintAny(out, value, "Data", level);
2040 } else {
2041 do {
2042 secu_PrintGeneralName(out, current, msg, level);
2043 current = CERT_GetNextGeneralName(current);
2044 } while (current != nameList);
2046 PORT_FreeArena(pool, PR_FALSE);
2049 static void
2050 secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level)
2052 CERTCrlDistributionPoints * dPoints;
2053 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2055 if (!pool) {
2056 SECU_PrintError("Error", "Allocating new ArenaPool");
2057 return;
2059 dPoints = CERT_DecodeCRLDistributionPoints(pool, value);
2060 if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) {
2061 CRLDistributionPoint ** pPoints = dPoints->distPoints;
2062 CRLDistributionPoint * pPoint;
2063 while (NULL != (pPoint = *pPoints++)) {
2064 if (pPoint->distPointType == generalName &&
2065 pPoint->distPoint.fullName != NULL) {
2066 secu_PrintGeneralNames(out, pPoint->distPoint.fullName, NULL,
2067 level);
2068 #if defined(LATER)
2069 } else if (pPoint->distPointType == relativeDistinguishedName) {
2070 /* print the relative name */
2071 #endif
2072 } else if (pPoint->derDistPoint.data) {
2073 SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level);
2075 if (pPoint->reasons.data) {
2076 secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons",
2077 level);
2079 if (pPoint->crlIssuer) {
2080 secu_PrintGeneralName(out, pPoint->crlIssuer, "Issuer", level);
2083 } else {
2084 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
2085 SECU_PrintAny(out, value, "Data", level);
2087 PORT_FreeArena(pool, PR_FALSE);
2091 static void
2092 secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value,
2093 char *msg, int level)
2095 CERTNameConstraint *head = value;
2096 SECU_Indent(out, level); fprintf(out, "%s Subtree:\n", msg);
2097 level++;
2098 do {
2099 secu_PrintGeneralName(out, &value->name, NULL, level);
2100 if (value->min.data)
2101 SECU_PrintInteger(out, &value->min, "Minimum", level+1);
2102 if (value->max.data)
2103 SECU_PrintInteger(out, &value->max, "Maximum", level+1);
2104 value = CERT_GetNextNameConstraint(value);
2105 } while (value != head);
2108 static void
2109 secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, char *msg, int level)
2111 CERTNameConstraints * cnstrnts;
2112 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2114 if (!pool) {
2115 SECU_PrintError("Error", "Allocating new ArenaPool");
2116 return;
2118 cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value);
2119 if (!cnstrnts) {
2120 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
2121 SECU_PrintAny(out, value, "Raw", level);
2122 } else {
2123 if (cnstrnts->permited)
2124 secu_PrintNameConstraintSubtree(out, cnstrnts->permited,
2125 "Permitted", level);
2126 if (cnstrnts->excluded)
2127 secu_PrintNameConstraintSubtree(out, cnstrnts->excluded,
2128 "Excluded", level);
2130 PORT_FreeArena(pool, PR_FALSE);
2134 static void
2135 secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level)
2137 CERTAuthInfoAccess **infos = NULL;
2138 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2140 if (!pool) {
2141 SECU_PrintError("Error", "Allocating new ArenaPool");
2142 return;
2144 infos = CERT_DecodeAuthInfoAccessExtension(pool, value);
2145 if (!infos) {
2146 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
2147 SECU_PrintAny(out, value, "Raw", level);
2148 } else {
2149 CERTAuthInfoAccess *info;
2150 while (NULL != (info = *infos++)) {
2151 if (info->method.data) {
2152 SECU_PrintObjectID(out, &info->method, "Method", level);
2153 } else {
2154 SECU_Indent(out,level);
2155 fprintf(out, "Error: missing method\n");
2157 if (info->location) {
2158 secu_PrintGeneralName(out, info->location, "Location", level);
2159 } else {
2160 SECU_PrintAny(out, &info->derLocation, "Location", level);
2164 PORT_FreeArena(pool, PR_FALSE);
2168 void
2169 SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions,
2170 char *msg, int level)
2172 SECOidTag oidTag;
2174 if ( extensions ) {
2175 if (msg && *msg) {
2176 SECU_Indent(out, level++); fprintf(out, "%s:\n", msg);
2179 while ( *extensions ) {
2180 SECItem *tmpitem;
2182 tmpitem = &(*extensions)->id;
2183 SECU_PrintObjectID(out, tmpitem, "Name", level);
2185 tmpitem = &(*extensions)->critical;
2186 if ( tmpitem->len ) {
2187 secu_PrintBoolean(out, tmpitem, "Critical", level);
2190 oidTag = SECOID_FindOIDTag (&((*extensions)->id));
2191 tmpitem = &((*extensions)->value);
2193 switch (oidTag) {
2194 case SEC_OID_X509_INVALID_DATE:
2195 case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME:
2196 secu_PrintX509InvalidDate(out, tmpitem, "Date", level );
2197 break;
2198 case SEC_OID_X509_CERTIFICATE_POLICIES:
2199 SECU_PrintPolicy(out, tmpitem, "Data", level );
2200 break;
2201 case SEC_OID_NS_CERT_EXT_BASE_URL:
2202 case SEC_OID_NS_CERT_EXT_REVOCATION_URL:
2203 case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL:
2204 case SEC_OID_NS_CERT_EXT_CA_CRL_URL:
2205 case SEC_OID_NS_CERT_EXT_CA_CERT_URL:
2206 case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL:
2207 case SEC_OID_NS_CERT_EXT_CA_POLICY_URL:
2208 case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL:
2209 case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL:
2210 case SEC_OID_OCSP_RESPONDER:
2211 SECU_PrintString(out,tmpitem, "URL", level);
2212 break;
2213 case SEC_OID_NS_CERT_EXT_COMMENT:
2214 SECU_PrintString(out,tmpitem, "Comment", level);
2215 break;
2216 case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME:
2217 SECU_PrintString(out,tmpitem, "ServerName", level);
2218 break;
2219 case SEC_OID_NS_CERT_EXT_CERT_TYPE:
2220 secu_PrintNSCertType(out,tmpitem,"Data",level);
2221 break;
2222 case SEC_OID_X509_BASIC_CONSTRAINTS:
2223 secu_PrintBasicConstraints(out,tmpitem,"Data",level);
2224 break;
2225 case SEC_OID_X509_EXT_KEY_USAGE:
2226 PrintExtKeyUsageExtension(out, tmpitem, NULL, level);
2227 break;
2228 case SEC_OID_X509_KEY_USAGE:
2229 secu_PrintX509KeyUsage(out, tmpitem, NULL, level );
2230 break;
2231 case SEC_OID_X509_AUTH_KEY_ID:
2232 secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level );
2233 break;
2234 case SEC_OID_X509_SUBJECT_ALT_NAME:
2235 case SEC_OID_X509_ISSUER_ALT_NAME:
2236 secu_PrintAltNameExtension(out, tmpitem, NULL, level );
2237 break;
2238 case SEC_OID_X509_CRL_DIST_POINTS:
2239 secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level );
2240 break;
2241 case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD:
2242 SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL,
2243 level );
2244 break;
2245 case SEC_OID_X509_NAME_CONSTRAINTS:
2246 secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level);
2247 break;
2248 case SEC_OID_X509_AUTH_INFO_ACCESS:
2249 secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level);
2250 break;
2252 case SEC_OID_X509_CRL_NUMBER:
2253 case SEC_OID_X509_REASON_CODE:
2255 /* PKIX OIDs */
2256 case SEC_OID_PKIX_OCSP:
2257 case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:
2258 case SEC_OID_PKIX_OCSP_NONCE:
2259 case SEC_OID_PKIX_OCSP_CRL:
2260 case SEC_OID_PKIX_OCSP_RESPONSE:
2261 case SEC_OID_PKIX_OCSP_NO_CHECK:
2262 case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF:
2263 case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR:
2264 case SEC_OID_PKIX_REGCTRL_REGTOKEN:
2265 case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
2266 case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
2267 case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
2268 case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
2269 case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
2270 case SEC_OID_PKIX_REGINFO_UTF8_PAIRS:
2271 case SEC_OID_PKIX_REGINFO_CERT_REQUEST:
2273 /* Netscape extension OIDs. */
2274 case SEC_OID_NS_CERT_EXT_NETSCAPE_OK:
2275 case SEC_OID_NS_CERT_EXT_ISSUER_LOGO:
2276 case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO:
2277 case SEC_OID_NS_CERT_EXT_ENTITY_LOGO:
2278 case SEC_OID_NS_CERT_EXT_USER_PICTURE:
2280 /* x.509 v3 Extensions */
2281 case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR:
2282 case SEC_OID_X509_SUBJECT_KEY_ID:
2283 case SEC_OID_X509_POLICY_MAPPINGS:
2284 case SEC_OID_X509_POLICY_CONSTRAINTS:
2287 default:
2288 SECU_PrintAny(out, tmpitem, "Data", level);
2289 break;
2292 secu_Newline(out);
2293 extensions++;
2299 void
2300 SECU_PrintName(FILE *out, CERTName *name, char *msg, int level)
2302 char *nameStr;
2303 char *str;
2304 SECItem my;
2306 str = nameStr = CERT_NameToAscii(name);
2307 if (!str) {
2308 str = "!Invalid AVA!";
2310 my.data = (unsigned char *)str;
2311 my.len = PORT_Strlen(str);
2312 #if 1
2313 secu_PrintRawString(out, &my, msg, level);
2314 #else
2315 SECU_Indent(out, level); fprintf(out, "%s: ", msg);
2316 fprintf(out, str);
2317 secu_Newline(out);
2318 #endif
2319 PORT_Free(nameStr);
2322 void
2323 printflags(char *trusts, unsigned int flags)
2325 if (flags & CERTDB_VALID_CA)
2326 if (!(flags & CERTDB_TRUSTED_CA) &&
2327 !(flags & CERTDB_TRUSTED_CLIENT_CA))
2328 PORT_Strcat(trusts, "c");
2329 if (flags & CERTDB_VALID_PEER)
2330 if (!(flags & CERTDB_TRUSTED))
2331 PORT_Strcat(trusts, "p");
2332 if (flags & CERTDB_TRUSTED_CA)
2333 PORT_Strcat(trusts, "C");
2334 if (flags & CERTDB_TRUSTED_CLIENT_CA)
2335 PORT_Strcat(trusts, "T");
2336 if (flags & CERTDB_TRUSTED)
2337 PORT_Strcat(trusts, "P");
2338 if (flags & CERTDB_USER)
2339 PORT_Strcat(trusts, "u");
2340 if (flags & CERTDB_SEND_WARN)
2341 PORT_Strcat(trusts, "w");
2342 if (flags & CERTDB_INVISIBLE_CA)
2343 PORT_Strcat(trusts, "I");
2344 if (flags & CERTDB_GOVT_APPROVED_CA)
2345 PORT_Strcat(trusts, "G");
2346 return;
2349 /* callback for listing certs through pkcs11 */
2350 SECStatus
2351 SECU_PrintCertNickname(CERTCertListNode *node, void *data)
2353 CERTCertTrust *trust;
2354 CERTCertificate* cert;
2355 FILE *out;
2356 char trusts[30];
2357 char *name;
2359 cert = node->cert;
2361 PORT_Memset (trusts, 0, sizeof (trusts));
2362 out = (FILE *)data;
2364 name = node->appData;
2365 if (!name || !name[0]) {
2366 name = cert->nickname;
2368 if (!name || !name[0]) {
2369 name = cert->emailAddr;
2371 if (!name || !name[0]) {
2372 name = "(NULL)";
2375 trust = cert->trust;
2376 if (trust) {
2377 printflags(trusts, trust->sslFlags);
2378 PORT_Strcat(trusts, ",");
2379 printflags(trusts, trust->emailFlags);
2380 PORT_Strcat(trusts, ",");
2381 printflags(trusts, trust->objectSigningFlags);
2382 } else {
2383 PORT_Memcpy(trusts,",,",3);
2385 fprintf(out, "%-60s %-5s\n", name, trusts);
2387 return (SECSuccess);
2391 SECU_DecodeAndPrintExtensions(FILE *out, SECItem *any, char *m, int level)
2393 CERTCertExtension **extensions = NULL;
2394 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2395 int rv = 0;
2397 if (!arena)
2398 return SEC_ERROR_NO_MEMORY;
2400 rv = SEC_QuickDERDecodeItem(arena, &extensions,
2401 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), any);
2402 if (!rv)
2403 SECU_PrintExtensions(out, extensions, m, level);
2404 else
2405 SECU_PrintAny(out, any, m, level);
2406 PORT_FreeArena(arena, PR_FALSE);
2407 return rv;
2410 /* print a decoded SET OF or SEQUENCE OF Extensions */
2412 SECU_PrintSetOfExtensions(FILE *out, SECItem **any, char *m, int level)
2414 int rv = 0;
2415 if (m && *m) {
2416 SECU_Indent(out, level++); fprintf(out, "%s:\n", m);
2418 while (any && any[0]) {
2419 rv |= SECU_DecodeAndPrintExtensions(out, any[0], "", level);
2420 any++;
2422 return rv;
2425 /* print a decoded SET OF or SEQUENCE OF "ANY" */
2427 SECU_PrintSetOfAny(FILE *out, SECItem **any, char *m, int level)
2429 int rv = 0;
2430 if (m && *m) {
2431 SECU_Indent(out, level++); fprintf(out, "%s:\n", m);
2433 while (any && any[0]) {
2434 SECU_PrintAny(out, any[0], "", level);
2435 any++;
2437 return rv;
2441 SECU_PrintCertAttribute(FILE *out, CERTAttribute *attr, char *m, int level)
2443 int rv = 0;
2444 SECOidTag tag;
2445 tag = SECU_PrintObjectID(out, &attr->attrType, "Attribute Type", level);
2446 if (tag == SEC_OID_PKCS9_EXTENSION_REQUEST) {
2447 rv = SECU_PrintSetOfExtensions(out, attr->attrValue, "Extensions", level);
2448 } else {
2449 rv = SECU_PrintSetOfAny(out, attr->attrValue, "Attribute Values", level);
2451 return rv;
2455 SECU_PrintCertAttributes(FILE *out, CERTAttribute **attrs, char *m, int level)
2457 int rv = 0;
2458 while (attrs[0]) {
2459 rv |= SECU_PrintCertAttribute(out, attrs[0], m, level+1);
2460 attrs++;
2462 return rv;
2465 int /* sometimes a PRErrorCode, other times a SECStatus. Sigh. */
2466 SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, int level)
2468 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2469 CERTCertificateRequest *cr;
2470 int rv = SEC_ERROR_NO_MEMORY;
2472 if (!arena)
2473 return rv;
2475 /* Decode certificate request */
2476 cr = PORT_ArenaZNew(arena, CERTCertificateRequest);
2477 if (!cr)
2478 goto loser;
2479 cr->arena = arena;
2480 rv = SEC_QuickDERDecodeItem(arena, cr,
2481 SEC_ASN1_GET(CERT_CertificateRequestTemplate), der);
2482 if (rv)
2483 goto loser;
2485 /* Pretty print it out */
2486 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2487 SECU_PrintInteger(out, &cr->version, "Version", level+1);
2488 SECU_PrintName(out, &cr->subject, "Subject", level+1);
2489 secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo,
2490 "Subject Public Key Info", level+1);
2491 if (cr->attributes)
2492 SECU_PrintCertAttributes(out, cr->attributes, "Attributes", level+1);
2493 rv = 0;
2494 loser:
2495 PORT_FreeArena(arena, PR_FALSE);
2496 return rv;
2500 SECU_PrintCertificate(FILE *out, SECItem *der, char *m, int level)
2502 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2503 CERTCertificate *c;
2504 int rv = SEC_ERROR_NO_MEMORY;
2505 int iv;
2507 if (!arena)
2508 return rv;
2510 /* Decode certificate */
2511 c = PORT_ArenaZNew(arena, CERTCertificate);
2512 if (!c)
2513 goto loser;
2514 c->arena = arena;
2515 rv = SEC_ASN1DecodeItem(arena, c,
2516 SEC_ASN1_GET(CERT_CertificateTemplate), der);
2517 if (rv) {
2518 SECU_Indent(out, level);
2519 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
2520 SECU_PrintAny(out, der, "Raw", level);
2521 goto loser;
2523 /* Pretty print it out */
2524 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2525 iv = c->version.len ? DER_GetInteger(&c->version) : 0; /* version is optional */
2526 SECU_Indent(out, level+1); fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv);
2528 SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level+1);
2529 SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level+1);
2530 SECU_PrintName(out, &c->issuer, "Issuer", level+1);
2531 secu_PrintValidity(out, &c->validity, "Validity", level+1);
2532 SECU_PrintName(out, &c->subject, "Subject", level+1);
2533 secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo,
2534 "Subject Public Key Info", level+1);
2535 if (c->issuerID.data)
2536 secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level+1);
2537 if (c->subjectID.data)
2538 secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level+1);
2539 SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1);
2540 loser:
2541 PORT_FreeArena(arena, PR_FALSE);
2542 return rv;
2546 SECU_PrintRSAPublicKey(FILE *out, SECItem *der, char *m, int level)
2548 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2549 SECKEYPublicKey key;
2550 int rv = SEC_ERROR_NO_MEMORY;
2552 if (!arena)
2553 return rv;
2555 PORT_Memset(&key, 0, sizeof(key));
2556 rv = SEC_ASN1DecodeItem(arena, &key,
2557 SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate), der);
2558 if (!rv) {
2559 /* Pretty print it out */
2560 secu_PrintRSAPublicKey(out, &key, m, level);
2563 PORT_FreeArena(arena, PR_FALSE);
2564 return rv;
2568 SECU_PrintSubjectPublicKeyInfo(FILE *out, SECItem *der, char *m, int level)
2570 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2571 int rv = SEC_ERROR_NO_MEMORY;
2572 CERTSubjectPublicKeyInfo spki;
2574 if (!arena)
2575 return rv;
2577 PORT_Memset(&spki, 0, sizeof spki);
2578 rv = SEC_ASN1DecodeItem(arena, &spki,
2579 SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate),
2580 der);
2581 if (!rv) {
2582 if (m && *m) {
2583 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2585 secu_PrintSubjectPublicKeyInfo(out, arena, &spki,
2586 "Subject Public Key Info", level+1);
2589 PORT_FreeArena(arena, PR_FALSE);
2590 return rv;
2593 #ifdef HAVE_EPV_TEMPLATE
2595 SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level)
2597 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2598 SECKEYEncryptedPrivateKeyInfo key;
2599 int rv = SEC_ERROR_NO_MEMORY;
2601 if (!arena)
2602 return rv;
2604 PORT_Memset(&key, 0, sizeof(key));
2605 rv = SEC_ASN1DecodeItem(arena, &key,
2606 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der);
2607 if (rv)
2608 goto loser;
2610 /* Pretty print it out */
2611 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2612 SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm",
2613 level+1);
2614 SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level+1);
2615 loser:
2616 PORT_FreeArena(arena, PR_TRUE);
2617 return rv;
2619 #endif
2622 SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level)
2624 unsigned char fingerprint[20];
2625 char *fpStr = NULL;
2626 int err = PORT_GetError();
2627 SECStatus rv;
2628 SECItem fpItem;
2630 /* print MD5 fingerprint */
2631 memset(fingerprint, 0, sizeof fingerprint);
2632 rv = PK11_HashBuf(SEC_OID_MD5,fingerprint, derCert->data, derCert->len);
2633 fpItem.data = fingerprint;
2634 fpItem.len = MD5_LENGTH;
2635 fpStr = CERT_Hexify(&fpItem, 1);
2636 SECU_Indent(out, level); fprintf(out, "%s (MD5):\n", m);
2637 SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr);
2638 PORT_Free(fpStr);
2639 fpStr = NULL;
2640 if (rv != SECSuccess && !err)
2641 err = PORT_GetError();
2643 /* print SHA1 fingerprint */
2644 memset(fingerprint, 0, sizeof fingerprint);
2645 rv = PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len);
2646 fpItem.data = fingerprint;
2647 fpItem.len = SHA1_LENGTH;
2648 fpStr = CERT_Hexify(&fpItem, 1);
2649 SECU_Indent(out, level); fprintf(out, "%s (SHA1):\n", m);
2650 SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr);
2651 PORT_Free(fpStr);
2652 fprintf(out, "\n");
2654 if (err)
2655 PORT_SetError(err);
2656 if (err || rv != SECSuccess)
2657 return SECFailure;
2659 return 0;
2663 ** PKCS7 Support
2666 /* forward declaration */
2667 static int
2668 secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *, int);
2671 ** secu_PrintPKCS7EncContent
2672 ** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it)
2674 static void
2675 secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src,
2676 char *m, int level)
2678 if (src->contentTypeTag == NULL)
2679 src->contentTypeTag = SECOID_FindOID(&(src->contentType));
2681 SECU_Indent(out, level);
2682 fprintf(out, "%s:\n", m);
2683 SECU_Indent(out, level + 1);
2684 fprintf(out, "Content Type: %s\n",
2685 (src->contentTypeTag != NULL) ? src->contentTypeTag->desc
2686 : "Unknown");
2687 SECU_PrintAlgorithmID(out, &(src->contentEncAlg),
2688 "Content Encryption Algorithm", level+1);
2689 SECU_PrintAsHex(out, &(src->encContent),
2690 "Encrypted Content", level+1);
2694 ** secu_PrintRecipientInfo
2695 ** Prints a PKCS7RecipientInfo type
2697 static void
2698 secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m,
2699 int level)
2701 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2702 SECU_PrintInteger(out, &(info->version), "Version", level + 1);
2704 SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer",
2705 level + 1);
2706 SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber),
2707 "Serial Number", level + 1);
2709 /* Parse and display encrypted key */
2710 SECU_PrintAlgorithmID(out, &(info->keyEncAlg),
2711 "Key Encryption Algorithm", level + 1);
2712 SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1);
2716 ** secu_PrintSignerInfo
2717 ** Prints a PKCS7SingerInfo type
2719 static void
2720 secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level)
2722 SEC_PKCS7Attribute *attr;
2723 int iv;
2724 char om[100];
2726 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2727 SECU_PrintInteger(out, &(info->version), "Version", level + 1);
2729 SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer",
2730 level + 1);
2731 SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber),
2732 "Serial Number", level + 1);
2734 SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm",
2735 level + 1);
2737 if (info->authAttr != NULL) {
2738 SECU_Indent(out, level + 1);
2739 fprintf(out, "Authenticated Attributes:\n");
2740 iv = 0;
2741 while ((attr = info->authAttr[iv++]) != NULL) {
2742 sprintf(om, "Attribute (%d)", iv);
2743 secu_PrintAttribute(out, attr, om, level + 2);
2747 /* Parse and display signature */
2748 SECU_PrintAlgorithmID(out, &(info->digestEncAlg),
2749 "Digest Encryption Algorithm", level + 1);
2750 SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1);
2752 if (info->unAuthAttr != NULL) {
2753 SECU_Indent(out, level + 1);
2754 fprintf(out, "Unauthenticated Attributes:\n");
2755 iv = 0;
2756 while ((attr = info->unAuthAttr[iv++]) != NULL) {
2757 sprintf(om, "Attribute (%x)", iv);
2758 secu_PrintAttribute(out, attr, om, level + 2);
2763 /* callers of this function must make sure that the CERTSignedCrl
2764 from which they are extracting the CERTCrl has been fully-decoded.
2765 Otherwise it will not have the entries even though the CRL may have
2766 some */
2768 void
2769 SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level)
2771 CERTCrlEntry *entry;
2772 int iv;
2773 char om[100];
2775 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2776 /* version is optional */
2777 iv = crl->version.len ? DER_GetInteger(&crl->version) : 0;
2778 SECU_Indent(out, level+1);
2779 fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv);
2780 SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm",
2781 level + 1);
2782 SECU_PrintName(out, &(crl->name), "Issuer", level + 1);
2783 SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1);
2784 if (crl->nextUpdate.data && crl->nextUpdate.len) /* is optional */
2785 SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1);
2787 if (crl->entries != NULL) {
2788 iv = 0;
2789 while ((entry = crl->entries[iv++]) != NULL) {
2790 sprintf(om, "Entry (%x):\n", iv);
2791 SECU_Indent(out, level + 1); fprintf(out, om);
2792 SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number",
2793 level + 2);
2794 SECU_PrintTimeChoice(out, &(entry->revocationDate),
2795 "Revocation Date", level + 2);
2796 SECU_PrintExtensions(out, entry->extensions,
2797 "Entry Extensions", level + 2);
2800 SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1);
2804 ** secu_PrintPKCS7Signed
2805 ** Pretty print a PKCS7 signed data type (up to version 1).
2807 static int
2808 secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src,
2809 const char *m, int level)
2811 SECAlgorithmID *digAlg; /* digest algorithms */
2812 SECItem *aCert; /* certificate */
2813 CERTSignedCrl *aCrl; /* certificate revocation list */
2814 SEC_PKCS7SignerInfo *sigInfo; /* signer information */
2815 int rv, iv;
2816 char om[100];
2818 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2819 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
2821 /* Parse and list digest algorithms (if any) */
2822 if (src->digestAlgorithms != NULL) {
2823 SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n");
2824 iv = 0;
2825 while ((digAlg = src->digestAlgorithms[iv++]) != NULL) {
2826 sprintf(om, "Digest Algorithm (%x)", iv);
2827 SECU_PrintAlgorithmID(out, digAlg, om, level + 2);
2831 /* Now for the content */
2832 rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo),
2833 "Content Information", level + 1);
2834 if (rv != 0)
2835 return rv;
2837 /* Parse and list certificates (if any) */
2838 if (src->rawCerts != NULL) {
2839 SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n");
2840 iv = 0;
2841 while ((aCert = src->rawCerts[iv++]) != NULL) {
2842 sprintf(om, "Certificate (%x)", iv);
2843 rv = SECU_PrintSignedData(out, aCert, om, level + 2,
2844 SECU_PrintCertificate);
2845 if (rv)
2846 return rv;
2850 /* Parse and list CRL's (if any) */
2851 if (src->crls != NULL) {
2852 SECU_Indent(out, level + 1);
2853 fprintf(out, "Signed Revocation Lists:\n");
2854 iv = 0;
2855 while ((aCrl = src->crls[iv++]) != NULL) {
2856 sprintf(om, "Signed Revocation List (%x)", iv);
2857 SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om);
2858 SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm,
2859 "Signature Algorithm", level+3);
2860 DER_ConvertBitString(&aCrl->signatureWrap.signature);
2861 SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature",
2862 level+3);
2863 SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List",
2864 level + 3);
2868 /* Parse and list signatures (if any) */
2869 if (src->signerInfos != NULL) {
2870 SECU_Indent(out, level + 1);
2871 fprintf(out, "Signer Information List:\n");
2872 iv = 0;
2873 while ((sigInfo = src->signerInfos[iv++]) != NULL) {
2874 sprintf(om, "Signer Information (%x)", iv);
2875 secu_PrintSignerInfo(out, sigInfo, om, level + 2);
2879 return 0;
2883 ** secu_PrintPKCS7Enveloped
2884 ** Pretty print a PKCS7 enveloped data type (up to version 1).
2886 static void
2887 secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src,
2888 const char *m, int level)
2890 SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */
2891 int iv;
2892 char om[100];
2894 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2895 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
2897 /* Parse and list recipients (this is not optional) */
2898 if (src->recipientInfos != NULL) {
2899 SECU_Indent(out, level + 1);
2900 fprintf(out, "Recipient Information List:\n");
2901 iv = 0;
2902 while ((recInfo = src->recipientInfos[iv++]) != NULL) {
2903 sprintf(om, "Recipient Information (%x)", iv);
2904 secu_PrintRecipientInfo(out, recInfo, om, level + 2);
2908 secu_PrintPKCS7EncContent(out, &src->encContentInfo,
2909 "Encrypted Content Information", level + 1);
2913 ** secu_PrintPKCS7SignedEnveloped
2914 ** Pretty print a PKCS7 singed and enveloped data type (up to version 1).
2916 static int
2917 secu_PrintPKCS7SignedAndEnveloped(FILE *out,
2918 SEC_PKCS7SignedAndEnvelopedData *src,
2919 const char *m, int level)
2921 SECAlgorithmID *digAlg; /* pointer for digest algorithms */
2922 SECItem *aCert; /* pointer for certificate */
2923 CERTSignedCrl *aCrl; /* pointer for certificate revocation list */
2924 SEC_PKCS7SignerInfo *sigInfo; /* pointer for signer information */
2925 SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */
2926 int rv, iv;
2927 char om[100];
2929 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
2930 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
2932 /* Parse and list recipients (this is not optional) */
2933 if (src->recipientInfos != NULL) {
2934 SECU_Indent(out, level + 1);
2935 fprintf(out, "Recipient Information List:\n");
2936 iv = 0;
2937 while ((recInfo = src->recipientInfos[iv++]) != NULL) {
2938 sprintf(om, "Recipient Information (%x)", iv);
2939 secu_PrintRecipientInfo(out, recInfo, om, level + 2);
2943 /* Parse and list digest algorithms (if any) */
2944 if (src->digestAlgorithms != NULL) {
2945 SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n");
2946 iv = 0;
2947 while ((digAlg = src->digestAlgorithms[iv++]) != NULL) {
2948 sprintf(om, "Digest Algorithm (%x)", iv);
2949 SECU_PrintAlgorithmID(out, digAlg, om, level + 2);
2953 secu_PrintPKCS7EncContent(out, &src->encContentInfo,
2954 "Encrypted Content Information", level + 1);
2956 /* Parse and list certificates (if any) */
2957 if (src->rawCerts != NULL) {
2958 SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n");
2959 iv = 0;
2960 while ((aCert = src->rawCerts[iv++]) != NULL) {
2961 sprintf(om, "Certificate (%x)", iv);
2962 rv = SECU_PrintSignedData(out, aCert, om, level + 2,
2963 SECU_PrintCertificate);
2964 if (rv)
2965 return rv;
2969 /* Parse and list CRL's (if any) */
2970 if (src->crls != NULL) {
2971 SECU_Indent(out, level + 1);
2972 fprintf(out, "Signed Revocation Lists:\n");
2973 iv = 0;
2974 while ((aCrl = src->crls[iv++]) != NULL) {
2975 sprintf(om, "Signed Revocation List (%x)", iv);
2976 SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om);
2977 SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm,
2978 "Signature Algorithm", level+3);
2979 DER_ConvertBitString(&aCrl->signatureWrap.signature);
2980 SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature",
2981 level+3);
2982 SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List",
2983 level + 3);
2987 /* Parse and list signatures (if any) */
2988 if (src->signerInfos != NULL) {
2989 SECU_Indent(out, level + 1);
2990 fprintf(out, "Signer Information List:\n");
2991 iv = 0;
2992 while ((sigInfo = src->signerInfos[iv++]) != NULL) {
2993 sprintf(om, "Signer Information (%x)", iv);
2994 secu_PrintSignerInfo(out, sigInfo, om, level + 2);
2998 return 0;
3002 SECU_PrintCrl (FILE *out, SECItem *der, char *m, int level)
3004 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
3005 CERTCrl *c = NULL;
3006 int rv = SEC_ERROR_NO_MEMORY;
3008 if (!arena)
3009 return rv;
3010 do {
3011 /* Decode CRL */
3012 c = PORT_ArenaZNew(arena, CERTCrl);
3013 if (!c)
3014 break;
3016 rv = SEC_QuickDERDecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der);
3017 if (rv != SECSuccess)
3018 break;
3019 SECU_PrintCRLInfo (out, c, m, level);
3020 } while (0);
3021 PORT_FreeArena (arena, PR_FALSE);
3022 return rv;
3027 ** secu_PrintPKCS7Encrypted
3028 ** Pretty print a PKCS7 encrypted data type (up to version 1).
3030 static void
3031 secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src,
3032 const char *m, int level)
3034 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
3035 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
3037 secu_PrintPKCS7EncContent(out, &src->encContentInfo,
3038 "Encrypted Content Information", level + 1);
3042 ** secu_PrintPKCS7Digested
3043 ** Pretty print a PKCS7 digested data type (up to version 1).
3045 static void
3046 secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src,
3047 const char *m, int level)
3049 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
3050 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
3052 SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm",
3053 level + 1);
3054 secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information",
3055 level + 1);
3056 SECU_PrintAsHex(out, &src->digest, "Digest", level + 1);
3060 ** secu_PrintPKCS7ContentInfo
3061 ** Takes a SEC_PKCS7ContentInfo type and sends the contents to the
3062 ** appropriate function
3064 static int
3065 secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src,
3066 char *m, int level)
3068 const char *desc;
3069 SECOidTag kind;
3070 int rv;
3072 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
3073 level++;
3075 if (src->contentTypeTag == NULL)
3076 src->contentTypeTag = SECOID_FindOID(&(src->contentType));
3078 if (src->contentTypeTag == NULL) {
3079 desc = "Unknown";
3080 kind = SEC_OID_PKCS7_DATA;
3081 } else {
3082 desc = src->contentTypeTag->desc;
3083 kind = src->contentTypeTag->offset;
3086 if (src->content.data == NULL) {
3087 SECU_Indent(out, level); fprintf(out, "%s:\n", desc);
3088 level++;
3089 SECU_Indent(out, level); fprintf(out, "<no content>\n");
3090 return 0;
3093 rv = 0;
3094 switch (kind) {
3095 case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */
3096 rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level);
3097 break;
3099 case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */
3100 secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level);
3101 break;
3103 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */
3104 rv = secu_PrintPKCS7SignedAndEnveloped(out,
3105 src->content.signedAndEnvelopedData,
3106 desc, level);
3107 break;
3109 case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */
3110 secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level);
3111 break;
3113 case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */
3114 secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level);
3115 break;
3117 default:
3118 SECU_PrintAsHex(out, src->content.data, desc, level);
3119 break;
3122 return rv;
3126 ** SECU_PrintPKCS7ContentInfo
3127 ** Decode and print any major PKCS7 data type (up to version 1).
3130 SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level)
3132 SEC_PKCS7ContentInfo *cinfo;
3133 int rv;
3135 cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3136 if (cinfo != NULL) {
3137 /* Send it to recursive parsing and printing module */
3138 rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level);
3139 SEC_PKCS7DestroyContentInfo(cinfo);
3140 } else {
3141 rv = -1;
3144 return rv;
3148 ** End of PKCS7 functions
3151 void
3152 printFlags(FILE *out, unsigned int flags, int level)
3154 if ( flags & CERTDB_VALID_PEER ) {
3155 SECU_Indent(out, level); fprintf(out, "Valid Peer\n");
3157 if ( flags & CERTDB_TRUSTED ) {
3158 SECU_Indent(out, level); fprintf(out, "Trusted\n");
3160 if ( flags & CERTDB_SEND_WARN ) {
3161 SECU_Indent(out, level); fprintf(out, "Warn When Sending\n");
3163 if ( flags & CERTDB_VALID_CA ) {
3164 SECU_Indent(out, level); fprintf(out, "Valid CA\n");
3166 if ( flags & CERTDB_TRUSTED_CA ) {
3167 SECU_Indent(out, level); fprintf(out, "Trusted CA\n");
3169 if ( flags & CERTDB_NS_TRUSTED_CA ) {
3170 SECU_Indent(out, level); fprintf(out, "Netscape Trusted CA\n");
3172 if ( flags & CERTDB_USER ) {
3173 SECU_Indent(out, level); fprintf(out, "User\n");
3175 if ( flags & CERTDB_TRUSTED_CLIENT_CA ) {
3176 SECU_Indent(out, level); fprintf(out, "Trusted Client CA\n");
3178 if ( flags & CERTDB_GOVT_APPROVED_CA ) {
3179 SECU_Indent(out, level); fprintf(out, "Step-up\n");
3183 void
3184 SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level)
3186 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
3187 SECU_Indent(out, level+1); fprintf(out, "SSL Flags:\n");
3188 printFlags(out, trust->sslFlags, level+2);
3189 SECU_Indent(out, level+1); fprintf(out, "Email Flags:\n");
3190 printFlags(out, trust->emailFlags, level+2);
3191 SECU_Indent(out, level+1); fprintf(out, "Object Signing Flags:\n");
3192 printFlags(out, trust->objectSigningFlags, level+2);
3195 int SECU_PrintSignedData(FILE *out, SECItem *der, char *m,
3196 int level, SECU_PPFunc inner)
3198 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
3199 CERTSignedData *sd;
3200 int rv = SEC_ERROR_NO_MEMORY;
3202 if (!arena)
3203 return rv;
3205 /* Strip off the signature */
3206 sd = PORT_ArenaZNew(arena, CERTSignedData);
3207 if (!sd)
3208 goto loser;
3210 rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate),
3211 der);
3212 if (rv)
3213 goto loser;
3215 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
3216 rv = (*inner)(out, &sd->data, "Data", level+1);
3218 SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm",
3219 level+1);
3220 DER_ConvertBitString(&sd->signature);
3221 SECU_PrintAsHex(out, &sd->signature, "Signature", level+1);
3222 SECU_PrintFingerprints(out, der, "Fingerprint", level+1);
3223 loser:
3224 PORT_FreeArena(arena, PR_FALSE);
3225 return rv;
3229 SECStatus
3230 SEC_PrintCertificateAndTrust(CERTCertificate *cert,
3231 const char *label,
3232 CERTCertTrust *trust)
3234 SECStatus rv;
3235 SECItem data;
3237 data.data = cert->derCert.data;
3238 data.len = cert->derCert.len;
3240 rv = SECU_PrintSignedData(stdout, &data, label, 0,
3241 SECU_PrintCertificate);
3242 if (rv) {
3243 return(SECFailure);
3245 if (trust) {
3246 SECU_PrintTrustFlags(stdout, trust,
3247 "Certificate Trust Flags", 1);
3248 } else if (cert->trust) {
3249 SECU_PrintTrustFlags(stdout, cert->trust,
3250 "Certificate Trust Flags", 1);
3253 printf("\n");
3255 return(SECSuccess);
3259 SECStatus
3260 SECU_ParseCommandLine(int argc, char **argv, char *progName,
3261 const secuCommand *cmd)
3263 PRBool found;
3264 PLOptState *optstate;
3265 PLOptStatus status;
3266 char *optstring;
3267 PLLongOpt *longopts = NULL;
3268 int i, j;
3269 int lcmd = 0, lopt = 0;
3271 optstring = (char *)PORT_Alloc(cmd->numCommands + 2*cmd->numOptions);
3272 if (optstring == NULL)
3273 return SECFailure;
3275 j = 0;
3276 for (i=0; i<cmd->numCommands; i++) {
3277 if (cmd->commands[i].flag) /* single character option ? */
3278 optstring[j++] = cmd->commands[i].flag;
3279 if (cmd->commands[i].longform)
3280 lcmd++;
3282 for (i=0; i<cmd->numOptions; i++) {
3283 if (cmd->options[i].flag) {
3284 optstring[j++] = cmd->options[i].flag;
3285 if (cmd->options[i].needsArg)
3286 optstring[j++] = ':';
3288 if (cmd->options[i].longform)
3289 lopt++;
3292 optstring[j] = '\0';
3294 if (lcmd + lopt > 0) {
3295 longopts = PORT_NewArray(PLLongOpt, lcmd+lopt+1);
3296 if (!longopts) {
3297 PORT_Free(optstring);
3298 return SECFailure;
3301 j = 0;
3302 for (i=0; j<lcmd && i<cmd->numCommands; i++) {
3303 if (cmd->commands[i].longform) {
3304 longopts[j].longOptName = cmd->commands[i].longform;
3305 longopts[j].longOption = 0;
3306 longopts[j++].valueRequired = cmd->commands[i].needsArg;
3309 lopt += lcmd;
3310 for (i=0; j<lopt && i<cmd->numOptions; i++) {
3311 if (cmd->options[i].longform) {
3312 longopts[j].longOptName = cmd->options[i].longform;
3313 longopts[j].longOption = 0;
3314 longopts[j++].valueRequired = cmd->options[i].needsArg;
3317 longopts[j].longOptName = NULL;
3320 optstate = PL_CreateLongOptState(argc, argv, optstring, longopts);
3321 if (!optstate) {
3322 PORT_Free(optstring);
3323 PORT_Free(longopts);
3324 return SECFailure;
3326 /* Parse command line arguments */
3327 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
3328 const char *optstatelong;
3329 char option = optstate->option;
3331 /* positional parameter, single-char option or long opt? */
3332 if (optstate->longOptIndex == -1) {
3333 /* not a long opt */
3334 if (option == '\0')
3335 continue; /* it's a positional parameter */
3336 optstatelong = "";
3337 } else {
3338 /* long opt */
3339 if (option == '\0')
3340 option = '\377'; /* force unequal with all flags */
3341 optstatelong = longopts[optstate->longOptIndex].longOptName;
3344 found = PR_FALSE;
3346 for (i=0; i<cmd->numCommands; i++) {
3347 if (cmd->commands[i].flag == option ||
3348 cmd->commands[i].longform == optstatelong) {
3349 cmd->commands[i].activated = PR_TRUE;
3350 if (optstate->value) {
3351 cmd->commands[i].arg = (char *)optstate->value;
3353 found = PR_TRUE;
3354 break;
3358 if (found)
3359 continue;
3361 for (i=0; i<cmd->numOptions; i++) {
3362 if (cmd->options[i].flag == option ||
3363 cmd->options[i].longform == optstatelong) {
3364 cmd->options[i].activated = PR_TRUE;
3365 if (optstate->value) {
3366 cmd->options[i].arg = (char *)optstate->value;
3367 } else if (cmd->options[i].needsArg) {
3368 status = PL_OPT_BAD;
3369 goto loser;
3371 found = PR_TRUE;
3372 break;
3376 if (!found) {
3377 status = PL_OPT_BAD;
3378 break;
3382 loser:
3383 PL_DestroyOptState(optstate);
3384 PORT_Free(optstring);
3385 if (longopts)
3386 PORT_Free(longopts);
3387 if (status == PL_OPT_BAD)
3388 return SECFailure;
3389 return SECSuccess;
3392 char *
3393 SECU_GetOptionArg(const secuCommand *cmd, int optionNum)
3395 if (optionNum < 0 || optionNum >= cmd->numOptions)
3396 return NULL;
3397 if (cmd->options[optionNum].activated)
3398 return PL_strdup(cmd->options[optionNum].arg);
3399 else
3400 return NULL;
3403 static char SECUErrorBuf[64];
3405 char *
3406 SECU_ErrorStringRaw(int16 err)
3408 if (err == 0)
3409 SECUErrorBuf[0] = '\0';
3410 else if (err == SEC_ERROR_BAD_DATA)
3411 sprintf(SECUErrorBuf, "Bad data");
3412 else if (err == SEC_ERROR_BAD_DATABASE)
3413 sprintf(SECUErrorBuf, "Problem with database");
3414 else if (err == SEC_ERROR_BAD_DER)
3415 sprintf(SECUErrorBuf, "Problem with DER");
3416 else if (err == SEC_ERROR_BAD_KEY)
3417 sprintf(SECUErrorBuf, "Problem with key");
3418 else if (err == SEC_ERROR_BAD_PASSWORD)
3419 sprintf(SECUErrorBuf, "Incorrect password");
3420 else if (err == SEC_ERROR_BAD_SIGNATURE)
3421 sprintf(SECUErrorBuf, "Bad signature");
3422 else if (err == SEC_ERROR_EXPIRED_CERTIFICATE)
3423 sprintf(SECUErrorBuf, "Expired certificate");
3424 else if (err == SEC_ERROR_EXTENSION_VALUE_INVALID)
3425 sprintf(SECUErrorBuf, "Invalid extension value");
3426 else if (err == SEC_ERROR_INPUT_LEN)
3427 sprintf(SECUErrorBuf, "Problem with input length");
3428 else if (err == SEC_ERROR_INVALID_ALGORITHM)
3429 sprintf(SECUErrorBuf, "Invalid algorithm");
3430 else if (err == SEC_ERROR_INVALID_ARGS)
3431 sprintf(SECUErrorBuf, "Invalid arguments");
3432 else if (err == SEC_ERROR_INVALID_AVA)
3433 sprintf(SECUErrorBuf, "Invalid AVA");
3434 else if (err == SEC_ERROR_INVALID_TIME)
3435 sprintf(SECUErrorBuf, "Invalid time");
3436 else if (err == SEC_ERROR_IO)
3437 sprintf(SECUErrorBuf, "Security I/O error");
3438 else if (err == SEC_ERROR_LIBRARY_FAILURE)
3439 sprintf(SECUErrorBuf, "Library failure");
3440 else if (err == SEC_ERROR_NO_MEMORY)
3441 sprintf(SECUErrorBuf, "Out of memory");
3442 else if (err == SEC_ERROR_OLD_CRL)
3443 sprintf(SECUErrorBuf, "CRL is older than the current one");
3444 else if (err == SEC_ERROR_OUTPUT_LEN)
3445 sprintf(SECUErrorBuf, "Problem with output length");
3446 else if (err == SEC_ERROR_UNKNOWN_ISSUER)
3447 sprintf(SECUErrorBuf, "Unknown issuer");
3448 else if (err == SEC_ERROR_UNTRUSTED_CERT)
3449 sprintf(SECUErrorBuf, "Untrusted certificate");
3450 else if (err == SEC_ERROR_UNTRUSTED_ISSUER)
3451 sprintf(SECUErrorBuf, "Untrusted issuer");
3452 else if (err == SSL_ERROR_BAD_CERTIFICATE)
3453 sprintf(SECUErrorBuf, "Bad certificate");
3454 else if (err == SSL_ERROR_BAD_CLIENT)
3455 sprintf(SECUErrorBuf, "Bad client");
3456 else if (err == SSL_ERROR_BAD_SERVER)
3457 sprintf(SECUErrorBuf, "Bad server");
3458 else if (err == SSL_ERROR_EXPORT_ONLY_SERVER)
3459 sprintf(SECUErrorBuf, "Export only server");
3460 else if (err == SSL_ERROR_NO_CERTIFICATE)
3461 sprintf(SECUErrorBuf, "No certificate");
3462 else if (err == SSL_ERROR_NO_CYPHER_OVERLAP)
3463 sprintf(SECUErrorBuf, "No cypher overlap");
3464 else if (err == SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE)
3465 sprintf(SECUErrorBuf, "Unsupported certificate type");
3466 else if (err == SSL_ERROR_UNSUPPORTED_VERSION)
3467 sprintf(SECUErrorBuf, "Unsupported version");
3468 else if (err == SSL_ERROR_US_ONLY_SERVER)
3469 sprintf(SECUErrorBuf, "U.S. only server");
3470 else if (err == PR_IO_ERROR)
3471 sprintf(SECUErrorBuf, "I/O error");
3473 else if (err == SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE)
3474 sprintf (SECUErrorBuf, "Expired Issuer Certificate");
3475 else if (err == SEC_ERROR_REVOKED_CERTIFICATE)
3476 sprintf (SECUErrorBuf, "Revoked certificate");
3477 else if (err == SEC_ERROR_NO_KEY)
3478 sprintf (SECUErrorBuf, "No private key in database for this cert");
3479 else if (err == SEC_ERROR_CERT_NOT_VALID)
3480 sprintf (SECUErrorBuf, "Certificate is not valid");
3481 else if (err == SEC_ERROR_EXTENSION_NOT_FOUND)
3482 sprintf (SECUErrorBuf, "Certificate extension was not found");
3483 else if (err == SEC_ERROR_EXTENSION_VALUE_INVALID)
3484 sprintf (SECUErrorBuf, "Certificate extension value invalid");
3485 else if (err == SEC_ERROR_CA_CERT_INVALID)
3486 sprintf (SECUErrorBuf, "Issuer certificate is invalid");
3487 else if (err == SEC_ERROR_CERT_USAGES_INVALID)
3488 sprintf (SECUErrorBuf, "Certificate usages is invalid");
3489 else if (err == SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION)
3490 sprintf (SECUErrorBuf, "Certificate has unknown critical extension");
3491 else if (err == SEC_ERROR_PKCS7_BAD_SIGNATURE)
3492 sprintf (SECUErrorBuf, "Bad PKCS7 signature");
3493 else if (err == SEC_ERROR_INADEQUATE_KEY_USAGE)
3494 sprintf (SECUErrorBuf, "Certificate not approved for this operation");
3495 else if (err == SEC_ERROR_INADEQUATE_CERT_TYPE)
3496 sprintf (SECUErrorBuf, "Certificate not approved for this operation");
3498 return SECUErrorBuf;
3501 char *
3502 SECU_ErrorString(int16 err)
3504 char *error_string;
3506 *SECUErrorBuf = 0;
3507 SECU_ErrorStringRaw (err);
3509 if (*SECUErrorBuf == 0) {
3510 error_string = SECU_GetString(err);
3511 if (error_string == NULL || *error_string == '\0')
3512 sprintf(SECUErrorBuf, "No error string found for %d.", err);
3513 else
3514 return error_string;
3517 return SECUErrorBuf;
3521 void
3522 SECU_PrintPRandOSError(char *progName)
3524 char buffer[513];
3525 PRInt32 errLen = PR_GetErrorTextLength();
3526 if (errLen > 0 && errLen < sizeof buffer) {
3527 PR_GetErrorText(buffer);
3529 SECU_PrintError(progName, "function failed");
3530 if (errLen > 0 && errLen < sizeof buffer) {
3531 PR_fprintf(PR_STDERR, "\t%s\n", buffer);
3536 static char *
3537 bestCertName(CERTCertificate *cert) {
3538 if (cert->nickname) {
3539 return cert->nickname;
3541 if (cert->emailAddr && cert->emailAddr[0]) {
3542 return cert->emailAddr;
3544 return cert->subjectName;
3547 void
3548 SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle,
3549 CERTCertificate *cert, PRBool checksig,
3550 SECCertificateUsage certUsage, void *pinArg, PRBool verbose,
3551 PRTime datetime)
3553 CERTVerifyLog log;
3554 CERTVerifyLogNode *node;
3556 PRErrorCode err = PORT_GetError();
3558 log.arena = PORT_NewArena(512);
3559 log.head = log.tail = NULL;
3560 log.count = 0;
3561 CERT_VerifyCertificate(handle, cert, checksig, certUsage, datetime, pinArg, &log, NULL);
3563 SECU_displayVerifyLog(outfile, &log, verbose);
3565 for (node = log.head; node; node = node->next) {
3566 if (node->cert)
3567 CERT_DestroyCertificate(node->cert);
3569 PORT_FreeArena(log.arena, PR_FALSE);
3571 PORT_SetError(err); /* restore original error code */
3574 void
3575 SECU_displayVerifyLog(FILE *outfile, CERTVerifyLog *log,
3576 PRBool verbose)
3578 CERTVerifyLogNode *node = NULL;
3579 unsigned int depth = (unsigned int)-1;
3580 unsigned int flags = 0;
3581 char * errstr = NULL;
3583 if (log->count > 0) {
3584 fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n");
3585 for (node = log->head; node; node = node->next) {
3586 if (depth != node->depth) {
3587 depth = node->depth;
3588 fprintf(outfile,"CERT %d. %s %s:\n", depth,
3589 bestCertName(node->cert),
3590 depth ? "[Certificate Authority]": "");
3591 if (verbose) {
3592 const char * emailAddr;
3593 emailAddr = CERT_GetFirstEmailAddress(node->cert);
3594 if (emailAddr) {
3595 fprintf(outfile,"Email Address(es): ");
3596 do {
3597 fprintf(outfile, "%s\n", emailAddr);
3598 emailAddr = CERT_GetNextEmailAddress(node->cert,
3599 emailAddr);
3600 } while (emailAddr);
3604 fprintf(outfile," ERROR %ld: %s\n", node->error,
3605 SECU_Strerror(node->error));
3606 errstr = NULL;
3607 switch (node->error) {
3608 case SEC_ERROR_INADEQUATE_KEY_USAGE:
3609 flags = (unsigned int)node->arg;
3610 switch (flags) {
3611 case KU_DIGITAL_SIGNATURE:
3612 errstr = "Cert cannot sign.";
3613 break;
3614 case KU_KEY_ENCIPHERMENT:
3615 errstr = "Cert cannot encrypt.";
3616 break;
3617 case KU_KEY_CERT_SIGN:
3618 errstr = "Cert cannot sign other certs.";
3619 break;
3620 default:
3621 errstr = "[unknown usage].";
3622 break;
3624 case SEC_ERROR_INADEQUATE_CERT_TYPE:
3625 flags = (unsigned int)node->arg;
3626 switch (flags) {
3627 case NS_CERT_TYPE_SSL_CLIENT:
3628 case NS_CERT_TYPE_SSL_SERVER:
3629 errstr = "Cert cannot be used for SSL.";
3630 break;
3631 case NS_CERT_TYPE_SSL_CA:
3632 errstr = "Cert cannot be used as an SSL CA.";
3633 break;
3634 case NS_CERT_TYPE_EMAIL:
3635 errstr = "Cert cannot be used for SMIME.";
3636 break;
3637 case NS_CERT_TYPE_EMAIL_CA:
3638 errstr = "Cert cannot be used as an SMIME CA.";
3639 break;
3640 case NS_CERT_TYPE_OBJECT_SIGNING:
3641 errstr = "Cert cannot be used for object signing.";
3642 break;
3643 case NS_CERT_TYPE_OBJECT_SIGNING_CA:
3644 errstr = "Cert cannot be used as an object signing CA.";
3645 break;
3646 default:
3647 errstr = "[unknown usage].";
3648 break;
3650 case SEC_ERROR_UNKNOWN_ISSUER:
3651 case SEC_ERROR_UNTRUSTED_ISSUER:
3652 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
3653 errstr = node->cert->issuerName;
3654 break;
3655 default:
3656 break;
3658 if (errstr) {
3659 fprintf(stderr," %s\n",errstr);
3665 void
3666 SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle,
3667 CERTCertificate *cert, PRBool checksig,
3668 SECCertificateUsage certUsage, void *pinArg, PRBool verbose)
3670 SECU_printCertProblemsOnDate(outfile, handle, cert, checksig,
3671 certUsage, pinArg, verbose, PR_Now());
3674 SECOidTag
3675 SECU_StringToSignatureAlgTag(const char *alg)
3677 SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
3679 if (alg) {
3680 if (!PL_strcmp(alg, "MD2")) {
3681 hashAlgTag = SEC_OID_MD2;
3682 } else if (!PL_strcmp(alg, "MD4")) {
3683 hashAlgTag = SEC_OID_MD4;
3684 } else if (!PL_strcmp(alg, "MD5")) {
3685 hashAlgTag = SEC_OID_MD5;
3686 } else if (!PL_strcmp(alg, "SHA1")) {
3687 hashAlgTag = SEC_OID_SHA1;
3688 } else if (!PL_strcmp(alg, "SHA256")) {
3689 hashAlgTag = SEC_OID_SHA256;
3690 } else if (!PL_strcmp(alg, "SHA384")) {
3691 hashAlgTag = SEC_OID_SHA384;
3692 } else if (!PL_strcmp(alg, "SHA512")) {
3693 hashAlgTag = SEC_OID_SHA512;
3696 return hashAlgTag;
3700 SECStatus
3701 SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile,
3702 PRBool ascii, char *url)
3704 PORT_Assert(derCrl != NULL);
3705 if (!derCrl) {
3706 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3707 return SECFailure;
3710 if (outFile != NULL) {
3711 if (ascii) {
3712 PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER,
3713 BTOA_DataToAscii(derCrl->data, derCrl->len),
3714 NS_CRL_TRAILER);
3715 } else {
3716 if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) {
3717 return SECFailure;
3721 if (slot) {
3722 CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url,
3723 SEC_CRL_TYPE, NULL, 0, NULL, 0);
3724 if (newCrl != NULL) {
3725 SEC_DestroyCrl(newCrl);
3726 return SECSuccess;
3728 return SECFailure;
3730 if (!outFile && !slot) {
3731 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3732 return SECFailure;
3734 return SECSuccess;
3737 SECStatus
3738 SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl,
3739 SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode)
3741 SECItem der;
3742 SECKEYPrivateKey *caPrivateKey = NULL;
3743 SECStatus rv;
3744 PRArenaPool *arena;
3745 SECOidTag algID;
3746 void *dummy;
3748 PORT_Assert(issuer != NULL && signCrl != NULL);
3749 if (!issuer || !signCrl) {
3750 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3751 return SECFailure;
3754 arena = signCrl->arena;
3756 caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL);
3757 if (caPrivateKey == NULL) {
3758 *resCode = noKeyFound;
3759 return SECFailure;
3762 algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag);
3763 if (algID == SEC_OID_UNKNOWN) {
3764 *resCode = noSignatureMatch;
3765 rv = SECFailure;
3766 goto done;
3769 if (!signCrl->crl.signatureAlg.parameters.data) {
3770 rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0);
3771 if (rv != SECSuccess) {
3772 *resCode = failToEncode;
3773 goto done;
3777 der.len = 0;
3778 der.data = NULL;
3779 dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl,
3780 SEC_ASN1_GET(CERT_CrlTemplate));
3781 if (!dummy) {
3782 *resCode = failToEncode;
3783 rv = SECFailure;
3784 goto done;
3787 rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap,
3788 der.data, der.len, caPrivateKey, algID);
3789 if (rv != SECSuccess) {
3790 *resCode = failToSign;
3791 goto done;
3794 signCrl->derCrl = PORT_ArenaZNew(arena, SECItem);
3795 if (signCrl->derCrl == NULL) {
3796 *resCode = noMem;
3797 PORT_SetError(SEC_ERROR_NO_MEMORY);
3798 rv = SECFailure;
3799 goto done;
3802 signCrl->derCrl->len = 0;
3803 signCrl->derCrl->data = NULL;
3804 dummy = SEC_ASN1EncodeItem (arena, signCrl->derCrl, signCrl,
3805 SEC_ASN1_GET(CERT_SignedCrlTemplate));
3806 if (!dummy) {
3807 *resCode = failToEncode;
3808 rv = SECFailure;
3809 goto done;
3812 done:
3813 if (caPrivateKey) {
3814 SECKEY_DestroyPrivateKey(caPrivateKey);
3816 return rv;
3821 SECStatus
3822 SECU_CopyCRL(PRArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl)
3824 void *dummy;
3825 SECStatus rv = SECSuccess;
3826 SECItem der;
3828 PORT_Assert(destArena && srcCrl && destCrl);
3829 if (!destArena || !srcCrl || !destCrl) {
3830 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3831 return SECFailure;
3834 der.len = 0;
3835 der.data = NULL;
3836 dummy = SEC_ASN1EncodeItem (destArena, &der, srcCrl,
3837 SEC_ASN1_GET(CERT_CrlTemplate));
3838 if (!dummy) {
3839 return SECFailure;
3842 rv = SEC_QuickDERDecodeItem(destArena, destCrl,
3843 SEC_ASN1_GET(CERT_CrlTemplate), &der);
3844 if (rv != SECSuccess) {
3845 return SECFailure;
3848 destCrl->arena = destArena;
3850 return rv;
3853 SECStatus
3854 SECU_DerSignDataCRL(PRArenaPool *arena, CERTSignedData *sd,
3855 unsigned char *buf, int len, SECKEYPrivateKey *pk,
3856 SECOidTag algID)
3858 SECItem it;
3859 SECStatus rv;
3861 it.data = 0;
3863 /* XXX We should probably have some asserts here to make sure the key type
3864 * and algID match
3867 /* Sign input buffer */
3868 rv = SEC_SignData(&it, buf, len, pk, algID);
3869 if (rv) goto loser;
3871 /* Fill out SignedData object */
3872 PORT_Memset(sd, 0, sizeof(sd));
3873 sd->data.data = buf;
3874 sd->data.len = len;
3875 sd->signature.data = it.data;
3876 sd->signature.len = it.len << 3; /* convert to bit string */
3877 if (!sd->signatureAlgorithm.parameters.data) {
3878 rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0);
3879 if (rv) goto loser;
3882 return rv;
3884 loser:
3885 PORT_Free(it.data);
3886 return rv;
3889 #if 0
3891 /* we need access to the private function cert_FindExtension for this code to work */
3893 CERTAuthKeyID *
3894 SECU_FindCRLAuthKeyIDExten (PRArenaPool *arena, CERTSignedCrl *scrl)
3896 SECItem encodedExtenValue;
3897 SECStatus rv;
3898 CERTAuthKeyID *ret;
3899 CERTCrl* crl;
3901 if (!scrl) {
3902 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3903 return NULL;
3906 crl = &scrl->crl;
3908 encodedExtenValue.data = NULL;
3909 encodedExtenValue.len = 0;
3911 rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID,
3912 &encodedExtenValue);
3913 if ( rv != SECSuccess ) {
3914 return (NULL);
3917 ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
3919 PORT_Free(encodedExtenValue.data);
3920 encodedExtenValue.data = NULL;
3922 return(ret);
3925 #endif
3928 * Find the issuer of a Crl. Use the authorityKeyID if it exists.
3930 CERTCertificate *
3931 SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem* subject,
3932 CERTAuthKeyID* authorityKeyID, PRTime validTime)
3934 CERTCertificate *issuerCert = NULL;
3935 CERTCertList *certList = NULL;
3937 if (!subject) {
3938 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3939 return NULL;
3942 certList =
3943 CERT_CreateSubjectCertList(NULL, dbhandle, subject,
3944 validTime, PR_TRUE);
3945 if (certList) {
3946 CERTCertListNode *node = CERT_LIST_HEAD(certList);
3948 /* XXX and authoritykeyid in the future */
3949 while ( ! CERT_LIST_END(node, certList) ) {
3950 CERTCertificate *cert = node->cert;
3951 /* check cert CERTCertTrust data is allocated, check cert
3952 usage extension, check that cert has pkey in db. Select
3953 the first (newest) user cert */
3954 if (cert->trust &&
3955 CERT_CheckCertUsage(cert, KU_CRL_SIGN) == SECSuccess &&
3956 CERT_IsUserCert(cert)) {
3958 issuerCert = CERT_DupCertificate(cert);
3959 break;
3961 node = CERT_LIST_NEXT(node);
3963 CERT_DestroyCertList(certList);
3965 return(issuerCert);
3969 /* Encodes and adds extensions to the CRL or CRL entries. */
3970 SECStatus
3971 SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle,
3972 void *value, PRBool criticality, int extenType,
3973 EXTEN_EXT_VALUE_ENCODER EncodeValueFn)
3975 SECItem encodedValue;
3976 SECStatus rv;
3978 encodedValue.data = NULL;
3979 encodedValue.len = 0;
3980 do {
3981 rv = (*EncodeValueFn)(arena, value, &encodedValue);
3982 if (rv != SECSuccess)
3983 break;
3985 rv = CERT_AddExtension(extHandle, extenType, &encodedValue,
3986 criticality, PR_TRUE);
3987 if (rv != SECSuccess)
3988 break;
3989 } while (0);
3991 return (rv);
3994 /* Caller ensures that dst is at least item->len*2+1 bytes long */
3995 void
3996 SECU_SECItemToHex(const SECItem * item, char * dst)
3998 if (dst && item && item->data) {
3999 unsigned char * src = item->data;
4000 unsigned int len = item->len;
4001 for (; len > 0; --len, dst += 2) {
4002 sprintf(dst, "%02x", *src++);
4004 *dst = '\0';
4008 static unsigned char nibble(char c) {
4009 c = PORT_Tolower(c);
4010 return ( c >= '0' && c <= '9') ? c - '0' :
4011 ( c >= 'a' && c <= 'f') ? c - 'a' +10 : -1;
4014 SECStatus
4015 SECU_SECItemHexStringToBinary(SECItem* srcdest)
4017 int i;
4019 if (!srcdest) {
4020 PORT_SetError(SEC_ERROR_INVALID_ARGS);
4021 return SECFailure;
4023 if (srcdest->len < 4 || (srcdest->len % 2) ) {
4024 /* too short to convert, or even number of characters */
4025 PORT_SetError(SEC_ERROR_BAD_DATA);
4026 return SECFailure;
4028 if (PORT_Strncasecmp((const char*)srcdest->data, "0x", 2)) {
4029 /* wrong prefix */
4030 PORT_SetError(SEC_ERROR_BAD_DATA);
4031 return SECFailure;
4034 /* 1st pass to check for hex characters */
4035 for (i=2; i<srcdest->len; i++) {
4036 char c = PORT_Tolower(srcdest->data[i]);
4037 if (! ( ( c >= '0' && c <= '9') ||
4038 ( c >= 'a' && c <= 'f')
4039 ) ) {
4040 PORT_SetError(SEC_ERROR_BAD_DATA);
4041 return SECFailure;
4045 /* 2nd pass to convert */
4046 for (i=2; i<srcdest->len; i+=2) {
4047 srcdest->data[(i-2)/2] = (nibble(srcdest->data[i]) << 4) +
4048 nibble(srcdest->data[i+1]);
4051 /* adjust length */
4052 srcdest->len -= 2;
4053 srcdest->len /= 2;
4054 return SECSuccess;