tor-browser

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

certdb.c (98367B)


      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 "nssilock.h"
     10 #include "prmon.h"
     11 #include "prtime.h"
     12 #include "cert.h"
     13 #include "certi.h"
     14 #include "secder.h"
     15 #include "secoid.h"
     16 #include "secasn1.h"
     17 #include "genname.h"
     18 #include "keyhi.h"
     19 #include "secitem.h"
     20 #include "certdb.h"
     21 #include "prprf.h"
     22 #include "sechash.h"
     23 #include "prlong.h"
     24 #include "certxutl.h"
     25 #include "portreg.h"
     26 #include "secerr.h"
     27 #include "sslerr.h"
     28 #include "pk11func.h"
     29 #include "xconst.h" /* for  CERT_DecodeAltNameExtension */
     30 
     31 #include "pki.h"
     32 #include "pki3hack.h"
     33 
     34 SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
     35 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
     36 SEC_ASN1_MKSUB(SEC_BitStringTemplate)
     37 SEC_ASN1_MKSUB(SEC_IntegerTemplate)
     38 SEC_ASN1_MKSUB(SEC_SkipTemplate)
     39 
     40 /*
     41 * Certificate database handling code
     42 */
     43 
     44 const SEC_ASN1Template CERT_CertExtensionTemplate[] = {
     45    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertExtension) },
     46    { SEC_ASN1_OBJECT_ID, offsetof(CERTCertExtension, id) },
     47    { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
     48      offsetof(CERTCertExtension, critical) },
     49    { SEC_ASN1_OCTET_STRING, offsetof(CERTCertExtension, value) },
     50    { 0 }
     51 };
     52 
     53 const SEC_ASN1Template CERT_SequenceOfCertExtensionTemplate[] = {
     54    { SEC_ASN1_SEQUENCE_OF, 0, CERT_CertExtensionTemplate }
     55 };
     56 
     57 const SEC_ASN1Template CERT_TimeChoiceTemplate[] = {
     58    { SEC_ASN1_CHOICE, offsetof(SECItem, type), 0, sizeof(SECItem) },
     59    { SEC_ASN1_UTC_TIME, 0, 0, siUTCTime },
     60    { SEC_ASN1_GENERALIZED_TIME, 0, 0, siGeneralizedTime },
     61    { 0 }
     62 };
     63 
     64 const SEC_ASN1Template CERT_ValidityTemplate[] = {
     65    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTValidity) },
     66    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTValidity, notBefore),
     67      SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
     68    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTValidity, notAfter),
     69      SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
     70    { 0 }
     71 };
     72 
     73 const SEC_ASN1Template CERT_CertificateTemplate[] = {
     74    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificate) },
     75    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
     76          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, /* XXX DER_DEFAULT */
     77      offsetof(CERTCertificate, version),
     78      SEC_ASN1_SUB(SEC_IntegerTemplate) },
     79    { SEC_ASN1_INTEGER, offsetof(CERTCertificate, serialNumber) },
     80    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCertificate, signature),
     81      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
     82    { SEC_ASN1_SAVE, offsetof(CERTCertificate, derIssuer) },
     83    { SEC_ASN1_INLINE, offsetof(CERTCertificate, issuer), CERT_NameTemplate },
     84    { SEC_ASN1_INLINE, offsetof(CERTCertificate, validity),
     85      CERT_ValidityTemplate },
     86    { SEC_ASN1_SAVE, offsetof(CERTCertificate, derSubject) },
     87    { SEC_ASN1_INLINE, offsetof(CERTCertificate, subject), CERT_NameTemplate },
     88    { SEC_ASN1_SAVE, offsetof(CERTCertificate, derPublicKey) },
     89    { SEC_ASN1_INLINE, offsetof(CERTCertificate, subjectPublicKeyInfo),
     90      CERT_SubjectPublicKeyInfoTemplate },
     91    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
     92      offsetof(CERTCertificate, issuerID),
     93      SEC_ASN1_SUB(SEC_BitStringTemplate) },
     94    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
     95      offsetof(CERTCertificate, subjectID),
     96      SEC_ASN1_SUB(SEC_BitStringTemplate) },
     97    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
     98          SEC_ASN1_CONTEXT_SPECIFIC | 3,
     99      offsetof(CERTCertificate, extensions),
    100      CERT_SequenceOfCertExtensionTemplate },
    101    { 0 }
    102 };
    103 
    104 const SEC_ASN1Template SEC_SignedCertificateTemplate[] = {
    105    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificate) },
    106    { SEC_ASN1_SAVE, offsetof(CERTCertificate, signatureWrap.data) },
    107    { SEC_ASN1_INLINE, 0, CERT_CertificateTemplate },
    108    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    109      offsetof(CERTCertificate, signatureWrap.signatureAlgorithm),
    110      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
    111    { SEC_ASN1_BIT_STRING, offsetof(CERTCertificate, signatureWrap.signature) },
    112    { 0 }
    113 };
    114 
    115 /*
    116 * Find the subjectName in a DER encoded certificate
    117 */
    118 const SEC_ASN1Template SEC_CertSubjectTemplate[] = {
    119    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
    120    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
    121          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
    122      0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
    123    { SEC_ASN1_SKIP },                     /* serial number */
    124    { SEC_ASN1_SKIP },                     /* signature algorithm */
    125    { SEC_ASN1_SKIP },                     /* issuer */
    126    { SEC_ASN1_SKIP },                     /* validity */
    127    { SEC_ASN1_ANY, 0, NULL },             /* subject */
    128    { SEC_ASN1_SKIP_REST },
    129    { 0 }
    130 };
    131 
    132 /*
    133 * Find the issuerName in a DER encoded certificate
    134 */
    135 const SEC_ASN1Template SEC_CertIssuerTemplate[] = {
    136    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
    137    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
    138          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
    139      0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
    140    { SEC_ASN1_SKIP },                     /* serial number */
    141    { SEC_ASN1_SKIP },                     /* signature algorithm */
    142    { SEC_ASN1_ANY, 0, NULL },             /* issuer */
    143    { SEC_ASN1_SKIP_REST },
    144    { 0 }
    145 };
    146 /*
    147 * Find the subjectName in a DER encoded certificate
    148 */
    149 const SEC_ASN1Template SEC_CertSerialNumberTemplate[] = {
    150    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
    151    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
    152          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
    153      0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
    154    { SEC_ASN1_ANY, 0, NULL },             /* serial number */
    155    { SEC_ASN1_SKIP_REST },
    156    { 0 }
    157 };
    158 
    159 /*
    160 * Find the issuer and serialNumber in a DER encoded certificate.
    161 * This data is used as the database lookup key since its the unique
    162 * identifier of a certificate.
    163 */
    164 const SEC_ASN1Template CERT_CertKeyTemplate[] = {
    165    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertKey) },
    166    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
    167          SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
    168      0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
    169    { SEC_ASN1_INTEGER, offsetof(CERTCertKey, serialNumber) },
    170    { SEC_ASN1_SKIP }, /* signature algorithm */
    171    { SEC_ASN1_ANY, offsetof(CERTCertKey, derIssuer) },
    172    { SEC_ASN1_SKIP_REST },
    173    { 0 }
    174 };
    175 
    176 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_TimeChoiceTemplate)
    177 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateTemplate)
    178 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SignedCertificateTemplate)
    179 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SequenceOfCertExtensionTemplate)
    180 
    181 SECStatus
    182 CERT_KeyFromIssuerAndSN(PLArenaPool *arena, SECItem *issuer, SECItem *sn,
    183                        SECItem *key)
    184 {
    185    key->len = sn->len + issuer->len;
    186 
    187    if ((sn->data == NULL) || (issuer->data == NULL)) {
    188        goto loser;
    189    }
    190 
    191    key->data = (unsigned char *)PORT_ArenaAlloc(arena, key->len);
    192    if (!key->data) {
    193        goto loser;
    194    }
    195 
    196    /* copy the serialNumber */
    197    PORT_Memcpy(key->data, sn->data, sn->len);
    198 
    199    /* copy the issuer */
    200    PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
    201 
    202    return (SECSuccess);
    203 
    204 loser:
    205    return (SECFailure);
    206 }
    207 
    208 /*
    209 * Extract the subject name from a DER certificate
    210 */
    211 SECStatus
    212 CERT_NameFromDERCert(SECItem *derCert, SECItem *derName)
    213 {
    214    int rv;
    215    PLArenaPool *arena;
    216    CERTSignedData sd;
    217    void *tmpptr;
    218 
    219    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    220 
    221    if (!arena) {
    222        return (SECFailure);
    223    }
    224 
    225    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
    226    rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
    227 
    228    if (rv) {
    229        goto loser;
    230    }
    231 
    232    PORT_Memset(derName, 0, sizeof(SECItem));
    233    rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSubjectTemplate,
    234                                &sd.data);
    235 
    236    if (rv) {
    237        goto loser;
    238    }
    239 
    240    tmpptr = derName->data;
    241    derName->data = (unsigned char *)PORT_Alloc(derName->len);
    242    if (derName->data == NULL) {
    243        goto loser;
    244    }
    245 
    246    PORT_Memcpy(derName->data, tmpptr, derName->len);
    247 
    248    PORT_FreeArena(arena, PR_FALSE);
    249    return (SECSuccess);
    250 
    251 loser:
    252    PORT_FreeArena(arena, PR_FALSE);
    253    return (SECFailure);
    254 }
    255 
    256 SECStatus
    257 CERT_IssuerNameFromDERCert(SECItem *derCert, SECItem *derName)
    258 {
    259    int rv;
    260    PORTCheapArenaPool tmpArena;
    261    CERTSignedData sd;
    262    void *tmpptr;
    263 
    264    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
    265 
    266    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
    267    rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &sd, CERT_SignedDataTemplate,
    268                                derCert);
    269    if (rv) {
    270        goto loser;
    271    }
    272 
    273    PORT_Memset(derName, 0, sizeof(SECItem));
    274    rv = SEC_QuickDERDecodeItem(&tmpArena.arena, derName,
    275                                SEC_CertIssuerTemplate, &sd.data);
    276    if (rv) {
    277        goto loser;
    278    }
    279 
    280    tmpptr = derName->data;
    281    derName->data = (unsigned char *)PORT_Alloc(derName->len);
    282    if (derName->data == NULL) {
    283        goto loser;
    284    }
    285 
    286    PORT_Memcpy(derName->data, tmpptr, derName->len);
    287 
    288    PORT_DestroyCheapArena(&tmpArena);
    289    return (SECSuccess);
    290 
    291 loser:
    292    PORT_DestroyCheapArena(&tmpArena);
    293    return (SECFailure);
    294 }
    295 
    296 SECStatus
    297 CERT_SerialNumberFromDERCert(SECItem *derCert, SECItem *derName)
    298 {
    299    int rv;
    300    PORTCheapArenaPool tmpArena;
    301    CERTSignedData sd;
    302    void *tmpptr;
    303 
    304    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
    305 
    306    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
    307    rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &sd, CERT_SignedDataTemplate,
    308                                derCert);
    309    if (rv) {
    310        goto loser;
    311    }
    312 
    313    PORT_Memset(derName, 0, sizeof(SECItem));
    314    rv = SEC_QuickDERDecodeItem(&tmpArena.arena, derName,
    315                                SEC_CertSerialNumberTemplate, &sd.data);
    316    if (rv) {
    317        goto loser;
    318    }
    319 
    320    tmpptr = derName->data;
    321    derName->data = (unsigned char *)PORT_Alloc(derName->len);
    322    if (derName->data == NULL) {
    323        goto loser;
    324    }
    325 
    326    PORT_Memcpy(derName->data, tmpptr, derName->len);
    327 
    328    PORT_DestroyCheapArena(&tmpArena);
    329    return (SECSuccess);
    330 
    331 loser:
    332    PORT_DestroyCheapArena(&tmpArena);
    333    return (SECFailure);
    334 }
    335 
    336 /*
    337 * Generate a database key, based on serial number and issuer, from a
    338 * DER certificate.
    339 */
    340 SECStatus
    341 CERT_KeyFromDERCert(PLArenaPool *reqArena, SECItem *derCert, SECItem *key)
    342 {
    343    int rv;
    344    CERTSignedData sd;
    345    CERTCertKey certkey;
    346 
    347    if (!reqArena) {
    348        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    349        return SECFailure;
    350    }
    351 
    352    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
    353    rv =
    354        SEC_QuickDERDecodeItem(reqArena, &sd, CERT_SignedDataTemplate, derCert);
    355 
    356    if (rv) {
    357        goto loser;
    358    }
    359 
    360    PORT_Memset(&certkey, 0, sizeof(CERTCertKey));
    361    rv = SEC_QuickDERDecodeItem(reqArena, &certkey, CERT_CertKeyTemplate,
    362                                &sd.data);
    363 
    364    if (rv) {
    365        goto loser;
    366    }
    367 
    368    return (CERT_KeyFromIssuerAndSN(reqArena, &certkey.derIssuer,
    369                                    &certkey.serialNumber, key));
    370 loser:
    371    return (SECFailure);
    372 }
    373 
    374 /*
    375 * fill in keyUsage field of the cert based on the cert extension
    376 * if the extension is not critical, then we allow all uses
    377 */
    378 static SECStatus
    379 GetKeyUsage(CERTCertificate *cert)
    380 {
    381    SECStatus rv;
    382    SECItem tmpitem;
    383 
    384    rv = CERT_FindKeyUsageExtension(cert, &tmpitem);
    385    if (rv == SECSuccess) {
    386        /* remember the actual value of the extension */
    387        cert->rawKeyUsage = tmpitem.len ? tmpitem.data[0] : 0;
    388        cert->keyUsagePresent = PR_TRUE;
    389        cert->keyUsage = cert->rawKeyUsage;
    390 
    391        PORT_Free(tmpitem.data);
    392        tmpitem.data = NULL;
    393    } else {
    394        /* if the extension is not present, then we allow all uses */
    395        cert->keyUsage = KU_ALL;
    396        cert->rawKeyUsage = KU_ALL;
    397        cert->keyUsagePresent = PR_FALSE;
    398    }
    399 
    400    if (CERT_GovtApprovedBitSet(cert)) {
    401        cert->keyUsage |= KU_NS_GOVT_APPROVED;
    402        cert->rawKeyUsage |= KU_NS_GOVT_APPROVED;
    403    }
    404 
    405    return (SECSuccess);
    406 }
    407 
    408 static SECStatus
    409 findOIDinOIDSeqByTagNum(CERTOidSequence *seq, SECOidTag tagnum)
    410 {
    411    SECItem **oids;
    412    SECItem *oid;
    413    SECStatus rv = SECFailure;
    414 
    415    if (seq != NULL) {
    416        oids = seq->oids;
    417        while (oids != NULL && *oids != NULL) {
    418            oid = *oids;
    419            if (SECOID_FindOIDTag(oid) == tagnum) {
    420                rv = SECSuccess;
    421                break;
    422            }
    423            oids++;
    424        }
    425    }
    426    return rv;
    427 }
    428 
    429 /*
    430 * fill in nsCertType field of the cert based on the cert extension
    431 */
    432 SECStatus
    433 cert_GetCertType(CERTCertificate *cert)
    434 {
    435    PRUint32 nsCertType;
    436 
    437    if (cert->nsCertType) {
    438        /* once set, no need to recalculate */
    439        return SECSuccess;
    440    }
    441    nsCertType = cert_ComputeCertType(cert);
    442 
    443    /* Assert that it is safe to cast &cert->nsCertType to "PRInt32 *" */
    444    PORT_Assert(sizeof(cert->nsCertType) == sizeof(PRInt32));
    445    PR_ATOMIC_SET((PRInt32 *)&cert->nsCertType, nsCertType);
    446    return SECSuccess;
    447 }
    448 
    449 PRBool
    450 cert_IsIPsecOID(CERTOidSequence *extKeyUsage)
    451 {
    452    if (findOIDinOIDSeqByTagNum(
    453            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_IKE) == SECSuccess) {
    454        return PR_TRUE;
    455    }
    456    if (findOIDinOIDSeqByTagNum(
    457            extKeyUsage, SEC_OID_IPSEC_IKE_END) == SECSuccess) {
    458        return PR_TRUE;
    459    }
    460    if (findOIDinOIDSeqByTagNum(
    461            extKeyUsage, SEC_OID_IPSEC_IKE_INTERMEDIATE) == SECSuccess) {
    462        return PR_TRUE;
    463    }
    464    /* these are now deprecated, but may show up. Treat them the same as IKE */
    465    if (findOIDinOIDSeqByTagNum(
    466            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_END) == SECSuccess) {
    467        return PR_TRUE;
    468    }
    469    if (findOIDinOIDSeqByTagNum(
    470            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL) == SECSuccess) {
    471        return PR_TRUE;
    472    }
    473    if (findOIDinOIDSeqByTagNum(
    474            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_USER) == SECSuccess) {
    475        return PR_TRUE;
    476    }
    477    /* this one should probably be in cert_ComputeCertType and set all usages? */
    478    if (findOIDinOIDSeqByTagNum(
    479            extKeyUsage, SEC_OID_X509_ANY_EXT_KEY_USAGE) == SECSuccess) {
    480        return PR_TRUE;
    481    }
    482    return PR_FALSE;
    483 }
    484 
    485 PRUint32
    486 cert_ComputeCertType(CERTCertificate *cert)
    487 {
    488    SECStatus rv;
    489    SECItem tmpitem;
    490    SECItem encodedExtKeyUsage;
    491    CERTOidSequence *extKeyUsage = NULL;
    492    CERTBasicConstraints basicConstraint;
    493    PRUint32 nsCertType = 0;
    494    PRBool isCA = PR_FALSE;
    495 
    496    tmpitem.data = NULL;
    497    CERT_FindNSCertTypeExtension(cert, &tmpitem);
    498    encodedExtKeyUsage.data = NULL;
    499    rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE,
    500                                &encodedExtKeyUsage);
    501    if (rv == SECSuccess) {
    502        extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);
    503    }
    504    rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
    505    if (rv == SECSuccess) {
    506        isCA = basicConstraint.isCA;
    507    }
    508    if (tmpitem.data != NULL || extKeyUsage != NULL) {
    509        if (tmpitem.data == NULL || tmpitem.len == 0) {
    510            nsCertType = 0;
    511        } else {
    512            nsCertType = tmpitem.data[0];
    513        }
    514 
    515        /* free tmpitem data pointer to avoid memory leak */
    516        PORT_Free(tmpitem.data);
    517        tmpitem.data = NULL;
    518 
    519        /*
    520         * for this release, we will allow SSL certs with an email address
    521         * to be used for email
    522         */
    523        if ((nsCertType & NS_CERT_TYPE_SSL_CLIENT) && cert->emailAddr &&
    524            cert->emailAddr[0]) {
    525            nsCertType |= NS_CERT_TYPE_EMAIL;
    526        }
    527        /*
    528         * for this release, we will allow SSL intermediate CAs to be
    529         * email intermediate CAs too.
    530         */
    531        if (nsCertType & NS_CERT_TYPE_SSL_CA) {
    532            nsCertType |= NS_CERT_TYPE_EMAIL_CA;
    533        }
    534        /*
    535         * allow a cert with the extended key usage of EMail Protect
    536         * to be used for email or as an email CA, if basic constraints
    537         * indicates that it is a CA.
    538         */
    539        if (findOIDinOIDSeqByTagNum(extKeyUsage,
    540                                    SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT) ==
    541            SECSuccess) {
    542            nsCertType |= isCA ? NS_CERT_TYPE_EMAIL_CA : NS_CERT_TYPE_EMAIL;
    543        }
    544        if (findOIDinOIDSeqByTagNum(
    545                extKeyUsage, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) == SECSuccess) {
    546            nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_SERVER;
    547        }
    548        /*
    549         * Treat certs with step-up OID as also having SSL server type.
    550         * COMODO needs this behaviour until June 2020.  See Bug 737802.
    551         */
    552        if (findOIDinOIDSeqByTagNum(extKeyUsage,
    553                                    SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) ==
    554            SECSuccess) {
    555            nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_SERVER;
    556        }
    557        if (findOIDinOIDSeqByTagNum(
    558                extKeyUsage, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH) == SECSuccess) {
    559            nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_CLIENT;
    560        }
    561        if (cert_IsIPsecOID(extKeyUsage)) {
    562            nsCertType |= isCA ? NS_CERT_TYPE_IPSEC_CA : NS_CERT_TYPE_IPSEC;
    563        }
    564        if (findOIDinOIDSeqByTagNum(
    565                extKeyUsage, SEC_OID_EXT_KEY_USAGE_CODE_SIGN) == SECSuccess) {
    566            nsCertType |= isCA ? NS_CERT_TYPE_OBJECT_SIGNING_CA : NS_CERT_TYPE_OBJECT_SIGNING;
    567        }
    568        if (findOIDinOIDSeqByTagNum(
    569                extKeyUsage, SEC_OID_EXT_KEY_USAGE_TIME_STAMP) == SECSuccess) {
    570            nsCertType |= EXT_KEY_USAGE_TIME_STAMP;
    571        }
    572        if (findOIDinOIDSeqByTagNum(extKeyUsage, SEC_OID_OCSP_RESPONDER) ==
    573            SECSuccess) {
    574            nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
    575        }
    576    } else {
    577        /* If no NS Cert Type extension and no EKU extension, then */
    578        nsCertType = 0;
    579        if (CERT_IsCACert(cert, &nsCertType))
    580            nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
    581        /* if the basic constraint extension says the cert is a CA, then
    582           allow SSL CA and EMAIL CA and Status Responder */
    583        if (isCA) {
    584            nsCertType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
    585                           EXT_KEY_USAGE_STATUS_RESPONDER);
    586        }
    587        /* allow any ssl or email (no ca or object signing. */
    588        nsCertType |= NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER |
    589                      NS_CERT_TYPE_EMAIL;
    590    }
    591 
    592    /* IPSEC is allowed to use SSL client and server certs as well as email certs */
    593    if (nsCertType & (NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_EMAIL)) {
    594        nsCertType |= NS_CERT_TYPE_IPSEC;
    595    }
    596    if (nsCertType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA)) {
    597        nsCertType |= NS_CERT_TYPE_IPSEC_CA;
    598    }
    599 
    600    if (encodedExtKeyUsage.data != NULL) {
    601        PORT_Free(encodedExtKeyUsage.data);
    602    }
    603    if (extKeyUsage != NULL) {
    604        CERT_DestroyOidSequence(extKeyUsage);
    605    }
    606    return nsCertType;
    607 }
    608 
    609 /*
    610 * cert_GetKeyID() - extract or generate the subjectKeyID from a certificate
    611 */
    612 SECStatus
    613 cert_GetKeyID(CERTCertificate *cert)
    614 {
    615    SECItem tmpitem;
    616    SECStatus rv;
    617 
    618    cert->subjectKeyID.len = 0;
    619 
    620    /* see of the cert has a key identifier extension */
    621    rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
    622    if (rv == SECSuccess) {
    623        cert->subjectKeyID.data =
    624            (unsigned char *)PORT_ArenaAlloc(cert->arena, tmpitem.len);
    625        if (cert->subjectKeyID.data != NULL) {
    626            PORT_Memcpy(cert->subjectKeyID.data, tmpitem.data, tmpitem.len);
    627            cert->subjectKeyID.len = tmpitem.len;
    628            cert->keyIDGenerated = PR_FALSE;
    629        }
    630 
    631        PORT_Free(tmpitem.data);
    632    }
    633 
    634    /* if the cert doesn't have a key identifier extension, then generate one*/
    635    if (cert->subjectKeyID.len == 0) {
    636        /*
    637         * pkix says that if the subjectKeyID is not present, then we should
    638         * use the SHA-1 hash of the DER-encoded publicKeyInfo from the cert
    639         */
    640        cert->subjectKeyID.data =
    641            (unsigned char *)PORT_ArenaAlloc(cert->arena, SHA1_LENGTH);
    642        if (cert->subjectKeyID.data != NULL) {
    643            rv = PK11_HashBuf(SEC_OID_SHA1, cert->subjectKeyID.data,
    644                              cert->derPublicKey.data, cert->derPublicKey.len);
    645            if (rv == SECSuccess) {
    646                cert->subjectKeyID.len = SHA1_LENGTH;
    647            }
    648        }
    649    }
    650 
    651    if (cert->subjectKeyID.len == 0) {
    652        return (SECFailure);
    653    }
    654    return (SECSuccess);
    655 }
    656 
    657 static PRBool
    658 cert_IsRootCert(CERTCertificate *cert)
    659 {
    660    SECStatus rv;
    661    SECItem tmpitem;
    662 
    663    /* cache the authKeyID extension, if present */
    664    cert->authKeyID = CERT_FindAuthKeyIDExten(cert->arena, cert);
    665 
    666    /* it MUST be self-issued to be a root */
    667    if (cert->derIssuer.len == 0 ||
    668        !SECITEM_ItemsAreEqual(&cert->derIssuer, &cert->derSubject)) {
    669        return PR_FALSE;
    670    }
    671 
    672    /* check the authKeyID extension */
    673    if (cert->authKeyID) {
    674        /* authority key identifier is present */
    675        if (cert->authKeyID->keyID.len > 0) {
    676            /* the keyIdentifier field is set, look for subjectKeyID */
    677            rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
    678            if (rv == SECSuccess) {
    679                PRBool match;
    680                /* also present, they MUST match for it to be a root */
    681                match =
    682                    SECITEM_ItemsAreEqual(&cert->authKeyID->keyID, &tmpitem);
    683                PORT_Free(tmpitem.data);
    684                if (!match)
    685                    return PR_FALSE; /* else fall through */
    686            } else {
    687                /* the subject key ID is required when AKI is present */
    688                return PR_FALSE;
    689            }
    690        }
    691        if (cert->authKeyID->authCertIssuer) {
    692            SECItem *caName;
    693            caName = (SECItem *)CERT_GetGeneralNameByType(
    694                cert->authKeyID->authCertIssuer, certDirectoryName, PR_TRUE);
    695            if (caName) {
    696                if (!SECITEM_ItemsAreEqual(&cert->derIssuer, caName)) {
    697                    return PR_FALSE;
    698                } /* else fall through */
    699            }     /* else ??? could not get general name as directory name? */
    700        }
    701        if (cert->authKeyID->authCertSerialNumber.len > 0) {
    702            if (!SECITEM_ItemsAreEqual(
    703                    &cert->serialNumber,
    704                    &cert->authKeyID->authCertSerialNumber)) {
    705                return PR_FALSE;
    706            } /* else fall through */
    707        }
    708        /* all of the AKI fields that were present passed the test */
    709        return PR_TRUE;
    710    }
    711    /* else the AKI was not present, so this is a root */
    712    return PR_TRUE;
    713 }
    714 
    715 /*
    716 * take a DER certificate and decode it into a certificate structure
    717 */
    718 CERTCertificate *
    719 CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
    720                          char *nickname)
    721 {
    722    CERTCertificate *cert;
    723    PLArenaPool *arena;
    724    void *data;
    725    int rv;
    726    int len;
    727    char *tmpname;
    728 
    729    /* make a new arena */
    730    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    731 
    732    if (!arena) {
    733        return 0;
    734    }
    735 
    736    /* allocate the certificate structure */
    737    cert = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
    738 
    739    if (!cert) {
    740        goto loser;
    741    }
    742 
    743    cert->arena = arena;
    744 
    745    if (copyDER) {
    746        /* copy the DER data for the cert into this arena */
    747        data = (void *)PORT_ArenaAlloc(arena, derSignedCert->len);
    748        if (!data) {
    749            goto loser;
    750        }
    751        cert->derCert.data = (unsigned char *)data;
    752        cert->derCert.len = derSignedCert->len;
    753        PORT_Memcpy(data, derSignedCert->data, derSignedCert->len);
    754    } else {
    755        /* point to passed in DER data */
    756        cert->derCert = *derSignedCert;
    757    }
    758 
    759    /* decode the certificate info */
    760    rv = SEC_QuickDERDecodeItem(arena, cert, SEC_SignedCertificateTemplate,
    761                                &cert->derCert);
    762 
    763    if (rv) {
    764        goto loser;
    765    }
    766 
    767    if (cert_HasUnknownCriticalExten(cert->extensions) == PR_TRUE) {
    768        cert->options.bits.hasUnsupportedCriticalExt = PR_TRUE;
    769    }
    770 
    771    /* generate and save the database key for the cert */
    772    rv = CERT_KeyFromIssuerAndSN(arena, &cert->derIssuer, &cert->serialNumber,
    773                                 &cert->certKey);
    774    if (rv) {
    775        goto loser;
    776    }
    777 
    778    /* set the nickname */
    779    if (nickname == NULL) {
    780        cert->nickname = NULL;
    781    } else {
    782        /* copy and install the nickname */
    783        len = PORT_Strlen(nickname) + 1;
    784        cert->nickname = (char *)PORT_ArenaAlloc(arena, len);
    785        if (cert->nickname == NULL) {
    786            goto loser;
    787        }
    788 
    789        PORT_Memcpy(cert->nickname, nickname, len);
    790    }
    791 
    792    /* set the email address */
    793    cert->emailAddr = cert_GetCertificateEmailAddresses(cert);
    794 
    795    /* initialize the subjectKeyID */
    796    rv = cert_GetKeyID(cert);
    797    if (rv != SECSuccess) {
    798        goto loser;
    799    }
    800 
    801    /* initialize keyUsage */
    802    rv = GetKeyUsage(cert);
    803    if (rv != SECSuccess) {
    804        goto loser;
    805    }
    806 
    807    /* determine if this is a root cert */
    808    cert->isRoot = cert_IsRootCert(cert);
    809 
    810    /* initialize the certType */
    811    rv = cert_GetCertType(cert);
    812    if (rv != SECSuccess) {
    813        goto loser;
    814    }
    815 
    816    tmpname = CERT_NameToAscii(&cert->subject);
    817    if (tmpname != NULL) {
    818        cert->subjectName = PORT_ArenaStrdup(cert->arena, tmpname);
    819        PORT_Free(tmpname);
    820    }
    821 
    822    tmpname = CERT_NameToAscii(&cert->issuer);
    823    if (tmpname != NULL) {
    824        cert->issuerName = PORT_ArenaStrdup(cert->arena, tmpname);
    825        PORT_Free(tmpname);
    826    }
    827 
    828    cert->referenceCount = 1;
    829    cert->slot = NULL;
    830    cert->pkcs11ID = CK_INVALID_HANDLE;
    831    cert->dbnickname = NULL;
    832 
    833    return (cert);
    834 
    835 loser:
    836 
    837    if (arena) {
    838        PORT_FreeArena(arena, PR_FALSE);
    839    }
    840 
    841    return (0);
    842 }
    843 
    844 CERTCertificate *
    845 __CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
    846                            char *nickname)
    847 {
    848    return CERT_DecodeDERCertificate(derSignedCert, copyDER, nickname);
    849 }
    850 
    851 CERTValidity *
    852 CERT_CreateValidity(PRTime notBefore, PRTime notAfter)
    853 {
    854    CERTValidity *v;
    855    int rv;
    856    PLArenaPool *arena;
    857 
    858    if (notBefore > notAfter) {
    859        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    860        return NULL;
    861    }
    862    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    863 
    864    if (!arena) {
    865        return (0);
    866    }
    867 
    868    v = (CERTValidity *)PORT_ArenaZAlloc(arena, sizeof(CERTValidity));
    869    if (v) {
    870        v->arena = arena;
    871        rv = DER_EncodeTimeChoice(arena, &v->notBefore, notBefore);
    872        if (rv)
    873            goto loser;
    874        rv = DER_EncodeTimeChoice(arena, &v->notAfter, notAfter);
    875        if (rv)
    876            goto loser;
    877    }
    878    return v;
    879 
    880 loser:
    881    CERT_DestroyValidity(v);
    882    return 0;
    883 }
    884 
    885 SECStatus
    886 CERT_CopyValidity(PLArenaPool *arena, CERTValidity *to, CERTValidity *from)
    887 {
    888    SECStatus rv;
    889 
    890    CERT_DestroyValidity(to);
    891    to->arena = arena;
    892 
    893    rv = SECITEM_CopyItem(arena, &to->notBefore, &from->notBefore);
    894    if (rv)
    895        return rv;
    896    rv = SECITEM_CopyItem(arena, &to->notAfter, &from->notAfter);
    897    return rv;
    898 }
    899 
    900 void
    901 CERT_DestroyValidity(CERTValidity *v)
    902 {
    903    if (v && v->arena) {
    904        PORT_FreeArena(v->arena, PR_FALSE);
    905    }
    906    return;
    907 }
    908 
    909 /*
    910 ** Amount of time that a certifiate is allowed good before it is actually
    911 ** good. This is used for pending certificates, ones that are about to be
    912 ** valid. The slop is designed to allow for some variance in the clocks
    913 ** of the machine checking the certificate.
    914 */
    915 #define PENDING_SLOP (24L * 60L * 60L)     /* seconds per day */
    916 static PRInt32 pendingSlop = PENDING_SLOP; /* seconds */
    917 
    918 PRInt32
    919 CERT_GetSlopTime(void)
    920 {
    921    return pendingSlop; /* seconds */
    922 }
    923 
    924 SECStatus
    925 CERT_SetSlopTime(PRInt32 slop) /* seconds */
    926 {
    927    if (slop < 0)
    928        return SECFailure;
    929    pendingSlop = slop;
    930    return SECSuccess;
    931 }
    932 
    933 SECStatus
    934 CERT_GetCertTimes(const CERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
    935 {
    936    SECStatus rv;
    937 
    938    if (!c || !notBefore || !notAfter) {
    939        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    940        return SECFailure;
    941    }
    942 
    943    /* convert DER not-before time */
    944    rv = DER_DecodeTimeChoice(notBefore, &c->validity.notBefore);
    945    if (rv) {
    946        return (SECFailure);
    947    }
    948 
    949    /* convert DER not-after time */
    950    rv = DER_DecodeTimeChoice(notAfter, &c->validity.notAfter);
    951    if (rv) {
    952        return (SECFailure);
    953    }
    954 
    955    return (SECSuccess);
    956 }
    957 
    958 /*
    959 * Check the validity times of a certificate
    960 */
    961 SECCertTimeValidity
    962 CERT_CheckCertValidTimes(const CERTCertificate *c, PRTime t,
    963                         PRBool allowOverride)
    964 {
    965    PRTime notBefore, notAfter, llPendingSlop, tmp1;
    966    SECStatus rv;
    967 
    968    if (!c) {
    969        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    970        return (secCertTimeUndetermined);
    971    }
    972    /* if cert is already marked OK, then don't bother to check */
    973    if (allowOverride && c->timeOK) {
    974        return (secCertTimeValid);
    975    }
    976 
    977    rv = CERT_GetCertTimes(c, &notBefore, &notAfter);
    978 
    979    if (rv) {
    980        return (secCertTimeExpired); /*XXX is this the right thing to do here?*/
    981    }
    982 
    983    LL_I2L(llPendingSlop, pendingSlop);
    984    /* convert to micro seconds */
    985    LL_UI2L(tmp1, PR_USEC_PER_SEC);
    986    LL_MUL(llPendingSlop, llPendingSlop, tmp1);
    987    LL_SUB(notBefore, notBefore, llPendingSlop);
    988    if (LL_CMP(t, <, notBefore)) {
    989        PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
    990        return (secCertTimeNotValidYet);
    991    }
    992    if (LL_CMP(t, >, notAfter)) {
    993        PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
    994        return (secCertTimeExpired);
    995    }
    996 
    997    return (secCertTimeValid);
    998 }
    999 
   1000 SECStatus
   1001 SEC_GetCrlTimes(CERTCrl *date, PRTime *notBefore, PRTime *notAfter)
   1002 {
   1003    int rv;
   1004 
   1005    /* convert DER not-before time */
   1006    rv = DER_DecodeTimeChoice(notBefore, &date->lastUpdate);
   1007    if (rv) {
   1008        return (SECFailure);
   1009    }
   1010 
   1011    /* convert DER not-after time */
   1012    if (date->nextUpdate.data) {
   1013        rv = DER_DecodeTimeChoice(notAfter, &date->nextUpdate);
   1014        if (rv) {
   1015            return (SECFailure);
   1016        }
   1017    } else {
   1018        LL_I2L(*notAfter, 0L);
   1019    }
   1020    return (SECSuccess);
   1021 }
   1022 
   1023 /* These routines should probably be combined with the cert
   1024 * routines using an common extraction routine.
   1025 */
   1026 SECCertTimeValidity
   1027 SEC_CheckCrlTimes(CERTCrl *crl, PRTime t)
   1028 {
   1029    PRTime notBefore, notAfter, llPendingSlop, tmp1;
   1030    SECStatus rv;
   1031 
   1032    if (!crl) {
   1033        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1034        return (secCertTimeUndetermined);
   1035    }
   1036 
   1037    rv = SEC_GetCrlTimes(crl, &notBefore, &notAfter);
   1038 
   1039    if (rv) {
   1040        return (secCertTimeExpired);
   1041    }
   1042 
   1043    LL_I2L(llPendingSlop, pendingSlop);
   1044    /* convert to micro seconds */
   1045    LL_I2L(tmp1, PR_USEC_PER_SEC);
   1046    LL_MUL(llPendingSlop, llPendingSlop, tmp1);
   1047    LL_SUB(notBefore, notBefore, llPendingSlop);
   1048    if (LL_CMP(t, <, notBefore)) {
   1049        PORT_SetError(SEC_ERROR_CRL_EXPIRED);
   1050        return (secCertTimeNotValidYet);
   1051    }
   1052 
   1053    /* If next update is omitted and the test for notBefore passes, then
   1054       we assume that the crl is up to date.
   1055     */
   1056    if (LL_IS_ZERO(notAfter)) {
   1057        return (secCertTimeValid);
   1058    }
   1059 
   1060    if (LL_CMP(t, >, notAfter)) {
   1061        PORT_SetError(SEC_ERROR_CRL_EXPIRED);
   1062        return (secCertTimeExpired);
   1063    }
   1064 
   1065    return (secCertTimeValid);
   1066 }
   1067 
   1068 PRBool
   1069 SEC_CrlIsNewer(CERTCrl *inNew, CERTCrl *old)
   1070 {
   1071    PRTime newNotBefore, newNotAfter;
   1072    PRTime oldNotBefore, oldNotAfter;
   1073    SECStatus rv;
   1074 
   1075    /* problems with the new CRL? reject it */
   1076    rv = SEC_GetCrlTimes(inNew, &newNotBefore, &newNotAfter);
   1077    if (rv)
   1078        return PR_FALSE;
   1079 
   1080    /* problems with the old CRL? replace it */
   1081    rv = SEC_GetCrlTimes(old, &oldNotBefore, &oldNotAfter);
   1082    if (rv)
   1083        return PR_TRUE;
   1084 
   1085    /* Question: what about the notAfter's? */
   1086    return ((PRBool)LL_CMP(oldNotBefore, <, newNotBefore));
   1087 }
   1088 
   1089 /*
   1090 * return required key usage and cert type based on cert usage
   1091 */
   1092 SECStatus
   1093 CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage, PRBool ca,
   1094                                 unsigned int *retKeyUsage,
   1095                                 unsigned int *retCertType)
   1096 {
   1097    unsigned int requiredKeyUsage = 0;
   1098    unsigned int requiredCertType = 0;
   1099 
   1100    if (ca) {
   1101        switch (usage) {
   1102            case certUsageSSLServerWithStepUp:
   1103                requiredKeyUsage = KU_NS_GOVT_APPROVED | KU_KEY_CERT_SIGN;
   1104                requiredCertType = NS_CERT_TYPE_SSL_CA;
   1105                break;
   1106            case certUsageSSLClient:
   1107                requiredKeyUsage = KU_KEY_CERT_SIGN;
   1108                requiredCertType = NS_CERT_TYPE_SSL_CA;
   1109                break;
   1110            case certUsageSSLServer:
   1111                requiredKeyUsage = KU_KEY_CERT_SIGN;
   1112                requiredCertType = NS_CERT_TYPE_SSL_CA;
   1113                break;
   1114            case certUsageIPsec:
   1115                requiredKeyUsage = KU_KEY_CERT_SIGN;
   1116                requiredCertType = NS_CERT_TYPE_IPSEC_CA;
   1117                break;
   1118            case certUsageSSLCA:
   1119                requiredKeyUsage = KU_KEY_CERT_SIGN;
   1120                requiredCertType = NS_CERT_TYPE_SSL_CA;
   1121                break;
   1122            case certUsageEmailSigner:
   1123                requiredKeyUsage = KU_KEY_CERT_SIGN;
   1124                requiredCertType = NS_CERT_TYPE_EMAIL_CA;
   1125                break;
   1126            case certUsageEmailRecipient:
   1127                requiredKeyUsage = KU_KEY_CERT_SIGN;
   1128                requiredCertType = NS_CERT_TYPE_EMAIL_CA;
   1129                break;
   1130            case certUsageObjectSigner:
   1131                requiredKeyUsage = KU_KEY_CERT_SIGN;
   1132                requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA;
   1133                break;
   1134            case certUsageAnyCA:
   1135            case certUsageVerifyCA:
   1136            case certUsageStatusResponder:
   1137                requiredKeyUsage = KU_KEY_CERT_SIGN;
   1138                requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA |
   1139                                   NS_CERT_TYPE_EMAIL_CA | NS_CERT_TYPE_SSL_CA;
   1140                break;
   1141            default:
   1142                PORT_Assert(0);
   1143                goto loser;
   1144        }
   1145    } else {
   1146        switch (usage) {
   1147            case certUsageSSLClient:
   1148                /*
   1149                 * RFC 5280 lists digitalSignature and keyAgreement for
   1150                 * id-kp-clientAuth.  NSS does not support the *_fixed_dh and
   1151                 * *_fixed_ecdh client certificate types.
   1152                 */
   1153                requiredKeyUsage = KU_DIGITAL_SIGNATURE;
   1154                requiredCertType = NS_CERT_TYPE_SSL_CLIENT;
   1155                break;
   1156            case certUsageSSLServer:
   1157                requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
   1158                requiredCertType = NS_CERT_TYPE_SSL_SERVER;
   1159                break;
   1160            case certUsageIPsec:
   1161                /* RFC 4945 Section 5.1.3.2 */
   1162                requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
   1163                requiredCertType = NS_CERT_TYPE_IPSEC;
   1164                break;
   1165            case certUsageSSLServerWithStepUp:
   1166                requiredKeyUsage =
   1167                    KU_KEY_AGREEMENT_OR_ENCIPHERMENT | KU_NS_GOVT_APPROVED;
   1168                requiredCertType = NS_CERT_TYPE_SSL_SERVER;
   1169                break;
   1170            case certUsageSSLCA:
   1171                requiredKeyUsage = KU_KEY_CERT_SIGN;
   1172                requiredCertType = NS_CERT_TYPE_SSL_CA;
   1173                break;
   1174            case certUsageEmailSigner:
   1175                requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
   1176                requiredCertType = NS_CERT_TYPE_EMAIL;
   1177                break;
   1178            case certUsageEmailRecipient:
   1179                requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
   1180                requiredCertType = NS_CERT_TYPE_EMAIL;
   1181                break;
   1182            case certUsageObjectSigner:
   1183                /* RFC 5280 lists only digitalSignature for id-kp-codeSigning.
   1184                 */
   1185                requiredKeyUsage = KU_DIGITAL_SIGNATURE;
   1186                requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING;
   1187                break;
   1188            case certUsageStatusResponder:
   1189                requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
   1190                requiredCertType = EXT_KEY_USAGE_STATUS_RESPONDER;
   1191                break;
   1192            default:
   1193                PORT_Assert(0);
   1194                goto loser;
   1195        }
   1196    }
   1197 
   1198    if (retKeyUsage != NULL) {
   1199        *retKeyUsage = requiredKeyUsage;
   1200    }
   1201    if (retCertType != NULL) {
   1202        *retCertType = requiredCertType;
   1203    }
   1204 
   1205    return (SECSuccess);
   1206 loser:
   1207    return (SECFailure);
   1208 }
   1209 
   1210 /*
   1211 * check the key usage of a cert against a set of required values
   1212 */
   1213 SECStatus
   1214 CERT_CheckKeyUsage(CERTCertificate *cert, unsigned int requiredUsage)
   1215 {
   1216    if (!cert) {
   1217        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1218        return SECFailure;
   1219    }
   1220    /* choose between key agreement or key encipherment based on key
   1221     * type in cert
   1222     */
   1223    if (requiredUsage & KU_KEY_AGREEMENT_OR_ENCIPHERMENT) {
   1224        KeyType keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
   1225        /* turn off the special bit */
   1226        requiredUsage &= (~KU_KEY_AGREEMENT_OR_ENCIPHERMENT);
   1227 
   1228        switch (keyType) {
   1229            case rsaKey:
   1230                requiredUsage |= KU_KEY_ENCIPHERMENT;
   1231                break;
   1232            case rsaPssKey:
   1233            case dsaKey:
   1234            case mldsaKey:
   1235                requiredUsage |= KU_DIGITAL_SIGNATURE;
   1236                break;
   1237            case dhKey:
   1238                requiredUsage |= KU_KEY_AGREEMENT;
   1239                break;
   1240            case ecKey:
   1241                /* Accept either signature or agreement. */
   1242                if (!(cert->keyUsage &
   1243                      (KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT)))
   1244                    goto loser;
   1245                break;
   1246            default:
   1247                goto loser;
   1248        }
   1249    }
   1250 
   1251    /* Allow either digital signature or non-repudiation */
   1252    if (requiredUsage & KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION) {
   1253        /* turn off the special bit */
   1254        requiredUsage &= (~KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION);
   1255 
   1256        if (!(cert->keyUsage & (KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION)))
   1257            goto loser;
   1258    }
   1259 
   1260    if ((cert->keyUsage & requiredUsage) == requiredUsage)
   1261        return SECSuccess;
   1262 
   1263 loser:
   1264    PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
   1265    return SECFailure;
   1266 }
   1267 
   1268 CERTCertificate *
   1269 CERT_DupCertificate(CERTCertificate *c)
   1270 {
   1271    if (c) {
   1272        NSSCertificate *tmp = STAN_GetNSSCertificate(c);
   1273        nssCertificate_AddRef(tmp);
   1274    }
   1275    return c;
   1276 }
   1277 
   1278 SECStatus
   1279 CERT_GetCertificateDer(const CERTCertificate *c, SECItem *der)
   1280 {
   1281    if (!c || !der) {
   1282        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1283        return SECFailure;
   1284    }
   1285    *der = c->derCert;
   1286    return SECSuccess;
   1287 }
   1288 
   1289 /*
   1290 * Allow use of default cert database, so that apps(such as mozilla) don't
   1291 * have to pass the handle all over the place.
   1292 */
   1293 static CERTCertDBHandle *default_cert_db_handle = 0;
   1294 
   1295 void
   1296 CERT_SetDefaultCertDB(CERTCertDBHandle *handle)
   1297 {
   1298    default_cert_db_handle = handle;
   1299 
   1300    return;
   1301 }
   1302 
   1303 CERTCertDBHandle *
   1304 CERT_GetDefaultCertDB(void)
   1305 {
   1306    return (default_cert_db_handle);
   1307 }
   1308 
   1309 /* XXX this would probably be okay/better as an xp routine? */
   1310 static void
   1311 sec_lower_string(char *s)
   1312 {
   1313    if (s == NULL) {
   1314        return;
   1315    }
   1316 
   1317    while (*s) {
   1318        *s = PORT_Tolower((unsigned char)*s);
   1319        s++;
   1320    }
   1321 
   1322    return;
   1323 }
   1324 
   1325 static PRBool
   1326 cert_IsIPAddr(const char *hn)
   1327 {
   1328    PRBool isIPaddr = PR_FALSE;
   1329    PRNetAddr netAddr;
   1330    isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
   1331    return isIPaddr;
   1332 }
   1333 
   1334 /*
   1335 ** Add a domain name to the list of names that the user has explicitly
   1336 ** allowed (despite cert name mismatches) for use with a server cert.
   1337 */
   1338 SECStatus
   1339 CERT_AddOKDomainName(CERTCertificate *cert, const char *hn)
   1340 {
   1341    CERTOKDomainName *domainOK;
   1342    int newNameLen;
   1343 
   1344    if (!hn || !(newNameLen = strlen(hn))) {
   1345        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1346        return SECFailure;
   1347    }
   1348    domainOK = (CERTOKDomainName *)PORT_ArenaZAlloc(cert->arena, sizeof(*domainOK));
   1349    if (!domainOK) {
   1350        return SECFailure; /* error code is already set. */
   1351    }
   1352    domainOK->name = (char *)PORT_ArenaZAlloc(cert->arena, newNameLen + 1);
   1353    if (!domainOK->name) {
   1354        return SECFailure; /* error code is already set. */
   1355    }
   1356 
   1357    PORT_Strncpy(domainOK->name, hn, newNameLen + 1);
   1358    sec_lower_string(domainOK->name);
   1359 
   1360    /* put at head of list. */
   1361    domainOK->next = cert->domainOK;
   1362    cert->domainOK = domainOK;
   1363    return SECSuccess;
   1364 }
   1365 
   1366 /* returns SECSuccess if hn matches pattern cn,
   1367 ** returns SECFailure with SSL_ERROR_BAD_CERT_DOMAIN if no match,
   1368 ** returns SECFailure with some other error code if another error occurs.
   1369 **
   1370 ** This function may modify string cn, so caller must pass a modifiable copy.
   1371 */
   1372 static SECStatus
   1373 cert_TestHostName(char *cn, const char *hn)
   1374 {
   1375    static int useShellExp = -1;
   1376 
   1377    if (useShellExp < 0) {
   1378        useShellExp = (NULL != PR_GetEnvSecure("NSS_USE_SHEXP_IN_CERT_NAME"));
   1379    }
   1380    if (useShellExp) {
   1381        /* Backward compatible code, uses Shell Expressions (SHEXP). */
   1382        int regvalid = PORT_RegExpValid(cn);
   1383        if (regvalid != NON_SXP) {
   1384            SECStatus rv;
   1385            /* cn is a regular expression, try to match the shexp */
   1386            int match = PORT_RegExpCaseSearch(hn, cn);
   1387 
   1388            if (match == 0) {
   1389                rv = SECSuccess;
   1390            } else {
   1391                PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
   1392                rv = SECFailure;
   1393            }
   1394            return rv;
   1395        }
   1396    } else {
   1397        /* New approach conforms to RFC 6125. */
   1398        char *wildcard = PORT_Strchr(cn, '*');
   1399        char *firstcndot = PORT_Strchr(cn, '.');
   1400        char *secondcndot =
   1401            firstcndot ? PORT_Strchr(firstcndot + 1, '.') : NULL;
   1402        char *firsthndot = PORT_Strchr(hn, '.');
   1403 
   1404        /* For a cn pattern to be considered valid, the wildcard character...
   1405         * - may occur only in a DNS name with at least 3 components, and
   1406         * - may occur only as last character in the first component, and
   1407         * - may be preceded by additional characters, and
   1408         * - must not be preceded by an IDNA ACE prefix (xn--)
   1409         */
   1410        if (wildcard && secondcndot && secondcndot[1] && firsthndot &&
   1411            firstcndot - wildcard == 1           /* wildcard is last char in first component */
   1412            && secondcndot - firstcndot > 1      /* second component is non-empty */
   1413            && PORT_Strrchr(cn, '*') == wildcard /* only one wildcard in cn */
   1414            && !PORT_Strncasecmp(cn, hn, wildcard - cn) &&
   1415            !PORT_Strcasecmp(firstcndot, firsthndot)
   1416            /* If hn starts with xn--, then cn must start with wildcard */
   1417            && (PORT_Strncasecmp(hn, "xn--", 4) || wildcard == cn)) {
   1418            /* valid wildcard pattern match */
   1419            return SECSuccess;
   1420        }
   1421    }
   1422    /* String cn has no wildcard or shell expression.
   1423     * Compare entire string hn with cert name.
   1424     */
   1425    if (PORT_Strcasecmp(hn, cn) == 0) {
   1426        return SECSuccess;
   1427    }
   1428 
   1429    PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
   1430    return SECFailure;
   1431 }
   1432 
   1433 SECStatus
   1434 cert_VerifySubjectAltName(const CERTCertificate *cert, const char *hn)
   1435 {
   1436    PLArenaPool *arena = NULL;
   1437    CERTGeneralName *nameList = NULL;
   1438    CERTGeneralName *current;
   1439    char *cn;
   1440    int cnBufLen;
   1441    int DNSextCount = 0;
   1442    int IPextCount = 0;
   1443    PRBool isIPaddr = PR_FALSE;
   1444    SECStatus rv = SECFailure;
   1445    SECItem subAltName;
   1446    PRNetAddr netAddr;
   1447    char cnbuf[128];
   1448 
   1449    subAltName.data = NULL;
   1450    cn = cnbuf;
   1451    cnBufLen = sizeof cnbuf;
   1452 
   1453    rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
   1454                                &subAltName);
   1455    if (rv != SECSuccess) {
   1456        goto fail;
   1457    }
   1458    isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
   1459    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1460    if (!arena)
   1461        goto fail;
   1462 
   1463    nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
   1464    if (!current)
   1465        goto fail;
   1466 
   1467    do {
   1468        switch (current->type) {
   1469            case certDNSName:
   1470                if (!isIPaddr) {
   1471                    /* DNS name current->name.other.data is not null terminated.
   1472                    ** so must copy it.
   1473                    */
   1474                    int cnLen = current->name.other.len;
   1475                    rv = CERT_RFC1485_EscapeAndQuote(
   1476                        cn, cnBufLen, (char *)current->name.other.data, cnLen);
   1477                    if (rv != SECSuccess &&
   1478                        PORT_GetError() == SEC_ERROR_OUTPUT_LEN) {
   1479                        cnBufLen =
   1480                            cnLen * 3 + 3; /* big enough for worst case */
   1481                        cn = (char *)PORT_ArenaAlloc(arena, cnBufLen);
   1482                        if (!cn)
   1483                            goto fail;
   1484                        rv = CERT_RFC1485_EscapeAndQuote(
   1485                            cn, cnBufLen, (char *)current->name.other.data,
   1486                            cnLen);
   1487                    }
   1488                    if (rv == SECSuccess)
   1489                        rv = cert_TestHostName(cn, hn);
   1490                    if (rv == SECSuccess)
   1491                        goto finish;
   1492                }
   1493                DNSextCount++;
   1494                break;
   1495            case certIPAddress:
   1496                if (isIPaddr) {
   1497                    int match = 0;
   1498                    PRIPv6Addr v6Addr;
   1499                    if (current->name.other.len == 4 && /* IP v4 address */
   1500                        netAddr.inet.family == PR_AF_INET) {
   1501                        match = !memcmp(&netAddr.inet.ip,
   1502                                        current->name.other.data, 4);
   1503                    } else if (current->name.other.len ==
   1504                                   16 && /* IP v6 address */
   1505                               netAddr.ipv6.family == PR_AF_INET6) {
   1506                        match = !memcmp(&netAddr.ipv6.ip,
   1507                                        current->name.other.data, 16);
   1508                    } else if (current->name.other.len ==
   1509                                   16 && /* IP v6 address */
   1510                               netAddr.inet.family == PR_AF_INET) {
   1511                        /* convert netAddr to ipv6, then compare. */
   1512                        /* ipv4 must be in Network Byte Order on input. */
   1513                        PR_ConvertIPv4AddrToIPv6(netAddr.inet.ip, &v6Addr);
   1514                        match = !memcmp(&v6Addr, current->name.other.data, 16);
   1515                    } else if (current->name.other.len == 4 && /* IP v4 address */
   1516                               netAddr.inet.family == PR_AF_INET6) {
   1517                        /* convert netAddr to ipv6, then compare. */
   1518                        PRUint32 ipv4 = (current->name.other.data[0] << 24) |
   1519                                        (current->name.other.data[1] << 16) |
   1520                                        (current->name.other.data[2] << 8) |
   1521                                        current->name.other.data[3];
   1522                        /* ipv4 must be in Network Byte Order on input. */
   1523                        PR_ConvertIPv4AddrToIPv6(PR_htonl(ipv4), &v6Addr);
   1524                        match = !memcmp(&netAddr.ipv6.ip, &v6Addr, 16);
   1525                    }
   1526                    if (match) {
   1527                        rv = SECSuccess;
   1528                        goto finish;
   1529                    }
   1530                }
   1531                IPextCount++;
   1532                break;
   1533            default:
   1534                break;
   1535        }
   1536        current = CERT_GetNextGeneralName(current);
   1537    } while (current != nameList);
   1538 
   1539 fail:
   1540 
   1541    if (!(isIPaddr ? IPextCount : DNSextCount)) {
   1542        /* no relevant value in the extension was found. */
   1543        PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
   1544    } else {
   1545        PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
   1546    }
   1547    rv = SECFailure;
   1548 
   1549 finish:
   1550 
   1551    /* Don't free nameList, it's part of the arena. */
   1552    if (arena) {
   1553        PORT_FreeArena(arena, PR_FALSE);
   1554    }
   1555 
   1556    if (subAltName.data) {
   1557        SECITEM_FreeItem(&subAltName, PR_FALSE);
   1558    }
   1559 
   1560    return rv;
   1561 }
   1562 
   1563 /*
   1564 * If found:
   1565 *   - subAltName contains the extension (caller must free)
   1566 *   - return value is the decoded namelist (allocated off arena)
   1567 * if not found, or if failure to decode:
   1568 *   - return value is NULL
   1569 */
   1570 CERTGeneralName *
   1571 cert_GetSubjectAltNameList(const CERTCertificate *cert, PLArenaPool *arena)
   1572 {
   1573    CERTGeneralName *nameList = NULL;
   1574    SECStatus rv = SECFailure;
   1575    SECItem subAltName;
   1576 
   1577    if (!cert || !arena)
   1578        return NULL;
   1579 
   1580    subAltName.data = NULL;
   1581 
   1582    rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
   1583                                &subAltName);
   1584    if (rv != SECSuccess)
   1585        return NULL;
   1586 
   1587    nameList = CERT_DecodeAltNameExtension(arena, &subAltName);
   1588    SECITEM_FreeItem(&subAltName, PR_FALSE);
   1589    return nameList;
   1590 }
   1591 
   1592 PRUint32
   1593 cert_CountDNSPatterns(CERTGeneralName *firstName)
   1594 {
   1595    CERTGeneralName *current;
   1596    PRUint32 count = 0;
   1597 
   1598    if (!firstName)
   1599        return 0;
   1600 
   1601    current = firstName;
   1602    do {
   1603        switch (current->type) {
   1604            case certDNSName:
   1605            case certIPAddress:
   1606                ++count;
   1607                break;
   1608            default:
   1609                break;
   1610        }
   1611        current = CERT_GetNextGeneralName(current);
   1612    } while (current != firstName);
   1613 
   1614    return count;
   1615 }
   1616 
   1617 #ifndef INET6_ADDRSTRLEN
   1618 #define INET6_ADDRSTRLEN 46
   1619 #endif
   1620 
   1621 /* will fill nickNames,
   1622 * will allocate all data from nickNames->arena,
   1623 * numberOfGeneralNames should have been obtained from cert_CountDNSPatterns,
   1624 * will ensure the numberOfGeneralNames matches the number of output entries.
   1625 */
   1626 SECStatus
   1627 cert_GetDNSPatternsFromGeneralNames(CERTGeneralName *firstName,
   1628                                    PRUint32 numberOfGeneralNames,
   1629                                    CERTCertNicknames *nickNames)
   1630 {
   1631    CERTGeneralName *currentInput;
   1632    char **currentOutput;
   1633 
   1634    if (!firstName || !nickNames || !numberOfGeneralNames)
   1635        return SECFailure;
   1636 
   1637    nickNames->numnicknames = numberOfGeneralNames;
   1638    nickNames->nicknames = PORT_ArenaAlloc(
   1639        nickNames->arena, sizeof(char *) * numberOfGeneralNames);
   1640    if (!nickNames->nicknames)
   1641        return SECFailure;
   1642 
   1643    currentInput = firstName;
   1644    currentOutput = nickNames->nicknames;
   1645    do {
   1646        char *cn = NULL;
   1647        char ipbuf[INET6_ADDRSTRLEN];
   1648        PRNetAddr addr;
   1649 
   1650        if (numberOfGeneralNames < 1) {
   1651            /* internal consistency error */
   1652            return SECFailure;
   1653        }
   1654 
   1655        switch (currentInput->type) {
   1656            case certDNSName:
   1657                /* DNS name currentInput->name.other.data is not null
   1658                 *terminated.
   1659                 ** so must copy it.
   1660                 */
   1661                cn = (char *)PORT_ArenaAlloc(nickNames->arena,
   1662                                             currentInput->name.other.len + 1);
   1663                if (!cn)
   1664                    return SECFailure;
   1665                PORT_Memcpy(cn, currentInput->name.other.data,
   1666                            currentInput->name.other.len);
   1667                cn[currentInput->name.other.len] = 0;
   1668                break;
   1669            case certIPAddress:
   1670                if (currentInput->name.other.len == 4) {
   1671                    addr.inet.family = PR_AF_INET;
   1672                    memcpy(&addr.inet.ip, currentInput->name.other.data,
   1673                           currentInput->name.other.len);
   1674                } else if (currentInput->name.other.len == 16) {
   1675                    addr.ipv6.family = PR_AF_INET6;
   1676                    memcpy(&addr.ipv6.ip, currentInput->name.other.data,
   1677                           currentInput->name.other.len);
   1678                }
   1679                if (PR_NetAddrToString(&addr, ipbuf, sizeof(ipbuf)) ==
   1680                    PR_FAILURE)
   1681                    return SECFailure;
   1682                cn = PORT_ArenaStrdup(nickNames->arena, ipbuf);
   1683                if (!cn)
   1684                    return SECFailure;
   1685                break;
   1686            default:
   1687                break;
   1688        }
   1689        if (cn) {
   1690            *currentOutput = cn;
   1691            nickNames->totallen += PORT_Strlen(cn);
   1692            ++currentOutput;
   1693            --numberOfGeneralNames;
   1694        }
   1695        currentInput = CERT_GetNextGeneralName(currentInput);
   1696    } while (currentInput != firstName);
   1697 
   1698    return (numberOfGeneralNames == 0) ? SECSuccess : SECFailure;
   1699 }
   1700 
   1701 /*
   1702 * Collect all valid DNS names from the given cert.
   1703 * The output arena will reference some temporaray data,
   1704 * but this saves us from dealing with two arenas.
   1705 * The caller may free all data by freeing CERTCertNicknames->arena.
   1706 */
   1707 CERTCertNicknames *
   1708 CERT_GetValidDNSPatternsFromCert(CERTCertificate *cert)
   1709 {
   1710    CERTGeneralName *generalNames;
   1711    CERTCertNicknames *nickNames;
   1712    PLArenaPool *arena;
   1713    char *singleName;
   1714 
   1715    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1716    if (!arena) {
   1717        return NULL;
   1718    }
   1719 
   1720    nickNames = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
   1721    if (!nickNames) {
   1722        PORT_FreeArena(arena, PR_FALSE);
   1723        return NULL;
   1724    }
   1725 
   1726    /* init the structure */
   1727    nickNames->arena = arena;
   1728    nickNames->head = NULL;
   1729    nickNames->numnicknames = 0;
   1730    nickNames->nicknames = NULL;
   1731    nickNames->totallen = 0;
   1732 
   1733    generalNames = cert_GetSubjectAltNameList(cert, arena);
   1734    if (generalNames) {
   1735        SECStatus rv_getnames = SECFailure;
   1736        PRUint32 numNames = cert_CountDNSPatterns(generalNames);
   1737 
   1738        if (numNames) {
   1739            rv_getnames = cert_GetDNSPatternsFromGeneralNames(
   1740                generalNames, numNames, nickNames);
   1741        }
   1742 
   1743        /* if there were names, we'll exit now, either with success or failure
   1744         */
   1745        if (numNames) {
   1746            if (rv_getnames == SECSuccess) {
   1747                return nickNames;
   1748            }
   1749 
   1750            /* failure to produce output */
   1751            PORT_FreeArena(arena, PR_FALSE);
   1752            return NULL;
   1753        }
   1754    }
   1755 
   1756    /* no SAN extension or no names found in extension */
   1757    singleName = CERT_GetCommonName(&cert->subject);
   1758    if (singleName) {
   1759        nickNames->numnicknames = 1;
   1760        nickNames->nicknames = PORT_ArenaAlloc(arena, sizeof(char *));
   1761        if (nickNames->nicknames) {
   1762            *nickNames->nicknames = PORT_ArenaStrdup(arena, singleName);
   1763        }
   1764        PORT_Free(singleName);
   1765 
   1766        /* Did we allocate both the buffer of pointers and the string? */
   1767        if (nickNames->nicknames && *nickNames->nicknames) {
   1768            return nickNames;
   1769        }
   1770    }
   1771 
   1772    PORT_FreeArena(arena, PR_FALSE);
   1773    return NULL;
   1774 }
   1775 
   1776 /* Make sure that the name of the host we are connecting to matches the
   1777 * name that is incoded in the common-name component of the certificate
   1778 * that they are using.
   1779 */
   1780 SECStatus
   1781 CERT_VerifyCertName(const CERTCertificate *cert, const char *hn)
   1782 {
   1783    char *cn;
   1784    SECStatus rv;
   1785    CERTOKDomainName *domainOK;
   1786 
   1787    if (!hn || !strlen(hn)) {
   1788        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1789        return SECFailure;
   1790    }
   1791 
   1792    /* if the name is one that the user has already approved, it's OK. */
   1793    for (domainOK = cert->domainOK; domainOK; domainOK = domainOK->next) {
   1794        if (0 == PORT_Strcasecmp(hn, domainOK->name)) {
   1795            return SECSuccess;
   1796        }
   1797    }
   1798 
   1799    /* Per RFC 2818, if the SubjectAltName extension is present, it must
   1800    ** be used as the cert's identity.
   1801    */
   1802    rv = cert_VerifySubjectAltName(cert, hn);
   1803    if (rv == SECSuccess || PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND)
   1804        return rv;
   1805 
   1806    cn = CERT_GetCommonName(&cert->subject);
   1807    if (cn) {
   1808        PRBool isIPaddr = cert_IsIPAddr(hn);
   1809        if (isIPaddr) {
   1810            if (PORT_Strcasecmp(hn, cn) == 0) {
   1811                rv = SECSuccess;
   1812            } else {
   1813                PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
   1814                rv = SECFailure;
   1815            }
   1816        } else {
   1817            rv = cert_TestHostName(cn, hn);
   1818        }
   1819        PORT_Free(cn);
   1820    } else
   1821        PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
   1822    return rv;
   1823 }
   1824 
   1825 PRBool
   1826 CERT_CompareCerts(const CERTCertificate *c1, const CERTCertificate *c2)
   1827 {
   1828    SECComparison comp;
   1829 
   1830    comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
   1831    if (comp == SECEqual) { /* certs are the same */
   1832        return (PR_TRUE);
   1833    } else {
   1834        return (PR_FALSE);
   1835    }
   1836 }
   1837 
   1838 static SECStatus
   1839 StringsEqual(char *s1, char *s2)
   1840 {
   1841    if ((s1 == NULL) || (s2 == NULL)) {
   1842        if (s1 != s2) { /* only one is null */
   1843            return (SECFailure);
   1844        }
   1845        return (SECSuccess); /* both are null */
   1846    }
   1847 
   1848    if (PORT_Strcmp(s1, s2) != 0) {
   1849        return (SECFailure); /* not equal */
   1850    }
   1851 
   1852    return (SECSuccess); /* strings are equal */
   1853 }
   1854 
   1855 PRBool
   1856 CERT_CompareCertsForRedirection(CERTCertificate *c1, CERTCertificate *c2)
   1857 {
   1858    SECComparison comp;
   1859    char *c1str, *c2str;
   1860    SECStatus eq;
   1861 
   1862    comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
   1863    if (comp == SECEqual) { /* certs are the same */
   1864        return (PR_TRUE);
   1865    }
   1866 
   1867    /* check if they are issued by the same CA */
   1868    comp = SECITEM_CompareItem(&c1->derIssuer, &c2->derIssuer);
   1869    if (comp != SECEqual) { /* different issuer */
   1870        return (PR_FALSE);
   1871    }
   1872 
   1873    /* check country name */
   1874    c1str = CERT_GetCountryName(&c1->subject);
   1875    c2str = CERT_GetCountryName(&c2->subject);
   1876    eq = StringsEqual(c1str, c2str);
   1877    PORT_Free(c1str);
   1878    PORT_Free(c2str);
   1879    if (eq != SECSuccess) {
   1880        return (PR_FALSE);
   1881    }
   1882 
   1883    /* check locality name */
   1884    c1str = CERT_GetLocalityName(&c1->subject);
   1885    c2str = CERT_GetLocalityName(&c2->subject);
   1886    eq = StringsEqual(c1str, c2str);
   1887    PORT_Free(c1str);
   1888    PORT_Free(c2str);
   1889    if (eq != SECSuccess) {
   1890        return (PR_FALSE);
   1891    }
   1892 
   1893    /* check state name */
   1894    c1str = CERT_GetStateName(&c1->subject);
   1895    c2str = CERT_GetStateName(&c2->subject);
   1896    eq = StringsEqual(c1str, c2str);
   1897    PORT_Free(c1str);
   1898    PORT_Free(c2str);
   1899    if (eq != SECSuccess) {
   1900        return (PR_FALSE);
   1901    }
   1902 
   1903    /* check org name */
   1904    c1str = CERT_GetOrgName(&c1->subject);
   1905    c2str = CERT_GetOrgName(&c2->subject);
   1906    eq = StringsEqual(c1str, c2str);
   1907    PORT_Free(c1str);
   1908    PORT_Free(c2str);
   1909    if (eq != SECSuccess) {
   1910        return (PR_FALSE);
   1911    }
   1912 
   1913 #ifdef NOTDEF
   1914    /* check orgUnit name */
   1915    /*
   1916     * We need to revisit this and decide which fields should be allowed to be
   1917     * different
   1918     */
   1919    c1str = CERT_GetOrgUnitName(&c1->subject);
   1920    c2str = CERT_GetOrgUnitName(&c2->subject);
   1921    eq = StringsEqual(c1str, c2str);
   1922    PORT_Free(c1str);
   1923    PORT_Free(c2str);
   1924    if (eq != SECSuccess) {
   1925        return (PR_FALSE);
   1926    }
   1927 #endif
   1928 
   1929    return (PR_TRUE); /* all fields but common name are the same */
   1930 }
   1931 
   1932 /* CERT_CertChainFromCert and CERT_DestroyCertificateList moved
   1933   to certhigh.c */
   1934 
   1935 CERTIssuerAndSN *
   1936 CERT_GetCertIssuerAndSN(PLArenaPool *arena, CERTCertificate *cert)
   1937 {
   1938    CERTIssuerAndSN *result;
   1939    SECStatus rv;
   1940 
   1941    if (arena == NULL) {
   1942        arena = cert->arena;
   1943    }
   1944 
   1945    result = (CERTIssuerAndSN *)PORT_ArenaZAlloc(arena, sizeof(*result));
   1946    if (result == NULL) {
   1947        PORT_SetError(SEC_ERROR_NO_MEMORY);
   1948        return NULL;
   1949    }
   1950 
   1951    rv = SECITEM_CopyItem(arena, &result->derIssuer, &cert->derIssuer);
   1952    if (rv != SECSuccess)
   1953        return NULL;
   1954 
   1955    rv = CERT_CopyName(arena, &result->issuer, &cert->issuer);
   1956    if (rv != SECSuccess)
   1957        return NULL;
   1958 
   1959    rv = SECITEM_CopyItem(arena, &result->serialNumber, &cert->serialNumber);
   1960    if (rv != SECSuccess)
   1961        return NULL;
   1962 
   1963    return result;
   1964 }
   1965 
   1966 char *
   1967 CERT_MakeCANickname(CERTCertificate *cert)
   1968 {
   1969    char *firstname = NULL;
   1970    char *org = NULL;
   1971    char *nickname = NULL;
   1972    int count;
   1973    CERTCertificate *dummycert;
   1974 
   1975    firstname = CERT_GetCommonName(&cert->subject);
   1976    if (firstname == NULL) {
   1977        firstname = CERT_GetOrgUnitName(&cert->subject);
   1978    }
   1979 
   1980    org = CERT_GetOrgName(&cert->issuer);
   1981    if (org == NULL) {
   1982        org = CERT_GetDomainComponentName(&cert->issuer);
   1983        if (org == NULL) {
   1984            if (firstname) {
   1985                org = firstname;
   1986                firstname = NULL;
   1987            } else {
   1988                org = PORT_Strdup("Unknown CA");
   1989            }
   1990        }
   1991    }
   1992 
   1993    /* can only fail if PORT_Strdup fails, in which case
   1994     * we're having memory problems. */
   1995    if (org == NULL) {
   1996        goto done;
   1997    }
   1998 
   1999    count = 1;
   2000    while (1) {
   2001 
   2002        if (firstname) {
   2003            if (count == 1) {
   2004                nickname = PR_smprintf("%s - %s", firstname, org);
   2005            } else {
   2006                nickname = PR_smprintf("%s - %s #%d", firstname, org, count);
   2007            }
   2008        } else {
   2009            if (count == 1) {
   2010                nickname = PR_smprintf("%s", org);
   2011            } else {
   2012                nickname = PR_smprintf("%s #%d", org, count);
   2013            }
   2014        }
   2015        if (nickname == NULL) {
   2016            goto done;
   2017        }
   2018 
   2019        /* look up the nickname to make sure it isn't in use already */
   2020        dummycert = CERT_FindCertByNickname(cert->dbhandle, nickname);
   2021 
   2022        if (dummycert == NULL) {
   2023            goto done;
   2024        }
   2025 
   2026        /* found a cert, destroy it and loop */
   2027        CERT_DestroyCertificate(dummycert);
   2028 
   2029        /* free the nickname */
   2030        PORT_Free(nickname);
   2031 
   2032        count++;
   2033    }
   2034 
   2035 done:
   2036    if (firstname) {
   2037        PORT_Free(firstname);
   2038    }
   2039    if (org) {
   2040        PORT_Free(org);
   2041    }
   2042 
   2043    return (nickname);
   2044 }
   2045 
   2046 /* CERT_Import_CAChain moved to certhigh.c */
   2047 
   2048 void
   2049 CERT_DestroyCrl(CERTSignedCrl *crl)
   2050 {
   2051    SEC_DestroyCrl(crl);
   2052 }
   2053 
   2054 static int
   2055 cert_Version(CERTCertificate *cert)
   2056 {
   2057    int version = 0;
   2058    if (cert && cert->version.data && cert->version.len) {
   2059        version = DER_GetInteger(&cert->version);
   2060        if (version < 0)
   2061            version = 0;
   2062    }
   2063    return version;
   2064 }
   2065 
   2066 static unsigned int
   2067 cert_ComputeTrustOverrides(CERTCertificate *cert, unsigned int cType)
   2068 {
   2069    CERTCertTrust trust;
   2070    SECStatus rv = SECFailure;
   2071 
   2072    rv = CERT_GetCertTrust(cert, &trust);
   2073 
   2074    if (rv == SECSuccess &&
   2075        (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags)) {
   2076 
   2077        if (trust.sslFlags & (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED))
   2078            cType |= NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_SSL_CLIENT;
   2079        if (trust.sslFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA))
   2080            cType |= NS_CERT_TYPE_SSL_CA;
   2081 #if defined(CERTDB_NOT_TRUSTED)
   2082        if (trust.sslFlags & CERTDB_NOT_TRUSTED)
   2083            cType &= ~(NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_SSL_CLIENT |
   2084                       NS_CERT_TYPE_SSL_CA);
   2085 #endif
   2086        if (trust.emailFlags & (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED))
   2087            cType |= NS_CERT_TYPE_EMAIL;
   2088        if (trust.emailFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA))
   2089            cType |= NS_CERT_TYPE_EMAIL_CA;
   2090 #if defined(CERTDB_NOT_TRUSTED)
   2091        if (trust.emailFlags & CERTDB_NOT_TRUSTED)
   2092            cType &= ~(NS_CERT_TYPE_EMAIL | NS_CERT_TYPE_EMAIL_CA);
   2093 #endif
   2094        if (trust.objectSigningFlags &
   2095            (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED))
   2096            cType |= NS_CERT_TYPE_OBJECT_SIGNING;
   2097        if (trust.objectSigningFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA))
   2098            cType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
   2099 #if defined(CERTDB_NOT_TRUSTED)
   2100        if (trust.objectSigningFlags & CERTDB_NOT_TRUSTED)
   2101            cType &=
   2102                ~(NS_CERT_TYPE_OBJECT_SIGNING | NS_CERT_TYPE_OBJECT_SIGNING_CA);
   2103 #endif
   2104    }
   2105    return cType;
   2106 }
   2107 
   2108 /*
   2109 * Does a cert belong to a CA?  We decide based on perm database trust
   2110 * flags, Netscape Cert Type Extension, and KeyUsage Extension.
   2111 */
   2112 PRBool
   2113 CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype)
   2114 {
   2115    unsigned int cType = cert->nsCertType;
   2116    PRBool ret = PR_FALSE;
   2117 
   2118    /*
   2119     * Check if the constraints are available and it's a CA, OR if it's
   2120     * a X.509 v1 Root CA.
   2121     */
   2122    CERTBasicConstraints constraints;
   2123    if ((CERT_FindBasicConstraintExten(cert, &constraints) == SECSuccess &&
   2124         constraints.isCA) ||
   2125        (cert->isRoot && cert_Version(cert) < SEC_CERTIFICATE_VERSION_3))
   2126        cType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
   2127 
   2128    /*
   2129     * Apply trust overrides, if any.
   2130     */
   2131    cType = cert_ComputeTrustOverrides(cert, cType);
   2132    ret = (cType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
   2133                    NS_CERT_TYPE_OBJECT_SIGNING_CA))
   2134              ? PR_TRUE
   2135              : PR_FALSE;
   2136 
   2137    if (rettype) {
   2138        *rettype = cType;
   2139    }
   2140 
   2141    return ret;
   2142 }
   2143 
   2144 PRBool
   2145 CERT_IsCADERCert(SECItem *derCert, unsigned int *type)
   2146 {
   2147    CERTCertificate *cert;
   2148    PRBool isCA;
   2149 
   2150    /* This is okay -- only looks at extensions */
   2151    cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
   2152    if (cert == NULL)
   2153        return PR_FALSE;
   2154 
   2155    isCA = CERT_IsCACert(cert, type);
   2156    CERT_DestroyCertificate(cert);
   2157    return isCA;
   2158 }
   2159 
   2160 PRBool
   2161 CERT_IsRootDERCert(SECItem *derCert)
   2162 {
   2163    CERTCertificate *cert;
   2164    PRBool isRoot;
   2165 
   2166    /* This is okay -- only looks at extensions */
   2167    cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
   2168    if (cert == NULL)
   2169        return PR_FALSE;
   2170 
   2171    isRoot = cert->isRoot;
   2172    CERT_DestroyCertificate(cert);
   2173    return isRoot;
   2174 }
   2175 
   2176 CERTCompareValidityStatus
   2177 CERT_CompareValidityTimes(CERTValidity *val_a, CERTValidity *val_b)
   2178 {
   2179    PRTime notBeforeA, notBeforeB, notAfterA, notAfterB;
   2180 
   2181    if (!val_a || !val_b) {
   2182        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2183        return certValidityUndetermined;
   2184    }
   2185 
   2186    if (SECSuccess != DER_DecodeTimeChoice(&notBeforeA, &val_a->notBefore) ||
   2187        SECSuccess != DER_DecodeTimeChoice(&notBeforeB, &val_b->notBefore) ||
   2188        SECSuccess != DER_DecodeTimeChoice(&notAfterA, &val_a->notAfter) ||
   2189        SECSuccess != DER_DecodeTimeChoice(&notAfterB, &val_b->notAfter)) {
   2190        return certValidityUndetermined;
   2191    }
   2192 
   2193    /* sanity check */
   2194    if (LL_CMP(notBeforeA, >, notAfterA) || LL_CMP(notBeforeB, >, notAfterB)) {
   2195        PORT_SetError(SEC_ERROR_INVALID_TIME);
   2196        return certValidityUndetermined;
   2197    }
   2198 
   2199    if (LL_CMP(notAfterA, !=, notAfterB)) {
   2200        /* one cert validity goes farther into the future, select it */
   2201        return LL_CMP(notAfterA, <, notAfterB) ? certValidityChooseB
   2202                                               : certValidityChooseA;
   2203    }
   2204    /* the two certs have the same expiration date */
   2205    PORT_Assert(LL_CMP(notAfterA, ==, notAfterB));
   2206    /* do they also have the same start date ? */
   2207    if (LL_CMP(notBeforeA, ==, notBeforeB)) {
   2208        return certValidityEqual;
   2209    }
   2210    /* choose cert with the later start date */
   2211    return LL_CMP(notBeforeA, <, notBeforeB) ? certValidityChooseB
   2212                                             : certValidityChooseA;
   2213 }
   2214 
   2215 /*
   2216 * is certa newer than certb?  If one is expired, pick the other one.
   2217 */
   2218 PRBool
   2219 CERT_IsNewer(CERTCertificate *certa, CERTCertificate *certb)
   2220 {
   2221    PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
   2222    SECStatus rv;
   2223    PRBool newerbefore, newerafter;
   2224 
   2225    rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
   2226    if (rv != SECSuccess) {
   2227        return (PR_FALSE);
   2228    }
   2229 
   2230    rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
   2231    if (rv != SECSuccess) {
   2232        return (PR_TRUE);
   2233    }
   2234 
   2235    newerbefore = PR_FALSE;
   2236    if (LL_CMP(notBeforeA, >, notBeforeB)) {
   2237        newerbefore = PR_TRUE;
   2238    }
   2239 
   2240    newerafter = PR_FALSE;
   2241    if (LL_CMP(notAfterA, >, notAfterB)) {
   2242        newerafter = PR_TRUE;
   2243    }
   2244 
   2245    if (newerbefore && newerafter) {
   2246        return (PR_TRUE);
   2247    }
   2248 
   2249    if ((!newerbefore) && (!newerafter)) {
   2250        return (PR_FALSE);
   2251    }
   2252 
   2253    /* get current time */
   2254    now = PR_Now();
   2255 
   2256    if (newerbefore) {
   2257        /* cert A was issued after cert B, but expires sooner */
   2258        /* if A is expired, then pick B */
   2259        if (LL_CMP(notAfterA, <, now)) {
   2260            return (PR_FALSE);
   2261        }
   2262        return (PR_TRUE);
   2263    } else {
   2264        /* cert B was issued after cert A, but expires sooner */
   2265        /* if B is expired, then pick A */
   2266        if (LL_CMP(notAfterB, <, now)) {
   2267            return (PR_TRUE);
   2268        }
   2269        return (PR_FALSE);
   2270    }
   2271 }
   2272 
   2273 void
   2274 CERT_DestroyCertArray(CERTCertificate **certs, unsigned int ncerts)
   2275 {
   2276    unsigned int i;
   2277 
   2278    if (certs) {
   2279        for (i = 0; i < ncerts; i++) {
   2280            if (certs[i]) {
   2281                CERT_DestroyCertificate(certs[i]);
   2282            }
   2283        }
   2284 
   2285        PORT_Free(certs);
   2286    }
   2287 
   2288    return;
   2289 }
   2290 
   2291 char *
   2292 CERT_FixupEmailAddr(const char *emailAddr)
   2293 {
   2294    char *retaddr;
   2295    char *str;
   2296 
   2297    if (emailAddr == NULL) {
   2298        return (NULL);
   2299    }
   2300 
   2301    /* copy the string */
   2302    str = retaddr = PORT_Strdup(emailAddr);
   2303    if (str == NULL) {
   2304        return (NULL);
   2305    }
   2306 
   2307    /* make it lower case */
   2308    while (*str) {
   2309        *str = tolower((unsigned char)*str);
   2310        str++;
   2311    }
   2312 
   2313    return (retaddr);
   2314 }
   2315 
   2316 /*
   2317 * NOTE - don't allow encode of govt-approved or invisible bits
   2318 */
   2319 SECStatus
   2320 CERT_DecodeTrustString(CERTCertTrust *trust, const char *trusts)
   2321 {
   2322    unsigned int i;
   2323    unsigned int *pflags;
   2324 
   2325    if (!trust) {
   2326        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2327        return SECFailure;
   2328    }
   2329    trust->sslFlags = 0;
   2330    trust->emailFlags = 0;
   2331    trust->objectSigningFlags = 0;
   2332    if (!trusts) {
   2333        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2334        return SECFailure;
   2335    }
   2336 
   2337    pflags = &trust->sslFlags;
   2338 
   2339    for (i = 0; i < PORT_Strlen(trusts); i++) {
   2340        switch (trusts[i]) {
   2341            case 'p':
   2342                *pflags = *pflags | CERTDB_TERMINAL_RECORD;
   2343                break;
   2344 
   2345            case 'P':
   2346                *pflags = *pflags | CERTDB_TRUSTED | CERTDB_TERMINAL_RECORD;
   2347                break;
   2348 
   2349            case 'w':
   2350                *pflags = *pflags | CERTDB_SEND_WARN;
   2351                break;
   2352 
   2353            case 'c':
   2354                *pflags = *pflags | CERTDB_VALID_CA;
   2355                break;
   2356 
   2357            case 'T':
   2358                *pflags = *pflags | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA;
   2359                break;
   2360 
   2361            case 'C':
   2362                *pflags = *pflags | CERTDB_TRUSTED_CA | CERTDB_VALID_CA;
   2363                break;
   2364 
   2365            case 'u':
   2366                *pflags = *pflags | CERTDB_USER;
   2367                break;
   2368 
   2369            case 'i':
   2370                *pflags = *pflags | CERTDB_INVISIBLE_CA;
   2371                break;
   2372            case 'g':
   2373                *pflags = *pflags | CERTDB_GOVT_APPROVED_CA;
   2374                break;
   2375 
   2376            case ',':
   2377                if (pflags == &trust->sslFlags) {
   2378                    pflags = &trust->emailFlags;
   2379                } else {
   2380                    pflags = &trust->objectSigningFlags;
   2381                }
   2382                break;
   2383            default:
   2384                PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2385                return SECFailure;
   2386        }
   2387    }
   2388 
   2389    return SECSuccess;
   2390 }
   2391 
   2392 static void
   2393 EncodeFlags(char *trusts, unsigned int flags)
   2394 {
   2395    if (flags & CERTDB_VALID_CA)
   2396        if (!(flags & CERTDB_TRUSTED_CA) && !(flags & CERTDB_TRUSTED_CLIENT_CA))
   2397            PORT_Strcat(trusts, "c");
   2398    if (flags & CERTDB_TERMINAL_RECORD)
   2399        if (!(flags & CERTDB_TRUSTED))
   2400            PORT_Strcat(trusts, "p");
   2401    if (flags & CERTDB_TRUSTED_CA)
   2402        PORT_Strcat(trusts, "C");
   2403    if (flags & CERTDB_TRUSTED_CLIENT_CA)
   2404        PORT_Strcat(trusts, "T");
   2405    if (flags & CERTDB_TRUSTED)
   2406        PORT_Strcat(trusts, "P");
   2407    if (flags & CERTDB_USER)
   2408        PORT_Strcat(trusts, "u");
   2409    if (flags & CERTDB_SEND_WARN)
   2410        PORT_Strcat(trusts, "w");
   2411    if (flags & CERTDB_INVISIBLE_CA)
   2412        PORT_Strcat(trusts, "I");
   2413    if (flags & CERTDB_GOVT_APPROVED_CA)
   2414        PORT_Strcat(trusts, "G");
   2415    return;
   2416 }
   2417 
   2418 char *
   2419 CERT_EncodeTrustString(CERTCertTrust *trust)
   2420 {
   2421    char tmpTrustSSL[32];
   2422    char tmpTrustEmail[32];
   2423    char tmpTrustSigning[32];
   2424    char *retstr = NULL;
   2425 
   2426    if (trust) {
   2427        tmpTrustSSL[0] = '\0';
   2428        tmpTrustEmail[0] = '\0';
   2429        tmpTrustSigning[0] = '\0';
   2430 
   2431        EncodeFlags(tmpTrustSSL, trust->sslFlags);
   2432        EncodeFlags(tmpTrustEmail, trust->emailFlags);
   2433        EncodeFlags(tmpTrustSigning, trust->objectSigningFlags);
   2434 
   2435        retstr = PR_smprintf("%s,%s,%s", tmpTrustSSL, tmpTrustEmail,
   2436                             tmpTrustSigning);
   2437    }
   2438 
   2439    return (retstr);
   2440 }
   2441 
   2442 SECStatus
   2443 CERT_ImportCerts(CERTCertDBHandle *certdb, SECCertUsage usage,
   2444                 unsigned int ncerts, SECItem **derCerts,
   2445                 CERTCertificate ***retCerts, PRBool keepCerts, PRBool caOnly,
   2446                 char *nickname)
   2447 {
   2448    unsigned int i;
   2449    CERTCertificate **certs = NULL;
   2450    unsigned int fcerts = 0;
   2451 
   2452    if (ncerts) {
   2453        certs = PORT_ZNewArray(CERTCertificate *, ncerts);
   2454        if (certs == NULL) {
   2455            return (SECFailure);
   2456        }
   2457 
   2458        /* decode all of the certs into the temporary DB */
   2459        for (i = 0, fcerts = 0; i < ncerts; i++) {
   2460            certs[fcerts] = CERT_NewTempCertificate(certdb, derCerts[i], NULL,
   2461                                                    PR_FALSE, PR_TRUE);
   2462            if (certs[fcerts]) {
   2463                SECItem subjKeyID = { siBuffer, NULL, 0 };
   2464                if (CERT_FindSubjectKeyIDExtension(certs[fcerts], &subjKeyID) ==
   2465                    SECSuccess) {
   2466                    if (subjKeyID.data) {
   2467                        cert_AddSubjectKeyIDMapping(&subjKeyID, certs[fcerts]);
   2468                    }
   2469                    SECITEM_FreeItem(&subjKeyID, PR_FALSE);
   2470                }
   2471                fcerts++;
   2472            }
   2473        }
   2474 
   2475        if (keepCerts) {
   2476            for (i = 0; i < fcerts; i++) {
   2477                char *canickname = NULL;
   2478                PRBool isCA;
   2479 
   2480                SECKEY_UpdateCertPQG(certs[i]);
   2481 
   2482                isCA = CERT_IsCACert(certs[i], NULL);
   2483                if (isCA) {
   2484                    canickname = CERT_MakeCANickname(certs[i]);
   2485                }
   2486 
   2487                if (isCA && (fcerts > 1)) {
   2488                    /* if we are importing only a single cert and specifying
   2489                     * a nickname, we want to use that nickname if it a CA,
   2490                     * otherwise if there are more than one cert, we don't
   2491                     * know which cert it belongs to. But we still may try
   2492                     * the individual canickname from the cert itself.
   2493                     */
   2494                    /* Bug 1192442 - propagate errors from these calls. */
   2495                    (void)CERT_AddTempCertToPerm(certs[i], canickname, NULL);
   2496                } else {
   2497                    (void)CERT_AddTempCertToPerm(
   2498                        certs[i], nickname ? nickname : canickname, NULL);
   2499                }
   2500 
   2501                PORT_Free(canickname);
   2502                /* don't care if it fails - keep going */
   2503            }
   2504        }
   2505    }
   2506 
   2507    if (retCerts) {
   2508        *retCerts = certs;
   2509    } else {
   2510        if (certs) {
   2511            CERT_DestroyCertArray(certs, fcerts);
   2512        }
   2513    }
   2514 
   2515    return (fcerts || !ncerts) ? SECSuccess : SECFailure;
   2516 }
   2517 
   2518 /*
   2519 * a real list of certificates - need to convert CERTCertificateList
   2520 * stuff and ASN 1 encoder/decoder over to using this...
   2521 */
   2522 CERTCertList *
   2523 CERT_NewCertList(void)
   2524 {
   2525    PLArenaPool *arena = NULL;
   2526    CERTCertList *ret = NULL;
   2527 
   2528    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   2529    if (arena == NULL) {
   2530        goto loser;
   2531    }
   2532 
   2533    ret = (CERTCertList *)PORT_ArenaZAlloc(arena, sizeof(CERTCertList));
   2534    if (ret == NULL) {
   2535        goto loser;
   2536    }
   2537 
   2538    ret->arena = arena;
   2539 
   2540    PR_INIT_CLIST(&ret->list);
   2541 
   2542    return (ret);
   2543 
   2544 loser:
   2545    if (arena != NULL) {
   2546        PORT_FreeArena(arena, PR_FALSE);
   2547    }
   2548 
   2549    return (NULL);
   2550 }
   2551 
   2552 void
   2553 CERT_DestroyCertList(CERTCertList *certs)
   2554 {
   2555    PRCList *node;
   2556 
   2557    if (!certs) {
   2558        return;
   2559    }
   2560 
   2561    while (!PR_CLIST_IS_EMPTY(&certs->list)) {
   2562        node = PR_LIST_HEAD(&certs->list);
   2563        CERT_DestroyCertificate(((CERTCertListNode *)node)->cert);
   2564        PR_REMOVE_LINK(node);
   2565    }
   2566 
   2567    PORT_FreeArena(certs->arena, PR_FALSE);
   2568 
   2569    return;
   2570 }
   2571 
   2572 void
   2573 CERT_RemoveCertListNode(CERTCertListNode *node)
   2574 {
   2575    CERT_DestroyCertificate(node->cert);
   2576    PR_REMOVE_LINK(&node->links);
   2577    return;
   2578 }
   2579 
   2580 SECStatus
   2581 CERT_AddCertToListTailWithData(CERTCertList *certs, CERTCertificate *cert,
   2582                               void *appData)
   2583 {
   2584    CERTCertListNode *node;
   2585 
   2586    node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
   2587                                                sizeof(CERTCertListNode));
   2588    if (node == NULL) {
   2589        goto loser;
   2590    }
   2591 
   2592    PR_INSERT_BEFORE(&node->links, &certs->list);
   2593    /* certs->count++; */
   2594    node->cert = cert;
   2595    node->appData = appData;
   2596    return (SECSuccess);
   2597 
   2598 loser:
   2599    return (SECFailure);
   2600 }
   2601 
   2602 SECStatus
   2603 CERT_AddCertToListTail(CERTCertList *certs, CERTCertificate *cert)
   2604 {
   2605    return CERT_AddCertToListTailWithData(certs, cert, NULL);
   2606 }
   2607 
   2608 SECStatus
   2609 CERT_AddCertToListHeadWithData(CERTCertList *certs, CERTCertificate *cert,
   2610                               void *appData)
   2611 {
   2612    CERTCertListNode *node;
   2613    CERTCertListNode *head;
   2614 
   2615    head = CERT_LIST_HEAD(certs);
   2616    if (head == NULL) {
   2617        goto loser;
   2618    }
   2619 
   2620    node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
   2621                                                sizeof(CERTCertListNode));
   2622    if (node == NULL) {
   2623        goto loser;
   2624    }
   2625 
   2626    PR_INSERT_BEFORE(&node->links, &head->links);
   2627    /* certs->count++; */
   2628    node->cert = cert;
   2629    node->appData = appData;
   2630    return (SECSuccess);
   2631 
   2632 loser:
   2633    return (SECFailure);
   2634 }
   2635 
   2636 SECStatus
   2637 CERT_AddCertToListHead(CERTCertList *certs, CERTCertificate *cert)
   2638 {
   2639    return CERT_AddCertToListHeadWithData(certs, cert, NULL);
   2640 }
   2641 
   2642 /*
   2643 * Sort callback function to determine if cert a is newer than cert b.
   2644 * Not valid certs are considered older than valid certs.
   2645 */
   2646 PRBool
   2647 CERT_SortCBValidity(CERTCertificate *certa, CERTCertificate *certb, void *arg)
   2648 {
   2649    PRTime sorttime;
   2650    PRTime notBeforeA, notAfterA, notBeforeB, notAfterB;
   2651    SECStatus rv;
   2652    PRBool newerbefore, newerafter;
   2653    PRBool aNotValid = PR_FALSE, bNotValid = PR_FALSE;
   2654 
   2655    sorttime = *(PRTime *)arg;
   2656 
   2657    rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
   2658    if (rv != SECSuccess) {
   2659        return (PR_FALSE);
   2660    }
   2661 
   2662    rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
   2663    if (rv != SECSuccess) {
   2664        return (PR_TRUE);
   2665    }
   2666    newerbefore = PR_FALSE;
   2667    if (LL_CMP(notBeforeA, >, notBeforeB)) {
   2668        newerbefore = PR_TRUE;
   2669    }
   2670    newerafter = PR_FALSE;
   2671    if (LL_CMP(notAfterA, >, notAfterB)) {
   2672        newerafter = PR_TRUE;
   2673    }
   2674 
   2675    /* check if A is valid at sorttime */
   2676    if (CERT_CheckCertValidTimes(certa, sorttime, PR_FALSE) !=
   2677        secCertTimeValid) {
   2678        aNotValid = PR_TRUE;
   2679    }
   2680 
   2681    /* check if B is valid at sorttime */
   2682    if (CERT_CheckCertValidTimes(certb, sorttime, PR_FALSE) !=
   2683        secCertTimeValid) {
   2684        bNotValid = PR_TRUE;
   2685    }
   2686 
   2687    /* a is valid, b is not */
   2688    if (bNotValid && (!aNotValid)) {
   2689        return (PR_TRUE);
   2690    }
   2691 
   2692    /* b is valid, a is not */
   2693    if (aNotValid && (!bNotValid)) {
   2694        return (PR_FALSE);
   2695    }
   2696 
   2697    /* a and b are either valid or not valid */
   2698    if (newerbefore && newerafter) {
   2699        return (PR_TRUE);
   2700    }
   2701 
   2702    if ((!newerbefore) && (!newerafter)) {
   2703        return (PR_FALSE);
   2704    }
   2705 
   2706    if (newerbefore) {
   2707        /* cert A was issued after cert B, but expires sooner */
   2708        return (PR_TRUE);
   2709    } else {
   2710        /* cert B was issued after cert A, but expires sooner */
   2711        return (PR_FALSE);
   2712    }
   2713 }
   2714 
   2715 SECStatus
   2716 CERT_AddCertToListSorted(CERTCertList *certs, CERTCertificate *cert,
   2717                         CERTSortCallback f, void *arg)
   2718 {
   2719    CERTCertListNode *node;
   2720    CERTCertListNode *head;
   2721    PRBool ret;
   2722 
   2723    node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
   2724                                                sizeof(CERTCertListNode));
   2725    if (node == NULL) {
   2726        goto loser;
   2727    }
   2728 
   2729    head = CERT_LIST_HEAD(certs);
   2730 
   2731    while (!CERT_LIST_END(head, certs)) {
   2732 
   2733        /* if cert is already in the list, then don't add it again */
   2734        if (cert == head->cert) {
   2735            /*XXX*/
   2736            /* don't keep a reference */
   2737            CERT_DestroyCertificate(cert);
   2738            goto done;
   2739        }
   2740 
   2741        ret = (*f)(cert, head->cert, arg);
   2742        /* if sort function succeeds, then insert before current node */
   2743        if (ret) {
   2744            PR_INSERT_BEFORE(&node->links, &head->links);
   2745            goto done;
   2746        }
   2747 
   2748        head = CERT_LIST_NEXT(head);
   2749    }
   2750    /* if we get to the end, then just insert it at the tail */
   2751    PR_INSERT_BEFORE(&node->links, &certs->list);
   2752 
   2753 done:
   2754    /* certs->count++; */
   2755    node->cert = cert;
   2756    return (SECSuccess);
   2757 
   2758 loser:
   2759    return (SECFailure);
   2760 }
   2761 
   2762 /* This routine is here because pcertdb.c still has a call to it.
   2763 * The SMIME profile code in pcertdb.c should be split into high (find
   2764 * the email cert) and low (store the profile) code.  At that point, we
   2765 * can move this to certhigh.c where it belongs.
   2766 *
   2767 * remove certs from a list that don't have keyUsage and certType
   2768 * that match the given usage.
   2769 */
   2770 SECStatus
   2771 CERT_FilterCertListByUsage(CERTCertList *certList, SECCertUsage usage,
   2772                           PRBool ca)
   2773 {
   2774    unsigned int requiredKeyUsage;
   2775    unsigned int requiredCertType;
   2776    CERTCertListNode *node, *savenode;
   2777    SECStatus rv;
   2778 
   2779    if (certList == NULL)
   2780        goto loser;
   2781 
   2782    rv = CERT_KeyUsageAndTypeForCertUsage(usage, ca, &requiredKeyUsage,
   2783                                          &requiredCertType);
   2784    if (rv != SECSuccess) {
   2785        goto loser;
   2786    }
   2787 
   2788    node = CERT_LIST_HEAD(certList);
   2789 
   2790    while (!CERT_LIST_END(node, certList)) {
   2791 
   2792        PRBool bad = (PRBool)(!node->cert);
   2793 
   2794        /* bad key usage ? */
   2795        if (!bad &&
   2796            CERT_CheckKeyUsage(node->cert, requiredKeyUsage) != SECSuccess) {
   2797            bad = PR_TRUE;
   2798        }
   2799        /* bad cert type ? */
   2800        if (!bad) {
   2801            unsigned int certType = 0;
   2802            if (ca) {
   2803                /* This function returns a more comprehensive cert type that
   2804                 * takes trust flags into consideration.  Should probably
   2805                 * fix the cert decoding code to do this.
   2806                 */
   2807                (void)CERT_IsCACert(node->cert, &certType);
   2808            } else {
   2809                certType = node->cert->nsCertType;
   2810            }
   2811            if (!(certType & requiredCertType)) {
   2812                bad = PR_TRUE;
   2813            }
   2814        }
   2815 
   2816        if (bad) {
   2817            /* remove the node if it is bad */
   2818            savenode = CERT_LIST_NEXT(node);
   2819            CERT_RemoveCertListNode(node);
   2820            node = savenode;
   2821        } else {
   2822            node = CERT_LIST_NEXT(node);
   2823        }
   2824    }
   2825    return (SECSuccess);
   2826 
   2827 loser:
   2828    return (SECFailure);
   2829 }
   2830 
   2831 PRBool
   2832 CERT_IsUserCert(CERTCertificate *cert)
   2833 {
   2834    CERTCertTrust trust;
   2835    SECStatus rv = SECFailure;
   2836 
   2837    rv = CERT_GetCertTrust(cert, &trust);
   2838    if (rv == SECSuccess &&
   2839        ((trust.sslFlags & CERTDB_USER) || (trust.emailFlags & CERTDB_USER) ||
   2840         (trust.objectSigningFlags & CERTDB_USER))) {
   2841        return PR_TRUE;
   2842    } else {
   2843        return PR_FALSE;
   2844    }
   2845 }
   2846 
   2847 SECStatus
   2848 CERT_FilterCertListForUserCerts(CERTCertList *certList)
   2849 {
   2850    CERTCertListNode *node, *freenode;
   2851    CERTCertificate *cert;
   2852 
   2853    if (!certList) {
   2854        return SECFailure;
   2855    }
   2856 
   2857    node = CERT_LIST_HEAD(certList);
   2858 
   2859    while (!CERT_LIST_END(node, certList)) {
   2860        cert = node->cert;
   2861        if (PR_TRUE != CERT_IsUserCert(cert)) {
   2862            /* Not a User Cert, so remove this cert from the list */
   2863            freenode = node;
   2864            node = CERT_LIST_NEXT(node);
   2865            CERT_RemoveCertListNode(freenode);
   2866        } else {
   2867            /* Is a User cert, so leave it in the list */
   2868            node = CERT_LIST_NEXT(node);
   2869        }
   2870    }
   2871 
   2872    return (SECSuccess);
   2873 }
   2874 
   2875 /* return true if cert is in the list */
   2876 PRBool
   2877 CERT_IsInList(const CERTCertificate *cert, const CERTCertList *certList)
   2878 {
   2879    CERTCertListNode *node;
   2880    for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
   2881         node = CERT_LIST_NEXT(node)) {
   2882        if (node->cert == cert) {
   2883            return PR_TRUE;
   2884        }
   2885    }
   2886    return PR_FALSE;
   2887 }
   2888 
   2889 /* returned certList is the intersection of the certs on certList and the
   2890 * certs on filterList */
   2891 SECStatus
   2892 CERT_FilterCertListByCertList(CERTCertList *certList,
   2893                              const CERTCertList *filterList)
   2894 {
   2895    CERTCertListNode *node, *freenode;
   2896    CERTCertificate *cert;
   2897 
   2898    if (!certList) {
   2899        return SECFailure;
   2900    }
   2901 
   2902    if (!filterList || CERT_LIST_EMPTY(certList)) {
   2903        /* if the filterList is empty, just clear out certList and return */
   2904        for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);) {
   2905            freenode = node;
   2906            node = CERT_LIST_NEXT(node);
   2907            CERT_RemoveCertListNode(freenode);
   2908        }
   2909        return SECSuccess;
   2910    }
   2911 
   2912    node = CERT_LIST_HEAD(certList);
   2913 
   2914    while (!CERT_LIST_END(node, certList)) {
   2915        cert = node->cert;
   2916        if (!CERT_IsInList(cert, filterList)) {
   2917            // no matching cert on filter list, remove it from certlist */
   2918            freenode = node;
   2919            node = CERT_LIST_NEXT(node);
   2920            CERT_RemoveCertListNode(freenode);
   2921        } else {
   2922            /* matching cert, keep it around */
   2923            node = CERT_LIST_NEXT(node);
   2924        }
   2925    }
   2926 
   2927    return (SECSuccess);
   2928 }
   2929 
   2930 SECStatus
   2931 CERT_FilterCertListByNickname(CERTCertList *certList, char *nickname,
   2932                              void *pwarg)
   2933 {
   2934    CERTCertList *nameList;
   2935    SECStatus rv;
   2936 
   2937    if (!certList) {
   2938        return SECFailure;
   2939    }
   2940 
   2941    /* we could try to match the nickname to the individual cert,
   2942     * but nickname parsing is quite complicated, so it's best just
   2943     * to use the existing code and get a list of certs that match the
   2944     * nickname. We can then compare that list with our input cert list
   2945     * and return only those certs that are on both. */
   2946    nameList = PK11_FindCertsFromNickname(nickname, pwarg);
   2947 
   2948    /* namelist could be NULL, this will force certList to become empty */
   2949    rv = CERT_FilterCertListByCertList(certList, nameList);
   2950    /* CERT_DestroyCertList can now accept a NULL pointer */
   2951    CERT_DestroyCertList(nameList);
   2952    return rv;
   2953 }
   2954 
   2955 static PZLock *certRefCountLock = NULL;
   2956 
   2957 /*
   2958 * Acquire the cert reference count lock
   2959 * There is currently one global lock for all certs, but I'm putting a cert
   2960 * arg here so that it will be easy to make it per-cert in the future if
   2961 * that turns out to be necessary.
   2962 */
   2963 void
   2964 CERT_LockCertRefCount(CERTCertificate *cert)
   2965 {
   2966    PORT_Assert(certRefCountLock != NULL);
   2967    PZ_Lock(certRefCountLock);
   2968    return;
   2969 }
   2970 
   2971 /*
   2972 * Free the cert reference count lock
   2973 */
   2974 void
   2975 CERT_UnlockCertRefCount(CERTCertificate *cert)
   2976 {
   2977    PORT_Assert(certRefCountLock != NULL);
   2978    PRStatus prstat = PZ_Unlock(certRefCountLock);
   2979    PORT_AssertArg(prstat == PR_SUCCESS);
   2980 }
   2981 
   2982 static PZLock *certTrustLock = NULL;
   2983 
   2984 /*
   2985 * Acquire the cert trust lock
   2986 * There is currently one global lock for all certs, but I'm putting a cert
   2987 * arg here so that it will be easy to make it per-cert in the future if
   2988 * that turns out to be necessary.
   2989 */
   2990 void
   2991 CERT_LockCertTrust(const CERTCertificate *cert)
   2992 {
   2993    PORT_Assert(certTrustLock != NULL);
   2994    PZ_Lock(certTrustLock);
   2995 }
   2996 
   2997 static PZLock *certTempPermCertLock = NULL;
   2998 
   2999 /*
   3000 * Acquire the cert temp/perm/nssCert lock
   3001 */
   3002 void
   3003 CERT_LockCertTempPerm(const CERTCertificate *cert)
   3004 {
   3005    PORT_Assert(certTempPermCertLock != NULL);
   3006    PZ_Lock(certTempPermCertLock);
   3007 }
   3008 
   3009 /* Maybe[Lock, Unlock] variants are only to be used by
   3010 * CERT_DestroyCertificate, since an application could
   3011 * call this after NSS_Shutdown destroys cert locks. */
   3012 void
   3013 CERT_MaybeLockCertTempPerm(const CERTCertificate *cert)
   3014 {
   3015    if (certTempPermCertLock) {
   3016        PZ_Lock(certTempPermCertLock);
   3017    }
   3018 }
   3019 
   3020 SECStatus
   3021 cert_InitLocks(void)
   3022 {
   3023    if (certRefCountLock == NULL) {
   3024        certRefCountLock = PZ_NewLock(nssILockRefLock);
   3025        PORT_Assert(certRefCountLock != NULL);
   3026        if (!certRefCountLock) {
   3027            return SECFailure;
   3028        }
   3029    }
   3030 
   3031    if (certTrustLock == NULL) {
   3032        certTrustLock = PZ_NewLock(nssILockCertDB);
   3033        PORT_Assert(certTrustLock != NULL);
   3034        if (!certTrustLock) {
   3035            PZ_DestroyLock(certRefCountLock);
   3036            certRefCountLock = NULL;
   3037            return SECFailure;
   3038        }
   3039    }
   3040 
   3041    if (certTempPermCertLock == NULL) {
   3042        certTempPermCertLock = PZ_NewLock(nssILockCertDB);
   3043        PORT_Assert(certTempPermCertLock != NULL);
   3044        if (!certTempPermCertLock) {
   3045            PZ_DestroyLock(certTrustLock);
   3046            PZ_DestroyLock(certRefCountLock);
   3047            certRefCountLock = NULL;
   3048            certTrustLock = NULL;
   3049            return SECFailure;
   3050        }
   3051    }
   3052 
   3053    return SECSuccess;
   3054 }
   3055 
   3056 SECStatus
   3057 cert_DestroyLocks(void)
   3058 {
   3059    SECStatus rv = SECSuccess;
   3060 
   3061    PORT_Assert(certRefCountLock != NULL);
   3062    if (certRefCountLock) {
   3063        PZ_DestroyLock(certRefCountLock);
   3064        certRefCountLock = NULL;
   3065    } else {
   3066        rv = SECFailure;
   3067    }
   3068 
   3069    PORT_Assert(certTrustLock != NULL);
   3070    if (certTrustLock) {
   3071        PZ_DestroyLock(certTrustLock);
   3072        certTrustLock = NULL;
   3073    } else {
   3074        rv = SECFailure;
   3075    }
   3076 
   3077    PORT_Assert(certTempPermCertLock != NULL);
   3078    if (certTempPermCertLock) {
   3079        PZ_DestroyLock(certTempPermCertLock);
   3080        certTempPermCertLock = NULL;
   3081    } else {
   3082        rv = SECFailure;
   3083    }
   3084    return rv;
   3085 }
   3086 
   3087 /*
   3088 * Free the cert trust lock
   3089 */
   3090 void
   3091 CERT_UnlockCertTrust(const CERTCertificate *cert)
   3092 {
   3093    PORT_Assert(certTrustLock != NULL);
   3094    PRStatus prstat = PZ_Unlock(certTrustLock);
   3095    PORT_AssertArg(prstat == PR_SUCCESS);
   3096 }
   3097 
   3098 /*
   3099 * Free the temp/perm/nssCert lock
   3100 */
   3101 void
   3102 CERT_UnlockCertTempPerm(const CERTCertificate *cert)
   3103 {
   3104    PORT_Assert(certTempPermCertLock != NULL);
   3105    PRStatus prstat = PZ_Unlock(certTempPermCertLock);
   3106    PORT_AssertArg(prstat == PR_SUCCESS);
   3107 }
   3108 
   3109 void
   3110 CERT_MaybeUnlockCertTempPerm(const CERTCertificate *cert)
   3111 {
   3112    if (certTempPermCertLock) {
   3113        PZ_Unlock(certTempPermCertLock);
   3114    }
   3115 }
   3116 
   3117 /*
   3118 * Get the StatusConfig data for this handle
   3119 */
   3120 CERTStatusConfig *
   3121 CERT_GetStatusConfig(CERTCertDBHandle *handle)
   3122 {
   3123    return handle->statusConfig;
   3124 }
   3125 
   3126 /*
   3127 * Set the StatusConfig data for this handle.  There
   3128 * should not be another configuration set.
   3129 */
   3130 void
   3131 CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig)
   3132 {
   3133    PORT_Assert(handle->statusConfig == NULL);
   3134    handle->statusConfig = statusConfig;
   3135 }
   3136 
   3137 /*
   3138 * Code for dealing with subjKeyID to cert mappings.
   3139 */
   3140 
   3141 static PLHashTable *gSubjKeyIDHash = NULL;
   3142 static PRLock *gSubjKeyIDLock = NULL;
   3143 static PLHashTable *gSubjKeyIDSlotCheckHash = NULL;
   3144 static PRLock *gSubjKeyIDSlotCheckLock = NULL;
   3145 
   3146 static void *
   3147 cert_AllocTable(void *pool, PRSize size)
   3148 {
   3149    return PORT_Alloc(size);
   3150 }
   3151 
   3152 static void
   3153 cert_FreeTable(void *pool, void *item)
   3154 {
   3155    PORT_Free(item);
   3156 }
   3157 
   3158 static PLHashEntry *
   3159 cert_AllocEntry(void *pool, const void *key)
   3160 {
   3161    return PORT_New(PLHashEntry);
   3162 }
   3163 
   3164 static void
   3165 cert_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
   3166 {
   3167    SECITEM_FreeItem((SECItem *)(he->value), PR_TRUE);
   3168    if (flag == HT_FREE_ENTRY) {
   3169        SECITEM_FreeItem((SECItem *)(he->key), PR_TRUE);
   3170        PORT_Free(he);
   3171    }
   3172 }
   3173 
   3174 static PLHashAllocOps cert_AllocOps = { cert_AllocTable, cert_FreeTable,
   3175                                        cert_AllocEntry, cert_FreeEntry };
   3176 
   3177 SECStatus
   3178 cert_CreateSubjectKeyIDSlotCheckHash(void)
   3179 {
   3180    /*
   3181     * This hash is used to remember the series of a slot
   3182     * when we last checked for user certs
   3183     */
   3184    gSubjKeyIDSlotCheckHash =
   3185        PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
   3186                        SECITEM_HashCompare, &cert_AllocOps, NULL);
   3187    if (!gSubjKeyIDSlotCheckHash) {
   3188        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3189        return SECFailure;
   3190    }
   3191    gSubjKeyIDSlotCheckLock = PR_NewLock();
   3192    if (!gSubjKeyIDSlotCheckLock) {
   3193        PL_HashTableDestroy(gSubjKeyIDSlotCheckHash);
   3194        gSubjKeyIDSlotCheckHash = NULL;
   3195        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3196        return SECFailure;
   3197    }
   3198    return SECSuccess;
   3199 }
   3200 
   3201 SECStatus
   3202 cert_CreateSubjectKeyIDHashTable(void)
   3203 {
   3204    gSubjKeyIDHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
   3205                                     SECITEM_HashCompare, &cert_AllocOps, NULL);
   3206    if (!gSubjKeyIDHash) {
   3207        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3208        return SECFailure;
   3209    }
   3210    gSubjKeyIDLock = PR_NewLock();
   3211    if (!gSubjKeyIDLock) {
   3212        PL_HashTableDestroy(gSubjKeyIDHash);
   3213        gSubjKeyIDHash = NULL;
   3214        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3215        return SECFailure;
   3216    }
   3217    /* initialize the companion hash (for remembering slot series) */
   3218    if (cert_CreateSubjectKeyIDSlotCheckHash() != SECSuccess) {
   3219        cert_DestroySubjectKeyIDHashTable();
   3220        return SECFailure;
   3221    }
   3222    return SECSuccess;
   3223 }
   3224 
   3225 SECStatus
   3226 cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert)
   3227 {
   3228    SECItem *newKeyID, *oldVal, *newVal;
   3229    SECStatus rv = SECFailure;
   3230 
   3231    if (!gSubjKeyIDLock) {
   3232        /* If one is created, then both are there.  So only check for one. */
   3233        return SECFailure;
   3234    }
   3235 
   3236    newVal = SECITEM_DupItem(&cert->derCert);
   3237    if (!newVal) {
   3238        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3239        goto done;
   3240    }
   3241    newKeyID = SECITEM_DupItem(subjKeyID);
   3242    if (!newKeyID) {
   3243        SECITEM_FreeItem(newVal, PR_TRUE);
   3244        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3245        goto done;
   3246    }
   3247 
   3248    PR_Lock(gSubjKeyIDLock);
   3249    /* The hash table implementation does not free up the memory
   3250     * associated with the key of an already existing entry if we add a
   3251     * duplicate, so we would wind up leaking the previously allocated
   3252     * key if we don't remove before adding.
   3253     */
   3254    oldVal = (SECItem *)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
   3255    if (oldVal) {
   3256        PL_HashTableRemove(gSubjKeyIDHash, subjKeyID);
   3257    }
   3258 
   3259    rv = (PL_HashTableAdd(gSubjKeyIDHash, newKeyID, newVal)) ? SECSuccess
   3260                                                             : SECFailure;
   3261    PR_Unlock(gSubjKeyIDLock);
   3262 done:
   3263    return rv;
   3264 }
   3265 
   3266 SECStatus
   3267 cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID)
   3268 {
   3269    SECStatus rv;
   3270    if (!gSubjKeyIDLock)
   3271        return SECFailure;
   3272 
   3273    PR_Lock(gSubjKeyIDLock);
   3274    rv = (PL_HashTableRemove(gSubjKeyIDHash, subjKeyID)) ? SECSuccess
   3275                                                         : SECFailure;
   3276    PR_Unlock(gSubjKeyIDLock);
   3277    return rv;
   3278 }
   3279 
   3280 SECStatus
   3281 cert_UpdateSubjectKeyIDSlotCheck(SECItem *slotid, int series)
   3282 {
   3283    SECItem *oldSeries, *newSlotid, *newSeries;
   3284    SECStatus rv = SECFailure;
   3285 
   3286    if (!gSubjKeyIDSlotCheckLock) {
   3287        return rv;
   3288    }
   3289 
   3290    newSlotid = SECITEM_DupItem(slotid);
   3291    newSeries = SECITEM_AllocItem(NULL, NULL, sizeof(int));
   3292    if (!newSlotid || !newSeries) {
   3293        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3294        goto loser;
   3295    }
   3296    PORT_Memcpy(newSeries->data, &series, sizeof(int));
   3297 
   3298    PR_Lock(gSubjKeyIDSlotCheckLock);
   3299    oldSeries = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid);
   3300    if (oldSeries) {
   3301        /*
   3302         * make sure we don't leak the key of an existing entry
   3303         * (similar to cert_AddSubjectKeyIDMapping, see comment there)
   3304         */
   3305        PL_HashTableRemove(gSubjKeyIDSlotCheckHash, slotid);
   3306    }
   3307    rv = (PL_HashTableAdd(gSubjKeyIDSlotCheckHash, newSlotid, newSeries))
   3308             ? SECSuccess
   3309             : SECFailure;
   3310    PR_Unlock(gSubjKeyIDSlotCheckLock);
   3311    if (rv == SECSuccess) {
   3312        return rv;
   3313    }
   3314 
   3315 loser:
   3316    if (newSlotid) {
   3317        SECITEM_FreeItem(newSlotid, PR_TRUE);
   3318    }
   3319    if (newSeries) {
   3320        SECITEM_FreeItem(newSeries, PR_TRUE);
   3321    }
   3322    return rv;
   3323 }
   3324 
   3325 int
   3326 cert_SubjectKeyIDSlotCheckSeries(SECItem *slotid)
   3327 {
   3328    SECItem *seriesItem = NULL;
   3329    int series;
   3330 
   3331    if (!gSubjKeyIDSlotCheckLock) {
   3332        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
   3333        return -1;
   3334    }
   3335 
   3336    PR_Lock(gSubjKeyIDSlotCheckLock);
   3337    seriesItem = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid);
   3338    PR_Unlock(gSubjKeyIDSlotCheckLock);
   3339    /* getting a null series just means we haven't registered one yet,
   3340     * just return 0 */
   3341    if (seriesItem == NULL) {
   3342        return 0;
   3343    }
   3344    /* if we got a series back, assert if it's not the proper length. */
   3345    PORT_Assert(seriesItem->len == sizeof(int));
   3346    if (seriesItem->len != sizeof(int)) {
   3347        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   3348        return -1;
   3349    }
   3350    PORT_Memcpy(&series, seriesItem->data, sizeof(int));
   3351    return series;
   3352 }
   3353 
   3354 SECStatus
   3355 cert_DestroySubjectKeyIDSlotCheckHash(void)
   3356 {
   3357    if (gSubjKeyIDSlotCheckHash) {
   3358        PR_Lock(gSubjKeyIDSlotCheckLock);
   3359        PL_HashTableDestroy(gSubjKeyIDSlotCheckHash);
   3360        gSubjKeyIDSlotCheckHash = NULL;
   3361        PR_Unlock(gSubjKeyIDSlotCheckLock);
   3362        PR_DestroyLock(gSubjKeyIDSlotCheckLock);
   3363        gSubjKeyIDSlotCheckLock = NULL;
   3364    }
   3365    return SECSuccess;
   3366 }
   3367 
   3368 SECStatus
   3369 cert_DestroySubjectKeyIDHashTable(void)
   3370 {
   3371    if (gSubjKeyIDHash) {
   3372        PR_Lock(gSubjKeyIDLock);
   3373        PL_HashTableDestroy(gSubjKeyIDHash);
   3374        gSubjKeyIDHash = NULL;
   3375        PR_Unlock(gSubjKeyIDLock);
   3376        PR_DestroyLock(gSubjKeyIDLock);
   3377        gSubjKeyIDLock = NULL;
   3378    }
   3379    cert_DestroySubjectKeyIDSlotCheckHash();
   3380    return SECSuccess;
   3381 }
   3382 
   3383 SECItem *
   3384 cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID)
   3385 {
   3386    SECItem *val;
   3387 
   3388    if (!gSubjKeyIDLock)
   3389        return NULL;
   3390 
   3391    PR_Lock(gSubjKeyIDLock);
   3392    val = (SECItem *)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
   3393    if (val) {
   3394        val = SECITEM_DupItem(val);
   3395    }
   3396    PR_Unlock(gSubjKeyIDLock);
   3397    return val;
   3398 }
   3399 
   3400 CERTCertificate *
   3401 CERT_FindCertBySubjectKeyID(CERTCertDBHandle *handle, SECItem *subjKeyID)
   3402 {
   3403    CERTCertificate *cert = NULL;
   3404    SECItem *derCert;
   3405 
   3406    derCert = cert_FindDERCertBySubjectKeyID(subjKeyID);
   3407    if (derCert) {
   3408        cert = CERT_FindCertByDERCert(handle, derCert);
   3409        SECITEM_FreeItem(derCert, PR_TRUE);
   3410    }
   3411    return cert;
   3412 }