tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

secutil.c (148107B)


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