security/nss/cmd/lib/secutil.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/cmd/lib/secutil.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3751 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +/*
     1.8 +** secutil.c - various functions used by security stuff
     1.9 +**
    1.10 +*/
    1.11 +
    1.12 +#include "prtypes.h"
    1.13 +#include "prtime.h"
    1.14 +#include "prlong.h"
    1.15 +#include "prerror.h"
    1.16 +#include "prprf.h"
    1.17 +#include "plgetopt.h"
    1.18 +#include "prenv.h"
    1.19 +#include "prnetdb.h"
    1.20 +
    1.21 +#include "cryptohi.h"
    1.22 +#include "secutil.h"
    1.23 +#include "secpkcs7.h"
    1.24 +#include "secpkcs5.h"
    1.25 +#include <stdarg.h>
    1.26 +#include <sys/stat.h>
    1.27 +#include <errno.h>
    1.28 +
    1.29 +#ifdef XP_UNIX
    1.30 +#include <unistd.h>
    1.31 +#endif
    1.32 +
    1.33 +/* for SEC_TraverseNames */
    1.34 +#include "cert.h"
    1.35 +#include "certt.h"
    1.36 +#include "certdb.h"
    1.37 +
    1.38 +/* #include "secmod.h" */
    1.39 +#include "pk11func.h"
    1.40 +#include "secoid.h"
    1.41 +
    1.42 +static char consoleName[] =  {
    1.43 +#ifdef XP_UNIX
    1.44 +    "/dev/tty"
    1.45 +#else
    1.46 +#ifdef XP_OS2
    1.47 +    "\\DEV\\CON"
    1.48 +#else
    1.49 +    "CON:"
    1.50 +#endif
    1.51 +#endif
    1.52 +};
    1.53 +
    1.54 +#include "nssutil.h"
    1.55 +#include "ssl.h"
    1.56 +#include "sslproto.h"
    1.57 +
    1.58 +static PRBool utf8DisplayEnabled = PR_FALSE;
    1.59 +
    1.60 +void
    1.61 +SECU_EnableUtf8Display(PRBool enable)
    1.62 +{
    1.63 +    utf8DisplayEnabled = enable;
    1.64 +}
    1.65 +
    1.66 +PRBool
    1.67 +SECU_GetUtf8DisplayEnabled(void)
    1.68 +{
    1.69 +    return utf8DisplayEnabled;
    1.70 +}
    1.71 +
    1.72 +static void
    1.73 +secu_ClearPassword(char *p)
    1.74 +{
    1.75 +    if (p) {
    1.76 +	PORT_Memset(p, 0, PORT_Strlen(p));
    1.77 +	PORT_Free(p);
    1.78 +    }
    1.79 +}
    1.80 +
    1.81 +char *
    1.82 +SECU_GetPasswordString(void *arg, char *prompt)
    1.83 +{
    1.84 +#ifndef _WINDOWS
    1.85 +    char *p = NULL;
    1.86 +    FILE *input, *output;
    1.87 +
    1.88 +    /* open terminal */
    1.89 +    input = fopen(consoleName, "r");
    1.90 +    if (input == NULL) {
    1.91 +	fprintf(stderr, "Error opening input terminal for read\n");
    1.92 +	return NULL;
    1.93 +    }
    1.94 +
    1.95 +    output = fopen(consoleName, "w");
    1.96 +    if (output == NULL) {
    1.97 +	fprintf(stderr, "Error opening output terminal for write\n");
    1.98 +	return NULL;
    1.99 +    }
   1.100 +
   1.101 +    p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword);
   1.102 +        
   1.103 +
   1.104 +    fclose(input);
   1.105 +    fclose(output);
   1.106 +
   1.107 +    return p;
   1.108 +
   1.109 +#else
   1.110 +    /* Win32 version of above. opening the console may fail
   1.111 +       on windows95, and certainly isn't necessary.. */
   1.112 +
   1.113 +    char *p = NULL;
   1.114 +
   1.115 +    p = SEC_GetPassword (stdin, stdout, prompt, SEC_BlindCheckPassword);
   1.116 +    return p;
   1.117 +
   1.118 +#endif
   1.119 +}
   1.120 +
   1.121 +
   1.122 +/*
   1.123 + *  p a s s w o r d _ h a r d c o d e 
   1.124 + *
   1.125 + *  A function to use the password passed in the -f(pwfile) argument
   1.126 + *  of the command line.  
   1.127 + *  After use once, null it out otherwise PKCS11 calls us forever.?
   1.128 + *
   1.129 + */
   1.130 +char *
   1.131 +SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg)
   1.132 +{
   1.133 +    char* phrases, *phrase;
   1.134 +    PRFileDesc *fd;
   1.135 +    PRInt32 nb;
   1.136 +    char *pwFile = arg;
   1.137 +    int i;
   1.138 +    const long maxPwdFileSize = 4096;
   1.139 +    char* tokenName = NULL;
   1.140 +    int tokenLen = 0;
   1.141 +
   1.142 +    if (!pwFile)
   1.143 +	return 0;
   1.144 +
   1.145 +    if (retry) {
   1.146 +	return 0;  /* no good retrying - the files contents will be the same */
   1.147 +    }
   1.148 +
   1.149 +    phrases = PORT_ZAlloc(maxPwdFileSize);
   1.150 +
   1.151 +    if (!phrases) {
   1.152 +        return 0; /* out of memory */
   1.153 +    }
   1.154 + 
   1.155 +    fd = PR_Open(pwFile, PR_RDONLY, 0);
   1.156 +    if (!fd) {
   1.157 +	fprintf(stderr, "No password file \"%s\" exists.\n", pwFile);
   1.158 +        PORT_Free(phrases);
   1.159 +	return NULL;
   1.160 +    }
   1.161 +
   1.162 +    nb = PR_Read(fd, phrases, maxPwdFileSize);
   1.163 +  
   1.164 +    PR_Close(fd);
   1.165 +
   1.166 +    if (nb == 0) {
   1.167 +        fprintf(stderr,"password file contains no data\n");
   1.168 +        PORT_Free(phrases);
   1.169 +        return NULL;
   1.170 +    }
   1.171 +
   1.172 +    if (slot) {
   1.173 +        tokenName = PK11_GetTokenName(slot);
   1.174 +        if (tokenName) {
   1.175 +            tokenLen = PORT_Strlen(tokenName);
   1.176 +        }
   1.177 +    }
   1.178 +    i = 0;
   1.179 +    do
   1.180 +    {
   1.181 +        int startphrase = i;
   1.182 +        int phraseLen;
   1.183 +
   1.184 +        /* handle the Windows EOL case */
   1.185 +        while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++;
   1.186 +        /* terminate passphrase */
   1.187 +        phrases[i++] = '\0';
   1.188 +        /* clean up any EOL before the start of the next passphrase */
   1.189 +        while ( (i<nb) && (phrases[i] == '\r' || phrases[i] == '\n')) {
   1.190 +            phrases[i++] = '\0';
   1.191 +        }
   1.192 +        /* now analyze the current passphrase */
   1.193 +        phrase = &phrases[startphrase];
   1.194 +        if (!tokenName)
   1.195 +            break;
   1.196 +        if (PORT_Strncmp(phrase, tokenName, tokenLen)) continue;
   1.197 +        phraseLen = PORT_Strlen(phrase);
   1.198 +        if (phraseLen < (tokenLen+1)) continue;
   1.199 +        if (phrase[tokenLen] != ':') continue;
   1.200 +        phrase = &phrase[tokenLen+1];
   1.201 +        break;
   1.202 +
   1.203 +    } while (i<nb);
   1.204 +
   1.205 +    phrase = PORT_Strdup((char*)phrase);
   1.206 +    PORT_Free(phrases);
   1.207 +    return phrase;
   1.208 +}
   1.209 +
   1.210 +char *
   1.211 +SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg) 
   1.212 +{
   1.213 +    char prompt[255];
   1.214 +    secuPWData *pwdata = (secuPWData *)arg;
   1.215 +    secuPWData pwnull = { PW_NONE, 0 };
   1.216 +    secuPWData pwxtrn = { PW_EXTERNAL, "external" };
   1.217 +    char *pw;
   1.218 +
   1.219 +    if (pwdata == NULL)
   1.220 +	pwdata = &pwnull;
   1.221 +
   1.222 +    if (PK11_ProtectedAuthenticationPath(slot)) {
   1.223 +	pwdata = &pwxtrn;
   1.224 +    }
   1.225 +    if (retry && pwdata->source != PW_NONE) {
   1.226 +	PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n");
   1.227 +    	return NULL;
   1.228 +    }
   1.229 +
   1.230 +    switch (pwdata->source) {
   1.231 +    case PW_NONE:
   1.232 +	sprintf(prompt, "Enter Password or Pin for \"%s\":",
   1.233 +	                 PK11_GetTokenName(slot));
   1.234 +	return SECU_GetPasswordString(NULL, prompt);
   1.235 +    case PW_FROMFILE:
   1.236 +	/* Instead of opening and closing the file every time, get the pw
   1.237 +	 * once, then keep it in memory (duh).
   1.238 +	 */
   1.239 +	pw = SECU_FilePasswd(slot, retry, pwdata->data);
   1.240 +	pwdata->source = PW_PLAINTEXT;
   1.241 +	pwdata->data = PL_strdup(pw);
   1.242 +	/* it's already been dup'ed */
   1.243 +	return pw;
   1.244 +    case PW_EXTERNAL:
   1.245 +	sprintf(prompt, 
   1.246 +	        "Press Enter, then enter PIN for \"%s\" on external device.\n",
   1.247 +		PK11_GetTokenName(slot));
   1.248 +	(void) SECU_GetPasswordString(NULL, prompt);
   1.249 +    	/* Fall Through */
   1.250 +    case PW_PLAINTEXT:
   1.251 +	return PL_strdup(pwdata->data);
   1.252 +    default:
   1.253 +	break;
   1.254 +    }
   1.255 +
   1.256 +    PR_fprintf(PR_STDERR, "Password check failed:  No password found.\n");
   1.257 +    return NULL;
   1.258 +}
   1.259 +
   1.260 +char *
   1.261 +secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg)
   1.262 +{
   1.263 +    char *p0 = NULL;
   1.264 +    char *p1 = NULL;
   1.265 +    FILE *input, *output;
   1.266 +    secuPWData *pwdata = arg;
   1.267 +
   1.268 +    if (pwdata->source == PW_FROMFILE) {
   1.269 +	return SECU_FilePasswd(slot, retry, pwdata->data);
   1.270 +    } 
   1.271 +    if (pwdata->source == PW_PLAINTEXT) {
   1.272 +	return PL_strdup(pwdata->data);
   1.273 +    }
   1.274 +    
   1.275 +    /* PW_NONE - get it from tty */
   1.276 +    /* open terminal */
   1.277 +#ifdef _WINDOWS
   1.278 +    input = stdin;
   1.279 +#else
   1.280 +    input = fopen(consoleName, "r");
   1.281 +#endif
   1.282 +    if (input == NULL) {
   1.283 +	PR_fprintf(PR_STDERR, "Error opening input terminal for read\n");
   1.284 +	return NULL;
   1.285 +    }
   1.286 +
   1.287 +    /* we have no password, so initialize database with one */
   1.288 +    PR_fprintf(PR_STDERR, 
   1.289 +        "Enter a password which will be used to encrypt your keys.\n"
   1.290 +     	"The password should be at least 8 characters long,\n"
   1.291 +     	"and should contain at least one non-alphabetic character.\n\n");
   1.292 +
   1.293 +    output = fopen(consoleName, "w");
   1.294 +    if (output == NULL) {
   1.295 +	PR_fprintf(PR_STDERR, "Error opening output terminal for write\n");
   1.296 +	return NULL;
   1.297 +    }
   1.298 +
   1.299 +
   1.300 +    for (;;) {
   1.301 +	if (p0) 
   1.302 +	    PORT_Free(p0);
   1.303 +	p0 = SEC_GetPassword(input, output, "Enter new password: ",
   1.304 +			     SEC_BlindCheckPassword);
   1.305 +
   1.306 +	if (p1)
   1.307 +	    PORT_Free(p1);
   1.308 +	p1 = SEC_GetPassword(input, output, "Re-enter password: ",
   1.309 +			     SEC_BlindCheckPassword);
   1.310 +	if (p0 && p1 && !PORT_Strcmp(p0, p1)) {
   1.311 +	    break;
   1.312 +	}
   1.313 +	PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n");
   1.314 +    }
   1.315 +        
   1.316 +    /* clear out the duplicate password string */
   1.317 +    secu_ClearPassword(p1);
   1.318 +    
   1.319 +    fclose(input);
   1.320 +    fclose(output);
   1.321 +
   1.322 +    return p0;
   1.323 +}
   1.324 +
   1.325 +SECStatus
   1.326 +SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile)
   1.327 +{
   1.328 +    return SECU_ChangePW2(slot, passwd, 0, pwFile, 0);
   1.329 +}
   1.330 +
   1.331 +SECStatus
   1.332 +SECU_ChangePW2(PK11SlotInfo *slot, char *oldPass, char *newPass,
   1.333 +			char *oldPwFile, char *newPwFile)
   1.334 +{
   1.335 +    SECStatus rv;
   1.336 +    secuPWData pwdata, newpwdata;
   1.337 +    char *oldpw = NULL, *newpw = NULL;
   1.338 +
   1.339 +    if (oldPass) {
   1.340 +	pwdata.source = PW_PLAINTEXT;
   1.341 +	pwdata.data = oldPass;
   1.342 +    } else if (oldPwFile) {
   1.343 +	pwdata.source = PW_FROMFILE;
   1.344 +	pwdata.data = oldPwFile;
   1.345 +    } else {
   1.346 +	pwdata.source = PW_NONE;
   1.347 +	pwdata.data = NULL;
   1.348 +    }
   1.349 +
   1.350 +    if (newPass) {
   1.351 +	newpwdata.source = PW_PLAINTEXT;
   1.352 +	newpwdata.data = newPass;
   1.353 +    } else if (newPwFile) {
   1.354 +	newpwdata.source = PW_FROMFILE;
   1.355 +	newpwdata.data = newPwFile;
   1.356 +    } else {
   1.357 +	newpwdata.source = PW_NONE;
   1.358 +	newpwdata.data = NULL;
   1.359 +    }
   1.360 +
   1.361 +    if (PK11_NeedUserInit(slot)) {
   1.362 +	newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata);
   1.363 +	rv = PK11_InitPin(slot, (char*)NULL, newpw);
   1.364 +	goto done;
   1.365 +    }
   1.366 +
   1.367 +    for (;;) {
   1.368 +	oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata);
   1.369 +
   1.370 +	if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) {
   1.371 +	    if (pwdata.source == PW_NONE) {
   1.372 +		PR_fprintf(PR_STDERR, "Invalid password.  Try again.\n");
   1.373 +	    } else {
   1.374 +		PR_fprintf(PR_STDERR, "Invalid password.\n");
   1.375 +		PORT_Memset(oldpw, 0, PL_strlen(oldpw));
   1.376 +		PORT_Free(oldpw);
   1.377 +		return SECFailure;
   1.378 +	    }
   1.379 +	} else
   1.380 +	    break;
   1.381 +
   1.382 +	PORT_Free(oldpw);
   1.383 +    }
   1.384 +
   1.385 +    newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata);
   1.386 +
   1.387 +    if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) {
   1.388 +	PR_fprintf(PR_STDERR, "Failed to change password.\n");
   1.389 +	return SECFailure;
   1.390 +    }
   1.391 +
   1.392 +    PORT_Memset(oldpw, 0, PL_strlen(oldpw));
   1.393 +    PORT_Free(oldpw);
   1.394 +
   1.395 +    PR_fprintf(PR_STDOUT, "Password changed successfully.\n");
   1.396 +
   1.397 +done:
   1.398 +    PORT_Memset(newpw, 0, PL_strlen(newpw));
   1.399 +    PORT_Free(newpw);
   1.400 +    return SECSuccess;
   1.401 +}
   1.402 +
   1.403 +struct matchobj {
   1.404 +    SECItem index;
   1.405 +    char *nname;
   1.406 +    PRBool found;
   1.407 +};
   1.408 +
   1.409 +char *
   1.410 +SECU_DefaultSSLDir(void)
   1.411 +{
   1.412 +    char *dir;
   1.413 +    static char sslDir[1000];
   1.414 +
   1.415 +    dir = PR_GetEnv("SSL_DIR");
   1.416 +    if (!dir)
   1.417 +	return NULL;
   1.418 +
   1.419 +    sprintf(sslDir, "%s", dir);
   1.420 +
   1.421 +    if (sslDir[strlen(sslDir)-1] == '/')
   1.422 +	sslDir[strlen(sslDir)-1] = 0;
   1.423 +
   1.424 +    return sslDir;
   1.425 +}
   1.426 +
   1.427 +char *
   1.428 +SECU_AppendFilenameToDir(char *dir, char *filename)
   1.429 +{
   1.430 +    static char path[1000];
   1.431 +
   1.432 +    if (dir[strlen(dir)-1] == '/')
   1.433 +	sprintf(path, "%s%s", dir, filename);
   1.434 +    else
   1.435 +	sprintf(path, "%s/%s", dir, filename);
   1.436 +    return path;
   1.437 +}
   1.438 +
   1.439 +char *
   1.440 +SECU_ConfigDirectory(const char* base)
   1.441 +{
   1.442 +    static PRBool initted = PR_FALSE;
   1.443 +    const char *dir = ".netscape";
   1.444 +    char *home;
   1.445 +    static char buf[1000];
   1.446 +
   1.447 +    if (initted) return buf;
   1.448 +    
   1.449 +
   1.450 +    if (base == NULL || *base == 0) {
   1.451 +	home = PR_GetEnv("HOME");
   1.452 +	if (!home) home = "";
   1.453 +
   1.454 +	if (*home && home[strlen(home) - 1] == '/')
   1.455 +	    sprintf (buf, "%.900s%s", home, dir);
   1.456 +	else
   1.457 +	    sprintf (buf, "%.900s/%s", home, dir);
   1.458 +    } else {
   1.459 +	sprintf(buf, "%.900s", base);
   1.460 +	if (buf[strlen(buf) - 1] == '/')
   1.461 +	    buf[strlen(buf) - 1] = 0;
   1.462 +    }
   1.463 +
   1.464 +
   1.465 +    initted = PR_TRUE;
   1.466 +    return buf;
   1.467 +}
   1.468 +
   1.469 +/*Turn off SSL for now */
   1.470 +/* This gets called by SSL when server wants our cert & key */
   1.471 +int
   1.472 +SECU_GetClientAuthData(void *arg, PRFileDesc *fd,
   1.473 +		       struct CERTDistNamesStr *caNames,
   1.474 +                      struct CERTCertificateStr **pRetCert,
   1.475 +                      struct SECKEYPrivateKeyStr **pRetKey)
   1.476 +{
   1.477 +    SECKEYPrivateKey *key;
   1.478 +    CERTCertificate *cert;
   1.479 +    int errsave;
   1.480 +
   1.481 +    if (arg == NULL) {
   1.482 +        fprintf(stderr, "no key/cert name specified for client auth\n");
   1.483 +        return -1;
   1.484 +    }
   1.485 +    cert = PK11_FindCertFromNickname(arg, NULL);
   1.486 +    errsave = PORT_GetError();
   1.487 +    if (!cert) {
   1.488 +        if (errsave == SEC_ERROR_BAD_PASSWORD)
   1.489 +            fprintf(stderr, "Bad password\n");
   1.490 +        else if (errsave > 0)
   1.491 +            fprintf(stderr, "Unable to read cert (error %d)\n", errsave);
   1.492 +        else if (errsave == SEC_ERROR_BAD_DATABASE)
   1.493 +            fprintf(stderr, "Unable to get cert from database (%d)\n", errsave);
   1.494 +        else
   1.495 +            fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave);
   1.496 +        return -1;
   1.497 +    }
   1.498 +
   1.499 +    key = PK11_FindKeyByAnyCert(arg,NULL);
   1.500 +    if (!key) {
   1.501 +        fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError());
   1.502 +        return -1;
   1.503 +    }
   1.504 +
   1.505 +
   1.506 +    *pRetCert = cert;
   1.507 +    *pRetKey = key;
   1.508 +
   1.509 +    return 0;
   1.510 +}
   1.511 +
   1.512 +SECStatus
   1.513 +SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii,
   1.514 +		     PRBool warnOnPrivateKeyInAsciiFile)
   1.515 +{
   1.516 +    SECStatus rv;
   1.517 +    if (ascii) {
   1.518 +	/* First convert ascii to binary */
   1.519 +	SECItem filedata;
   1.520 +	char *asc, *body;
   1.521 +
   1.522 +	/* Read in ascii data */
   1.523 +	rv = SECU_FileToItem(&filedata, inFile);
   1.524 +	if (rv != SECSuccess)
   1.525 +	    return rv;
   1.526 +	asc = (char *)filedata.data;
   1.527 +	if (!asc) {
   1.528 +	    fprintf(stderr, "unable to read data from input file\n");
   1.529 +	    return SECFailure;
   1.530 +	}
   1.531 +
   1.532 +	if (warnOnPrivateKeyInAsciiFile && strstr(asc, "PRIVATE KEY")) {
   1.533 +	    fprintf(stderr, "Warning: ignoring private key. Consider to use "
   1.534 +	                    "pk12util.\n");
   1.535 +	}
   1.536 +
   1.537 +	/* check for headers and trailers and remove them */
   1.538 +	if ((body = strstr(asc, "-----BEGIN")) != NULL) {
   1.539 +	    char *trailer = NULL;
   1.540 +	    asc = body;
   1.541 +	    body = PORT_Strchr(body, '\n');
   1.542 +	    if (!body)
   1.543 +		body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
   1.544 +	    if (body)
   1.545 +		trailer = strstr(++body, "-----END");
   1.546 +	    if (trailer != NULL) {
   1.547 +		*trailer = '\0';
   1.548 +	    } else {
   1.549 +		fprintf(stderr, "input has header but no trailer\n");
   1.550 +		PORT_Free(filedata.data);
   1.551 +		return SECFailure;
   1.552 +	    }
   1.553 +	} else {
   1.554 +	    /* need one additional byte for zero terminator */
   1.555 +	    rv = SECITEM_ReallocItemV2(NULL, &filedata, filedata.len+1);
   1.556 +	    if (rv != SECSuccess) {
   1.557 +		PORT_Free(filedata.data);
   1.558 +		return rv;
   1.559 +	    }
   1.560 +	    body = (char*)filedata.data;
   1.561 +	    body[filedata.len-1] = '\0';
   1.562 +	}
   1.563 +     
   1.564 +	/* Convert to binary */
   1.565 +	rv = ATOB_ConvertAsciiToItem(der, body);
   1.566 +	if (rv != SECSuccess) {
   1.567 +	    fprintf(stderr, "error converting ascii to binary (%s)\n",
   1.568 +		    SECU_Strerror(PORT_GetError()));
   1.569 +	    PORT_Free(filedata.data);
   1.570 +	    return SECFailure;
   1.571 +	}
   1.572 +
   1.573 +	PORT_Free(filedata.data);
   1.574 +    } else {
   1.575 +	/* Read in binary der */
   1.576 +	rv = SECU_FileToItem(der, inFile);
   1.577 +	if (rv != SECSuccess) {
   1.578 +	    fprintf(stderr, "error converting der (%s)\n", 
   1.579 +		    SECU_Strerror(PORT_GetError()));
   1.580 +	    return SECFailure;
   1.581 +	}
   1.582 +    }
   1.583 +    return SECSuccess;
   1.584 +}
   1.585 +
   1.586 +#define INDENT_MULT	4
   1.587 +
   1.588 +SECStatus
   1.589 +SECU_StripTagAndLength(SECItem *i)
   1.590 +{
   1.591 +    unsigned int start;
   1.592 +
   1.593 +    if (!i || !i->data || i->len < 2) { /* must be at least tag and length */
   1.594 +        return SECFailure;
   1.595 +    }
   1.596 +    start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2);
   1.597 +    if (i->len < start) {
   1.598 +        return SECFailure;
   1.599 +    }
   1.600 +    i->data += start;
   1.601 +    i->len  -= start;
   1.602 +    return SECSuccess;
   1.603 +}
   1.604 +
   1.605 +
   1.606 +
   1.607 +static void
   1.608 +secu_PrintRawStringQuotesOptional(FILE *out, SECItem *si, const char *m, 
   1.609 +				  int level, PRBool quotes)
   1.610 +{
   1.611 +    int column;
   1.612 +    unsigned int i;
   1.613 +
   1.614 +    if ( m ) {
   1.615 +	SECU_Indent(out, level); fprintf(out, "%s: ", m);
   1.616 +	column = (level * INDENT_MULT) + strlen(m) + 2;
   1.617 +	level++;
   1.618 +    } else {
   1.619 +	SECU_Indent(out, level); 
   1.620 +	column = level*INDENT_MULT;
   1.621 +    }
   1.622 +    if (quotes) {
   1.623 +	fprintf(out, "\""); column++;
   1.624 +    }
   1.625 +
   1.626 +    for (i = 0; i < si->len; i++) {
   1.627 +	unsigned char val = si->data[i];
   1.628 +	unsigned char c;
   1.629 +	if (SECU_GetWrapEnabled() && column > 76) {
   1.630 +	    SECU_Newline(out);
   1.631 +	    SECU_Indent(out, level); column = level*INDENT_MULT;
   1.632 +	}
   1.633 +
   1.634 +	if (utf8DisplayEnabled) {
   1.635 +	    if (val < 32)
   1.636 +		c = '.';
   1.637 +	    else
   1.638 +		c = val;
   1.639 +	} else {
   1.640 +	    c = printable[val];
   1.641 +	}
   1.642 +	fprintf(out,"%c", c);
   1.643 +	column++;
   1.644 +    }
   1.645 +
   1.646 +    if (quotes) {
   1.647 +	fprintf(out, "\""); column++;
   1.648 +    }
   1.649 +    if (SECU_GetWrapEnabled() &&
   1.650 +        (column != level*INDENT_MULT || column > 76)) {
   1.651 +	SECU_Newline(out);
   1.652 +    }
   1.653 +}
   1.654 +
   1.655 +static void
   1.656 +secu_PrintRawString(FILE *out, SECItem *si, const char *m, int level)
   1.657 +{
   1.658 +    secu_PrintRawStringQuotesOptional(out, si, m, level, PR_TRUE);
   1.659 +}
   1.660 +
   1.661 +void
   1.662 +SECU_PrintString(FILE *out, const SECItem *si, const char *m, int level)
   1.663 +{
   1.664 +    SECItem my = *si;
   1.665 +
   1.666 +    if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len)
   1.667 +    	return;
   1.668 +    secu_PrintRawString(out, &my, m, level);
   1.669 +}
   1.670 +
   1.671 +/* print an unencoded boolean */
   1.672 +static void
   1.673 +secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level)
   1.674 +{
   1.675 +    int val = 0;
   1.676 +    
   1.677 +    if ( i->data && i->len ) {
   1.678 +	val = i->data[0];
   1.679 +    }
   1.680 +
   1.681 +    if (!m) {
   1.682 +    	m = "Boolean";
   1.683 +    }
   1.684 +    SECU_Indent(out, level); 
   1.685 +    fprintf(out, "%s: %s\n", m, (val ? "True" : "False"));
   1.686 +}
   1.687 +
   1.688 +/*
   1.689 + * Format and print "time".  If the tag message "m" is not NULL,
   1.690 + * do indent formatting based on "level" and add a newline afterward;
   1.691 + * otherwise just print the formatted time string only.
   1.692 + */
   1.693 +static void
   1.694 +secu_PrintTime(FILE *out, const PRTime time, const char *m, int level)
   1.695 +{
   1.696 +    PRExplodedTime printableTime; 
   1.697 +    char *timeString;
   1.698 +
   1.699 +    /* Convert to local time */
   1.700 +    PR_ExplodeTime(time, PR_GMTParameters, &printableTime);
   1.701 +
   1.702 +    timeString = PORT_Alloc(256);
   1.703 +    if (timeString == NULL)
   1.704 +	return;
   1.705 +
   1.706 +    if (m != NULL) {
   1.707 +	SECU_Indent(out, level);
   1.708 +	fprintf(out, "%s: ", m);
   1.709 +    }
   1.710 +
   1.711 +    if (PR_FormatTime(timeString, 256, "%a %b %d %H:%M:%S %Y", &printableTime)) {
   1.712 +        fputs(timeString, out);
   1.713 +    }
   1.714 +
   1.715 +    if (m != NULL)
   1.716 +	fprintf(out, "\n");
   1.717 +
   1.718 +    PORT_Free(timeString);
   1.719 +}
   1.720 +
   1.721 +/*
   1.722 + * Format and print the UTC Time "t".  If the tag message "m" is not NULL,
   1.723 + * do indent formatting based on "level" and add a newline afterward;
   1.724 + * otherwise just print the formatted time string only.
   1.725 + */
   1.726 +void
   1.727 +SECU_PrintUTCTime(FILE *out, const SECItem *t, const char *m, int level)
   1.728 +{
   1.729 +    PRTime time;
   1.730 +    SECStatus rv;
   1.731 +
   1.732 +    rv = DER_UTCTimeToTime(&time, t);
   1.733 +    if (rv != SECSuccess)
   1.734 +	return;
   1.735 +
   1.736 +    secu_PrintTime(out, time, m, level);
   1.737 +}
   1.738 +
   1.739 +/*
   1.740 + * Format and print the Generalized Time "t".  If the tag message "m"
   1.741 + * is not NULL, * do indent formatting based on "level" and add a newline
   1.742 + * afterward; otherwise just print the formatted time string only.
   1.743 + */
   1.744 +void
   1.745 +SECU_PrintGeneralizedTime(FILE *out, const SECItem *t, const char *m, int level)
   1.746 +{
   1.747 +    PRTime time;
   1.748 +    SECStatus rv;
   1.749 +
   1.750 +
   1.751 +    rv = DER_GeneralizedTimeToTime(&time, t);
   1.752 +    if (rv != SECSuccess)
   1.753 +	return;
   1.754 +
   1.755 +    secu_PrintTime(out, time, m, level);
   1.756 +}
   1.757 +
   1.758 +/*
   1.759 + * Format and print the UTC or Generalized Time "t".  If the tag message
   1.760 + * "m" is not NULL, do indent formatting based on "level" and add a newline
   1.761 + * afterward; otherwise just print the formatted time string only.
   1.762 + */
   1.763 +void
   1.764 +SECU_PrintTimeChoice(FILE *out, const SECItem *t, const char *m, int level)
   1.765 +{
   1.766 +    switch (t->type) {
   1.767 +        case siUTCTime:
   1.768 +            SECU_PrintUTCTime(out, t, m, level);
   1.769 +            break;
   1.770 +
   1.771 +        case siGeneralizedTime:
   1.772 +            SECU_PrintGeneralizedTime(out, t, m, level);
   1.773 +            break;
   1.774 +
   1.775 +        default:
   1.776 +            PORT_Assert(0);
   1.777 +            break;
   1.778 +    }
   1.779 +}
   1.780 +
   1.781 +
   1.782 +/* This prints a SET or SEQUENCE */
   1.783 +static void
   1.784 +SECU_PrintSet(FILE *out, const SECItem *t, const char *m, int level)
   1.785 +{
   1.786 +    int            type        = t->data[0] & SEC_ASN1_TAGNUM_MASK;
   1.787 +    int            constructed = t->data[0] & SEC_ASN1_CONSTRUCTED;
   1.788 +    const char *   label;
   1.789 +    SECItem        my          = *t;
   1.790 +
   1.791 +    if (!constructed) {
   1.792 +	SECU_PrintAsHex(out, t, m, level);
   1.793 +        return;
   1.794 +    }
   1.795 +    if (SECSuccess != SECU_StripTagAndLength(&my))
   1.796 +    	return;
   1.797 +
   1.798 +    SECU_Indent(out, level);
   1.799 +    if (m) {
   1.800 +    	fprintf(out, "%s: ", m);
   1.801 +    }
   1.802 +
   1.803 +    if (type == SEC_ASN1_SET)
   1.804 +    	label = "Set ";
   1.805 +    else if (type == SEC_ASN1_SEQUENCE)
   1.806 +    	label = "Sequence ";
   1.807 +    else
   1.808 +    	label = "";
   1.809 +    fprintf(out,"%s{\n", label); /* } */
   1.810 +
   1.811 +    while (my.len >= 2) {
   1.812 +	SECItem  tmp = my;
   1.813 +
   1.814 +        if (tmp.data[1] & 0x80) {
   1.815 +	    unsigned int i;
   1.816 +	    unsigned int lenlen = tmp.data[1] & 0x7f;
   1.817 +	    if (lenlen > sizeof tmp.len)
   1.818 +	        break;
   1.819 +	    tmp.len = 0;
   1.820 +	    for (i=0; i < lenlen; i++) {
   1.821 +		tmp.len = (tmp.len << 8) | tmp.data[2+i];
   1.822 +	    }
   1.823 +	    tmp.len += lenlen + 2;
   1.824 +	} else {
   1.825 +	    tmp.len = tmp.data[1] + 2;
   1.826 +	}
   1.827 +	if (tmp.len > my.len) {
   1.828 +	    tmp.len = my.len;
   1.829 +	}
   1.830 +	my.data += tmp.len;
   1.831 +	my.len  -= tmp.len;
   1.832 +	SECU_PrintAny(out, &tmp, NULL, level + 1);
   1.833 +    }
   1.834 +    SECU_Indent(out, level); fprintf(out, /* { */ "}\n");
   1.835 +}
   1.836 +
   1.837 +static void
   1.838 +secu_PrintContextSpecific(FILE *out, const SECItem *i, const char *m, int level)
   1.839 +{
   1.840 +    int type        = i->data[0] & SEC_ASN1_TAGNUM_MASK;
   1.841 +    int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED;
   1.842 +    SECItem tmp;
   1.843 +
   1.844 +    if (constructed) {
   1.845 +	char * m2;
   1.846 +	if (!m) 
   1.847 +	    m2 = PR_smprintf("[%d]", type);
   1.848 +	else
   1.849 +	    m2 = PR_smprintf("%s: [%d]", m, type);
   1.850 +	if (m2) {
   1.851 +	    SECU_PrintSet(out, i, m2, level);
   1.852 +	    PR_smprintf_free(m2);
   1.853 +	}
   1.854 +	return;
   1.855 +    }
   1.856 +
   1.857 +    SECU_Indent(out, level);
   1.858 +    if (m) {
   1.859 +    	fprintf(out, "%s: ", m);
   1.860 +    }
   1.861 +    fprintf(out,"[%d]\n", type);
   1.862 +
   1.863 +    tmp = *i;
   1.864 +    if (SECSuccess == SECU_StripTagAndLength(&tmp))
   1.865 +	SECU_PrintAsHex(out, &tmp, m, level+1);
   1.866 +}
   1.867 +
   1.868 +static void
   1.869 +secu_PrintOctetString(FILE *out, const SECItem *i, const char *m, int level)
   1.870 +{
   1.871 +    SECItem tmp = *i;
   1.872 +    if (SECSuccess == SECU_StripTagAndLength(&tmp))
   1.873 +	SECU_PrintAsHex(out, &tmp, m, level);
   1.874 +}
   1.875 +
   1.876 +static void
   1.877 +secu_PrintBitString(FILE *out, const SECItem *i, const char *m, int level)
   1.878 +{
   1.879 +    int unused_bits;
   1.880 +    SECItem tmp = *i;
   1.881 +
   1.882 +    if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2)
   1.883 +    	return;
   1.884 +
   1.885 +    unused_bits = *tmp.data++;
   1.886 +    tmp.len--;
   1.887 +
   1.888 +    SECU_PrintAsHex(out, &tmp, m, level);
   1.889 +    if (unused_bits) {
   1.890 +	SECU_Indent(out, level + 1);
   1.891 +	fprintf(out, "(%d least significant bits unused)\n", unused_bits);
   1.892 +    }
   1.893 +}
   1.894 +
   1.895 +/* in a decoded bit string, the len member is a bit length. */
   1.896 +static void
   1.897 +secu_PrintDecodedBitString(FILE *out, const SECItem *i, const char *m, int level)
   1.898 +{
   1.899 +    int unused_bits;
   1.900 +    SECItem tmp = *i;
   1.901 +
   1.902 +
   1.903 +    unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0;
   1.904 +    DER_ConvertBitString(&tmp); /* convert length to byte length */
   1.905 +
   1.906 +    SECU_PrintAsHex(out, &tmp, m, level);
   1.907 +    if (unused_bits) {
   1.908 +	SECU_Indent(out, level + 1);
   1.909 +	fprintf(out, "(%d least significant bits unused)\n", unused_bits);
   1.910 +    }
   1.911 +}
   1.912 +
   1.913 +
   1.914 +/* Print a DER encoded Boolean */
   1.915 +void
   1.916 +SECU_PrintEncodedBoolean(FILE *out, const SECItem *i, const char *m, int level)
   1.917 +{
   1.918 +    SECItem my    = *i;
   1.919 +    if (SECSuccess == SECU_StripTagAndLength(&my))
   1.920 +	secu_PrintBoolean(out, &my, m, level);
   1.921 +}
   1.922 +
   1.923 +/* Print a DER encoded integer */
   1.924 +void
   1.925 +SECU_PrintEncodedInteger(FILE *out, const SECItem *i, const char *m, int level)
   1.926 +{
   1.927 +    SECItem my    = *i;
   1.928 +    if (SECSuccess == SECU_StripTagAndLength(&my))
   1.929 +	SECU_PrintInteger(out, &my, m, level);
   1.930 +}
   1.931 +
   1.932 +/* Print a DER encoded OID */
   1.933 +void
   1.934 +SECU_PrintEncodedObjectID(FILE *out, const SECItem *i, const char *m, int level)
   1.935 +{
   1.936 +    SECItem my    = *i;
   1.937 +    if (SECSuccess == SECU_StripTagAndLength(&my))
   1.938 +	SECU_PrintObjectID(out, &my, m, level);
   1.939 +}
   1.940 +
   1.941 +static void
   1.942 +secu_PrintBMPString(FILE *out, const SECItem *i, const char *m, int level)
   1.943 +{
   1.944 +    unsigned char * s;
   1.945 +    unsigned char * d;
   1.946 +    int      len;
   1.947 +    SECItem  tmp = {0, 0, 0};
   1.948 +    SECItem  my  = *i;
   1.949 +
   1.950 +    if (SECSuccess != SECU_StripTagAndLength(&my))
   1.951 +	goto loser;
   1.952 +    if (my.len % 2) 
   1.953 +    	goto loser;
   1.954 +    len = (int)(my.len / 2);
   1.955 +    tmp.data = (unsigned char *)PORT_Alloc(len);
   1.956 +    if (!tmp.data)
   1.957 +    	goto loser;
   1.958 +    tmp.len = len;
   1.959 +    for (s = my.data, d = tmp.data ; len > 0; len--) {
   1.960 +    	PRUint32 bmpChar = (s[0] << 8) | s[1]; s += 2;
   1.961 +	if (!isprint(bmpChar))
   1.962 +	    goto loser;
   1.963 +	*d++ = (unsigned char)bmpChar;
   1.964 +    }
   1.965 +    secu_PrintRawString(out, &tmp, m, level);
   1.966 +    PORT_Free(tmp.data);
   1.967 +    return;
   1.968 +
   1.969 +loser:
   1.970 +    SECU_PrintAsHex(out, i, m, level);
   1.971 +    if (tmp.data)
   1.972 +	PORT_Free(tmp.data);
   1.973 +}
   1.974 +
   1.975 +static void
   1.976 +secu_PrintUniversalString(FILE *out, const SECItem *i, const char *m, int level)
   1.977 +{
   1.978 +    unsigned char * s;
   1.979 +    unsigned char * d;
   1.980 +    int      len;
   1.981 +    SECItem  tmp = {0, 0, 0};
   1.982 +    SECItem  my  = *i;
   1.983 +
   1.984 +    if (SECSuccess != SECU_StripTagAndLength(&my))
   1.985 +	goto loser;
   1.986 +    if (my.len % 4) 
   1.987 +    	goto loser;
   1.988 +    len = (int)(my.len / 4);
   1.989 +    tmp.data = (unsigned char *)PORT_Alloc(len);
   1.990 +    if (!tmp.data)
   1.991 +    	goto loser;
   1.992 +    tmp.len = len;
   1.993 +    for (s = my.data, d = tmp.data ; len > 0; len--) {
   1.994 +    	PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
   1.995 +	s += 4;
   1.996 +	if (!isprint(bmpChar))
   1.997 +	    goto loser;
   1.998 +	*d++ = (unsigned char)bmpChar;
   1.999 +    }
  1.1000 +    secu_PrintRawString(out, &tmp, m, level);
  1.1001 +    PORT_Free(tmp.data);
  1.1002 +    return;
  1.1003 +
  1.1004 +loser:
  1.1005 +    SECU_PrintAsHex(out, i, m, level);
  1.1006 +    if (tmp.data)
  1.1007 +	PORT_Free(tmp.data);
  1.1008 +}
  1.1009 +
  1.1010 +static void
  1.1011 +secu_PrintUniversal(FILE *out, const SECItem *i, const char *m, int level)
  1.1012 +{
  1.1013 +	switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) {
  1.1014 +	  case SEC_ASN1_ENUMERATED:
  1.1015 +	  case SEC_ASN1_INTEGER:
  1.1016 +	    SECU_PrintEncodedInteger(out, i, m, level);
  1.1017 +	    break;
  1.1018 +	  case SEC_ASN1_OBJECT_ID:
  1.1019 +	    SECU_PrintEncodedObjectID(out, i, m, level);
  1.1020 +	    break;
  1.1021 +	  case SEC_ASN1_BOOLEAN:
  1.1022 +	    SECU_PrintEncodedBoolean(out, i, m, level);
  1.1023 +	    break;
  1.1024 +	  case SEC_ASN1_UTF8_STRING:
  1.1025 +	  case SEC_ASN1_PRINTABLE_STRING:
  1.1026 +	  case SEC_ASN1_VISIBLE_STRING:
  1.1027 +	  case SEC_ASN1_IA5_STRING:
  1.1028 +	  case SEC_ASN1_T61_STRING:
  1.1029 +	    SECU_PrintString(out, i, m, level);
  1.1030 +	    break;
  1.1031 +	  case SEC_ASN1_GENERALIZED_TIME:
  1.1032 +	    SECU_PrintGeneralizedTime(out, i, m, level);
  1.1033 +	    break;
  1.1034 +	  case SEC_ASN1_UTC_TIME:
  1.1035 +	    SECU_PrintUTCTime(out, i, m, level);
  1.1036 +	    break;
  1.1037 +	  case SEC_ASN1_NULL:
  1.1038 +	    SECU_Indent(out, level); 
  1.1039 +	    if (m && m[0]) 
  1.1040 +	      fprintf(out, "%s: NULL\n", m);
  1.1041 +	    else
  1.1042 +	      fprintf(out, "NULL\n");
  1.1043 +	    break;
  1.1044 +          case SEC_ASN1_SET:
  1.1045 +          case SEC_ASN1_SEQUENCE:
  1.1046 +	    SECU_PrintSet(out, i, m, level);
  1.1047 +	    break;
  1.1048 +	  case SEC_ASN1_OCTET_STRING:
  1.1049 +	    secu_PrintOctetString(out, i, m, level);
  1.1050 +	    break;
  1.1051 +	  case SEC_ASN1_BIT_STRING:
  1.1052 +	    secu_PrintBitString(out, i, m, level);
  1.1053 +	    break;
  1.1054 +	  case SEC_ASN1_BMP_STRING:
  1.1055 +	    secu_PrintBMPString(out, i, m, level);
  1.1056 +	    break;
  1.1057 +	  case SEC_ASN1_UNIVERSAL_STRING:
  1.1058 +	    secu_PrintUniversalString(out, i, m, level);
  1.1059 +	    break;
  1.1060 +	  default:
  1.1061 +	    SECU_PrintAsHex(out, i, m, level);
  1.1062 +	    break;
  1.1063 +	}
  1.1064 +}
  1.1065 +
  1.1066 +void
  1.1067 +SECU_PrintAny(FILE *out, const SECItem *i, const char *m, int level)
  1.1068 +{
  1.1069 +    if ( i && i->len && i->data ) {
  1.1070 +	switch (i->data[0] & SEC_ASN1_CLASS_MASK) {
  1.1071 +	case SEC_ASN1_CONTEXT_SPECIFIC:
  1.1072 +	    secu_PrintContextSpecific(out, i, m, level);
  1.1073 +	    break;
  1.1074 +	case SEC_ASN1_UNIVERSAL:
  1.1075 +	    secu_PrintUniversal(out, i, m, level);
  1.1076 +	    break;
  1.1077 +	default:
  1.1078 +	    SECU_PrintAsHex(out, i, m, level);
  1.1079 +	    break;
  1.1080 +	}
  1.1081 +    }
  1.1082 +}
  1.1083 +
  1.1084 +static int
  1.1085 +secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level)
  1.1086 +{
  1.1087 +    SECU_Indent(out, level);  fprintf(out, "%s:\n", m);
  1.1088 +    SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level+1);
  1.1089 +    SECU_PrintTimeChoice(out, &v->notAfter,  "Not After ", level+1);
  1.1090 +    return 0;
  1.1091 +}
  1.1092 +
  1.1093 +/* This function does NOT expect a DER type and length. */
  1.1094 +SECOidTag
  1.1095 +SECU_PrintObjectID(FILE *out, const SECItem *oid, const char *m, int level)
  1.1096 +{
  1.1097 +    SECOidData *oiddata;
  1.1098 +    char *      oidString = NULL;
  1.1099 +    
  1.1100 +    oiddata = SECOID_FindOID(oid);
  1.1101 +    if (oiddata != NULL) {
  1.1102 +	const char *name = oiddata->desc;
  1.1103 +	SECU_Indent(out, level);
  1.1104 +	if (m != NULL)
  1.1105 +	    fprintf(out, "%s: ", m);
  1.1106 +	fprintf(out, "%s\n", name);
  1.1107 +	return oiddata->offset;
  1.1108 +    } 
  1.1109 +    oidString = CERT_GetOidString(oid);
  1.1110 +    if (oidString) {
  1.1111 +	SECU_Indent(out, level);
  1.1112 +	if (m != NULL)
  1.1113 +	    fprintf(out, "%s: ", m);
  1.1114 +	fprintf(out, "%s\n", oidString);
  1.1115 +	PR_smprintf_free(oidString);
  1.1116 +	return SEC_OID_UNKNOWN;
  1.1117 +    }
  1.1118 +    SECU_PrintAsHex(out, oid, m, level);
  1.1119 +    return SEC_OID_UNKNOWN;
  1.1120 +}
  1.1121 +
  1.1122 +typedef struct secuPBEParamsStr {
  1.1123 +    SECItem salt;
  1.1124 +    SECItem iterationCount;
  1.1125 +    SECItem keyLength;
  1.1126 +    SECAlgorithmID cipherAlg;
  1.1127 +    SECAlgorithmID kdfAlg;
  1.1128 +} secuPBEParams;
  1.1129 +
  1.1130 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
  1.1131 +
  1.1132 +/* SECOID_PKCS5_PBKDF2 */
  1.1133 +const SEC_ASN1Template secuKDF2Params[] =
  1.1134 +{
  1.1135 +    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) },
  1.1136 +    { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) },
  1.1137 +    { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) },
  1.1138 +    { SEC_ASN1_INTEGER, offsetof(secuPBEParams, keyLength) },
  1.1139 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg),
  1.1140 +        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1141 +    { 0 }
  1.1142 +};
  1.1143 +
  1.1144 +/* PKCS5v1 & PKCS12 */
  1.1145 +const SEC_ASN1Template secuPBEParamsTemp[] =
  1.1146 +{
  1.1147 +    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) },
  1.1148 +    { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) },
  1.1149 +    { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) },
  1.1150 +    { 0 }
  1.1151 +};
  1.1152 +
  1.1153 +/* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */
  1.1154 +const SEC_ASN1Template secuPBEV2Params[] =
  1.1155 +{
  1.1156 +    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams)},
  1.1157 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg),
  1.1158 +        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1159 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, cipherAlg),
  1.1160 +        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1161 +    { 0 }
  1.1162 +};
  1.1163 +
  1.1164 +void
  1.1165 +secu_PrintRSAPSSParams(FILE *out, SECItem *value, char *m, int level)
  1.1166 +{
  1.1167 +    PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1168 +    SECStatus rv;
  1.1169 +    SECKEYRSAPSSParams param;
  1.1170 +    SECAlgorithmID maskHashAlg;
  1.1171 +
  1.1172 +    if (m) {
  1.1173 +	SECU_Indent(out, level);
  1.1174 +	fprintf (out, "%s:\n", m);
  1.1175 +    }
  1.1176 +
  1.1177 +    if (!pool) {
  1.1178 +	SECU_Indent(out, level);
  1.1179 +	fprintf(out, "Out of memory\n");
  1.1180 +	return;
  1.1181 +    }
  1.1182 +
  1.1183 +    PORT_Memset(&param, 0, sizeof param);
  1.1184 +
  1.1185 +    rv = SEC_QuickDERDecodeItem(pool, &param,
  1.1186 +				SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate),
  1.1187 +				value);
  1.1188 +    if (rv == SECSuccess) {
  1.1189 +	if (!param.hashAlg) {
  1.1190 +	    SECU_Indent(out, level+1);
  1.1191 +	    fprintf(out, "Hash algorithm: default, SHA-1\n");
  1.1192 +	} else {
  1.1193 +	    SECU_PrintObjectID(out, &param.hashAlg->algorithm,
  1.1194 +			       "Hash algorithm", level+1);
  1.1195 +	}
  1.1196 +	if (!param.maskAlg) {
  1.1197 +	    SECU_Indent(out, level+1);
  1.1198 +	    fprintf(out, "Mask algorithm: default, MGF1\n");
  1.1199 +	    SECU_Indent(out, level+1);
  1.1200 +	    fprintf(out, "Mask hash algorithm: default, SHA-1\n");
  1.1201 +	} else {
  1.1202 +	    SECU_PrintObjectID(out, &param.maskAlg->algorithm,
  1.1203 +			       "Mask algorithm", level+1);
  1.1204 +	    rv = SEC_QuickDERDecodeItem(pool, &maskHashAlg,
  1.1205 +		     SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
  1.1206 +		     &param.maskAlg->parameters);
  1.1207 +	    if (rv == SECSuccess) {
  1.1208 +		SECU_PrintObjectID(out, &maskHashAlg.algorithm,
  1.1209 +				   "Mask hash algorithm", level+1);
  1.1210 +	    } else {
  1.1211 +		SECU_Indent(out, level+1);
  1.1212 +		fprintf(out, "Invalid mask generation algorithm parameters\n");
  1.1213 +	    }
  1.1214 +	}
  1.1215 +	if (!param.saltLength.data) {
  1.1216 +	    SECU_Indent(out, level+1);
  1.1217 +	    fprintf(out, "Salt length: default, %i (0x%2X)\n", 20, 20);
  1.1218 +	} else {
  1.1219 +	    SECU_PrintInteger(out, &param.saltLength, "Salt Length", level+1);
  1.1220 +	}
  1.1221 +    } else {
  1.1222 +	SECU_Indent(out, level+1);
  1.1223 +	fprintf(out, "Invalid RSA-PSS parameters\n");
  1.1224 +    }
  1.1225 +    PORT_FreeArena(pool, PR_FALSE);
  1.1226 +}
  1.1227 +
  1.1228 +void
  1.1229 +secu_PrintKDF2Params(FILE *out, SECItem *value, char *m, int level)
  1.1230 +{
  1.1231 +    PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1232 +    SECStatus rv;
  1.1233 +    secuPBEParams param;
  1.1234 +
  1.1235 +    if (m) {
  1.1236 +	SECU_Indent(out, level);
  1.1237 +	fprintf (out, "%s:\n", m);
  1.1238 +    }
  1.1239 +
  1.1240 +    if (!pool) {
  1.1241 +	SECU_Indent(out, level);
  1.1242 +	fprintf(out, "Out of memory\n");
  1.1243 +	return;
  1.1244 +    }
  1.1245 +
  1.1246 +    PORT_Memset(&param, 0, sizeof param);
  1.1247 +    rv = SEC_QuickDERDecodeItem(pool, &param, secuKDF2Params, value);
  1.1248 +    if (rv == SECSuccess) {
  1.1249 +	SECU_PrintAsHex(out, &param.salt, "Salt", level+1);
  1.1250 +	SECU_PrintInteger(out, &param.iterationCount, "Iteration Count", 
  1.1251 +			level+1);
  1.1252 +	SECU_PrintInteger(out, &param.keyLength, "Key Length", level+1);
  1.1253 +	SECU_PrintAlgorithmID(out, &param.kdfAlg, "KDF algorithm", level+1);
  1.1254 +    }
  1.1255 +    PORT_FreeArena(pool, PR_FALSE);
  1.1256 +}
  1.1257 +
  1.1258 +void
  1.1259 +secu_PrintPKCS5V2Params(FILE *out, SECItem *value, char *m, int level)
  1.1260 +{
  1.1261 +    PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1262 +    SECStatus rv;
  1.1263 +    secuPBEParams param;
  1.1264 +
  1.1265 +    if (m) {
  1.1266 +	SECU_Indent(out, level);
  1.1267 +	fprintf (out, "%s:\n", m);
  1.1268 +    }
  1.1269 +
  1.1270 +    if (!pool) {
  1.1271 +	SECU_Indent(out, level);
  1.1272 +	fprintf(out, "Out of memory\n");
  1.1273 +	return;
  1.1274 +    }
  1.1275 +
  1.1276 +    PORT_Memset(&param, 0, sizeof param);
  1.1277 +    rv = SEC_QuickDERDecodeItem(pool, &param, secuPBEV2Params, value);
  1.1278 +    if (rv == SECSuccess) {
  1.1279 +	SECU_PrintAlgorithmID(out, &param.kdfAlg, "KDF", level+1);
  1.1280 +	SECU_PrintAlgorithmID(out, &param.cipherAlg, "Cipher", level+1);
  1.1281 +    }
  1.1282 +    PORT_FreeArena(pool, PR_FALSE);
  1.1283 +}
  1.1284 +
  1.1285 +void
  1.1286 +secu_PrintPBEParams(FILE *out, SECItem *value, char *m, int level)
  1.1287 +{
  1.1288 +    PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1289 +    SECStatus rv;
  1.1290 +    secuPBEParams param;
  1.1291 +
  1.1292 +    if (m) {
  1.1293 +	SECU_Indent(out, level);
  1.1294 +	fprintf (out, "%s:\n", m);
  1.1295 +    }
  1.1296 +
  1.1297 +    if (!pool) {
  1.1298 +	SECU_Indent(out, level);
  1.1299 +	fprintf(out, "Out of memory\n");
  1.1300 +	return;
  1.1301 +    }
  1.1302 +
  1.1303 +    PORT_Memset(&param, 0, sizeof(secuPBEParams));
  1.1304 +    rv = SEC_QuickDERDecodeItem(pool, &param, secuPBEParamsTemp, value);
  1.1305 +    if (rv == SECSuccess) {
  1.1306 +	SECU_PrintAsHex(out, &param.salt, "Salt", level+1);
  1.1307 +	SECU_PrintInteger(out, &param.iterationCount, "Iteration Count", 
  1.1308 +			level+1);
  1.1309 +    }
  1.1310 +    PORT_FreeArena(pool, PR_FALSE);
  1.1311 +}
  1.1312 +
  1.1313 +/* This function does NOT expect a DER type and length. */
  1.1314 +void
  1.1315 +SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level)
  1.1316 +{
  1.1317 +    SECOidTag algtag;
  1.1318 +    SECU_PrintObjectID(out, &a->algorithm, m, level);
  1.1319 +
  1.1320 +    algtag = SECOID_GetAlgorithmTag(a);
  1.1321 +    if (SEC_PKCS5IsAlgorithmPBEAlgTag(algtag)) {
  1.1322 +	switch (algtag) {
  1.1323 +	case SEC_OID_PKCS5_PBKDF2:
  1.1324 +	    secu_PrintKDF2Params(out, &a->parameters, "Parameters", level+1);
  1.1325 +	    break;
  1.1326 +	case SEC_OID_PKCS5_PBES2:
  1.1327 +	    secu_PrintPKCS5V2Params(out, &a->parameters, "Encryption", level+1);
  1.1328 +	    break;
  1.1329 +	case SEC_OID_PKCS5_PBMAC1:
  1.1330 +	    secu_PrintPKCS5V2Params(out, &a->parameters, "MAC", level+1);
  1.1331 +	    break;
  1.1332 +	default:
  1.1333 +	    secu_PrintPBEParams(out, &a->parameters, "Parameters", level+1);
  1.1334 +	    break;
  1.1335 +	}
  1.1336 +	return;
  1.1337 +    }
  1.1338 +
  1.1339 +    if (algtag == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
  1.1340 +	secu_PrintRSAPSSParams(out, &a->parameters, "Parameters", level+1);
  1.1341 +	return;
  1.1342 +    }
  1.1343 +
  1.1344 +    if (a->parameters.len == 0
  1.1345 +	|| (a->parameters.len == 2
  1.1346 +	    && PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) {
  1.1347 +	/* No arguments or NULL argument */
  1.1348 +    } else {
  1.1349 +	/* Print args to algorithm */
  1.1350 +	SECU_PrintAsHex(out, &a->parameters, "Args", level+1);
  1.1351 +    }
  1.1352 +}
  1.1353 +
  1.1354 +static void
  1.1355 +secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level)
  1.1356 +{
  1.1357 +    SECItem *value;
  1.1358 +    int i;
  1.1359 +    char om[100];
  1.1360 +
  1.1361 +    if (m) {
  1.1362 +    	SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.1363 +    }
  1.1364 +
  1.1365 +    /*
  1.1366 +     * Should make this smarter; look at the type field and then decode
  1.1367 +     * and print the value(s) appropriately!
  1.1368 +     */
  1.1369 +    SECU_PrintObjectID(out, &(attr->type), "Type", level+1);
  1.1370 +    if (attr->values != NULL) {
  1.1371 +	i = 0;
  1.1372 +	while ((value = attr->values[i++]) != NULL) {
  1.1373 +	    sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : ""); 
  1.1374 +	    if (attr->encoded || attr->typeTag == NULL) {
  1.1375 +		SECU_PrintAny(out, value, om, level+1);
  1.1376 +	    } else {
  1.1377 +		switch (attr->typeTag->offset) {
  1.1378 +		  default:
  1.1379 +		    SECU_PrintAsHex(out, value, om, level+1);
  1.1380 +		    break;
  1.1381 +		  case SEC_OID_PKCS9_CONTENT_TYPE:
  1.1382 +		    SECU_PrintObjectID(out, value, om, level+1);
  1.1383 +		    break;
  1.1384 +		  case SEC_OID_PKCS9_SIGNING_TIME:
  1.1385 +		    SECU_PrintTimeChoice(out, value, om, level+1);
  1.1386 +		    break;
  1.1387 +		}
  1.1388 +	    }
  1.1389 +	}
  1.1390 +    }
  1.1391 +}
  1.1392 +
  1.1393 +#ifndef NSS_DISABLE_ECC
  1.1394 +static void
  1.1395 +secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
  1.1396 +{
  1.1397 +    SECItem curveOID = { siBuffer, NULL, 0};
  1.1398 +
  1.1399 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.1400 +    SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level+1);
  1.1401 +    /* For named curves, the DEREncodedParams field contains an
  1.1402 +     * ASN Object ID (0x06 is SEC_ASN1_OBJECT_ID).
  1.1403 +     */
  1.1404 +    if ((pk->u.ec.DEREncodedParams.len > 2) &&
  1.1405 +	(pk->u.ec.DEREncodedParams.data[0] == 0x06)) {
  1.1406 +        curveOID.len = pk->u.ec.DEREncodedParams.data[1];
  1.1407 +	curveOID.data = pk->u.ec.DEREncodedParams.data + 2;
  1.1408 +	SECU_PrintObjectID(out, &curveOID, "Curve", level +1);
  1.1409 +    }
  1.1410 +}
  1.1411 +#endif /* NSS_DISABLE_ECC */
  1.1412 +
  1.1413 +void
  1.1414 +SECU_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
  1.1415 +{
  1.1416 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.1417 +    SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1);
  1.1418 +    SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1);
  1.1419 +    if (pk->u.rsa.publicExponent.len == 1 &&
  1.1420 +        pk->u.rsa.publicExponent.data[0] == 1) {
  1.1421 +	SECU_Indent(out, level +1); fprintf(out, "Error: INVALID RSA KEY!\n");
  1.1422 +    }
  1.1423 +}
  1.1424 +
  1.1425 +void
  1.1426 +SECU_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
  1.1427 +{
  1.1428 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.1429 +    SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level+1);
  1.1430 +    SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level+1);
  1.1431 +    SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level+1);
  1.1432 +    SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level+1);
  1.1433 +}
  1.1434 +
  1.1435 +static void
  1.1436 +secu_PrintSubjectPublicKeyInfo(FILE *out, PLArenaPool *arena,
  1.1437 +		       CERTSubjectPublicKeyInfo *i,  char *msg, int level)
  1.1438 +{
  1.1439 +    SECKEYPublicKey *pk;
  1.1440 +
  1.1441 +    SECU_Indent(out, level); fprintf(out, "%s:\n", msg);
  1.1442 +    SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level+1);
  1.1443 +
  1.1444 +    pk = SECKEY_ExtractPublicKey(i);
  1.1445 +    if (pk) {
  1.1446 +	switch (pk->keyType) {
  1.1447 +	case rsaKey:
  1.1448 +	    SECU_PrintRSAPublicKey(out, pk, "RSA Public Key", level +1);
  1.1449 +	    break;
  1.1450 +
  1.1451 +	case dsaKey:
  1.1452 +	    SECU_PrintDSAPublicKey(out, pk, "DSA Public Key", level +1);
  1.1453 +	    break;
  1.1454 +
  1.1455 +#ifndef NSS_DISABLE_ECC
  1.1456 +	case ecKey:
  1.1457 +	    secu_PrintECPublicKey(out, pk, "EC Public Key", level +1);
  1.1458 +	    break;
  1.1459 +#endif
  1.1460 +
  1.1461 +	case dhKey:
  1.1462 +	case fortezzaKey:
  1.1463 +	case keaKey:
  1.1464 +	    SECU_Indent(out, level);
  1.1465 +    	    fprintf(out, "unable to format this SPKI algorithm type\n");
  1.1466 +	    goto loser;
  1.1467 +	default:
  1.1468 +	    SECU_Indent(out, level);
  1.1469 +	    fprintf(out, "unknown SPKI algorithm type\n");
  1.1470 +	    goto loser;
  1.1471 +	}
  1.1472 +	PORT_FreeArena(pk->arena, PR_FALSE);
  1.1473 +    } else {
  1.1474 +	SECU_PrintErrMsg(out, level, "Error", "Parsing public key");
  1.1475 +loser:
  1.1476 +	if (i->subjectPublicKey.data) {
  1.1477 +	    SECU_PrintAny(out, &i->subjectPublicKey, "Raw", level);
  1.1478 +	}
  1.1479 +    }
  1.1480 +}
  1.1481 +
  1.1482 +static void
  1.1483 +printStringWithoutCRLF(FILE *out, const char *str)
  1.1484 +{
  1.1485 +    const char *c = str;
  1.1486 +    while (*c) {
  1.1487 +	if (*c != '\r' && *c != '\n') {
  1.1488 +	    fputc(*c, out);
  1.1489 +	}
  1.1490 +	++c;
  1.1491 +    }
  1.1492 +}
  1.1493 +
  1.1494 +int
  1.1495 +SECU_PrintDumpDerIssuerAndSerial(FILE *out, SECItem *der, char *m,
  1.1496 +                                 int level)
  1.1497 +{
  1.1498 +    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1499 +    CERTCertificate *c;
  1.1500 +    int rv = SEC_ERROR_NO_MEMORY;
  1.1501 +    char *derIssuerB64;
  1.1502 +    char *derSerialB64;
  1.1503 +    
  1.1504 +    if (!arena)
  1.1505 +        return rv;
  1.1506 +
  1.1507 +    /* Decode certificate */
  1.1508 +    c = PORT_ArenaZNew(arena, CERTCertificate);
  1.1509 +    if (!c)
  1.1510 +        goto loser;
  1.1511 +    c->arena = arena;
  1.1512 +    rv = SEC_ASN1DecodeItem(arena, c, 
  1.1513 +                            SEC_ASN1_GET(CERT_CertificateTemplate), der);
  1.1514 +    if (rv) {
  1.1515 +        SECU_PrintErrMsg(out, 0, "Error", "Parsing extension");
  1.1516 +        goto loser;
  1.1517 +    }
  1.1518 +
  1.1519 +    SECU_PrintName(out, &c->subject, "Subject", 0);
  1.1520 +    if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
  1.1521 +	SECU_Newline(out);
  1.1522 +    SECU_PrintName(out, &c->issuer, "Issuer", 0);
  1.1523 +    if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
  1.1524 +	SECU_Newline(out);
  1.1525 +    SECU_PrintInteger(out, &c->serialNumber, "Serial Number", 0);
  1.1526 +    
  1.1527 +    derIssuerB64 = BTOA_ConvertItemToAscii(&c->derIssuer);
  1.1528 +    derSerialB64 = BTOA_ConvertItemToAscii(&c->serialNumber);
  1.1529 +
  1.1530 +    fprintf(out, "Issuer DER Base64:\n");
  1.1531 +    if (SECU_GetWrapEnabled()) {
  1.1532 +	fprintf(out, "%s\n", derIssuerB64);
  1.1533 +    } else {
  1.1534 +	printStringWithoutCRLF(out, derIssuerB64);
  1.1535 +	fputs("\n", out);
  1.1536 +    }
  1.1537 +
  1.1538 +    fprintf(out, "Serial DER Base64:\n");
  1.1539 +    if (SECU_GetWrapEnabled()) {
  1.1540 +	fprintf(out, "%s\n", derSerialB64);
  1.1541 +    } else {
  1.1542 +	printStringWithoutCRLF(out, derSerialB64);
  1.1543 +	fputs("\n", out);
  1.1544 +    }
  1.1545 +
  1.1546 +    PORT_Free(derIssuerB64);
  1.1547 +    PORT_Free(derSerialB64);
  1.1548 +    
  1.1549 +    fprintf(out, "Serial DER as C source: \n{ %d, \"", c->serialNumber.len);
  1.1550 +
  1.1551 +    {
  1.1552 +      int i;
  1.1553 +      for (i=0; i < c->serialNumber.len; ++i) {
  1.1554 +        unsigned char *chardata = (unsigned char*)(c->serialNumber.data);
  1.1555 +        unsigned char c = *(chardata + i);
  1.1556 +        
  1.1557 +        fprintf(out, "\\x%02x", c);
  1.1558 +      }
  1.1559 +      fprintf(out, "\" }\n");
  1.1560 +    }
  1.1561 +
  1.1562 +loser:
  1.1563 +    PORT_FreeArena(arena, PR_FALSE);
  1.1564 +    return rv;
  1.1565 +}
  1.1566 +
  1.1567 +static SECStatus
  1.1568 +secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level)
  1.1569 +{
  1.1570 +    SECItem decodedValue;
  1.1571 +    SECStatus rv;
  1.1572 +    PRTime invalidTime;
  1.1573 +    char *formattedTime = NULL;
  1.1574 +
  1.1575 +    decodedValue.data = NULL;
  1.1576 +    rv = SEC_ASN1DecodeItem (NULL, &decodedValue, 
  1.1577 +			    SEC_ASN1_GET(SEC_GeneralizedTimeTemplate),
  1.1578 +			    value);
  1.1579 +    if (rv == SECSuccess) {
  1.1580 +	rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue);
  1.1581 +	if (rv == SECSuccess) {
  1.1582 +	    formattedTime = CERT_GenTime2FormattedAscii
  1.1583 +			    (invalidTime, "%a %b %d %H:%M:%S %Y");
  1.1584 +	    SECU_Indent(out, level +1);
  1.1585 +	    fprintf (out, "%s: %s\n", msg, formattedTime);
  1.1586 +	    PORT_Free (formattedTime);
  1.1587 +	}
  1.1588 +    }
  1.1589 +    PORT_Free (decodedValue.data);
  1.1590 +    return (rv);
  1.1591 +}
  1.1592 +
  1.1593 +static SECStatus
  1.1594 +PrintExtKeyUsageExtension  (FILE *out, SECItem *value, char *msg, int level)
  1.1595 +{
  1.1596 +    CERTOidSequence *os;
  1.1597 +    SECItem **op;
  1.1598 +
  1.1599 +    os = CERT_DecodeOidSequence(value);
  1.1600 +    if( (CERTOidSequence *)NULL == os ) {
  1.1601 +	return SECFailure;
  1.1602 +    }
  1.1603 +
  1.1604 +    for( op = os->oids; *op; op++ ) {
  1.1605 +	SECU_PrintObjectID(out, *op, msg, level + 1);
  1.1606 +    }
  1.1607 +    CERT_DestroyOidSequence(os);
  1.1608 +    return SECSuccess;
  1.1609 +}
  1.1610 +
  1.1611 +static SECStatus
  1.1612 +secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) {
  1.1613 +    CERTBasicConstraints constraints;
  1.1614 +    SECStatus rv;
  1.1615 +
  1.1616 +    SECU_Indent(out, level);
  1.1617 +    if (msg) {
  1.1618 +	    fprintf(out,"%s: ",msg);
  1.1619 +    } 
  1.1620 +    rv = CERT_DecodeBasicConstraintValue(&constraints,value);
  1.1621 +    if (rv == SECSuccess && constraints.isCA) {
  1.1622 +	if (constraints.pathLenConstraint >= 0) {
  1.1623 +	    fprintf(out,"Is a CA with a maximum path length of %d.\n",
  1.1624 +			constraints.pathLenConstraint);
  1.1625 +    	} else {
  1.1626 +	    fprintf(out,"Is a CA with no maximum path length.\n");
  1.1627 +	}
  1.1628 +    } else  {
  1.1629 +	fprintf(out,"Is not a CA.\n");
  1.1630 +    }
  1.1631 +    return SECSuccess;
  1.1632 +}
  1.1633 +
  1.1634 +static const char * const nsTypeBits[] = {
  1.1635 +    "SSL Client",
  1.1636 +    "SSL Server",
  1.1637 +    "S/MIME",
  1.1638 +    "Object Signing",
  1.1639 +    "Reserved",
  1.1640 +    "SSL CA",
  1.1641 +    "S/MIME CA",
  1.1642 +    "ObjectSigning CA" 
  1.1643 +};
  1.1644 +
  1.1645 +/* NSCertType is merely a bit string whose bits are displayed symbolically */
  1.1646 +static SECStatus
  1.1647 +secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) 
  1.1648 +{
  1.1649 +    int     unused;
  1.1650 +    int     NS_Type;
  1.1651 +    int     i;
  1.1652 +    int     found   = 0;
  1.1653 +    SECItem my      = *value;
  1.1654 +
  1.1655 +    if ((my.data[0] != SEC_ASN1_BIT_STRING) || 
  1.1656 +        SECSuccess != SECU_StripTagAndLength(&my)) {
  1.1657 +	SECU_PrintAny(out, value, "Data", level);
  1.1658 +	return SECSuccess;
  1.1659 +    }
  1.1660 +
  1.1661 +    unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0;  
  1.1662 +    NS_Type = my.data[1] & (0xff << unused);
  1.1663 +	
  1.1664 +
  1.1665 +    SECU_Indent(out, level);
  1.1666 +    if (msg) {
  1.1667 +	fprintf(out,"%s: ",msg);
  1.1668 +    } else {
  1.1669 +	fprintf(out,"Netscape Certificate Type: ");
  1.1670 +    }
  1.1671 +    for (i=0; i < 8; i++) {
  1.1672 +	if ( (0x80 >> i) & NS_Type) {
  1.1673 +	    fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]);
  1.1674 +	    found = 1;
  1.1675 +	}
  1.1676 +    }
  1.1677 +    fprintf(out, (found ? ">\n" : "none\n"));
  1.1678 +    return SECSuccess;
  1.1679 +}
  1.1680 +
  1.1681 +static const char * const usageBits[] = {
  1.1682 +    "Digital Signature",   /* 0x80 */
  1.1683 +    "Non-Repudiation",     /* 0x40 */
  1.1684 +    "Key Encipherment",    /* 0x20 */
  1.1685 +    "Data Encipherment",   /* 0x10 */
  1.1686 +    "Key Agreement",       /* 0x08 */
  1.1687 +    "Certificate Signing", /* 0x04 */
  1.1688 +    "CRL Signing",         /* 0x02 */
  1.1689 +    "Encipher Only",       /* 0x01 */
  1.1690 +    "Decipher Only",       /* 0x0080 */ 
  1.1691 +    NULL
  1.1692 +};
  1.1693 +
  1.1694 +/* X509KeyUsage is merely a bit string whose bits are displayed symbolically */
  1.1695 +static void
  1.1696 +secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level) 
  1.1697 +{
  1.1698 +    int     unused;
  1.1699 +    int     usage;
  1.1700 +    int     i;
  1.1701 +    int     found   = 0;
  1.1702 +    SECItem my      = *value;
  1.1703 +
  1.1704 +    if ((my.data[0] != SEC_ASN1_BIT_STRING) || 
  1.1705 +        SECSuccess != SECU_StripTagAndLength(&my)) {
  1.1706 +	SECU_PrintAny(out, value, "Data", level);
  1.1707 +	return;
  1.1708 +    }
  1.1709 +
  1.1710 +    unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0;  
  1.1711 +    usage  = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8
  1.1712 +                           : (my.data[1] << 8) | 
  1.1713 +			     (my.data[2] & (0xff << unused));
  1.1714 +
  1.1715 +    SECU_Indent(out, level);
  1.1716 +    fprintf(out, "Usages: ");
  1.1717 +    for (i=0; usageBits[i]; i++) {
  1.1718 +	if ( (0x8000 >> i) & usage) {
  1.1719 +	    if (found)
  1.1720 +		SECU_Indent(out, level + 2);
  1.1721 +	    fprintf(out, "%s\n", usageBits[i]);
  1.1722 +	    found = 1;
  1.1723 +	}
  1.1724 +    }
  1.1725 +    if (!found) {
  1.1726 +	fprintf(out, "(none)\n");
  1.1727 +    }
  1.1728 +}
  1.1729 +
  1.1730 +static void
  1.1731 +secu_PrintIPAddress(FILE *out, SECItem *value, char *msg, int level)
  1.1732 +{
  1.1733 +    PRStatus   st;
  1.1734 +    PRNetAddr  addr;
  1.1735 +    char       addrBuf[80];
  1.1736 +
  1.1737 +    memset(&addr, 0, sizeof addr);
  1.1738 +    if (value->len == 4) {
  1.1739 +	addr.inet.family = PR_AF_INET;
  1.1740 +	memcpy(&addr.inet.ip, value->data, value->len);
  1.1741 +    } else if (value->len == 16) {
  1.1742 +	addr.ipv6.family = PR_AF_INET6;
  1.1743 +	memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len);
  1.1744 +	if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) {
  1.1745 +	    /* convert to IPv4.  */
  1.1746 +	    addr.inet.family = PR_AF_INET;
  1.1747 +	    memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4);
  1.1748 +	    memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad);
  1.1749 +	}
  1.1750 +    } else {
  1.1751 +	goto loser;
  1.1752 +    }
  1.1753 +
  1.1754 +    st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf);
  1.1755 +    if (st == PR_SUCCESS) {
  1.1756 +	SECU_Indent(out, level);
  1.1757 +	fprintf(out, "%s: %s\n", msg, addrBuf);
  1.1758 +    } else {
  1.1759 +loser:
  1.1760 +	SECU_PrintAsHex(out, value, msg, level);
  1.1761 +    }
  1.1762 +}
  1.1763 +
  1.1764 +
  1.1765 +static void
  1.1766 +secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, char *msg, int level) 
  1.1767 +{
  1.1768 +    char label[40];
  1.1769 +    if (msg && msg[0]) {
  1.1770 +    	SECU_Indent(out, level++); fprintf(out, "%s: \n", msg);
  1.1771 +    }
  1.1772 +    switch (gname->type) {
  1.1773 +    case certOtherName :
  1.1774 +	SECU_PrintAny(     out, &gname->name.OthName.name, "Other Name", level);
  1.1775 +	SECU_PrintObjectID(out, &gname->name.OthName.oid,  "OID",      level+1);
  1.1776 +	break;
  1.1777 +    case certDirectoryName :
  1.1778 +	SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level);
  1.1779 +	break;
  1.1780 +    case certRFC822Name :
  1.1781 +	secu_PrintRawString(   out, &gname->name.other, "RFC822 Name", level);
  1.1782 +	break;
  1.1783 +    case certDNSName :
  1.1784 +	secu_PrintRawString(   out, &gname->name.other, "DNS name", level);
  1.1785 +	break;
  1.1786 +    case certURI :
  1.1787 +	secu_PrintRawString(   out, &gname->name.other, "URI", level);
  1.1788 +	break;
  1.1789 +    case certIPAddress :
  1.1790 +	secu_PrintIPAddress(out, &gname->name.other, "IP Address", level);
  1.1791 +	break;
  1.1792 +    case certRegisterID :
  1.1793 +	SECU_PrintObjectID( out, &gname->name.other, "Registered ID", level);
  1.1794 +	break;
  1.1795 +    case certX400Address :
  1.1796 +	SECU_PrintAny(      out, &gname->name.other, "X400 Address", level);
  1.1797 +	break;
  1.1798 +    case certEDIPartyName :
  1.1799 +	SECU_PrintAny(      out, &gname->name.other, "EDI Party", level);
  1.1800 +	break;
  1.1801 +    default:
  1.1802 +	PR_snprintf(label, sizeof label, "unknown type [%d]", 
  1.1803 +	                                (int)gname->type - 1);
  1.1804 +	SECU_PrintAsHex(out, &gname->name.other, label, level);
  1.1805 +	break;
  1.1806 +    }
  1.1807 +}
  1.1808 +
  1.1809 +static void
  1.1810 +secu_PrintGeneralNames(FILE *out, CERTGeneralName *gname, char *msg, int level) 
  1.1811 +{
  1.1812 +    CERTGeneralName *name = gname;
  1.1813 +    do { 
  1.1814 +    	secu_PrintGeneralName(out, name, msg, level);
  1.1815 +	name = CERT_GetNextGeneralName(name);
  1.1816 +    } while (name && name != gname);
  1.1817 +}
  1.1818 +
  1.1819 +
  1.1820 +static void
  1.1821 +secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level) 
  1.1822 +{
  1.1823 +    CERTAuthKeyID *kid  = NULL;
  1.1824 +    PLArenaPool   *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1825 +
  1.1826 +    if (!pool) {
  1.1827 +	SECU_PrintError("Error", "Allocating new ArenaPool");
  1.1828 +	return;
  1.1829 +    }
  1.1830 +    kid = CERT_DecodeAuthKeyID(pool, value);
  1.1831 +    if (!kid) {
  1.1832 +	SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
  1.1833 +	SECU_PrintAny(out, value, "Data", level);
  1.1834 +    } else {
  1.1835 +	int keyIDPresent  = (kid->keyID.data && kid->keyID.len);
  1.1836 +	int issuerPresent = kid->authCertIssuer != NULL;
  1.1837 +	int snPresent = (kid->authCertSerialNumber.data &&
  1.1838 +	                 kid->authCertSerialNumber.len);
  1.1839 +
  1.1840 +	if (keyIDPresent)
  1.1841 +	    SECU_PrintAsHex(out, &kid->keyID, "Key ID", level);
  1.1842 +	if (issuerPresent)
  1.1843 +	    secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level);
  1.1844 +	if (snPresent)
  1.1845 +	    SECU_PrintInteger(out, &kid->authCertSerialNumber, 
  1.1846 +	                    "Serial Number", level);
  1.1847 +    }
  1.1848 +    PORT_FreeArena(pool, PR_FALSE);
  1.1849 +}
  1.1850 +
  1.1851 +
  1.1852 +static void
  1.1853 +secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level)
  1.1854 +{
  1.1855 +    CERTGeneralName * nameList;
  1.1856 +    CERTGeneralName * current;
  1.1857 +    PLArenaPool     * pool      = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1858 +
  1.1859 +    if (!pool) {
  1.1860 +	SECU_PrintError("Error", "Allocating new ArenaPool");
  1.1861 +	return;
  1.1862 +    }
  1.1863 +    nameList = current = CERT_DecodeAltNameExtension(pool, value);
  1.1864 +    if (!current) {
  1.1865 +	if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
  1.1866 +	    /* Decoder found empty sequence, which is invalid. */
  1.1867 +	    PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
  1.1868 +	}
  1.1869 +	SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
  1.1870 +	SECU_PrintAny(out, value, "Data", level);
  1.1871 +    } else {
  1.1872 +	do {
  1.1873 +	    secu_PrintGeneralName(out, current, msg, level);
  1.1874 +	    current = CERT_GetNextGeneralName(current);
  1.1875 +	} while (current != nameList);
  1.1876 +    }
  1.1877 +    PORT_FreeArena(pool, PR_FALSE);
  1.1878 +}
  1.1879 +
  1.1880 +static void
  1.1881 +secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level)
  1.1882 +{
  1.1883 +    CERTCrlDistributionPoints * dPoints;
  1.1884 +    PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1885 +
  1.1886 +    if (!pool) {
  1.1887 +	SECU_PrintError("Error", "Allocating new ArenaPool");
  1.1888 +	return;
  1.1889 +    }
  1.1890 +    dPoints = CERT_DecodeCRLDistributionPoints(pool, value);
  1.1891 +    if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) {
  1.1892 +	CRLDistributionPoint ** pPoints = dPoints->distPoints;
  1.1893 +	CRLDistributionPoint *  pPoint;
  1.1894 +	while (NULL != (pPoint = *pPoints++)) {
  1.1895 +	    SECU_Indent(out, level); fputs("Distribution point:\n", out);
  1.1896 +	    if (pPoint->distPointType == generalName && 
  1.1897 +	        pPoint->distPoint.fullName != NULL) {
  1.1898 +		secu_PrintGeneralNames(out, pPoint->distPoint.fullName, NULL,
  1.1899 +		                       level + 1);
  1.1900 +	    } else if (pPoint->distPointType == relativeDistinguishedName &&
  1.1901 +	               pPoint->distPoint.relativeName.avas) {
  1.1902 +		SECU_PrintRDN(out, &pPoint->distPoint.relativeName, "RDN", 
  1.1903 +		              level + 1);
  1.1904 +	    } else if (pPoint->derDistPoint.data) {
  1.1905 +		SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level + 1);
  1.1906 +	    }
  1.1907 +	    if (pPoint->reasons.data) {
  1.1908 +		secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons", 
  1.1909 +		                           level + 1);
  1.1910 +	    }
  1.1911 +	    if (pPoint->crlIssuer) {
  1.1912 +		secu_PrintGeneralName(out, pPoint->crlIssuer, "CRL issuer",
  1.1913 +				      level + 1);
  1.1914 +	    }
  1.1915 +	}
  1.1916 +    } else {
  1.1917 +	SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
  1.1918 +	SECU_PrintAny(out, value, "Data", level);
  1.1919 +    }
  1.1920 +    PORT_FreeArena(pool, PR_FALSE);
  1.1921 +}
  1.1922 +
  1.1923 +
  1.1924 +static void
  1.1925 +secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value, 
  1.1926 +                                char *msg, int level)
  1.1927 +{
  1.1928 +    CERTNameConstraint *head = value;
  1.1929 +    SECU_Indent(out, level); fprintf(out, "%s Subtree:\n", msg);
  1.1930 +    level++;
  1.1931 +    do {
  1.1932 +	secu_PrintGeneralName(out, &value->name, NULL, level);
  1.1933 +	if (value->min.data)
  1.1934 +	    SECU_PrintInteger(out, &value->min, "Minimum", level+1);
  1.1935 +	if (value->max.data)
  1.1936 +	    SECU_PrintInteger(out, &value->max, "Maximum", level+1);
  1.1937 +	value = CERT_GetNextNameConstraint(value);
  1.1938 +    } while (value != head);
  1.1939 +}
  1.1940 +
  1.1941 +static void
  1.1942 +secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, char *msg, int level)
  1.1943 +{
  1.1944 +    CERTNameConstraints * cnstrnts;
  1.1945 +    PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1946 +
  1.1947 +    if (!pool) {
  1.1948 +	SECU_PrintError("Error", "Allocating new ArenaPool");
  1.1949 +	return;
  1.1950 +    }
  1.1951 +    cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value);
  1.1952 +    if (!cnstrnts) {
  1.1953 +	SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
  1.1954 +    	SECU_PrintAny(out, value, "Raw", level);
  1.1955 +    } else {
  1.1956 +	if (cnstrnts->permited)
  1.1957 +	    secu_PrintNameConstraintSubtree(out, cnstrnts->permited, 
  1.1958 +	                                    "Permitted", level);
  1.1959 +	if (cnstrnts->excluded)
  1.1960 +	    secu_PrintNameConstraintSubtree(out, cnstrnts->excluded, 
  1.1961 +	                                    "Excluded", level);
  1.1962 +    }
  1.1963 +    PORT_FreeArena(pool, PR_FALSE);
  1.1964 +}
  1.1965 +
  1.1966 +
  1.1967 +static void
  1.1968 +secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level)
  1.1969 +{
  1.1970 +    CERTAuthInfoAccess **infos = NULL;
  1.1971 +    PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1972 +
  1.1973 +    if (!pool) {
  1.1974 +	SECU_PrintError("Error", "Allocating new ArenaPool");
  1.1975 +	return;
  1.1976 +    }
  1.1977 +    infos = CERT_DecodeAuthInfoAccessExtension(pool, value);
  1.1978 +    if (!infos) {
  1.1979 +	SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
  1.1980 +    	SECU_PrintAny(out, value, "Raw", level);
  1.1981 +    } else {
  1.1982 +	CERTAuthInfoAccess *info;
  1.1983 +	while (NULL != (info = *infos++)) {
  1.1984 +	    if (info->method.data) {
  1.1985 +		SECU_PrintObjectID(out, &info->method, "Method", level);
  1.1986 +	    } else {
  1.1987 +	    	SECU_Indent(out,level);
  1.1988 +		fprintf(out, "Error: missing method\n");
  1.1989 +	    }
  1.1990 +	    if (info->location) {
  1.1991 +		secu_PrintGeneralName(out, info->location, "Location", level);
  1.1992 +	    } else {
  1.1993 +		SECU_PrintAny(out, &info->derLocation, "Location", level);
  1.1994 +	    }
  1.1995 +	}
  1.1996 +    }
  1.1997 +    PORT_FreeArena(pool, PR_FALSE);
  1.1998 +}
  1.1999 +
  1.2000 +
  1.2001 +void
  1.2002 +SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions,
  1.2003 +		     char *msg, int level)
  1.2004 +{
  1.2005 +    SECOidTag oidTag;
  1.2006 +    
  1.2007 +    if ( extensions ) {
  1.2008 +	if (msg && *msg) {
  1.2009 +	    SECU_Indent(out, level++); fprintf(out, "%s:\n", msg);
  1.2010 +	}
  1.2011 +	
  1.2012 +	while ( *extensions ) {
  1.2013 +	    SECItem *tmpitem;
  1.2014 +
  1.2015 +	    tmpitem = &(*extensions)->id;
  1.2016 +	    SECU_PrintObjectID(out, tmpitem, "Name", level);
  1.2017 +
  1.2018 +	    tmpitem = &(*extensions)->critical;
  1.2019 +	    if ( tmpitem->len ) {
  1.2020 +		secu_PrintBoolean(out, tmpitem, "Critical", level);
  1.2021 +	    }
  1.2022 +
  1.2023 +	    oidTag = SECOID_FindOIDTag (&((*extensions)->id));
  1.2024 +	    tmpitem = &((*extensions)->value);
  1.2025 +
  1.2026 +	    switch (oidTag) {
  1.2027 +	      	case SEC_OID_X509_INVALID_DATE:
  1.2028 +		case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME:
  1.2029 +		   secu_PrintX509InvalidDate(out, tmpitem, "Date", level );
  1.2030 +		   break;
  1.2031 +		case SEC_OID_X509_CERTIFICATE_POLICIES:
  1.2032 +		   SECU_PrintPolicy(out, tmpitem, "Data", level );
  1.2033 +		   break;
  1.2034 +		case SEC_OID_NS_CERT_EXT_BASE_URL:
  1.2035 +		case SEC_OID_NS_CERT_EXT_REVOCATION_URL:
  1.2036 +		case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL:
  1.2037 +		case SEC_OID_NS_CERT_EXT_CA_CRL_URL:
  1.2038 +		case SEC_OID_NS_CERT_EXT_CA_CERT_URL:
  1.2039 +		case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL:
  1.2040 +		case SEC_OID_NS_CERT_EXT_CA_POLICY_URL:
  1.2041 +		case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL:
  1.2042 +		case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL:
  1.2043 +		case SEC_OID_OCSP_RESPONDER:
  1.2044 +		    SECU_PrintString(out,tmpitem, "URL", level);
  1.2045 +		    break;
  1.2046 +		case SEC_OID_NS_CERT_EXT_COMMENT:
  1.2047 +		    SECU_PrintString(out,tmpitem, "Comment", level);
  1.2048 +		    break;
  1.2049 +		case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME:
  1.2050 +		    SECU_PrintString(out,tmpitem, "ServerName", level);
  1.2051 +		    break;
  1.2052 +		case SEC_OID_NS_CERT_EXT_CERT_TYPE:
  1.2053 +		    secu_PrintNSCertType(out,tmpitem,"Data",level);
  1.2054 +		    break;
  1.2055 +		case SEC_OID_X509_BASIC_CONSTRAINTS:
  1.2056 +		    secu_PrintBasicConstraints(out,tmpitem,"Data",level);
  1.2057 +		    break;
  1.2058 +		case SEC_OID_X509_EXT_KEY_USAGE:
  1.2059 +		    PrintExtKeyUsageExtension(out, tmpitem, NULL, level);
  1.2060 +		    break;
  1.2061 +		case SEC_OID_X509_KEY_USAGE:
  1.2062 +		    secu_PrintX509KeyUsage(out, tmpitem, NULL, level );
  1.2063 +		    break;
  1.2064 +		case SEC_OID_X509_AUTH_KEY_ID:
  1.2065 +		    secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level );
  1.2066 +		    break;
  1.2067 +		case SEC_OID_X509_SUBJECT_ALT_NAME:
  1.2068 +		case SEC_OID_X509_ISSUER_ALT_NAME:
  1.2069 +		    secu_PrintAltNameExtension(out, tmpitem, NULL, level );
  1.2070 +		    break;
  1.2071 +		case SEC_OID_X509_CRL_DIST_POINTS:
  1.2072 +		    secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level );
  1.2073 +		    break;
  1.2074 +		case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD:
  1.2075 +		    SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL, 
  1.2076 +							level );
  1.2077 +		    break;
  1.2078 +		case SEC_OID_X509_NAME_CONSTRAINTS:
  1.2079 +		    secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level);
  1.2080 +		    break;
  1.2081 +		case SEC_OID_X509_AUTH_INFO_ACCESS:
  1.2082 +		    secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level);
  1.2083 +		    break;
  1.2084 +
  1.2085 +		case SEC_OID_X509_CRL_NUMBER:
  1.2086 +		case SEC_OID_X509_REASON_CODE:
  1.2087 +
  1.2088 +		/* PKIX OIDs */
  1.2089 +		case SEC_OID_PKIX_OCSP:
  1.2090 +		case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:
  1.2091 +		case SEC_OID_PKIX_OCSP_NONCE:
  1.2092 +		case SEC_OID_PKIX_OCSP_CRL:
  1.2093 +		case SEC_OID_PKIX_OCSP_RESPONSE:
  1.2094 +		case SEC_OID_PKIX_OCSP_NO_CHECK:
  1.2095 +		case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF:
  1.2096 +		case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR:
  1.2097 +		case SEC_OID_PKIX_REGCTRL_REGTOKEN:
  1.2098 +		case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
  1.2099 +		case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
  1.2100 +		case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
  1.2101 +		case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
  1.2102 +		case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
  1.2103 +		case SEC_OID_PKIX_REGINFO_UTF8_PAIRS:
  1.2104 +		case SEC_OID_PKIX_REGINFO_CERT_REQUEST:
  1.2105 +
  1.2106 +	        /* Netscape extension OIDs. */
  1.2107 +		case SEC_OID_NS_CERT_EXT_NETSCAPE_OK:
  1.2108 +		case SEC_OID_NS_CERT_EXT_ISSUER_LOGO:
  1.2109 +		case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO:
  1.2110 +		case SEC_OID_NS_CERT_EXT_ENTITY_LOGO:
  1.2111 +		case SEC_OID_NS_CERT_EXT_USER_PICTURE:
  1.2112 +
  1.2113 +		/* x.509 v3 Extensions */
  1.2114 +		case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR:
  1.2115 +		case SEC_OID_X509_SUBJECT_KEY_ID:
  1.2116 +		case SEC_OID_X509_POLICY_MAPPINGS:
  1.2117 +		case SEC_OID_X509_POLICY_CONSTRAINTS:
  1.2118 +
  1.2119 +
  1.2120 +	        default:
  1.2121 +		    SECU_PrintAny(out, tmpitem, "Data", level);
  1.2122 +		break;
  1.2123 +	    }
  1.2124 +
  1.2125 +	    SECU_Newline(out);
  1.2126 +	    extensions++;
  1.2127 +	}
  1.2128 +    }
  1.2129 +}
  1.2130 +
  1.2131 +/* An RDN is a subset of a DirectoryName, and we already know how to
  1.2132 + * print those, so make a directory name out of the RDN, and print it.
  1.2133 + */
  1.2134 +void
  1.2135 +SECU_PrintRDN(FILE *out, CERTRDN *rdn, const char *msg, int level)
  1.2136 +{
  1.2137 +    CERTName name;
  1.2138 +    CERTRDN *rdns[2];
  1.2139 +
  1.2140 +    name.arena = NULL;
  1.2141 +    name.rdns  = rdns;
  1.2142 +    rdns[0] = rdn;
  1.2143 +    rdns[1] = NULL;
  1.2144 +    SECU_PrintName(out, &name, msg, level);
  1.2145 +}
  1.2146 +
  1.2147 +void
  1.2148 +SECU_PrintNameQuotesOptional(FILE *out, CERTName *name, const char *msg, 
  1.2149 +			     int level, PRBool quotes)
  1.2150 +{
  1.2151 +    char *nameStr = NULL;
  1.2152 +    char *str;
  1.2153 +    SECItem my;
  1.2154 +
  1.2155 +    if (!name) {
  1.2156 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2157 +	return;
  1.2158 +    }
  1.2159 +    if (!name->rdns || !name->rdns[0]) {
  1.2160 +	str = "(empty)";
  1.2161 +    } else {
  1.2162 +	str = nameStr = CERT_NameToAscii(name);
  1.2163 +    }
  1.2164 +    if (!str) {
  1.2165 +    	str = "!Invalid AVA!";
  1.2166 +    }
  1.2167 +    my.data = (unsigned char *)str;
  1.2168 +    my.len  = PORT_Strlen(str);
  1.2169 +#if 1
  1.2170 +    secu_PrintRawStringQuotesOptional(out, &my, msg, level, quotes);
  1.2171 +#else
  1.2172 +    SECU_Indent(out, level); fprintf(out, "%s: ", msg);
  1.2173 +    fprintf(out, str);
  1.2174 +    SECU_Newline(out);
  1.2175 +#endif
  1.2176 +    PORT_Free(nameStr);
  1.2177 +}
  1.2178 +
  1.2179 +void
  1.2180 +SECU_PrintName(FILE *out, CERTName *name, const char *msg, int level)
  1.2181 +{
  1.2182 +    SECU_PrintNameQuotesOptional(out, name, msg, level, PR_TRUE);
  1.2183 +}
  1.2184 +
  1.2185 +void
  1.2186 +printflags(char *trusts, unsigned int flags)
  1.2187 +{
  1.2188 +    if (flags & CERTDB_VALID_CA)
  1.2189 +	if (!(flags & CERTDB_TRUSTED_CA) &&
  1.2190 +	    !(flags & CERTDB_TRUSTED_CLIENT_CA))
  1.2191 +	    PORT_Strcat(trusts, "c");
  1.2192 +    if (flags & CERTDB_TERMINAL_RECORD)
  1.2193 +	if (!(flags & CERTDB_TRUSTED))
  1.2194 +	    PORT_Strcat(trusts, "p");
  1.2195 +    if (flags & CERTDB_TRUSTED_CA)
  1.2196 +	PORT_Strcat(trusts, "C");
  1.2197 +    if (flags & CERTDB_TRUSTED_CLIENT_CA)
  1.2198 +	PORT_Strcat(trusts, "T");
  1.2199 +    if (flags & CERTDB_TRUSTED)
  1.2200 +	PORT_Strcat(trusts, "P");
  1.2201 +    if (flags & CERTDB_USER)
  1.2202 +	PORT_Strcat(trusts, "u");
  1.2203 +    if (flags & CERTDB_SEND_WARN)
  1.2204 +	PORT_Strcat(trusts, "w");
  1.2205 +    if (flags & CERTDB_INVISIBLE_CA)
  1.2206 +	PORT_Strcat(trusts, "I");
  1.2207 +    if (flags & CERTDB_GOVT_APPROVED_CA)
  1.2208 +	PORT_Strcat(trusts, "G");
  1.2209 +    return;
  1.2210 +}
  1.2211 +
  1.2212 +/* callback for listing certs through pkcs11 */
  1.2213 +SECStatus
  1.2214 +SECU_PrintCertNickname(CERTCertListNode *node, void *data)
  1.2215 +{
  1.2216 +    CERTCertTrust trust;
  1.2217 +    CERTCertificate* cert;
  1.2218 +    FILE *out;
  1.2219 +    char trusts[30];
  1.2220 +    char *name;
  1.2221 +
  1.2222 +    cert = node->cert;
  1.2223 +
  1.2224 +    PORT_Memset (trusts, 0, sizeof (trusts));
  1.2225 +    out = (FILE *)data;
  1.2226 +    
  1.2227 +    name = node->appData;
  1.2228 +    if (!name || !name[0]) {
  1.2229 +        name = cert->nickname;
  1.2230 +    }
  1.2231 +    if (!name || !name[0]) {
  1.2232 +        name = cert->emailAddr;
  1.2233 +    }
  1.2234 +    if (!name || !name[0]) {
  1.2235 +        name = "(NULL)";
  1.2236 +    }
  1.2237 +
  1.2238 +    if (CERT_GetCertTrust(cert, &trust) == SECSuccess) {
  1.2239 +        printflags(trusts, trust.sslFlags);
  1.2240 +        PORT_Strcat(trusts, ",");
  1.2241 +        printflags(trusts, trust.emailFlags);
  1.2242 +        PORT_Strcat(trusts, ",");
  1.2243 +        printflags(trusts, trust.objectSigningFlags);
  1.2244 +    } else {
  1.2245 +        PORT_Memcpy(trusts,",,",3);
  1.2246 +    }
  1.2247 +    fprintf(out, "%-60s %-5s\n", name, trusts);
  1.2248 +
  1.2249 +    return (SECSuccess);
  1.2250 +}
  1.2251 +
  1.2252 +int
  1.2253 +SECU_DecodeAndPrintExtensions(FILE *out, SECItem *any, char *m, int level)
  1.2254 +{
  1.2255 +    CERTCertExtension **extensions = NULL;
  1.2256 +    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.2257 +    int rv = 0;
  1.2258 +
  1.2259 +    if (!arena) 
  1.2260 +	return SEC_ERROR_NO_MEMORY;
  1.2261 +
  1.2262 +    rv = SEC_QuickDERDecodeItem(arena, &extensions, 
  1.2263 +		   SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), any);
  1.2264 +    if (!rv)
  1.2265 +	SECU_PrintExtensions(out, extensions, m, level);
  1.2266 +    else 
  1.2267 +    	SECU_PrintAny(out, any, m, level);
  1.2268 +    PORT_FreeArena(arena, PR_FALSE);
  1.2269 +    return rv;
  1.2270 +}
  1.2271 +
  1.2272 +/* print a decoded SET OF or SEQUENCE OF Extensions */
  1.2273 +int
  1.2274 +SECU_PrintSetOfExtensions(FILE *out, SECItem **any, char *m, int level)
  1.2275 +{
  1.2276 +    int rv = 0;
  1.2277 +    if (m && *m) {
  1.2278 +	SECU_Indent(out, level++); fprintf(out, "%s:\n", m);
  1.2279 +    }
  1.2280 +    while (any && any[0]) {
  1.2281 +    	rv |= SECU_DecodeAndPrintExtensions(out, any[0], "", level);
  1.2282 +	any++;
  1.2283 +    }
  1.2284 +    return rv;
  1.2285 +}
  1.2286 +
  1.2287 +/* print a decoded SET OF or SEQUENCE OF "ANY" */
  1.2288 +int
  1.2289 +SECU_PrintSetOfAny(FILE *out, SECItem **any, char *m, int level)
  1.2290 +{
  1.2291 +    int rv = 0;
  1.2292 +    if (m && *m) {
  1.2293 +	SECU_Indent(out, level++); fprintf(out, "%s:\n", m);
  1.2294 +    }
  1.2295 +    while (any && any[0]) {
  1.2296 +    	SECU_PrintAny(out, any[0], "", level);
  1.2297 +	any++;
  1.2298 +    }
  1.2299 +    return rv;
  1.2300 +}
  1.2301 +
  1.2302 +int
  1.2303 +SECU_PrintCertAttribute(FILE *out, CERTAttribute *attr, char *m, int level)
  1.2304 +{
  1.2305 +    int rv = 0;
  1.2306 +    SECOidTag tag;
  1.2307 +    tag = SECU_PrintObjectID(out, &attr->attrType, "Attribute Type", level);
  1.2308 +    if (tag == SEC_OID_PKCS9_EXTENSION_REQUEST) {
  1.2309 +	rv = SECU_PrintSetOfExtensions(out, attr->attrValue, "Extensions", level);
  1.2310 +    } else {
  1.2311 +	rv = SECU_PrintSetOfAny(out, attr->attrValue, "Attribute Values", level);
  1.2312 +    }
  1.2313 +    return rv;
  1.2314 +}
  1.2315 +
  1.2316 +int
  1.2317 +SECU_PrintCertAttributes(FILE *out, CERTAttribute **attrs, char *m, int level)
  1.2318 +{
  1.2319 +    int rv = 0;
  1.2320 +    while (attrs[0]) {
  1.2321 +	rv |= SECU_PrintCertAttribute(out, attrs[0], m, level+1);
  1.2322 +    	attrs++;
  1.2323 +    }
  1.2324 +    return rv;
  1.2325 +}
  1.2326 +
  1.2327 +int  /* sometimes a PRErrorCode, other times a SECStatus.  Sigh. */
  1.2328 +SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, int level)
  1.2329 +{
  1.2330 +    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.2331 +    CERTCertificateRequest *cr;
  1.2332 +    int rv = SEC_ERROR_NO_MEMORY;
  1.2333 +
  1.2334 +    if (!arena) 
  1.2335 +	return rv;
  1.2336 +
  1.2337 +    /* Decode certificate request */
  1.2338 +    cr = PORT_ArenaZNew(arena, CERTCertificateRequest);
  1.2339 +    if (!cr)
  1.2340 +	goto loser;
  1.2341 +    cr->arena = arena;
  1.2342 +    rv = SEC_QuickDERDecodeItem(arena, cr, 
  1.2343 +                           SEC_ASN1_GET(CERT_CertificateRequestTemplate), der);
  1.2344 +    if (rv) 
  1.2345 +	goto loser;
  1.2346 +
  1.2347 +    /* Pretty print it out */
  1.2348 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2349 +    SECU_PrintInteger(out, &cr->version, "Version", level+1);
  1.2350 +    SECU_PrintName(out, &cr->subject, "Subject", level+1);
  1.2351 +    if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
  1.2352 +	SECU_Newline(out);
  1.2353 +    secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo,
  1.2354 +			      "Subject Public Key Info", level+1);
  1.2355 +    if (cr->attributes)
  1.2356 +	SECU_PrintCertAttributes(out, cr->attributes, "Attributes", level+1);
  1.2357 +    rv = 0;
  1.2358 +loser:
  1.2359 +    PORT_FreeArena(arena, PR_FALSE);
  1.2360 +    return rv;
  1.2361 +}
  1.2362 +
  1.2363 +int
  1.2364 +SECU_PrintCertificate(FILE *out, const SECItem *der, const char *m, int level)
  1.2365 +{
  1.2366 +    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.2367 +    CERTCertificate *c;
  1.2368 +    int rv = SEC_ERROR_NO_MEMORY;
  1.2369 +    int iv;
  1.2370 +    
  1.2371 +    if (!arena)
  1.2372 +	return rv;
  1.2373 +
  1.2374 +    /* Decode certificate */
  1.2375 +    c = PORT_ArenaZNew(arena, CERTCertificate);
  1.2376 +    if (!c)
  1.2377 +	goto loser;
  1.2378 +    c->arena = arena;
  1.2379 +    rv = SEC_ASN1DecodeItem(arena, c, 
  1.2380 +                            SEC_ASN1_GET(CERT_CertificateTemplate), der);
  1.2381 +    if (rv) {
  1.2382 +        SECU_Indent(out, level); 
  1.2383 +	SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
  1.2384 +	SECU_PrintAny(out, der, "Raw", level);
  1.2385 +	goto loser;
  1.2386 +    }
  1.2387 +    /* Pretty print it out */
  1.2388 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2389 +    iv = c->version.len ? DER_GetInteger(&c->version) : 0;  /* version is optional */
  1.2390 +    SECU_Indent(out, level+1); fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv);
  1.2391 +
  1.2392 +    SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level+1);
  1.2393 +    SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level+1);
  1.2394 +    SECU_PrintName(out, &c->issuer, "Issuer", level+1);
  1.2395 +    if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
  1.2396 +	SECU_Newline(out);
  1.2397 +    secu_PrintValidity(out, &c->validity, "Validity", level+1);
  1.2398 +    SECU_PrintName(out, &c->subject, "Subject", level+1);
  1.2399 +    if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
  1.2400 +	SECU_Newline(out);
  1.2401 +    secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo,
  1.2402 +			      "Subject Public Key Info", level+1);
  1.2403 +    if (c->issuerID.data) 
  1.2404 +	secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level+1);
  1.2405 +    if (c->subjectID.data) 
  1.2406 +	secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level+1);
  1.2407 +    SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1);
  1.2408 +loser:
  1.2409 +    PORT_FreeArena(arena, PR_FALSE);
  1.2410 +    return rv;
  1.2411 +}
  1.2412 +
  1.2413 +int
  1.2414 +SECU_PrintSubjectPublicKeyInfo(FILE *out, SECItem *der, char *m, int level)
  1.2415 +{
  1.2416 +    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.2417 +    int          rv    = SEC_ERROR_NO_MEMORY;
  1.2418 +    CERTSubjectPublicKeyInfo spki;
  1.2419 +
  1.2420 +    if (!arena)
  1.2421 +	return rv;
  1.2422 +
  1.2423 +    PORT_Memset(&spki, 0, sizeof spki);
  1.2424 +    rv = SEC_ASN1DecodeItem(arena, &spki, 
  1.2425 +                            SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate), 
  1.2426 +			    der);
  1.2427 +    if (!rv) {
  1.2428 +	if (m && *m) {
  1.2429 +	    SECU_Indent(out, level);  fprintf(out, "%s:\n", m);
  1.2430 +	}
  1.2431 +	secu_PrintSubjectPublicKeyInfo(out, arena, &spki,
  1.2432 +				       "Subject Public Key Info", level+1);
  1.2433 +    }
  1.2434 +
  1.2435 +    PORT_FreeArena(arena, PR_FALSE);
  1.2436 +    return rv;
  1.2437 +}
  1.2438 +
  1.2439 +#ifdef HAVE_EPV_TEMPLATE
  1.2440 +int
  1.2441 +SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level)
  1.2442 +{
  1.2443 +    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.2444 +    SECKEYEncryptedPrivateKeyInfo key;
  1.2445 +    int rv = SEC_ERROR_NO_MEMORY;
  1.2446 +
  1.2447 +    if (!arena)
  1.2448 +	return rv;
  1.2449 +
  1.2450 +    PORT_Memset(&key, 0, sizeof(key));
  1.2451 +    rv = SEC_ASN1DecodeItem(arena, &key, 
  1.2452 +		SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der);
  1.2453 +    if (rv)
  1.2454 +	goto loser;
  1.2455 +
  1.2456 +    /* Pretty print it out */
  1.2457 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2458 +    SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm", 
  1.2459 +			  level+1);
  1.2460 +    SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level+1);
  1.2461 +loser:
  1.2462 +    PORT_FreeArena(arena, PR_TRUE);
  1.2463 +    return rv;
  1.2464 +}
  1.2465 +#endif
  1.2466 +
  1.2467 +int
  1.2468 +SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level)
  1.2469 +{
  1.2470 +    unsigned char fingerprint[SHA256_LENGTH];
  1.2471 +    char *fpStr = NULL;
  1.2472 +    int err     = PORT_GetError();
  1.2473 +    SECStatus rv;
  1.2474 +    SECItem fpItem;
  1.2475 +
  1.2476 +    /* Print SHA-256 fingerprint */
  1.2477 +    memset(fingerprint, 0, sizeof fingerprint);
  1.2478 +    rv = PK11_HashBuf(SEC_OID_SHA256, fingerprint, derCert->data, derCert->len);
  1.2479 +    fpItem.data = fingerprint;
  1.2480 +    fpItem.len = SHA256_LENGTH;
  1.2481 +    fpStr = CERT_Hexify(&fpItem, 1);
  1.2482 +    SECU_Indent(out, level);  fprintf(out, "%s (SHA-256):", m);
  1.2483 +    if (SECU_GetWrapEnabled()) {
  1.2484 +	fprintf(out, "\n");
  1.2485 +	SECU_Indent(out, level+1);
  1.2486 +    }
  1.2487 +    else {
  1.2488 +	fprintf(out, " ");
  1.2489 +    }
  1.2490 +    fprintf(out, "%s\n", fpStr);
  1.2491 +    PORT_Free(fpStr);
  1.2492 +    fpStr = NULL;
  1.2493 +    if (rv != SECSuccess && !err)
  1.2494 +	err = PORT_GetError();
  1.2495 +
  1.2496 +    /* print SHA1 fingerprint */
  1.2497 +    memset(fingerprint, 0, sizeof fingerprint);
  1.2498 +    rv = PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len);
  1.2499 +    fpItem.data = fingerprint;
  1.2500 +    fpItem.len = SHA1_LENGTH;
  1.2501 +    fpStr = CERT_Hexify(&fpItem, 1);
  1.2502 +    SECU_Indent(out, level);  fprintf(out, "%s (SHA1):", m);
  1.2503 +    if (SECU_GetWrapEnabled()) {
  1.2504 +	fprintf(out, "\n");
  1.2505 +	SECU_Indent(out, level+1);
  1.2506 +    }
  1.2507 +    else {
  1.2508 +	fprintf(out, " ");
  1.2509 +    }
  1.2510 +    fprintf(out, "%s\n", fpStr);
  1.2511 +    PORT_Free(fpStr);
  1.2512 +    if (SECU_GetWrapEnabled())
  1.2513 +	fprintf(out, "\n");
  1.2514 +
  1.2515 +    if (err) 
  1.2516 +	PORT_SetError(err);
  1.2517 +    if (err || rv != SECSuccess)
  1.2518 +	return SECFailure;
  1.2519 +
  1.2520 +    return 0;
  1.2521 +}
  1.2522 +
  1.2523 +/*
  1.2524 +** PKCS7 Support
  1.2525 +*/
  1.2526 +
  1.2527 +/* forward declaration */
  1.2528 +static int
  1.2529 +secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *, int);
  1.2530 +
  1.2531 +/*
  1.2532 +** secu_PrintPKCS7EncContent
  1.2533 +**   Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it)
  1.2534 +*/
  1.2535 +static void
  1.2536 +secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src, 
  1.2537 +			  char *m, int level)
  1.2538 +{
  1.2539 +    if (src->contentTypeTag == NULL)
  1.2540 +	src->contentTypeTag = SECOID_FindOID(&(src->contentType));
  1.2541 +
  1.2542 +    SECU_Indent(out, level);
  1.2543 +    fprintf(out, "%s:\n", m);
  1.2544 +    SECU_Indent(out, level + 1); 
  1.2545 +    fprintf(out, "Content Type: %s\n",
  1.2546 +	    (src->contentTypeTag != NULL) ? src->contentTypeTag->desc
  1.2547 +					  : "Unknown");
  1.2548 +    SECU_PrintAlgorithmID(out, &(src->contentEncAlg),
  1.2549 +			  "Content Encryption Algorithm", level+1);
  1.2550 +    SECU_PrintAsHex(out, &(src->encContent), 
  1.2551 +		    "Encrypted Content", level+1);
  1.2552 +}
  1.2553 +
  1.2554 +/*
  1.2555 +** secu_PrintRecipientInfo
  1.2556 +**   Prints a PKCS7RecipientInfo type
  1.2557 +*/
  1.2558 +static void
  1.2559 +secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m, 
  1.2560 +			int level)
  1.2561 +{
  1.2562 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2563 +    SECU_PrintInteger(out, &(info->version), "Version", level + 1);	
  1.2564 +
  1.2565 +    SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", 
  1.2566 +		 level + 1);
  1.2567 +    SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), 
  1.2568 +		      "Serial Number", level + 1);
  1.2569 +
  1.2570 +    /* Parse and display encrypted key */
  1.2571 +    SECU_PrintAlgorithmID(out, &(info->keyEncAlg), 
  1.2572 +			"Key Encryption Algorithm", level + 1);
  1.2573 +    SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1);
  1.2574 +}
  1.2575 +
  1.2576 +/* 
  1.2577 +** secu_PrintSignerInfo
  1.2578 +**   Prints a PKCS7SingerInfo type
  1.2579 +*/
  1.2580 +static void
  1.2581 +secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level)
  1.2582 +{
  1.2583 +    SEC_PKCS7Attribute *attr;
  1.2584 +    int iv;
  1.2585 +    char om[100];
  1.2586 +    
  1.2587 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2588 +    SECU_PrintInteger(out, &(info->version), "Version", level + 1);	
  1.2589 +
  1.2590 +    SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", 
  1.2591 +		 level + 1);
  1.2592 +    SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), 
  1.2593 +		      "Serial Number", level + 1);
  1.2594 +  
  1.2595 +    SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm",
  1.2596 +			  level + 1);
  1.2597 +    
  1.2598 +    if (info->authAttr != NULL) {
  1.2599 +	SECU_Indent(out, level + 1); 
  1.2600 +	fprintf(out, "Authenticated Attributes:\n");
  1.2601 +	iv = 0;
  1.2602 +	while ((attr = info->authAttr[iv++]) != NULL) {
  1.2603 +	    sprintf(om, "Attribute (%d)", iv); 
  1.2604 +	    secu_PrintAttribute(out, attr, om, level + 2);
  1.2605 +	}
  1.2606 +    }
  1.2607 +    
  1.2608 +    /* Parse and display signature */
  1.2609 +    SECU_PrintAlgorithmID(out, &(info->digestEncAlg), 
  1.2610 +			"Digest Encryption Algorithm", level + 1);
  1.2611 +    SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1);
  1.2612 +    
  1.2613 +    if (info->unAuthAttr != NULL) {
  1.2614 +	SECU_Indent(out, level + 1); 
  1.2615 +	fprintf(out, "Unauthenticated Attributes:\n");
  1.2616 +	iv = 0;
  1.2617 +	while ((attr = info->unAuthAttr[iv++]) != NULL) {
  1.2618 +	    sprintf(om, "Attribute (%x)", iv); 
  1.2619 +	    secu_PrintAttribute(out, attr, om, level + 2);
  1.2620 +	}
  1.2621 +    }
  1.2622 +}
  1.2623 +
  1.2624 +/* callers of this function must make sure that the CERTSignedCrl
  1.2625 +   from which they are extracting the CERTCrl has been fully-decoded.
  1.2626 +   Otherwise it will not have the entries even though the CRL may have
  1.2627 +   some */
  1.2628 +
  1.2629 +void
  1.2630 +SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level)
  1.2631 +{
  1.2632 +    CERTCrlEntry *entry;
  1.2633 +    int iv;
  1.2634 +    char om[100];
  1.2635 +    
  1.2636 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2637 +    /* version is optional */
  1.2638 +    iv = crl->version.len ? DER_GetInteger(&crl->version) : 0;  
  1.2639 +    SECU_Indent(out, level+1); 
  1.2640 +    	fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv);
  1.2641 +    SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm",
  1.2642 +			  level + 1);
  1.2643 +    SECU_PrintName(out, &(crl->name), "Issuer", level + 1);
  1.2644 +    SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1);
  1.2645 +    if (crl->nextUpdate.data && crl->nextUpdate.len) /* is optional */
  1.2646 +	SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1);
  1.2647 +    
  1.2648 +    if (crl->entries != NULL) {
  1.2649 +	iv = 0;
  1.2650 +	while ((entry = crl->entries[iv++]) != NULL) {
  1.2651 +	    sprintf(om, "Entry %d (0x%x):\n", iv, iv); 
  1.2652 +	    SECU_Indent(out, level + 1); fputs(om, out);
  1.2653 +	    SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number",
  1.2654 +			      level + 2);
  1.2655 +	    SECU_PrintTimeChoice(out, &(entry->revocationDate), 
  1.2656 +	                         "Revocation Date", level + 2);
  1.2657 +	    SECU_PrintExtensions(out, entry->extensions, 
  1.2658 +	                         "Entry Extensions", level + 2);
  1.2659 +	}
  1.2660 +    }
  1.2661 +    SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1);
  1.2662 +}
  1.2663 +
  1.2664 +/*
  1.2665 +** secu_PrintPKCS7Signed
  1.2666 +**   Pretty print a PKCS7 signed data type (up to version 1).
  1.2667 +*/
  1.2668 +static int
  1.2669 +secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src,
  1.2670 +		      const char *m, int level)
  1.2671 +{
  1.2672 +    SECAlgorithmID *digAlg;		/* digest algorithms */
  1.2673 +    SECItem *aCert;			/* certificate */
  1.2674 +    CERTSignedCrl *aCrl;		/* certificate revocation list */
  1.2675 +    SEC_PKCS7SignerInfo *sigInfo;	/* signer information */
  1.2676 +    int rv, iv;
  1.2677 +    char om[100];
  1.2678 +
  1.2679 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2680 +    SECU_PrintInteger(out, &(src->version), "Version", level + 1);
  1.2681 +
  1.2682 +    /* Parse and list digest algorithms (if any) */
  1.2683 +    if (src->digestAlgorithms != NULL) {
  1.2684 +	SECU_Indent(out, level + 1);  fprintf(out, "Digest Algorithm List:\n");
  1.2685 +	iv = 0;
  1.2686 +	while ((digAlg = src->digestAlgorithms[iv++]) != NULL) {
  1.2687 +	    sprintf(om, "Digest Algorithm (%x)", iv);
  1.2688 +	    SECU_PrintAlgorithmID(out, digAlg, om, level + 2);
  1.2689 +	}
  1.2690 +    }
  1.2691 +
  1.2692 +    /* Now for the content */
  1.2693 +    rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo), 
  1.2694 +				    "Content Information", level + 1);
  1.2695 +    if (rv != 0)
  1.2696 +	return rv;
  1.2697 +
  1.2698 +    /* Parse and list certificates (if any) */
  1.2699 +    if (src->rawCerts != NULL) {
  1.2700 +	SECU_Indent(out, level + 1);  fprintf(out, "Certificate List:\n");
  1.2701 +	iv = 0;
  1.2702 +	while ((aCert = src->rawCerts[iv++]) != NULL) {
  1.2703 +	    sprintf(om, "Certificate (%x)", iv);
  1.2704 +	    rv = SECU_PrintSignedData(out, aCert, om, level + 2, 
  1.2705 +				      SECU_PrintCertificate);
  1.2706 +	    if (rv)
  1.2707 +		return rv;
  1.2708 +	}
  1.2709 +    }
  1.2710 +
  1.2711 +    /* Parse and list CRL's (if any) */
  1.2712 +    if (src->crls != NULL) {
  1.2713 +	SECU_Indent(out, level + 1);  
  1.2714 +	fprintf(out, "Signed Revocation Lists:\n");
  1.2715 +	iv = 0;
  1.2716 +	while ((aCrl = src->crls[iv++]) != NULL) {
  1.2717 +	    sprintf(om, "Signed Revocation List (%x)", iv);
  1.2718 +	    SECU_Indent(out, level + 2);  fprintf(out, "%s:\n", om);
  1.2719 +	    SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, 
  1.2720 +				  "Signature Algorithm", level+3);
  1.2721 +	    DER_ConvertBitString(&aCrl->signatureWrap.signature);
  1.2722 +	    SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature",
  1.2723 +			    level+3);
  1.2724 +	    SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", 
  1.2725 +			  level + 3); 
  1.2726 +	}
  1.2727 +    }
  1.2728 +
  1.2729 +    /* Parse and list signatures (if any) */
  1.2730 +    if (src->signerInfos != NULL) {
  1.2731 +	SECU_Indent(out, level + 1);
  1.2732 +	fprintf(out, "Signer Information List:\n");
  1.2733 +	iv = 0;
  1.2734 +	while ((sigInfo = src->signerInfos[iv++]) != NULL) {
  1.2735 +	    sprintf(om, "Signer Information (%x)", iv);
  1.2736 +	    secu_PrintSignerInfo(out, sigInfo, om, level + 2);
  1.2737 +	}
  1.2738 +    }  
  1.2739 +
  1.2740 +    return 0;
  1.2741 +}
  1.2742 +
  1.2743 +/*
  1.2744 +** secu_PrintPKCS7Enveloped
  1.2745 +**  Pretty print a PKCS7 enveloped data type (up to version 1).
  1.2746 +*/
  1.2747 +static void
  1.2748 +secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src,
  1.2749 +			 const char *m, int level)
  1.2750 +{
  1.2751 +    SEC_PKCS7RecipientInfo *recInfo;   /* pointer for signer information */
  1.2752 +    int iv;
  1.2753 +    char om[100];
  1.2754 +
  1.2755 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2756 +    SECU_PrintInteger(out, &(src->version), "Version", level + 1);
  1.2757 +
  1.2758 +    /* Parse and list recipients (this is not optional) */
  1.2759 +    if (src->recipientInfos != NULL) {
  1.2760 +	SECU_Indent(out, level + 1);
  1.2761 +	fprintf(out, "Recipient Information List:\n");
  1.2762 +	iv = 0;
  1.2763 +	while ((recInfo = src->recipientInfos[iv++]) != NULL) {
  1.2764 +	    sprintf(om, "Recipient Information (%x)", iv);
  1.2765 +	    secu_PrintRecipientInfo(out, recInfo, om, level + 2);
  1.2766 +	}
  1.2767 +    }  
  1.2768 +
  1.2769 +    secu_PrintPKCS7EncContent(out, &src->encContentInfo, 
  1.2770 +			      "Encrypted Content Information", level + 1);
  1.2771 +}
  1.2772 +
  1.2773 +/*
  1.2774 +** secu_PrintPKCS7SignedEnveloped
  1.2775 +**   Pretty print a PKCS7 singed and enveloped data type (up to version 1).
  1.2776 +*/
  1.2777 +static int
  1.2778 +secu_PrintPKCS7SignedAndEnveloped(FILE *out,
  1.2779 +				  SEC_PKCS7SignedAndEnvelopedData *src,
  1.2780 +				  const char *m, int level)
  1.2781 +{
  1.2782 +    SECAlgorithmID *digAlg;  /* pointer for digest algorithms */
  1.2783 +    SECItem *aCert;           /* pointer for certificate */
  1.2784 +    CERTSignedCrl *aCrl;        /* pointer for certificate revocation list */
  1.2785 +    SEC_PKCS7SignerInfo *sigInfo;   /* pointer for signer information */
  1.2786 +    SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */
  1.2787 +    int rv, iv;
  1.2788 +    char om[100];
  1.2789 +
  1.2790 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2791 +    SECU_PrintInteger(out, &(src->version), "Version", level + 1);
  1.2792 +
  1.2793 +    /* Parse and list recipients (this is not optional) */
  1.2794 +    if (src->recipientInfos != NULL) {
  1.2795 +	SECU_Indent(out, level + 1);
  1.2796 +	fprintf(out, "Recipient Information List:\n");
  1.2797 +	iv = 0;
  1.2798 +	while ((recInfo = src->recipientInfos[iv++]) != NULL) {
  1.2799 +	    sprintf(om, "Recipient Information (%x)", iv);
  1.2800 +	    secu_PrintRecipientInfo(out, recInfo, om, level + 2);
  1.2801 +	}
  1.2802 +    }  
  1.2803 +
  1.2804 +    /* Parse and list digest algorithms (if any) */
  1.2805 +    if (src->digestAlgorithms != NULL) {
  1.2806 +	SECU_Indent(out, level + 1);  fprintf(out, "Digest Algorithm List:\n");
  1.2807 +	iv = 0;
  1.2808 +	while ((digAlg = src->digestAlgorithms[iv++]) != NULL) {
  1.2809 +	    sprintf(om, "Digest Algorithm (%x)", iv);
  1.2810 +	    SECU_PrintAlgorithmID(out, digAlg, om, level + 2);
  1.2811 +	}
  1.2812 +    }
  1.2813 +
  1.2814 +    secu_PrintPKCS7EncContent(out, &src->encContentInfo, 
  1.2815 +			      "Encrypted Content Information", level + 1);
  1.2816 +
  1.2817 +    /* Parse and list certificates (if any) */
  1.2818 +    if (src->rawCerts != NULL) {
  1.2819 +	SECU_Indent(out, level + 1);  fprintf(out, "Certificate List:\n");
  1.2820 +	iv = 0;
  1.2821 +	while ((aCert = src->rawCerts[iv++]) != NULL) {
  1.2822 +	    sprintf(om, "Certificate (%x)", iv);
  1.2823 +	    rv = SECU_PrintSignedData(out, aCert, om, level + 2, 
  1.2824 +				      SECU_PrintCertificate);
  1.2825 +	    if (rv)
  1.2826 +		return rv;
  1.2827 +	}
  1.2828 +    }
  1.2829 +
  1.2830 +    /* Parse and list CRL's (if any) */
  1.2831 +    if (src->crls != NULL) {
  1.2832 +	SECU_Indent(out, level + 1);  
  1.2833 +	fprintf(out, "Signed Revocation Lists:\n");
  1.2834 +	iv = 0;
  1.2835 +	while ((aCrl = src->crls[iv++]) != NULL) {
  1.2836 +	    sprintf(om, "Signed Revocation List (%x)", iv);
  1.2837 +	    SECU_Indent(out, level + 2);  fprintf(out, "%s:\n", om);
  1.2838 +	    SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, 
  1.2839 +				  "Signature Algorithm", level+3);
  1.2840 +	    DER_ConvertBitString(&aCrl->signatureWrap.signature);
  1.2841 +	    SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature",
  1.2842 +			    level+3);
  1.2843 +	    SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", 
  1.2844 +			  level + 3); 
  1.2845 +	}
  1.2846 +    }
  1.2847 +
  1.2848 +    /* Parse and list signatures (if any) */
  1.2849 +    if (src->signerInfos != NULL) {
  1.2850 +	SECU_Indent(out, level + 1);
  1.2851 +	fprintf(out, "Signer Information List:\n");
  1.2852 +	iv = 0;
  1.2853 +	while ((sigInfo = src->signerInfos[iv++]) != NULL) {
  1.2854 +	    sprintf(om, "Signer Information (%x)", iv);
  1.2855 +	    secu_PrintSignerInfo(out, sigInfo, om, level + 2);
  1.2856 +	}
  1.2857 +    }  
  1.2858 +
  1.2859 +    return 0;
  1.2860 +}
  1.2861 +
  1.2862 +int
  1.2863 +SECU_PrintCrl (FILE *out, SECItem *der, char *m, int level)
  1.2864 +{
  1.2865 +    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.2866 +    CERTCrl *c = NULL;
  1.2867 +    int rv = SEC_ERROR_NO_MEMORY;
  1.2868 +
  1.2869 +    if (!arena)
  1.2870 +    	return rv;
  1.2871 +    do {
  1.2872 +	/* Decode CRL */
  1.2873 +	c = PORT_ArenaZNew(arena, CERTCrl);
  1.2874 +	if (!c)
  1.2875 +	    break;
  1.2876 +
  1.2877 +	rv = SEC_QuickDERDecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der);
  1.2878 +	if (rv != SECSuccess)
  1.2879 +	    break;
  1.2880 +	SECU_PrintCRLInfo (out, c, m, level);
  1.2881 +    } while (0);
  1.2882 +    PORT_FreeArena (arena, PR_FALSE);
  1.2883 +    return rv;
  1.2884 +}
  1.2885 +
  1.2886 +
  1.2887 +/*
  1.2888 +** secu_PrintPKCS7Encrypted
  1.2889 +**   Pretty print a PKCS7 encrypted data type (up to version 1).
  1.2890 +*/
  1.2891 +static void
  1.2892 +secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src,
  1.2893 +			 const char *m, int level)
  1.2894 +{
  1.2895 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2896 +    SECU_PrintInteger(out, &(src->version), "Version", level + 1);
  1.2897 +
  1.2898 +    secu_PrintPKCS7EncContent(out, &src->encContentInfo, 
  1.2899 +			      "Encrypted Content Information", level + 1);
  1.2900 +}
  1.2901 +
  1.2902 +/*
  1.2903 +** secu_PrintPKCS7Digested
  1.2904 +**   Pretty print a PKCS7 digested data type (up to version 1).
  1.2905 +*/
  1.2906 +static void
  1.2907 +secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src,
  1.2908 +			const char *m, int level)
  1.2909 +{
  1.2910 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.2911 +    SECU_PrintInteger(out, &(src->version), "Version", level + 1);
  1.2912 +    
  1.2913 +    SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm",
  1.2914 +			  level + 1);
  1.2915 +    secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information",
  1.2916 +			       level + 1);
  1.2917 +    SECU_PrintAsHex(out, &src->digest, "Digest", level + 1);  
  1.2918 +}
  1.2919 +
  1.2920 +/*
  1.2921 +** secu_PrintPKCS7ContentInfo
  1.2922 +**   Takes a SEC_PKCS7ContentInfo type and sends the contents to the 
  1.2923 +** appropriate function
  1.2924 +*/
  1.2925 +static int
  1.2926 +secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src,
  1.2927 +			   char *m, int level)
  1.2928 +{
  1.2929 +    const char *desc;
  1.2930 +    SECOidTag kind;
  1.2931 +    int rv;
  1.2932 +
  1.2933 +    SECU_Indent(out, level);  fprintf(out, "%s:\n", m);
  1.2934 +    level++;
  1.2935 +
  1.2936 +    if (src->contentTypeTag == NULL)
  1.2937 +	src->contentTypeTag = SECOID_FindOID(&(src->contentType));
  1.2938 +
  1.2939 +    if (src->contentTypeTag == NULL) {
  1.2940 +	desc = "Unknown";
  1.2941 +	kind = SEC_OID_PKCS7_DATA;
  1.2942 +    } else {
  1.2943 +	desc = src->contentTypeTag->desc;
  1.2944 +	kind = src->contentTypeTag->offset;
  1.2945 +    }
  1.2946 +
  1.2947 +    if (src->content.data == NULL) {
  1.2948 +	SECU_Indent(out, level); fprintf(out, "%s:\n", desc);
  1.2949 +	level++;
  1.2950 +	SECU_Indent(out, level); fprintf(out, "<no content>\n");
  1.2951 +	return 0;
  1.2952 +    }
  1.2953 +
  1.2954 +    rv = 0;
  1.2955 +    switch (kind) {
  1.2956 +      case SEC_OID_PKCS7_SIGNED_DATA:  /* Signed Data */
  1.2957 +	rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level);
  1.2958 +	break;
  1.2959 +
  1.2960 +      case SEC_OID_PKCS7_ENVELOPED_DATA:  /* Enveloped Data */
  1.2961 +        secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level);
  1.2962 +	break;
  1.2963 +
  1.2964 +      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:  /* Signed and Enveloped */
  1.2965 +	rv = secu_PrintPKCS7SignedAndEnveloped(out,
  1.2966 +					src->content.signedAndEnvelopedData,
  1.2967 +					desc, level);
  1.2968 +	break;
  1.2969 +
  1.2970 +      case SEC_OID_PKCS7_DIGESTED_DATA:  /* Digested Data */
  1.2971 +	secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level);
  1.2972 +	break;
  1.2973 +
  1.2974 +      case SEC_OID_PKCS7_ENCRYPTED_DATA:  /* Encrypted Data */
  1.2975 +	secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level);
  1.2976 +	break;
  1.2977 +
  1.2978 +      default:
  1.2979 +	SECU_PrintAsHex(out, src->content.data, desc, level);
  1.2980 +	break;
  1.2981 +    }
  1.2982 +
  1.2983 +    return rv;
  1.2984 +}
  1.2985 +
  1.2986 +/*
  1.2987 +** SECU_PrintPKCS7ContentInfo
  1.2988 +**   Decode and print any major PKCS7 data type (up to version 1).
  1.2989 +*/
  1.2990 +int
  1.2991 +SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level)
  1.2992 +{
  1.2993 +    SEC_PKCS7ContentInfo *cinfo;
  1.2994 +    int rv;
  1.2995 +
  1.2996 +    cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  1.2997 +    if (cinfo != NULL) {
  1.2998 +	/* Send it to recursive parsing and printing module */
  1.2999 +	rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level);
  1.3000 +	SEC_PKCS7DestroyContentInfo(cinfo);
  1.3001 +    } else {
  1.3002 +	rv = -1;
  1.3003 +    }
  1.3004 +
  1.3005 +    return rv;
  1.3006 +}
  1.3007 +
  1.3008 +/*
  1.3009 +** End of PKCS7 functions
  1.3010 +*/
  1.3011 +
  1.3012 +void
  1.3013 +printFlags(FILE *out, unsigned int flags, int level)
  1.3014 +{
  1.3015 +    if ( flags & CERTDB_TERMINAL_RECORD ) {
  1.3016 +	SECU_Indent(out, level); fprintf(out, "Terminal Record\n");
  1.3017 +    }
  1.3018 +    if ( flags & CERTDB_TRUSTED ) {
  1.3019 +	SECU_Indent(out, level); fprintf(out, "Trusted\n");
  1.3020 +    }
  1.3021 +    if ( flags & CERTDB_SEND_WARN ) {
  1.3022 +	SECU_Indent(out, level); fprintf(out, "Warn When Sending\n");
  1.3023 +    }
  1.3024 +    if ( flags & CERTDB_VALID_CA ) {
  1.3025 +	SECU_Indent(out, level); fprintf(out, "Valid CA\n");
  1.3026 +    }
  1.3027 +    if ( flags & CERTDB_TRUSTED_CA ) {
  1.3028 +	SECU_Indent(out, level); fprintf(out, "Trusted CA\n");
  1.3029 +    }
  1.3030 +    if ( flags & CERTDB_NS_TRUSTED_CA ) {
  1.3031 +	SECU_Indent(out, level); fprintf(out, "Netscape Trusted CA\n");
  1.3032 +    }
  1.3033 +    if ( flags & CERTDB_USER ) {
  1.3034 +	SECU_Indent(out, level); fprintf(out, "User\n");
  1.3035 +    }
  1.3036 +    if ( flags & CERTDB_TRUSTED_CLIENT_CA ) {
  1.3037 +	SECU_Indent(out, level); fprintf(out, "Trusted Client CA\n");
  1.3038 +    }
  1.3039 +    if ( flags & CERTDB_GOVT_APPROVED_CA ) {
  1.3040 +	SECU_Indent(out, level); fprintf(out, "Step-up\n");
  1.3041 +    }
  1.3042 +}
  1.3043 +
  1.3044 +void
  1.3045 +SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level)
  1.3046 +{
  1.3047 +    SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.3048 +    SECU_Indent(out, level+1); fprintf(out, "SSL Flags:\n");
  1.3049 +    printFlags(out, trust->sslFlags, level+2);
  1.3050 +    SECU_Indent(out, level+1); fprintf(out, "Email Flags:\n");
  1.3051 +    printFlags(out, trust->emailFlags, level+2);
  1.3052 +    SECU_Indent(out, level+1); fprintf(out, "Object Signing Flags:\n");
  1.3053 +    printFlags(out, trust->objectSigningFlags, level+2);
  1.3054 +}
  1.3055 +
  1.3056 +int SECU_PrintDERName(FILE *out, SECItem *der, const char *m, int level)
  1.3057 +{
  1.3058 +    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.3059 +    CERTName *name;
  1.3060 +    int rv = SEC_ERROR_NO_MEMORY;
  1.3061 +
  1.3062 +    if (!arena)
  1.3063 +	return rv;
  1.3064 +
  1.3065 +    name = PORT_ArenaZNew(arena, CERTName);
  1.3066 +    if (!name)
  1.3067 +	goto loser;
  1.3068 +
  1.3069 +    rv = SEC_ASN1DecodeItem(arena, name, SEC_ASN1_GET(CERT_NameTemplate), der);
  1.3070 +    if (rv)
  1.3071 +	goto loser;
  1.3072 +
  1.3073 +    SECU_PrintName(out, name, m, level);
  1.3074 +    if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
  1.3075 +	SECU_Newline(out);
  1.3076 +loser:
  1.3077 +    PORT_FreeArena(arena, PR_FALSE);
  1.3078 +    return rv;
  1.3079 +}
  1.3080 +
  1.3081 +typedef enum  {
  1.3082 +    noSignature = 0,
  1.3083 +    withSignature = 1
  1.3084 +} SignatureOptionType;
  1.3085 +
  1.3086 +static int
  1.3087 +secu_PrintSignedDataSigOpt(FILE *out, SECItem *der, const char *m,
  1.3088 +			   int level, SECU_PPFunc inner,
  1.3089 +                           SignatureOptionType withSignature)
  1.3090 +{
  1.3091 +    PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.3092 +    CERTSignedData *sd;
  1.3093 +    int rv = SEC_ERROR_NO_MEMORY;
  1.3094 +
  1.3095 +    if (!arena)
  1.3096 +	return rv;
  1.3097 +
  1.3098 +    /* Strip off the signature */
  1.3099 +    sd = PORT_ArenaZNew(arena, CERTSignedData);
  1.3100 +    if (!sd)
  1.3101 +	goto loser;
  1.3102 +
  1.3103 +    rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate), 
  1.3104 +                            der);
  1.3105 +    if (rv)
  1.3106 +	goto loser;
  1.3107 +
  1.3108 +    if (m) {
  1.3109 +        SECU_Indent(out, level); fprintf(out, "%s:\n", m);
  1.3110 +    } else {
  1.3111 +        level -= 1;
  1.3112 +    }
  1.3113 +    rv = (*inner)(out, &sd->data, "Data", level+1);
  1.3114 +
  1.3115 +    if (withSignature) {
  1.3116 +        SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm",
  1.3117 +                              level+1);
  1.3118 +        DER_ConvertBitString(&sd->signature);
  1.3119 +        SECU_PrintAsHex(out, &sd->signature, "Signature", level+1);
  1.3120 +    }
  1.3121 +    SECU_PrintFingerprints(out, der, "Fingerprint", level+1);
  1.3122 +loser:
  1.3123 +    PORT_FreeArena(arena, PR_FALSE);
  1.3124 +    return rv;
  1.3125 +}
  1.3126 +
  1.3127 +int SECU_PrintSignedData(FILE *out, SECItem *der, const char *m,
  1.3128 +                           int level, SECU_PPFunc inner)
  1.3129 +{
  1.3130 +    return secu_PrintSignedDataSigOpt(out, der, m, level, inner, 
  1.3131 +                                      withSignature);
  1.3132 +}
  1.3133 +
  1.3134 +int SECU_PrintSignedContent(FILE *out, SECItem *der, char *m,
  1.3135 +                            int level, SECU_PPFunc inner)
  1.3136 +{
  1.3137 +    return secu_PrintSignedDataSigOpt(out, der, m, level, inner, 
  1.3138 +                                      noSignature);
  1.3139 +}
  1.3140 +
  1.3141 +SECStatus
  1.3142 +SEC_PrintCertificateAndTrust(CERTCertificate *cert,
  1.3143 +                             const char *label,
  1.3144 +                             CERTCertTrust *trust)
  1.3145 +{
  1.3146 +    SECStatus rv;
  1.3147 +    SECItem data;
  1.3148 +    CERTCertTrust certTrust;
  1.3149 +    
  1.3150 +    data.data = cert->derCert.data;
  1.3151 +    data.len = cert->derCert.len;
  1.3152 +
  1.3153 +    rv = SECU_PrintSignedData(stdout, &data, label, 0,
  1.3154 +			      SECU_PrintCertificate);
  1.3155 +    if (rv) {
  1.3156 +	return(SECFailure);
  1.3157 +    }
  1.3158 +    if (trust) {
  1.3159 +	SECU_PrintTrustFlags(stdout, trust,
  1.3160 +	                     "Certificate Trust Flags", 1);
  1.3161 +    } else if (CERT_GetCertTrust(cert, &certTrust) == SECSuccess) {
  1.3162 +	SECU_PrintTrustFlags(stdout, &certTrust,
  1.3163 +	                     "Certificate Trust Flags", 1);
  1.3164 +    }
  1.3165 +
  1.3166 +    printf("\n");
  1.3167 +
  1.3168 +    return(SECSuccess);
  1.3169 +}
  1.3170 +
  1.3171 +
  1.3172 +static char *
  1.3173 +bestCertName(CERTCertificate *cert) {
  1.3174 +    if (cert->nickname) {
  1.3175 +	return cert->nickname;
  1.3176 +    }
  1.3177 +    if (cert->emailAddr && cert->emailAddr[0]) {
  1.3178 +	return cert->emailAddr;
  1.3179 +    }
  1.3180 +    return cert->subjectName;
  1.3181 +}
  1.3182 +
  1.3183 +void
  1.3184 +SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle, 
  1.3185 +	CERTCertificate *cert, PRBool checksig, 
  1.3186 +	SECCertificateUsage certUsage, void *pinArg, PRBool verbose,
  1.3187 +	PRTime datetime)
  1.3188 +{
  1.3189 +    CERTVerifyLog      log;
  1.3190 +    CERTVerifyLogNode *node;
  1.3191 +
  1.3192 +    PRErrorCode	       err    = PORT_GetError();
  1.3193 +
  1.3194 +    log.arena = PORT_NewArena(512);
  1.3195 +    log.head = log.tail = NULL;
  1.3196 +    log.count = 0;
  1.3197 +    CERT_VerifyCertificate(handle, cert, checksig, certUsage, datetime, pinArg, &log, NULL);
  1.3198 +
  1.3199 +    SECU_displayVerifyLog(outfile, &log, verbose);
  1.3200 +
  1.3201 +    for (node = log.head; node; node = node->next) {
  1.3202 +        if (node->cert)
  1.3203 +            CERT_DestroyCertificate(node->cert);
  1.3204 +    }
  1.3205 +    PORT_FreeArena(log.arena, PR_FALSE);
  1.3206 +
  1.3207 +    PORT_SetError(err); /* restore original error code */
  1.3208 +}
  1.3209 +
  1.3210 +void
  1.3211 +SECU_displayVerifyLog(FILE *outfile, CERTVerifyLog *log,
  1.3212 +                      PRBool verbose)
  1.3213 +{
  1.3214 +    CERTVerifyLogNode *node   = NULL;
  1.3215 +    unsigned int       depth  = (unsigned int)-1;
  1.3216 +    unsigned int       flags  = 0;
  1.3217 +    char *             errstr = NULL;
  1.3218 +
  1.3219 +    if (log->count > 0) {
  1.3220 +	fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n");
  1.3221 +	for (node = log->head; node; node = node->next) {
  1.3222 +	    if (depth != node->depth) {
  1.3223 +		depth = node->depth;
  1.3224 +		fprintf(outfile,"CERT %d. %s %s:\n", depth,
  1.3225 +				 bestCertName(node->cert), 
  1.3226 +			  	 depth ? "[Certificate Authority]": "");
  1.3227 +	    	if (verbose) {
  1.3228 +		    const char * emailAddr;
  1.3229 +		    emailAddr = CERT_GetFirstEmailAddress(node->cert);
  1.3230 +		    if (emailAddr) {
  1.3231 +		    	fprintf(outfile,"Email Address(es): ");
  1.3232 +			do {
  1.3233 +			    fprintf(outfile, "%s\n", emailAddr);
  1.3234 +			    emailAddr = CERT_GetNextEmailAddress(node->cert,
  1.3235 +			                                         emailAddr);
  1.3236 +			} while (emailAddr);
  1.3237 +		    }
  1.3238 +		}
  1.3239 +	    }
  1.3240 +	    fprintf(outfile, "  ERROR %ld: %s\n", node->error,
  1.3241 +			    SECU_Strerror(node->error));
  1.3242 +	    errstr = NULL;
  1.3243 +	    switch (node->error) {
  1.3244 +	    case SEC_ERROR_INADEQUATE_KEY_USAGE:
  1.3245 +		flags = (unsigned int)node->arg;
  1.3246 +		switch (flags) {
  1.3247 +		case KU_DIGITAL_SIGNATURE:
  1.3248 +		    errstr = "Cert cannot sign.";
  1.3249 +		    break;
  1.3250 +		case KU_KEY_ENCIPHERMENT:
  1.3251 +		    errstr = "Cert cannot encrypt.";
  1.3252 +		    break;
  1.3253 +		case KU_KEY_CERT_SIGN:
  1.3254 +		    errstr = "Cert cannot sign other certs.";
  1.3255 +		    break;
  1.3256 +		default:
  1.3257 +		    errstr = "[unknown usage].";
  1.3258 +		    break;
  1.3259 +		}
  1.3260 +	    case SEC_ERROR_INADEQUATE_CERT_TYPE:
  1.3261 +		flags = (unsigned int)node->arg;
  1.3262 +		switch (flags) {
  1.3263 +		case NS_CERT_TYPE_SSL_CLIENT:
  1.3264 +		case NS_CERT_TYPE_SSL_SERVER:
  1.3265 +		    errstr = "Cert cannot be used for SSL.";
  1.3266 +		    break;
  1.3267 +		case NS_CERT_TYPE_SSL_CA:
  1.3268 +		    errstr = "Cert cannot be used as an SSL CA.";
  1.3269 +		    break;
  1.3270 +		case NS_CERT_TYPE_EMAIL:
  1.3271 +		    errstr = "Cert cannot be used for SMIME.";
  1.3272 +		    break;
  1.3273 +		case NS_CERT_TYPE_EMAIL_CA:
  1.3274 +		    errstr = "Cert cannot be used as an SMIME CA.";
  1.3275 +		    break;
  1.3276 +		case NS_CERT_TYPE_OBJECT_SIGNING:
  1.3277 +		    errstr = "Cert cannot be used for object signing.";
  1.3278 +		    break;
  1.3279 +		case NS_CERT_TYPE_OBJECT_SIGNING_CA:
  1.3280 +		    errstr = "Cert cannot be used as an object signing CA.";
  1.3281 +		    break;
  1.3282 +		default:
  1.3283 +		    errstr = "[unknown usage].";
  1.3284 +		    break;
  1.3285 +		}
  1.3286 +	    case SEC_ERROR_UNKNOWN_ISSUER:
  1.3287 +	    case SEC_ERROR_UNTRUSTED_ISSUER:
  1.3288 +	    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
  1.3289 +		errstr = node->cert->issuerName;
  1.3290 +		break;
  1.3291 +	    default:
  1.3292 +		break;
  1.3293 +	    }
  1.3294 +	    if (errstr) {
  1.3295 +		fprintf(stderr,"    %s\n",errstr);
  1.3296 +	    }
  1.3297 +	}    
  1.3298 +    }
  1.3299 +}
  1.3300 +
  1.3301 +void
  1.3302 +SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle, 
  1.3303 +	CERTCertificate *cert, PRBool checksig, 
  1.3304 +	SECCertificateUsage certUsage, void *pinArg, PRBool verbose)
  1.3305 +{
  1.3306 +    SECU_printCertProblemsOnDate(outfile, handle, cert, checksig, 
  1.3307 +	                         certUsage, pinArg, verbose, PR_Now());
  1.3308 +}
  1.3309 +
  1.3310 +SECStatus
  1.3311 +SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile,
  1.3312 +              PRBool ascii, char *url)
  1.3313 +{
  1.3314 +    PORT_Assert(derCrl != NULL);
  1.3315 +    if (!derCrl) {
  1.3316 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3317 +        return SECFailure;
  1.3318 +    }
  1.3319 +
  1.3320 +    if (outFile != NULL) {
  1.3321 +        if (ascii) {
  1.3322 +            PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER, 
  1.3323 +                       BTOA_DataToAscii(derCrl->data, derCrl->len), 
  1.3324 +                       NS_CRL_TRAILER);
  1.3325 +        } else {
  1.3326 +            if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) {
  1.3327 +                return SECFailure;
  1.3328 +            }
  1.3329 +        }
  1.3330 +    }
  1.3331 +    if (slot) {
  1.3332 +        CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url,
  1.3333 +                                               SEC_CRL_TYPE, NULL, 0, NULL, 0);
  1.3334 +        if (newCrl != NULL) {
  1.3335 +            SEC_DestroyCrl(newCrl);
  1.3336 +            return SECSuccess;
  1.3337 +        }
  1.3338 +        return SECFailure;
  1.3339 +    }
  1.3340 +    if (!outFile && !slot) {
  1.3341 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3342 +        return SECFailure;
  1.3343 +    }
  1.3344 +    return SECSuccess;
  1.3345 +}
  1.3346 +
  1.3347 +SECStatus
  1.3348 +SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl,
  1.3349 +                      SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode)
  1.3350 +{
  1.3351 +    SECItem der;
  1.3352 +    SECKEYPrivateKey *caPrivateKey = NULL;    
  1.3353 +    SECStatus rv;
  1.3354 +    PLArenaPool *arena;
  1.3355 +    SECOidTag algID;
  1.3356 +    void *dummy;
  1.3357 +
  1.3358 +    PORT_Assert(issuer != NULL && signCrl != NULL);
  1.3359 +    if (!issuer || !signCrl) {
  1.3360 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3361 +        return SECFailure;
  1.3362 +    }
  1.3363 +
  1.3364 +    arena = signCrl->arena;
  1.3365 +
  1.3366 +    caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL);
  1.3367 +    if (caPrivateKey == NULL) {
  1.3368 +        *resCode = noKeyFound;
  1.3369 +        return SECFailure;
  1.3370 +    }
  1.3371 +
  1.3372 +    algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag);
  1.3373 +    if (algID == SEC_OID_UNKNOWN) {
  1.3374 +        *resCode = noSignatureMatch;
  1.3375 +        rv = SECFailure;
  1.3376 +        goto done;
  1.3377 +    }
  1.3378 +
  1.3379 +    if (!signCrl->crl.signatureAlg.parameters.data) {
  1.3380 +        rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0);
  1.3381 +        if (rv != SECSuccess) {
  1.3382 +            *resCode = failToEncode;
  1.3383 +            goto done;
  1.3384 +        }
  1.3385 +    }
  1.3386 +
  1.3387 +    der.len = 0;
  1.3388 +    der.data = NULL;
  1.3389 +    dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl,
  1.3390 +                               SEC_ASN1_GET(CERT_CrlTemplate));
  1.3391 +    if (!dummy) {
  1.3392 +        *resCode = failToEncode;
  1.3393 +        rv = SECFailure;
  1.3394 +        goto done;
  1.3395 +    }
  1.3396 +
  1.3397 +    rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap,
  1.3398 +                             der.data, der.len, caPrivateKey, algID);
  1.3399 +    if (rv != SECSuccess) {
  1.3400 +        *resCode = failToSign;
  1.3401 +        goto done;
  1.3402 +    }
  1.3403 +
  1.3404 +    signCrl->derCrl = PORT_ArenaZNew(arena, SECItem);
  1.3405 +    if (signCrl->derCrl == NULL) {
  1.3406 +        *resCode = noMem;
  1.3407 +        PORT_SetError(SEC_ERROR_NO_MEMORY);
  1.3408 +        rv = SECFailure;
  1.3409 +        goto done;
  1.3410 +    }
  1.3411 +
  1.3412 +    signCrl->derCrl->len = 0;
  1.3413 +    signCrl->derCrl->data = NULL;
  1.3414 +    dummy = SEC_ASN1EncodeItem (arena, signCrl->derCrl, signCrl,
  1.3415 +                                SEC_ASN1_GET(CERT_SignedCrlTemplate));
  1.3416 +    if (!dummy) {
  1.3417 +        *resCode = failToEncode;
  1.3418 +        rv = SECFailure;
  1.3419 +        goto done;
  1.3420 +    }
  1.3421 +
  1.3422 +done:
  1.3423 +    if (caPrivateKey) {
  1.3424 +        SECKEY_DestroyPrivateKey(caPrivateKey);
  1.3425 +    }
  1.3426 +    return rv;
  1.3427 +}
  1.3428 +
  1.3429 +
  1.3430 +
  1.3431 +SECStatus
  1.3432 +SECU_CopyCRL(PLArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl)
  1.3433 +{
  1.3434 +    void *dummy;
  1.3435 +    SECStatus rv = SECSuccess;
  1.3436 +    SECItem der;
  1.3437 +
  1.3438 +    PORT_Assert(destArena && srcCrl && destCrl);
  1.3439 +    if (!destArena || !srcCrl || !destCrl) {
  1.3440 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3441 +        return SECFailure;
  1.3442 +    }
  1.3443 +
  1.3444 +    der.len = 0;
  1.3445 +    der.data = NULL;
  1.3446 +    dummy = SEC_ASN1EncodeItem (destArena, &der, srcCrl,
  1.3447 +                                SEC_ASN1_GET(CERT_CrlTemplate));
  1.3448 +    if (!dummy) {
  1.3449 +        return SECFailure;
  1.3450 +    }
  1.3451 +
  1.3452 +    rv = SEC_QuickDERDecodeItem(destArena, destCrl,
  1.3453 +                                SEC_ASN1_GET(CERT_CrlTemplate), &der);
  1.3454 +    if (rv != SECSuccess) {
  1.3455 +        return SECFailure;
  1.3456 +    }
  1.3457 +    
  1.3458 +    destCrl->arena = destArena;
  1.3459 +
  1.3460 +    return rv;
  1.3461 +}
  1.3462 +
  1.3463 +SECStatus
  1.3464 +SECU_DerSignDataCRL(PLArenaPool *arena, CERTSignedData *sd,
  1.3465 +                    unsigned char *buf, int len, SECKEYPrivateKey *pk,
  1.3466 +                    SECOidTag algID)
  1.3467 +{
  1.3468 +    SECItem it;
  1.3469 +    SECStatus rv;
  1.3470 +
  1.3471 +    it.data = 0;
  1.3472 +
  1.3473 +    /* XXX We should probably have some asserts here to make sure the key type
  1.3474 +     * and algID match
  1.3475 +     */
  1.3476 +
  1.3477 +    /* Sign input buffer */
  1.3478 +    rv = SEC_SignData(&it, buf, len, pk, algID);
  1.3479 +    if (rv) goto loser;
  1.3480 +
  1.3481 +    /* Fill out SignedData object */
  1.3482 +    PORT_Memset(sd, 0, sizeof(*sd));
  1.3483 +    sd->data.data = buf;
  1.3484 +    sd->data.len = len;
  1.3485 +    sd->signature.data = it.data;
  1.3486 +    sd->signature.len = it.len << 3;		/* convert to bit string */
  1.3487 +    rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0);
  1.3488 +    if (rv) goto loser;
  1.3489 +
  1.3490 +    return rv;
  1.3491 +
  1.3492 +  loser:
  1.3493 +    PORT_Free(it.data);
  1.3494 +    return rv;
  1.3495 +}
  1.3496 +
  1.3497 +#if 0
  1.3498 +
  1.3499 +/* we need access to the private function cert_FindExtension for this code to work */
  1.3500 +
  1.3501 +CERTAuthKeyID *
  1.3502 +SECU_FindCRLAuthKeyIDExten (PLArenaPool *arena, CERTSignedCrl *scrl)
  1.3503 +{
  1.3504 +    SECItem encodedExtenValue;
  1.3505 +    SECStatus rv;
  1.3506 +    CERTAuthKeyID *ret;
  1.3507 +    CERTCrl* crl;
  1.3508 +
  1.3509 +    if (!scrl) {
  1.3510 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3511 +        return NULL;
  1.3512 +    }
  1.3513 +
  1.3514 +    crl = &scrl->crl;
  1.3515 +    
  1.3516 +    encodedExtenValue.data = NULL;
  1.3517 +    encodedExtenValue.len = 0;
  1.3518 +
  1.3519 +    rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID,
  1.3520 +			    &encodedExtenValue);
  1.3521 +    if ( rv != SECSuccess ) {
  1.3522 +	return (NULL);
  1.3523 +    }
  1.3524 +
  1.3525 +    ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
  1.3526 +
  1.3527 +    PORT_Free(encodedExtenValue.data);
  1.3528 +    encodedExtenValue.data = NULL;
  1.3529 +    
  1.3530 +    return(ret);
  1.3531 +}
  1.3532 +
  1.3533 +#endif
  1.3534 +
  1.3535 +/*
  1.3536 + * Find the issuer of a Crl.  Use the authorityKeyID if it exists.
  1.3537 + */
  1.3538 +CERTCertificate *
  1.3539 +SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem* subject,
  1.3540 +                   CERTAuthKeyID* authorityKeyID, PRTime validTime)
  1.3541 +{
  1.3542 +    CERTCertificate *issuerCert = NULL;
  1.3543 +    CERTCertList *certList = NULL;
  1.3544 +    CERTCertTrust trust;
  1.3545 +
  1.3546 +    if (!subject) {
  1.3547 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3548 +        return NULL;
  1.3549 +    }
  1.3550 +
  1.3551 +    certList =
  1.3552 +        CERT_CreateSubjectCertList(NULL, dbhandle, subject,
  1.3553 +                                   validTime, PR_TRUE);
  1.3554 +    if (certList) {
  1.3555 +        CERTCertListNode *node = CERT_LIST_HEAD(certList);
  1.3556 +    
  1.3557 +        /* XXX and authoritykeyid in the future */
  1.3558 +        while ( ! CERT_LIST_END(node, certList) ) {
  1.3559 +            CERTCertificate *cert = node->cert;
  1.3560 +            /* check cert CERTCertTrust data is allocated, check cert
  1.3561 +               usage extension, check that cert has pkey in db. Select
  1.3562 +               the first (newest) user cert */
  1.3563 +            if (CERT_GetCertTrust(cert, &trust) == SECSuccess &&
  1.3564 +                CERT_CheckCertUsage(cert, KU_CRL_SIGN) == SECSuccess &&
  1.3565 +                CERT_IsUserCert(cert)) {
  1.3566 +                
  1.3567 +                issuerCert = CERT_DupCertificate(cert);
  1.3568 +                break;
  1.3569 +            }
  1.3570 +            node = CERT_LIST_NEXT(node);   
  1.3571 +        }
  1.3572 +        CERT_DestroyCertList(certList);
  1.3573 +    }
  1.3574 +    return(issuerCert);
  1.3575 +}
  1.3576 +
  1.3577 +
  1.3578 +/* Encodes and adds extensions to the CRL or CRL entries. */
  1.3579 +SECStatus 
  1.3580 +SECU_EncodeAndAddExtensionValue(PLArenaPool *arena, void *extHandle, 
  1.3581 +                                void *value, PRBool criticality, int extenType, 
  1.3582 +                                EXTEN_EXT_VALUE_ENCODER EncodeValueFn)
  1.3583 +{
  1.3584 +    SECItem encodedValue;
  1.3585 +    SECStatus rv;
  1.3586 +
  1.3587 +    encodedValue.data = NULL;
  1.3588 +    encodedValue.len = 0;
  1.3589 +    do {
  1.3590 +        rv = (*EncodeValueFn)(arena, value, &encodedValue);
  1.3591 +        if (rv != SECSuccess)
  1.3592 +            break;
  1.3593 +
  1.3594 +        rv = CERT_AddExtension(extHandle, extenType, &encodedValue,
  1.3595 +                               criticality, PR_TRUE);
  1.3596 +        if (rv != SECSuccess)
  1.3597 +            break;
  1.3598 +    } while (0);
  1.3599 +
  1.3600 +    return (rv);
  1.3601 +}
  1.3602 +
  1.3603 +CERTCertificate*
  1.3604 +SECU_FindCertByNicknameOrFilename(CERTCertDBHandle *handle,
  1.3605 +                                  char *name, PRBool ascii,
  1.3606 +                                  void *pwarg)
  1.3607 +{
  1.3608 +    CERTCertificate *the_cert;
  1.3609 +    the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
  1.3610 +    if (the_cert) {
  1.3611 +        return the_cert;
  1.3612 +    }
  1.3613 +    the_cert = PK11_FindCertFromNickname(name, pwarg);
  1.3614 +    if (!the_cert) {
  1.3615 +        /* Don't have a cert with name "name" in the DB. Try to
  1.3616 +         * open a file with such name and get the cert from there.*/
  1.3617 +        SECStatus rv;
  1.3618 +        SECItem item = {0, NULL, 0};
  1.3619 +        PRFileDesc* fd = PR_Open(name, PR_RDONLY, 0777); 
  1.3620 +        if (!fd) {
  1.3621 +            return NULL;
  1.3622 +        }
  1.3623 +        rv = SECU_ReadDERFromFile(&item, fd, ascii, PR_FALSE);
  1.3624 +        PR_Close(fd);
  1.3625 +        if (rv != SECSuccess || !item.len) {
  1.3626 +            PORT_Free(item.data);
  1.3627 +            return NULL;
  1.3628 +        }
  1.3629 +        the_cert = CERT_NewTempCertificate(handle, &item, 
  1.3630 +                                           NULL     /* nickname */, 
  1.3631 +                                           PR_FALSE /* isPerm */, 
  1.3632 +                                           PR_TRUE  /* copyDER */);
  1.3633 +        PORT_Free(item.data);
  1.3634 +    }
  1.3635 +    return the_cert;
  1.3636 +}
  1.3637 +
  1.3638 +/* Convert a SSL/TLS protocol version string into the respective numeric value
  1.3639 + * defined by the SSL_LIBRARY_VERSION_* constants,
  1.3640 + * while accepting a flexible set of case-insensitive identifiers.
  1.3641 + *
  1.3642 + * Caller must specify bufLen, allowing the function to operate on substrings.
  1.3643 + */
  1.3644 +static SECStatus
  1.3645 +SECU_GetSSLVersionFromName(const char *buf, size_t bufLen, PRUint16 *version)
  1.3646 +{
  1.3647 +    if (!buf || !version) {
  1.3648 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3649 +        return SECFailure;
  1.3650 +    }
  1.3651 +
  1.3652 +    if (!PL_strncasecmp(buf, "ssl2", bufLen)) {
  1.3653 +        *version = SSL_LIBRARY_VERSION_2;
  1.3654 +        return SECSuccess;
  1.3655 +    }
  1.3656 +    if (!PL_strncasecmp(buf, "ssl3", bufLen)) {
  1.3657 +        *version = SSL_LIBRARY_VERSION_3_0;
  1.3658 +        return SECSuccess;
  1.3659 +    }
  1.3660 +    if (!PL_strncasecmp(buf, "tls1.0", bufLen)) {
  1.3661 +        *version = SSL_LIBRARY_VERSION_TLS_1_0;
  1.3662 +        return SECSuccess;
  1.3663 +    }
  1.3664 +    if (!PL_strncasecmp(buf, "tls1.1", bufLen)) {
  1.3665 +        *version = SSL_LIBRARY_VERSION_TLS_1_1;
  1.3666 +        return SECSuccess;
  1.3667 +    }
  1.3668 +    if (!PL_strncasecmp(buf, "tls1.2", bufLen)) {
  1.3669 +        *version = SSL_LIBRARY_VERSION_TLS_1_2;
  1.3670 +        return SECSuccess;
  1.3671 +    }
  1.3672 +    PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3673 +    return SECFailure;
  1.3674 +}
  1.3675 +
  1.3676 +SECStatus
  1.3677 +SECU_ParseSSLVersionRangeString(const char *input,
  1.3678 +                                const SSLVersionRange defaultVersionRange,
  1.3679 +                                const PRBool defaultEnableSSL2,
  1.3680 +                                SSLVersionRange *vrange, PRBool *enableSSL2)
  1.3681 +{
  1.3682 +    const char *colonPos;
  1.3683 +    size_t colonIndex;
  1.3684 +    const char *maxStr;
  1.3685 +
  1.3686 +    if (!input || !vrange || !enableSSL2) {
  1.3687 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3688 +        return SECFailure;
  1.3689 +    }
  1.3690 +
  1.3691 +    if (!strcmp(input, ":")) {
  1.3692 +        /* special value, use default */
  1.3693 +        *enableSSL2 = defaultEnableSSL2;
  1.3694 +        *vrange = defaultVersionRange;
  1.3695 +        return SECSuccess;
  1.3696 +    }
  1.3697 +
  1.3698 +    colonPos = strchr(input, ':');
  1.3699 +    if (!colonPos) {
  1.3700 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3701 +        return SECFailure;
  1.3702 +    }
  1.3703 +
  1.3704 +    colonIndex = colonPos - input;
  1.3705 +    maxStr = colonPos + 1;
  1.3706 +
  1.3707 +    if (!colonIndex) {
  1.3708 +        /* colon was first character, min version is empty */
  1.3709 +        *enableSSL2 = defaultEnableSSL2;
  1.3710 +        vrange->min = defaultVersionRange.min;
  1.3711 +    } else {
  1.3712 +        PRUint16 version;
  1.3713 +        /* colonIndex is equivalent to the length of the min version substring */
  1.3714 +        if (SECU_GetSSLVersionFromName(input, colonIndex, &version) != SECSuccess) {
  1.3715 +            PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3716 +            return SECFailure;
  1.3717 +        }
  1.3718 +
  1.3719 +        if (version == SSL_LIBRARY_VERSION_2) {
  1.3720 +            *enableSSL2 = PR_TRUE;
  1.3721 +            vrange->min = defaultVersionRange.min;
  1.3722 +        } else {
  1.3723 +            *enableSSL2 = PR_FALSE;
  1.3724 +            vrange->min = version;
  1.3725 +        }
  1.3726 +    }
  1.3727 +
  1.3728 +    if (!*maxStr) {
  1.3729 +        vrange->max = defaultVersionRange.max;
  1.3730 +    } else {
  1.3731 +        PRUint16 version;
  1.3732 +        /* if max version is empty, then maxStr points to the string terminator */
  1.3733 +        if (SECU_GetSSLVersionFromName(maxStr, strlen(maxStr), &version)
  1.3734 +                != SECSuccess) {
  1.3735 +            PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3736 +            return SECFailure;
  1.3737 +        }
  1.3738 +
  1.3739 +        if (version == SSL_LIBRARY_VERSION_2) {
  1.3740 +            /* consistency checking, require that min allows enableSSL2, too */
  1.3741 +            if (!*enableSSL2) {
  1.3742 +                PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3743 +                return SECFailure;
  1.3744 +            }
  1.3745 +            /* we use 0 because SSL_LIBRARY_VERSION_NONE is private: */
  1.3746 +            vrange->min = 0;
  1.3747 +            vrange->max = 0;
  1.3748 +        } else {
  1.3749 +            vrange->max = version;
  1.3750 +        }
  1.3751 +    }
  1.3752 +
  1.3753 +    return SECSuccess;
  1.3754 +}

mercurial