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