tor-browser

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

lowcert.c (26341B)


      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 /*
      6 * Certificate handling code
      7 */
      8 
      9 #include "seccomon.h"
     10 #include "secder.h"
     11 #include "nssilock.h"
     12 #include "lowkeyi.h"
     13 #include "secasn1.h"
     14 #include "secoid.h"
     15 #include "secerr.h"
     16 #include "pcert.h"
     17 
     18 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
     19 
     20 static const SEC_ASN1Template nsslowcert_SubjectPublicKeyInfoTemplate[] = {
     21    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWCERTSubjectPublicKeyInfo) },
     22    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
     23      offsetof(NSSLOWCERTSubjectPublicKeyInfo, algorithm),
     24      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
     25    { SEC_ASN1_BIT_STRING,
     26      offsetof(NSSLOWCERTSubjectPublicKeyInfo, subjectPublicKey) },
     27    { 0 }
     28 };
     29 
     30 static const SEC_ASN1Template nsslowcert_RSAPublicKeyTemplate[] = {
     31    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPublicKey) },
     32    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.rsa.modulus) },
     33    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.rsa.publicExponent) },
     34    { 0 }
     35 };
     36 static const SEC_ASN1Template nsslowcert_DSAPublicKeyTemplate[] = {
     37    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.dsa.publicValue) },
     38    { 0 }
     39 };
     40 static const SEC_ASN1Template nsslowcert_DHPublicKeyTemplate[] = {
     41    { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.dh.publicValue) },
     42    { 0 }
     43 };
     44 
     45 /*
     46 * See bugzilla bug 125359
     47 * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
     48 * all of the templates above that en/decode into integers must be converted
     49 * from ASN.1's signed integer type.  This is done by marking either the
     50 * source or destination (encoding or decoding, respectively) type as
     51 * siUnsignedInteger.
     52 */
     53 
     54 static void
     55 prepare_low_rsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
     56 {
     57    pubk->u.rsa.modulus.type = siUnsignedInteger;
     58    pubk->u.rsa.publicExponent.type = siUnsignedInteger;
     59 }
     60 
     61 static void
     62 prepare_low_dsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
     63 {
     64    pubk->u.dsa.publicValue.type = siUnsignedInteger;
     65    pubk->u.dsa.params.prime.type = siUnsignedInteger;
     66    pubk->u.dsa.params.subPrime.type = siUnsignedInteger;
     67    pubk->u.dsa.params.base.type = siUnsignedInteger;
     68 }
     69 
     70 static void
     71 prepare_low_dh_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
     72 {
     73    pubk->u.dh.prime.type = siUnsignedInteger;
     74    pubk->u.dh.base.type = siUnsignedInteger;
     75    pubk->u.dh.publicValue.type = siUnsignedInteger;
     76 }
     77 
     78 /*
     79 * simple cert decoder to avoid the cost of asn1 engine
     80 */
     81 static unsigned char *
     82 nsslowcert_dataStart(unsigned char *buf, unsigned int length,
     83                     unsigned int *data_length, PRBool includeTag,
     84                     unsigned char *rettag)
     85 {
     86    unsigned char tag;
     87    unsigned int used_length = 0;
     88 
     89    /* need at least a tag and a 1 byte length */
     90    if (length < 2) {
     91        return NULL;
     92    }
     93 
     94    tag = buf[used_length++];
     95 
     96    if (rettag) {
     97        *rettag = tag;
     98    }
     99 
    100    /* blow out when we come to the end */
    101    if (tag == 0) {
    102        return NULL;
    103    }
    104 
    105    *data_length = buf[used_length++];
    106 
    107    if (*data_length & 0x80) {
    108        int len_count = *data_length & 0x7f;
    109 
    110        if (len_count + used_length > length) {
    111            return NULL;
    112        }
    113 
    114        *data_length = 0;
    115 
    116        while (len_count-- > 0) {
    117            *data_length = (*data_length << 8) | buf[used_length++];
    118        }
    119    }
    120 
    121    if (*data_length > (length - used_length)) {
    122        *data_length = length - used_length;
    123        return NULL;
    124    }
    125    if (includeTag)
    126        *data_length += used_length;
    127 
    128    return (buf + (includeTag ? 0 : used_length));
    129 }
    130 
    131 static void
    132 SetTimeType(SECItem *item, unsigned char tagtype)
    133 {
    134    switch (tagtype) {
    135        case SEC_ASN1_UTC_TIME:
    136            item->type = siUTCTime;
    137            break;
    138 
    139        case SEC_ASN1_GENERALIZED_TIME:
    140            item->type = siGeneralizedTime;
    141            break;
    142 
    143        default:
    144            PORT_Assert(0);
    145            break;
    146    }
    147 }
    148 
    149 static int
    150 nsslowcert_GetValidityFields(unsigned char *buf, int buf_length,
    151                             SECItem *notBefore, SECItem *notAfter)
    152 {
    153    unsigned char tagtype;
    154    notBefore->data = nsslowcert_dataStart(buf, buf_length,
    155                                           &notBefore->len, PR_FALSE, &tagtype);
    156    if (notBefore->data == NULL)
    157        return SECFailure;
    158    SetTimeType(notBefore, tagtype);
    159    buf_length -= (notBefore->data - buf) + notBefore->len;
    160    buf = notBefore->data + notBefore->len;
    161    notAfter->data = nsslowcert_dataStart(buf, buf_length,
    162                                          &notAfter->len, PR_FALSE, &tagtype);
    163    if (notAfter->data == NULL)
    164        return SECFailure;
    165    SetTimeType(notAfter, tagtype);
    166    return SECSuccess;
    167 }
    168 
    169 static int
    170 nsslowcert_GetCertFields(unsigned char *cert, int cert_length,
    171                         SECItem *issuer, SECItem *serial, SECItem *derSN, SECItem *subject,
    172                         SECItem *valid, SECItem *subjkey, SECItem *extensions)
    173 {
    174    unsigned char *buf;
    175    unsigned int buf_length;
    176    unsigned char *dummy;
    177    unsigned int dummylen;
    178 
    179    /* get past the signature wrap */
    180    buf = nsslowcert_dataStart(cert, cert_length, &buf_length, PR_FALSE, NULL);
    181    if (buf == NULL)
    182        return SECFailure;
    183    /* get into the raw cert data */
    184    buf = nsslowcert_dataStart(buf, buf_length, &buf_length, PR_FALSE, NULL);
    185    if (buf == NULL)
    186        return SECFailure;
    187    /* skip past any optional version number */
    188    if ((buf[0] & 0xa0) == 0xa0) {
    189        dummy = nsslowcert_dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
    190        if (dummy == NULL)
    191            return SECFailure;
    192        buf_length -= (dummy - buf) + dummylen;
    193        buf = dummy + dummylen;
    194    }
    195    /* serial number */
    196    if (derSN) {
    197        derSN->data = nsslowcert_dataStart(buf, buf_length, &derSN->len, PR_TRUE, NULL);
    198        /* derSN->data  doesn't need to be checked because if it fails so will
    199         * serial->data below. The only difference between the two calls is
    200         * whether or not the tags are included in the returned buffer */
    201    }
    202    serial->data = nsslowcert_dataStart(buf, buf_length, &serial->len, PR_FALSE, NULL);
    203    if (serial->data == NULL)
    204        return SECFailure;
    205    buf_length -= (serial->data - buf) + serial->len;
    206    buf = serial->data + serial->len;
    207    /* skip the OID */
    208    dummy = nsslowcert_dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
    209    if (dummy == NULL)
    210        return SECFailure;
    211    buf_length -= (dummy - buf) + dummylen;
    212    buf = dummy + dummylen;
    213    /* issuer */
    214    issuer->data = nsslowcert_dataStart(buf, buf_length, &issuer->len, PR_TRUE, NULL);
    215    if (issuer->data == NULL)
    216        return SECFailure;
    217    buf_length -= (issuer->data - buf) + issuer->len;
    218    buf = issuer->data + issuer->len;
    219 
    220    /* only wanted issuer/SN */
    221    if (valid == NULL) {
    222        return SECSuccess;
    223    }
    224    /* validity */
    225    valid->data = nsslowcert_dataStart(buf, buf_length, &valid->len, PR_FALSE, NULL);
    226    if (valid->data == NULL)
    227        return SECFailure;
    228    buf_length -= (valid->data - buf) + valid->len;
    229    buf = valid->data + valid->len;
    230    /*subject */
    231    subject->data = nsslowcert_dataStart(buf, buf_length, &subject->len, PR_TRUE, NULL);
    232    if (subject->data == NULL)
    233        return SECFailure;
    234    buf_length -= (subject->data - buf) + subject->len;
    235    buf = subject->data + subject->len;
    236    /* subject  key info */
    237    subjkey->data = nsslowcert_dataStart(buf, buf_length, &subjkey->len, PR_TRUE, NULL);
    238    if (subjkey->data == NULL)
    239        return SECFailure;
    240    buf_length -= (subjkey->data - buf) + subjkey->len;
    241    buf = subjkey->data + subjkey->len;
    242 
    243    extensions->data = NULL;
    244    extensions->len = 0;
    245    while (buf_length > 0) {
    246        /* EXTENSIONS */
    247        if (buf[0] == 0xa3) {
    248            extensions->data = nsslowcert_dataStart(buf, buf_length,
    249                                                    &extensions->len, PR_FALSE, NULL);
    250            /* if the DER is bad, we should fail. Previously we accepted
    251             * bad DER here and treated the extension as missin */
    252            if (extensions->data == NULL ||
    253                (extensions->data - buf) + extensions->len != buf_length)
    254                return SECFailure;
    255            buf = extensions->data;
    256            buf_length = extensions->len;
    257            /* now parse the SEQUENCE holding the extensions. */
    258            dummy = nsslowcert_dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
    259            if (dummy == NULL ||
    260                (dummy - buf) + dummylen != buf_length)
    261                return SECFailure;
    262            buf_length -= (dummy - buf);
    263            buf = dummy;
    264            /* Now parse the extensions inside this sequence */
    265        }
    266        dummy = nsslowcert_dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
    267        if (dummy == NULL)
    268            return SECFailure;
    269        buf_length -= (dummy - buf) + dummylen;
    270        buf = dummy + dummylen;
    271    }
    272    return SECSuccess;
    273 }
    274 
    275 static SECStatus
    276 nsslowcert_GetCertTimes(NSSLOWCERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
    277 {
    278    int rv;
    279    NSSLOWCERTValidity validity;
    280 
    281    rv = nsslowcert_GetValidityFields(c->validity.data, c->validity.len,
    282                                      &validity.notBefore, &validity.notAfter);
    283    if (rv != SECSuccess) {
    284        return rv;
    285    }
    286 
    287    /* convert DER not-before time */
    288    rv = DER_DecodeTimeChoice(notBefore, &validity.notBefore);
    289    if (rv) {
    290        return (SECFailure);
    291    }
    292 
    293    /* convert DER not-after time */
    294    rv = DER_DecodeTimeChoice(notAfter, &validity.notAfter);
    295    if (rv) {
    296        return (SECFailure);
    297    }
    298 
    299    return (SECSuccess);
    300 }
    301 
    302 /*
    303 * is certa newer than certb?  If one is expired, pick the other one.
    304 */
    305 PRBool
    306 nsslowcert_IsNewer(NSSLOWCERTCertificate *certa, NSSLOWCERTCertificate *certb)
    307 {
    308    PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
    309    SECStatus rv;
    310    PRBool newerbefore, newerafter;
    311 
    312    rv = nsslowcert_GetCertTimes(certa, &notBeforeA, &notAfterA);
    313    if (rv != SECSuccess) {
    314        return (PR_FALSE);
    315    }
    316 
    317    rv = nsslowcert_GetCertTimes(certb, &notBeforeB, &notAfterB);
    318    if (rv != SECSuccess) {
    319        return (PR_TRUE);
    320    }
    321 
    322    newerbefore = PR_FALSE;
    323    if (LL_CMP(notBeforeA, >, notBeforeB)) {
    324        newerbefore = PR_TRUE;
    325    }
    326 
    327    newerafter = PR_FALSE;
    328    if (LL_CMP(notAfterA, >, notAfterB)) {
    329        newerafter = PR_TRUE;
    330    }
    331 
    332    if (newerbefore && newerafter) {
    333        return (PR_TRUE);
    334    }
    335 
    336    if ((!newerbefore) && (!newerafter)) {
    337        return (PR_FALSE);
    338    }
    339 
    340    /* get current time */
    341    now = PR_Now();
    342 
    343    if (newerbefore) {
    344        /* cert A was issued after cert B, but expires sooner */
    345        /* if A is expired, then pick B */
    346        if (LL_CMP(notAfterA, <, now)) {
    347            return (PR_FALSE);
    348        }
    349        return (PR_TRUE);
    350    } else {
    351        /* cert B was issued after cert A, but expires sooner */
    352        /* if B is expired, then pick A */
    353        if (LL_CMP(notAfterB, <, now)) {
    354            return (PR_TRUE);
    355        }
    356        return (PR_FALSE);
    357    }
    358 }
    359 
    360 #define SOFT_DEFAULT_CHUNKSIZE 2048
    361 
    362 static SECStatus
    363 nsslowcert_KeyFromIssuerAndSN(PLArenaPool *arena,
    364                              SECItem *issuer, SECItem *sn, SECItem *key)
    365 {
    366    unsigned int len = sn->len + issuer->len;
    367 
    368    if (!arena) {
    369        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    370        goto loser;
    371    }
    372    if (len > NSS_MAX_LEGACY_DB_KEY_SIZE) {
    373        PORT_SetError(SEC_ERROR_INPUT_LEN);
    374        goto loser;
    375    }
    376    key->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
    377    if (!key->data) {
    378        goto loser;
    379    }
    380 
    381    key->len = len;
    382    /* copy the serialNumber */
    383    PORT_Memcpy(key->data, sn->data, sn->len);
    384 
    385    /* copy the issuer */
    386    PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
    387 
    388    return (SECSuccess);
    389 
    390 loser:
    391    return (SECFailure);
    392 }
    393 
    394 static SECStatus
    395 nsslowcert_KeyFromIssuerAndSNStatic(unsigned char *space,
    396                                    int spaceLen, SECItem *issuer, SECItem *sn, SECItem *key)
    397 {
    398    unsigned int len = sn->len + issuer->len;
    399 
    400    key->data = pkcs11_allocStaticData(len, space, spaceLen);
    401    if (!key->data) {
    402        goto loser;
    403    }
    404 
    405    key->len = len;
    406    /* copy the serialNumber */
    407    PORT_Memcpy(key->data, sn->data, sn->len);
    408 
    409    /* copy the issuer */
    410    PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
    411 
    412    return (SECSuccess);
    413 
    414 loser:
    415    return (SECFailure);
    416 }
    417 
    418 static char *
    419 nsslowcert_EmailName(SECItem *derDN, char *space, unsigned int len)
    420 {
    421    unsigned char *buf;
    422    unsigned int buf_length;
    423 
    424    /* unwrap outer sequence */
    425    buf = nsslowcert_dataStart(derDN->data, derDN->len, &buf_length, PR_FALSE, NULL);
    426    if (buf == NULL)
    427        return NULL;
    428 
    429    /* Walk each RDN */
    430    while (buf_length > 0) {
    431        unsigned char *rdn;
    432        unsigned int rdn_length;
    433 
    434        /* grab next rdn */
    435        rdn = nsslowcert_dataStart(buf, buf_length, &rdn_length, PR_FALSE, NULL);
    436        if (rdn == NULL) {
    437            return NULL;
    438        }
    439        buf_length -= (rdn - buf) + rdn_length;
    440        buf = rdn + rdn_length;
    441 
    442        while (rdn_length > 0) {
    443            unsigned char *ava;
    444            unsigned int ava_length;
    445            unsigned char *oid;
    446            unsigned int oid_length;
    447            unsigned char *name;
    448            unsigned int name_length;
    449            SECItem oidItem;
    450            SECOidTag type;
    451 
    452            /* unwrap the ava */
    453            ava = nsslowcert_dataStart(rdn, rdn_length, &ava_length, PR_FALSE,
    454                                       NULL);
    455            if (ava == NULL)
    456                return NULL;
    457            rdn_length -= (ava - rdn) + ava_length;
    458            rdn = ava + ava_length;
    459 
    460            oid = nsslowcert_dataStart(ava, ava_length, &oid_length, PR_FALSE,
    461                                       NULL);
    462            if (oid == NULL) {
    463                return NULL;
    464            }
    465            ava_length -= (oid - ava) + oid_length;
    466            ava = oid + oid_length;
    467 
    468            name = nsslowcert_dataStart(ava, ava_length, &name_length, PR_FALSE,
    469                                        NULL);
    470            if (name == NULL) {
    471                return NULL;
    472            }
    473            ava_length -= (name - ava) + name_length;
    474            ava = name + name_length;
    475 
    476            oidItem.data = oid;
    477            oidItem.len = oid_length;
    478            type = SECOID_FindOIDTag(&oidItem);
    479            if ((type == SEC_OID_PKCS9_EMAIL_ADDRESS) ||
    480                (type == SEC_OID_RFC1274_MAIL)) {
    481                /* Email is supposed to be IA5String, so no
    482                 * translation necessary */
    483                char *emailAddr;
    484                emailAddr = (char *)pkcs11_copyStaticData(name, name_length + 1,
    485                                                          (unsigned char *)space, len);
    486                if (emailAddr) {
    487                    emailAddr[name_length] = 0;
    488                }
    489                return emailAddr;
    490            }
    491        }
    492    }
    493    return NULL;
    494 }
    495 
    496 static char *
    497 nsslowcert_EmailAltName(NSSLOWCERTCertificate *cert, char *space,
    498                        unsigned int len)
    499 {
    500    unsigned char *exts;
    501    unsigned int exts_length;
    502 
    503    /* unwrap the sequence */
    504    exts = nsslowcert_dataStart(cert->extensions.data, cert->extensions.len,
    505                                &exts_length, PR_FALSE, NULL);
    506    /* loop through extension */
    507    while (exts && exts_length > 0) {
    508        unsigned char *ext;
    509        unsigned int ext_length;
    510        unsigned char *oid;
    511        unsigned int oid_length;
    512        unsigned char *nameList;
    513        unsigned int nameList_length;
    514        SECItem oidItem;
    515        SECOidTag type;
    516 
    517        ext = nsslowcert_dataStart(exts, exts_length, &ext_length,
    518                                   PR_FALSE, NULL);
    519        if (ext == NULL) {
    520            break;
    521        }
    522        exts_length -= (ext - exts) + ext_length;
    523        exts = ext + ext_length;
    524 
    525        oid = nsslowcert_dataStart(ext, ext_length, &oid_length, PR_FALSE, NULL);
    526        if (oid == NULL) {
    527            break;
    528        }
    529        ext_length -= (oid - ext) + oid_length;
    530        ext = oid + oid_length;
    531        oidItem.data = oid;
    532        oidItem.len = oid_length;
    533        type = SECOID_FindOIDTag(&oidItem);
    534 
    535        /* get Alt Extension */
    536        if (type != SEC_OID_X509_SUBJECT_ALT_NAME) {
    537            continue;
    538        }
    539 
    540        /* skip passed the critical flag */
    541        if (ext[0] == 0x01) { /* BOOLEAN */
    542            unsigned char *dummy;
    543            unsigned int dummy_length;
    544            dummy = nsslowcert_dataStart(ext, ext_length, &dummy_length,
    545                                         PR_FALSE, NULL);
    546            if (dummy == NULL) {
    547                break;
    548            }
    549            ext_length -= (dummy - ext) + dummy_length;
    550            ext = dummy + dummy_length;
    551        }
    552 
    553        /* unwrap the name list */
    554        nameList = nsslowcert_dataStart(ext, ext_length, &nameList_length,
    555                                        PR_FALSE, NULL);
    556        if (nameList == NULL) {
    557            break;
    558        }
    559        ext_length -= (nameList - ext) + nameList_length;
    560        ext = nameList + nameList_length;
    561        nameList = nsslowcert_dataStart(nameList, nameList_length,
    562                                        &nameList_length, PR_FALSE, NULL);
    563        /* loop through the name list */
    564        while (nameList && nameList_length > 0) {
    565            unsigned char *thisName;
    566            unsigned int thisName_length;
    567 
    568            thisName = nsslowcert_dataStart(nameList, nameList_length,
    569                                            &thisName_length, PR_FALSE, NULL);
    570            if (thisName == NULL) {
    571                break;
    572            }
    573            if (nameList[0] == 0xa2) { /* DNS Name */
    574                SECItem dn;
    575                char *emailAddr;
    576 
    577                dn.data = thisName;
    578                dn.len = thisName_length;
    579                emailAddr = nsslowcert_EmailName(&dn, space, len);
    580                if (emailAddr) {
    581                    return emailAddr;
    582                }
    583            }
    584            if (nameList[0] == 0x81) { /* RFC 822name */
    585                char *emailAddr;
    586                emailAddr = (char *)pkcs11_copyStaticData(thisName,
    587                                                          thisName_length + 1, (unsigned char *)space, len);
    588                if (emailAddr) {
    589                    emailAddr[thisName_length] = 0;
    590                }
    591                return emailAddr;
    592            }
    593            nameList_length -= (thisName - nameList) + thisName_length;
    594            nameList = thisName + thisName_length;
    595        }
    596        break;
    597    }
    598    return NULL;
    599 }
    600 
    601 static char *
    602 nsslowcert_GetCertificateEmailAddress(NSSLOWCERTCertificate *cert)
    603 {
    604    char *emailAddr = NULL;
    605    char *str;
    606 
    607    emailAddr = nsslowcert_EmailName(&cert->derSubject, cert->emailAddrSpace,
    608                                     sizeof(cert->emailAddrSpace));
    609    /* couldn't find the email address in the DN, check the subject Alt name */
    610    if (!emailAddr && cert->extensions.data) {
    611        emailAddr = nsslowcert_EmailAltName(cert, cert->emailAddrSpace,
    612                                            sizeof(cert->emailAddrSpace));
    613    }
    614 
    615    /* make it lower case */
    616    str = emailAddr;
    617    while (str && *str) {
    618        *str = tolower((unsigned char)*str);
    619        str++;
    620    }
    621    return emailAddr;
    622 }
    623 
    624 /*
    625 * take a DER certificate and decode it into a certificate structure
    626 */
    627 NSSLOWCERTCertificate *
    628 nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname)
    629 {
    630    NSSLOWCERTCertificate *cert;
    631    int rv;
    632 
    633    /* allocate the certificate structure */
    634    cert = nsslowcert_CreateCert();
    635 
    636    if (!cert) {
    637        goto loser;
    638    }
    639 
    640    /* point to passed in DER data */
    641    cert->derCert = *derSignedCert;
    642    cert->nickname = NULL;
    643    cert->certKey.data = NULL;
    644    cert->referenceCount = 1;
    645 
    646    /* decode the certificate info */
    647    rv = nsslowcert_GetCertFields(cert->derCert.data, cert->derCert.len,
    648                                  &cert->derIssuer, &cert->serialNumber, &cert->derSN, &cert->derSubject,
    649                                  &cert->validity, &cert->derSubjKeyInfo, &cert->extensions);
    650 
    651    if (rv != SECSuccess) {
    652        goto loser;
    653    }
    654 
    655    /* cert->subjectKeyID;   x509v3 subject key identifier */
    656    cert->subjectKeyID.data = NULL;
    657    cert->subjectKeyID.len = 0;
    658    cert->dbEntry = NULL;
    659    cert->trust = NULL;
    660    cert->dbhandle = NULL;
    661 
    662    /* generate and save the database key for the cert */
    663    rv = nsslowcert_KeyFromIssuerAndSNStatic(cert->certKeySpace,
    664                                             sizeof(cert->certKeySpace), &cert->derIssuer,
    665                                             &cert->serialNumber, &cert->certKey);
    666    if (rv) {
    667        goto loser;
    668    }
    669 
    670    /* set the nickname */
    671    if (nickname == NULL) {
    672        cert->nickname = NULL;
    673    } else {
    674        /* copy and install the nickname */
    675        cert->nickname = pkcs11_copyNickname(nickname, cert->nicknameSpace,
    676                                             sizeof(cert->nicknameSpace));
    677    }
    678 
    679 #ifdef FIXME
    680    /* initialize the subjectKeyID */
    681    rv = cert_GetKeyID(cert);
    682    if (rv != SECSuccess) {
    683        goto loser;
    684    }
    685 #endif
    686 
    687    /* set the email address */
    688    cert->emailAddr = nsslowcert_GetCertificateEmailAddress(cert);
    689 
    690    cert->referenceCount = 1;
    691 
    692    return (cert);
    693 
    694 loser:
    695    if (cert) {
    696        nsslowcert_DestroyCertificate(cert);
    697    }
    698 
    699    return (0);
    700 }
    701 
    702 char *
    703 nsslowcert_FixupEmailAddr(char *emailAddr)
    704 {
    705    char *retaddr;
    706    char *str;
    707 
    708    if (emailAddr == NULL) {
    709        return (NULL);
    710    }
    711 
    712    /* copy the string */
    713    str = retaddr = PORT_Strdup(emailAddr);
    714    if (str == NULL) {
    715        return (NULL);
    716    }
    717 
    718    /* make it lower case */
    719    while (*str) {
    720        *str = tolower((unsigned char)*str);
    721        str++;
    722    }
    723 
    724    return (retaddr);
    725 }
    726 
    727 /*
    728 * Generate a database key, based on serial number and issuer, from a
    729 * DER certificate.
    730 */
    731 SECStatus
    732 nsslowcert_KeyFromDERCert(PLArenaPool *arena, SECItem *derCert, SECItem *key)
    733 {
    734    int rv;
    735    NSSLOWCERTCertKey certkey;
    736 
    737    PORT_Memset(&certkey, 0, sizeof(NSSLOWCERTCertKey));
    738 
    739    rv = nsslowcert_GetCertFields(derCert->data, derCert->len,
    740                                  &certkey.derIssuer, &certkey.serialNumber, NULL, NULL,
    741                                  NULL, NULL, NULL);
    742 
    743    if (rv) {
    744        goto loser;
    745    }
    746 
    747    return (nsslowcert_KeyFromIssuerAndSN(arena, &certkey.derIssuer,
    748                                          &certkey.serialNumber, key));
    749 loser:
    750    return (SECFailure);
    751 }
    752 
    753 NSSLOWKEYPublicKey *
    754 nsslowcert_ExtractPublicKey(NSSLOWCERTCertificate *cert)
    755 {
    756    NSSLOWCERTSubjectPublicKeyInfo spki;
    757    NSSLOWKEYPublicKey *pubk;
    758    SECItem os;
    759    SECStatus rv;
    760    PLArenaPool *arena;
    761    SECOidTag tag;
    762    SECItem newDerSubjKeyInfo;
    763 
    764    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    765    if (arena == NULL)
    766        return NULL;
    767 
    768    pubk = (NSSLOWKEYPublicKey *)
    769        PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPublicKey));
    770    if (pubk == NULL) {
    771        PORT_FreeArena(arena, PR_FALSE);
    772        return NULL;
    773    }
    774 
    775    pubk->arena = arena;
    776    PORT_Memset(&spki, 0, sizeof(spki));
    777 
    778    /* copy the DER into the arena, since Quick DER returns data that points
    779       into the DER input, which may get freed by the caller */
    780    rv = SECITEM_CopyItem(arena, &newDerSubjKeyInfo, &cert->derSubjKeyInfo);
    781    if (rv != SECSuccess) {
    782        PORT_FreeArena(arena, PR_FALSE);
    783        return NULL;
    784    }
    785 
    786    /* we haven't bothered decoding the spki struct yet, do it now */
    787    rv = SEC_QuickDERDecodeItem(arena, &spki,
    788                                nsslowcert_SubjectPublicKeyInfoTemplate, &newDerSubjKeyInfo);
    789    if (rv != SECSuccess) {
    790        PORT_FreeArena(arena, PR_FALSE);
    791        return NULL;
    792    }
    793 
    794    /* Convert bit string length from bits to bytes */
    795    os = spki.subjectPublicKey;
    796    DER_ConvertBitString(&os);
    797 
    798    tag = SECOID_GetAlgorithmTag(&spki.algorithm);
    799    switch (tag) {
    800        case SEC_OID_X500_RSA_ENCRYPTION:
    801        case SEC_OID_PKCS1_RSA_ENCRYPTION:
    802        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
    803            pubk->keyType = NSSLOWKEYRSAKey;
    804            prepare_low_rsa_pub_key_for_asn1(pubk);
    805            rv = SEC_QuickDERDecodeItem(arena, pubk,
    806                                        nsslowcert_RSAPublicKeyTemplate, &os);
    807            if (rv == SECSuccess)
    808                return pubk;
    809            break;
    810        case SEC_OID_ANSIX9_DSA_SIGNATURE:
    811            pubk->keyType = NSSLOWKEYDSAKey;
    812            prepare_low_dsa_pub_key_for_asn1(pubk);
    813            rv = SEC_QuickDERDecodeItem(arena, pubk,
    814                                        nsslowcert_DSAPublicKeyTemplate, &os);
    815            if (rv == SECSuccess)
    816                return pubk;
    817            break;
    818        case SEC_OID_X942_DIFFIE_HELMAN_KEY:
    819            pubk->keyType = NSSLOWKEYDHKey;
    820            prepare_low_dh_pub_key_for_asn1(pubk);
    821            rv = SEC_QuickDERDecodeItem(arena, pubk,
    822                                        nsslowcert_DHPublicKeyTemplate, &os);
    823            if (rv == SECSuccess)
    824                return pubk;
    825            break;
    826        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
    827            pubk->keyType = NSSLOWKEYECKey;
    828            /* Since PKCS#11 directly takes the DER encoding of EC params
    829             * and public value, we don't need any decoding here.
    830             */
    831            rv = SECITEM_CopyItem(arena, &pubk->u.ec.ecParams.DEREncoding,
    832                                  &spki.algorithm.parameters);
    833            if (rv != SECSuccess)
    834                break;
    835 
    836            /* Fill out the rest of the ecParams structure
    837             * based on the encoded params
    838             */
    839            if (LGEC_FillParams(arena, &pubk->u.ec.ecParams.DEREncoding,
    840                                &pubk->u.ec.ecParams) != SECSuccess)
    841                break;
    842 
    843            rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &os);
    844            if (rv == SECSuccess)
    845                return pubk;
    846            break;
    847        default:
    848            rv = SECFailure;
    849            break;
    850    }
    851 
    852    lg_nsslowkey_DestroyPublicKey(pubk);
    853    return NULL;
    854 }