security/nss/cmd/lib/secutil.c

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

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

mercurial