Back to index

lightning-sunbird  0.9+nobinonly
certdb.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *    Aaron Spangler <aaron@spangler.ods.org>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * Certificate handling code
00040  *
00041  * $Id: certdb.c,v 1.76.2.1 2006/02/16 00:14:18 julien.pierre.bugs%sun.com Exp $
00042  */
00043 
00044 #include "nssilock.h"
00045 #include "prmon.h"
00046 #include "prtime.h"
00047 #include "cert.h"
00048 #include "certi.h"
00049 #include "secder.h"
00050 #include "secoid.h"
00051 #include "secasn1.h"
00052 #include "genname.h"
00053 #include "keyhi.h"
00054 #include "secitem.h"
00055 #include "mcom_db.h"
00056 #include "certdb.h"
00057 #include "prprf.h"
00058 #include "sechash.h"
00059 #include "prlong.h"
00060 #include "certxutl.h"
00061 #include "portreg.h"
00062 #include "secerr.h"
00063 #include "sslerr.h"
00064 #include "nsslocks.h"
00065 #include "pk11func.h"
00066 #include "xconst.h"   /* for  CERT_DecodeAltNameExtension */
00067 
00068 #ifndef NSS_3_4_CODE
00069 #define NSS_3_4_CODE
00070 #endif /* NSS_3_4_CODE */
00071 #include "pki.h"
00072 #include "pki3hack.h"
00073 
00074 /*
00075  * Certificate database handling code
00076  */
00077 
00078 
00079 const SEC_ASN1Template CERT_CertExtensionTemplate[] = {
00080     { SEC_ASN1_SEQUENCE,
00081          0, NULL, sizeof(CERTCertExtension) },
00082     { SEC_ASN1_OBJECT_ID,
00083          offsetof(CERTCertExtension,id) },
00084     { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN,             /* XXX DER_DEFAULT */
00085          offsetof(CERTCertExtension,critical) },
00086     { SEC_ASN1_OCTET_STRING,
00087          offsetof(CERTCertExtension,value) },
00088     { 0, }
00089 };
00090 
00091 const SEC_ASN1Template CERT_SequenceOfCertExtensionTemplate[] = {
00092     { SEC_ASN1_SEQUENCE_OF, 0, CERT_CertExtensionTemplate }
00093 };
00094 
00095 const SEC_ASN1Template CERT_CertificateTemplate[] = {
00096     { SEC_ASN1_SEQUENCE,
00097       0, NULL, sizeof(CERTCertificate) },
00098     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
00099          SEC_ASN1_CONTEXT_SPECIFIC | 0,          /* XXX DER_DEFAULT */ 
00100          offsetof(CERTCertificate,version),
00101          SEC_IntegerTemplate },
00102     { SEC_ASN1_INTEGER,
00103          offsetof(CERTCertificate,serialNumber) },
00104     { SEC_ASN1_INLINE,
00105          offsetof(CERTCertificate,signature),
00106          SECOID_AlgorithmIDTemplate },
00107     { SEC_ASN1_SAVE, 
00108          offsetof(CERTCertificate,derIssuer) },
00109     { SEC_ASN1_INLINE,
00110          offsetof(CERTCertificate,issuer),
00111          CERT_NameTemplate },
00112     { SEC_ASN1_INLINE,
00113          offsetof(CERTCertificate,validity),
00114          CERT_ValidityTemplate },
00115     { SEC_ASN1_SAVE,
00116          offsetof(CERTCertificate,derSubject) },
00117     { SEC_ASN1_INLINE,
00118          offsetof(CERTCertificate,subject),
00119          CERT_NameTemplate },
00120     { SEC_ASN1_SAVE,
00121          offsetof(CERTCertificate,derPublicKey) },
00122     { SEC_ASN1_INLINE,
00123          offsetof(CERTCertificate,subjectPublicKeyInfo),
00124          CERT_SubjectPublicKeyInfoTemplate },
00125     { SEC_ASN1_OPTIONAL |  SEC_ASN1_CONTEXT_SPECIFIC | 1,
00126          offsetof(CERTCertificate,issuerID),
00127          SEC_BitStringTemplate },
00128     { SEC_ASN1_OPTIONAL |  SEC_ASN1_CONTEXT_SPECIFIC | 2,
00129          offsetof(CERTCertificate,subjectID),
00130          SEC_BitStringTemplate },
00131     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
00132          SEC_ASN1_CONTEXT_SPECIFIC | 3,
00133          offsetof(CERTCertificate,extensions),
00134          CERT_SequenceOfCertExtensionTemplate },
00135     { 0 }
00136 };
00137 
00138 const SEC_ASN1Template SEC_SignedCertificateTemplate[] =
00139 {
00140     { SEC_ASN1_SEQUENCE,
00141          0, NULL, sizeof(CERTCertificate) },
00142     { SEC_ASN1_SAVE, 
00143          offsetof(CERTCertificate,signatureWrap.data) },
00144     { SEC_ASN1_INLINE, 
00145          0, CERT_CertificateTemplate },
00146     { SEC_ASN1_INLINE,
00147          offsetof(CERTCertificate,signatureWrap.signatureAlgorithm),
00148          SECOID_AlgorithmIDTemplate },
00149     { SEC_ASN1_BIT_STRING,
00150          offsetof(CERTCertificate,signatureWrap.signature) },
00151     { 0 }
00152 };
00153 
00154 /*
00155  * Find the subjectName in a DER encoded certificate
00156  */
00157 const SEC_ASN1Template SEC_CertSubjectTemplate[] = {
00158     { SEC_ASN1_SEQUENCE,
00159          0, NULL, sizeof(SECItem) },
00160     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
00161          SEC_ASN1_CONTEXT_SPECIFIC | 0,
00162          0, SEC_SkipTemplate },    /* version */
00163     { SEC_ASN1_SKIP },             /* serial number */
00164     { SEC_ASN1_SKIP },             /* signature algorithm */
00165     { SEC_ASN1_SKIP },             /* issuer */
00166     { SEC_ASN1_SKIP },             /* validity */
00167     { SEC_ASN1_ANY, 0, NULL },            /* subject */
00168     { SEC_ASN1_SKIP_REST },
00169     { 0 }
00170 };
00171 
00172 /*
00173  * Find the issuerName in a DER encoded certificate
00174  */
00175 const SEC_ASN1Template SEC_CertIssuerTemplate[] = {
00176     { SEC_ASN1_SEQUENCE,
00177          0, NULL, sizeof(SECItem) },
00178     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
00179          SEC_ASN1_CONTEXT_SPECIFIC | 0,
00180          0, SEC_SkipTemplate },    /* version */
00181     { SEC_ASN1_SKIP },             /* serial number */
00182     { SEC_ASN1_SKIP },             /* signature algorithm */
00183     { SEC_ASN1_ANY, 0, NULL },            /* issuer */
00184     { SEC_ASN1_SKIP_REST },
00185     { 0 }
00186 };
00187 /*
00188  * Find the subjectName in a DER encoded certificate
00189  */
00190 const SEC_ASN1Template SEC_CertSerialNumberTemplate[] = {
00191     { SEC_ASN1_SEQUENCE,
00192          0, NULL, sizeof(SECItem) },
00193     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
00194          SEC_ASN1_CONTEXT_SPECIFIC | 0,
00195          0, SEC_SkipTemplate },    /* version */
00196     { SEC_ASN1_ANY, 0, NULL }, /* serial number */
00197     { SEC_ASN1_SKIP_REST },
00198     { 0 }
00199 };
00200 
00201 /*
00202  * Find the issuer and serialNumber in a DER encoded certificate.
00203  * This data is used as the database lookup key since its the unique
00204  * identifier of a certificate.
00205  */
00206 const SEC_ASN1Template CERT_CertKeyTemplate[] = {
00207     { SEC_ASN1_SEQUENCE,
00208          0, NULL, sizeof(CERTCertKey) },
00209     { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 
00210          SEC_ASN1_CONTEXT_SPECIFIC | 0,
00211          0, SEC_SkipTemplate },    /* version */ 
00212     { SEC_ASN1_INTEGER,
00213          offsetof(CERTCertKey,serialNumber) },
00214     { SEC_ASN1_SKIP },             /* signature algorithm */
00215     { SEC_ASN1_ANY,
00216          offsetof(CERTCertKey,derIssuer) },
00217     { SEC_ASN1_SKIP_REST },
00218     { 0 }
00219 };
00220 
00221 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateTemplate)
00222 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SignedCertificateTemplate)
00223 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SequenceOfCertExtensionTemplate)
00224 
00225 SECStatus
00226 CERT_KeyFromIssuerAndSN(PRArenaPool *arena, SECItem *issuer, SECItem *sn,
00227                      SECItem *key)
00228 {
00229     key->len = sn->len + issuer->len;
00230 
00231     if ((sn->data == NULL) || (issuer->data == NULL)) {
00232        goto loser;
00233     }
00234     
00235     key->data = (unsigned char*)PORT_ArenaAlloc(arena, key->len);
00236     if ( !key->data ) {
00237        goto loser;
00238     }
00239 
00240     /* copy the serialNumber */
00241     PORT_Memcpy(key->data, sn->data, sn->len);
00242 
00243     /* copy the issuer */
00244     PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
00245 
00246     return(SECSuccess);
00247 
00248 loser:
00249     return(SECFailure);
00250 }
00251 
00252 
00253 /*
00254  * Extract the subject name from a DER certificate
00255  */
00256 SECStatus
00257 CERT_NameFromDERCert(SECItem *derCert, SECItem *derName)
00258 {
00259     int rv;
00260     PRArenaPool *arena;
00261     CERTSignedData sd;
00262     void *tmpptr;
00263     
00264     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00265     
00266     if ( ! arena ) {
00267        return(SECFailure);
00268     }
00269    
00270     PORT_Memset(&sd, 0, sizeof(CERTSignedData));
00271     rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
00272     
00273     if ( rv ) {
00274        goto loser;
00275     }
00276     
00277     PORT_Memset(derName, 0, sizeof(SECItem));
00278     rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSubjectTemplate, &sd.data);
00279 
00280     if ( rv ) {
00281        goto loser;
00282     }
00283 
00284     tmpptr = derName->data;
00285     derName->data = (unsigned char*)PORT_Alloc(derName->len);
00286     if ( derName->data == NULL ) {
00287        goto loser;
00288     }
00289     
00290     PORT_Memcpy(derName->data, tmpptr, derName->len);
00291     
00292     PORT_FreeArena(arena, PR_FALSE);
00293     return(SECSuccess);
00294 
00295 loser:
00296     PORT_FreeArena(arena, PR_FALSE);
00297     return(SECFailure);
00298 }
00299 
00300 SECStatus
00301 CERT_IssuerNameFromDERCert(SECItem *derCert, SECItem *derName)
00302 {
00303     int rv;
00304     PRArenaPool *arena;
00305     CERTSignedData sd;
00306     void *tmpptr;
00307     
00308     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00309     
00310     if ( ! arena ) {
00311        return(SECFailure);
00312     }
00313    
00314     PORT_Memset(&sd, 0, sizeof(CERTSignedData));
00315     rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
00316     
00317     if ( rv ) {
00318        goto loser;
00319     }
00320     
00321     PORT_Memset(derName, 0, sizeof(SECItem));
00322     rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertIssuerTemplate, &sd.data);
00323 
00324     if ( rv ) {
00325        goto loser;
00326     }
00327 
00328     tmpptr = derName->data;
00329     derName->data = (unsigned char*)PORT_Alloc(derName->len);
00330     if ( derName->data == NULL ) {
00331        goto loser;
00332     }
00333     
00334     PORT_Memcpy(derName->data, tmpptr, derName->len);
00335     
00336     PORT_FreeArena(arena, PR_FALSE);
00337     return(SECSuccess);
00338 
00339 loser:
00340     PORT_FreeArena(arena, PR_FALSE);
00341     return(SECFailure);
00342 }
00343 
00344 SECStatus
00345 CERT_SerialNumberFromDERCert(SECItem *derCert, SECItem *derName)
00346 {
00347     int rv;
00348     PRArenaPool *arena;
00349     CERTSignedData sd;
00350     void *tmpptr;
00351     
00352     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00353     
00354     if ( ! arena ) {
00355        return(SECFailure);
00356     }
00357    
00358     PORT_Memset(&sd, 0, sizeof(CERTSignedData));
00359     rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
00360     
00361     if ( rv ) {
00362        goto loser;
00363     }
00364     
00365     PORT_Memset(derName, 0, sizeof(SECItem));
00366     rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSerialNumberTemplate, &sd.data);
00367 
00368     if ( rv ) {
00369        goto loser;
00370     }
00371 
00372     tmpptr = derName->data;
00373     derName->data = (unsigned char*)PORT_Alloc(derName->len);
00374     if ( derName->data == NULL ) {
00375        goto loser;
00376     }
00377     
00378     PORT_Memcpy(derName->data, tmpptr, derName->len);
00379     
00380     PORT_FreeArena(arena, PR_FALSE);
00381     return(SECSuccess);
00382 
00383 loser:
00384     PORT_FreeArena(arena, PR_FALSE);
00385     return(SECFailure);
00386 }
00387 
00388 /*
00389  * Generate a database key, based on serial number and issuer, from a
00390  * DER certificate.
00391  */
00392 SECStatus
00393 CERT_KeyFromDERCert(PRArenaPool *arena, SECItem *derCert, SECItem *key)
00394 {
00395     int rv;
00396     CERTSignedData sd;
00397     CERTCertKey certkey;
00398 
00399     PORT_Memset(&sd, 0, sizeof(CERTSignedData));
00400     rv = SEC_ASN1DecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
00401     
00402     if ( rv ) {
00403        goto loser;
00404     }
00405     
00406     PORT_Memset(&certkey, 0, sizeof(CERTCertKey));
00407     rv = SEC_ASN1DecodeItem(arena, &certkey, CERT_CertKeyTemplate, &sd.data);
00408 
00409     if ( rv ) {
00410        goto loser;
00411     }
00412 
00413     return(CERT_KeyFromIssuerAndSN(arena, &certkey.derIssuer,
00414                                &certkey.serialNumber, key));
00415 loser:
00416     return(SECFailure);
00417 }
00418 
00419 /*
00420  * fill in keyUsage field of the cert based on the cert extension
00421  * if the extension is not critical, then we allow all uses
00422  */
00423 static SECStatus
00424 GetKeyUsage(CERTCertificate *cert)
00425 {
00426     SECStatus rv;
00427     SECItem tmpitem;
00428     
00429     rv = CERT_FindKeyUsageExtension(cert, &tmpitem);
00430     if ( rv == SECSuccess ) {
00431        /* remember the actual value of the extension */
00432        cert->rawKeyUsage = tmpitem.data[0];
00433        cert->keyUsagePresent = PR_TRUE;
00434        cert->keyUsage = tmpitem.data[0];
00435 
00436        PORT_Free(tmpitem.data);
00437        tmpitem.data = NULL;
00438        
00439     } else {
00440        /* if the extension is not present, then we allow all uses */
00441        cert->keyUsage = KU_ALL;
00442        cert->rawKeyUsage = KU_ALL;
00443        cert->keyUsagePresent = PR_FALSE;
00444     }
00445 
00446     if ( CERT_GovtApprovedBitSet(cert) ) {
00447        cert->keyUsage |= KU_NS_GOVT_APPROVED;
00448        cert->rawKeyUsage |= KU_NS_GOVT_APPROVED;
00449     }
00450     
00451     return(SECSuccess);
00452 }
00453 
00454 
00455 /*
00456  * determine if a fortezza V1 Cert is a CA or not.
00457  */
00458 static PRBool
00459 fortezzaIsCA( CERTCertificate *cert) {
00460     PRBool isCA = PR_FALSE;
00461     CERTSubjectPublicKeyInfo *spki = &cert->subjectPublicKeyInfo;
00462     int tag;
00463 
00464     tag = SECOID_GetAlgorithmTag(&spki->algorithm);
00465     if ((tag == SEC_OID_MISSI_KEA_DSS_OLD) ||
00466        (tag == SEC_OID_MISSI_KEA_DSS) ||
00467        (tag == SEC_OID_MISSI_DSS_OLD) ||
00468        (tag == SEC_OID_MISSI_DSS) ) {
00469        SECItem rawkey;
00470        unsigned char *rawptr;
00471        unsigned char *end;
00472        int len;
00473 
00474        rawkey = spki->subjectPublicKey;
00475        DER_ConvertBitString(&rawkey);
00476        rawptr = rawkey.data;
00477        end = rawkey.data + rawkey.len;
00478 
00479        /* version */ 
00480        rawptr += sizeof(((SECKEYPublicKey*)0)->u.fortezza.KMID)+2;
00481 
00482        /* clearance (the string up to the first byte with the hi-bit on */
00483        while ((rawptr < end) && (*rawptr++ & 0x80));
00484        if (rawptr >= end) { return PR_FALSE; }
00485 
00486        /* KEAPrivilege (the string up to the first byte with the hi-bit on */
00487        while ((rawptr < end) && (*rawptr++ & 0x80));
00488        if (rawptr >= end) { return PR_FALSE; }
00489 
00490        /* skip the key */
00491        len = (*rawptr << 8) | rawptr[1];
00492        rawptr += 2 + len;
00493 
00494        /* shared key */
00495        if (rawptr >= end) { return PR_FALSE; }
00496        /* DSS Version is next */
00497        rawptr += 2;
00498 
00499        /* DSSPrivilege (the string up to the first byte with the hi-bit on */
00500        if (*rawptr & 0x30) isCA = PR_TRUE;
00501        
00502    }
00503    return isCA;
00504 }
00505 
00506 static SECStatus
00507 findOIDinOIDSeqByTagNum(CERTOidSequence *seq, SECOidTag tagnum)
00508 {
00509     SECItem **oids;
00510     SECItem *oid;
00511     SECStatus rv = SECFailure;
00512     
00513     if (seq != NULL) {
00514        oids = seq->oids;
00515        while (oids != NULL && *oids != NULL) {
00516            oid = *oids;
00517            if (SECOID_FindOIDTag(oid) == tagnum) {
00518               rv = SECSuccess;
00519               break;
00520            }
00521            oids++;
00522        }
00523     }
00524     return rv;
00525 }
00526 
00527 /*
00528  * fill in nsCertType field of the cert based on the cert extension
00529  */
00530 SECStatus
00531 cert_GetCertType(CERTCertificate *cert)
00532 {
00533     SECStatus rv;
00534     SECItem tmpitem;
00535     SECItem encodedExtKeyUsage;
00536     CERTOidSequence *extKeyUsage = NULL;
00537     PRBool basicConstraintPresent = PR_FALSE;
00538     CERTBasicConstraints basicConstraint;
00539     unsigned int nsCertType = 0;
00540 
00541     if (cert->nsCertType) {
00542         /* once set, no need to recalculate */
00543         return SECSuccess;
00544     }
00545 
00546     tmpitem.data = NULL;
00547     CERT_FindNSCertTypeExtension(cert, &tmpitem);
00548     encodedExtKeyUsage.data = NULL;
00549     rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, 
00550                             &encodedExtKeyUsage);
00551     if (rv == SECSuccess) {
00552        extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);
00553     }
00554     rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
00555     if (rv == SECSuccess) {
00556        basicConstraintPresent = PR_TRUE;
00557     }
00558     if (tmpitem.data != NULL || extKeyUsage != NULL) {
00559        if (tmpitem.data == NULL) {
00560            nsCertType = 0;
00561        } else {
00562            nsCertType = tmpitem.data[0];
00563        }
00564 
00565        /* free tmpitem data pointer to avoid memory leak */
00566        PORT_Free(tmpitem.data);
00567        tmpitem.data = NULL;
00568        
00569        /*
00570         * for this release, we will allow SSL certs with an email address
00571         * to be used for email
00572         */
00573        if ( ( nsCertType & NS_CERT_TYPE_SSL_CLIENT ) &&
00574            cert->emailAddr && cert->emailAddr[0]) {
00575            nsCertType |= NS_CERT_TYPE_EMAIL;
00576        }
00577        /*
00578         * for this release, we will allow SSL intermediate CAs to be
00579         * email intermediate CAs too.
00580         */
00581        if ( nsCertType & NS_CERT_TYPE_SSL_CA ) {
00582            nsCertType |= NS_CERT_TYPE_EMAIL_CA;
00583        }
00584        /*
00585         * allow a cert with the extended key usage of EMail Protect
00586         * to be used for email or as an email CA, if basic constraints
00587         * indicates that it is a CA.
00588         */
00589        if (findOIDinOIDSeqByTagNum(extKeyUsage, 
00590                                 SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT) ==
00591            SECSuccess) {
00592            if (basicConstraintPresent == PR_TRUE &&
00593               (basicConstraint.isCA)) {
00594               nsCertType |= NS_CERT_TYPE_EMAIL_CA;
00595            } else {
00596               nsCertType |= NS_CERT_TYPE_EMAIL;
00597            }
00598        }
00599        if (findOIDinOIDSeqByTagNum(extKeyUsage, 
00600                                 SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) ==
00601            SECSuccess){
00602            if (basicConstraintPresent == PR_TRUE &&
00603               (basicConstraint.isCA)) {
00604               nsCertType |= NS_CERT_TYPE_SSL_CA;
00605            } else {
00606               nsCertType |= NS_CERT_TYPE_SSL_SERVER;
00607            }
00608        }
00609        /* Treat certs with step-up OID as also having SSL server type. */
00610        if (findOIDinOIDSeqByTagNum(extKeyUsage, 
00611                                 SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) ==
00612            SECSuccess){
00613            if (basicConstraintPresent == PR_TRUE &&
00614               (basicConstraint.isCA)) {
00615               nsCertType |= NS_CERT_TYPE_SSL_CA;
00616            } else {
00617               nsCertType |= NS_CERT_TYPE_SSL_SERVER;
00618            }
00619        }
00620        if (findOIDinOIDSeqByTagNum(extKeyUsage,
00621                                 SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH) ==
00622            SECSuccess){
00623            if (basicConstraintPresent == PR_TRUE &&
00624               (basicConstraint.isCA)) {
00625               nsCertType |= NS_CERT_TYPE_SSL_CA;
00626            } else {
00627               nsCertType |= NS_CERT_TYPE_SSL_CLIENT;
00628            }
00629        }
00630        if (findOIDinOIDSeqByTagNum(extKeyUsage,
00631                                 SEC_OID_EXT_KEY_USAGE_CODE_SIGN) ==
00632            SECSuccess) {
00633            if (basicConstraintPresent == PR_TRUE &&
00634               (basicConstraint.isCA)) {
00635               nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
00636            } else {
00637               nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING;
00638            }
00639        }
00640        if (findOIDinOIDSeqByTagNum(extKeyUsage,
00641                                 SEC_OID_EXT_KEY_USAGE_TIME_STAMP) ==
00642            SECSuccess) {
00643            nsCertType |= EXT_KEY_USAGE_TIME_STAMP;
00644        }
00645        if (findOIDinOIDSeqByTagNum(extKeyUsage,
00646                                 SEC_OID_OCSP_RESPONDER) == 
00647            SECSuccess) {
00648            nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
00649        }
00650     } else {
00651        /* if no extension, then allow any ssl or email (no ca or object
00652         * signing)
00653         */
00654        nsCertType = NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER |
00655            NS_CERT_TYPE_EMAIL;
00656 
00657        /* if the basic constraint extension says the cert is a CA, then
00658           allow SSL CA and EMAIL CA and Status Responder */
00659        if ((basicConstraintPresent == PR_TRUE)
00660            && (basicConstraint.isCA)) {
00661               nsCertType |= NS_CERT_TYPE_SSL_CA;
00662               nsCertType |= NS_CERT_TYPE_EMAIL_CA;
00663               nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
00664        } else if (CERT_IsCACert(cert, NULL) == PR_TRUE) {
00665               nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
00666        }
00667 
00668        /* if the cert is a fortezza CA cert, then allow SSL CA and EMAIL CA */
00669        if (fortezzaIsCA(cert)) {
00670               nsCertType |= NS_CERT_TYPE_SSL_CA;
00671               nsCertType |= NS_CERT_TYPE_EMAIL_CA;
00672        }
00673     }
00674 
00675     if (encodedExtKeyUsage.data != NULL) {
00676        PORT_Free(encodedExtKeyUsage.data);
00677     }
00678     if (extKeyUsage != NULL) {
00679        CERT_DestroyOidSequence(extKeyUsage);
00680     }
00681     /* Assert that it is safe to cast &cert->nsCertType to "PRInt32 *" */
00682     PORT_Assert(sizeof(cert->nsCertType) == sizeof(PRInt32));
00683     PR_AtomicSet((PRInt32 *)&cert->nsCertType, nsCertType);
00684     return(SECSuccess);
00685 }
00686 
00687 /*
00688  * cert_GetKeyID() - extract or generate the subjectKeyID from a certificate
00689  */
00690 SECStatus
00691 cert_GetKeyID(CERTCertificate *cert)
00692 {
00693     SECItem tmpitem;
00694     SECStatus rv;
00695     SECKEYPublicKey *key;
00696     
00697     cert->subjectKeyID.len = 0;
00698 
00699     /* see of the cert has a key identifier extension */
00700     rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
00701     if ( rv == SECSuccess ) {
00702        cert->subjectKeyID.data = (unsigned char*) PORT_ArenaAlloc(cert->arena, tmpitem.len);
00703        if ( cert->subjectKeyID.data != NULL ) {
00704            PORT_Memcpy(cert->subjectKeyID.data, tmpitem.data, tmpitem.len);
00705            cert->subjectKeyID.len = tmpitem.len;
00706            cert->keyIDGenerated = PR_FALSE;
00707        }
00708        
00709        PORT_Free(tmpitem.data);
00710     }
00711     
00712     /* if the cert doesn't have a key identifier extension and the cert is
00713      * a V1 fortezza certificate, use the cert's 8 byte KMID as the
00714      * key identifier.  */
00715     key = CERT_KMIDPublicKey(cert);
00716 
00717     if (key != NULL) {
00718        
00719        if (key->keyType == fortezzaKey) {
00720 
00721            cert->subjectKeyID.data = (unsigned char *)PORT_ArenaAlloc(cert->arena, 8);
00722            if ( cert->subjectKeyID.data != NULL ) {
00723               PORT_Memcpy(cert->subjectKeyID.data, key->u.fortezza.KMID, 8);
00724               cert->subjectKeyID.len = 8;
00725               cert->keyIDGenerated = PR_FALSE;
00726            }
00727        }
00728               
00729        SECKEY_DestroyPublicKey(key);
00730     }
00731 
00732     /* if the cert doesn't have a key identifier extension, then generate one*/
00733     if ( cert->subjectKeyID.len == 0 ) {
00734        /*
00735         * pkix says that if the subjectKeyID is not present, then we should
00736         * use the SHA-1 hash of the DER-encoded publicKeyInfo from the cert
00737         */
00738        cert->subjectKeyID.data = (unsigned char *)PORT_ArenaAlloc(cert->arena, SHA1_LENGTH);
00739        if ( cert->subjectKeyID.data != NULL ) {
00740            rv = PK11_HashBuf(SEC_OID_SHA1,cert->subjectKeyID.data,
00741                            cert->derPublicKey.data,
00742                            cert->derPublicKey.len);
00743            if ( rv == SECSuccess ) {
00744               cert->subjectKeyID.len = SHA1_LENGTH;
00745            }
00746        }
00747     }
00748 
00749     if ( cert->subjectKeyID.len == 0 ) {
00750        return(SECFailure);
00751     }
00752     return(SECSuccess);
00753 
00754 }
00755 
00756 static PRBool
00757 cert_IsRootCert(CERTCertificate *cert)
00758 {
00759     SECStatus rv;
00760     SECItem tmpitem;
00761 
00762     /* cache the authKeyID extension, if present */
00763     cert->authKeyID = CERT_FindAuthKeyIDExten(cert->arena, cert);
00764 
00765     /* it MUST be self-issued to be a root */
00766     if (cert->derIssuer.len == 0 ||
00767         !SECITEM_ItemsAreEqual(&cert->derIssuer, &cert->derSubject))
00768     {
00769        return PR_FALSE;
00770     }
00771 
00772     /* check the authKeyID extension */
00773     if (cert->authKeyID) {
00774        /* authority key identifier is present */
00775        if (cert->authKeyID->keyID.len > 0) {
00776            /* the keyIdentifier field is set, look for subjectKeyID */
00777            rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
00778            if (rv == SECSuccess) {
00779               PRBool match;
00780               /* also present, they MUST match for it to be a root */
00781               match = SECITEM_ItemsAreEqual(&cert->authKeyID->keyID,
00782                                             &tmpitem);
00783               PORT_Free(tmpitem.data);
00784               if (!match) return PR_FALSE; /* else fall through */
00785            } else {
00786               /* the subject key ID is required when AKI is present */
00787               return PR_FALSE;
00788            }
00789        }
00790        if (cert->authKeyID->authCertIssuer) {
00791            SECItem *caName;
00792            caName = (SECItem *)CERT_GetGeneralNameByType(
00793                                          cert->authKeyID->authCertIssuer,
00794                                          certDirectoryName, PR_TRUE);
00795            if (caName) {
00796               if (!SECITEM_ItemsAreEqual(&cert->derIssuer, caName)) {
00797                   return PR_FALSE;
00798               } /* else fall through */
00799            } /* else ??? could not get general name as directory name? */
00800        }
00801        if (cert->authKeyID->authCertSerialNumber.len > 0) {
00802            if (!SECITEM_ItemsAreEqual(&cert->serialNumber,
00803                                 &cert->authKeyID->authCertSerialNumber)) {
00804               return PR_FALSE;
00805            } /* else fall through */
00806        }
00807        /* all of the AKI fields that were present passed the test */
00808        return PR_TRUE;
00809     }
00810     /* else the AKI was not present, so this is a root */
00811     return PR_TRUE;
00812 }
00813 
00814 /*
00815  * take a DER certificate and decode it into a certificate structure
00816  */
00817 CERTCertificate *
00818 CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
00819                       char *nickname)
00820 {
00821     CERTCertificate *cert;
00822     PRArenaPool *arena;
00823     void *data;
00824     int rv;
00825     int len;
00826     char *tmpname;
00827     
00828     /* make a new arena */
00829     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00830     
00831     if ( !arena ) {
00832        return 0;
00833     }
00834 
00835     /* allocate the certificate structure */
00836     cert = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
00837     
00838     if ( !cert ) {
00839        goto loser;
00840     }
00841     
00842     cert->arena = arena;
00843     
00844     if ( copyDER ) {
00845        /* copy the DER data for the cert into this arena */
00846        data = (void *)PORT_ArenaAlloc(arena, derSignedCert->len);
00847        if ( !data ) {
00848            goto loser;
00849        }
00850        cert->derCert.data = (unsigned char *)data;
00851        cert->derCert.len = derSignedCert->len;
00852        PORT_Memcpy(data, derSignedCert->data, derSignedCert->len);
00853     } else {
00854        /* point to passed in DER data */
00855        cert->derCert = *derSignedCert;
00856     }
00857 
00858     /* decode the certificate info */
00859     rv = SEC_QuickDERDecodeItem(arena, cert, SEC_SignedCertificateTemplate,
00860                   &cert->derCert);
00861 
00862     if ( rv ) {
00863        goto loser;
00864     }
00865 
00866     if (cert_HasUnknownCriticalExten (cert->extensions) == PR_TRUE) {
00867         cert->options.bits.hasUnsupportedCriticalExt = PR_TRUE;
00868     }
00869 
00870     /* generate and save the database key for the cert */
00871     rv = CERT_KeyFromIssuerAndSN(arena, &cert->derIssuer, &cert->serialNumber,
00872                      &cert->certKey);
00873     if ( rv ) {
00874        goto loser;
00875     }
00876 
00877     /* set the nickname */
00878     if ( nickname == NULL ) {
00879        cert->nickname = NULL;
00880     } else {
00881        /* copy and install the nickname */
00882        len = PORT_Strlen(nickname) + 1;
00883        cert->nickname = (char*)PORT_ArenaAlloc(arena, len);
00884        if ( cert->nickname == NULL ) {
00885            goto loser;
00886        }
00887 
00888        PORT_Memcpy(cert->nickname, nickname, len);
00889     }
00890 
00891     /* set the email address */
00892     cert->emailAddr = cert_GetCertificateEmailAddresses(cert);
00893     
00894     /* initialize the subjectKeyID */
00895     rv = cert_GetKeyID(cert);
00896     if ( rv != SECSuccess ) {
00897        goto loser;
00898     }
00899 
00900     /* initialize keyUsage */
00901     rv = GetKeyUsage(cert);
00902     if ( rv != SECSuccess ) {
00903        goto loser;
00904     }
00905 
00906     /* initialize the certType */
00907     rv = cert_GetCertType(cert);
00908     if ( rv != SECSuccess ) {
00909        goto loser;
00910     }
00911 
00912     /* determine if this is a root cert */
00913     cert->isRoot = cert_IsRootCert(cert);
00914 
00915     tmpname = CERT_NameToAscii(&cert->subject);
00916     if ( tmpname != NULL ) {
00917        cert->subjectName = PORT_ArenaStrdup(cert->arena, tmpname);
00918        PORT_Free(tmpname);
00919     }
00920     
00921     tmpname = CERT_NameToAscii(&cert->issuer);
00922     if ( tmpname != NULL ) {
00923        cert->issuerName = PORT_ArenaStrdup(cert->arena, tmpname);
00924        PORT_Free(tmpname);
00925     }
00926     
00927     cert->referenceCount = 1;
00928     cert->slot = NULL;
00929     cert->pkcs11ID = CK_INVALID_HANDLE;
00930     cert->dbnickname = NULL;
00931     
00932     return(cert);
00933     
00934 loser:
00935 
00936     if ( arena ) {
00937        PORT_FreeArena(arena, PR_FALSE);
00938     }
00939     
00940     return(0);
00941 }
00942 
00943 CERTCertificate *
00944 __CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
00945                       char *nickname)
00946 {
00947     return CERT_DecodeDERCertificate(derSignedCert, copyDER, nickname);
00948 }
00949 
00950 
00951 /*
00952 ** Amount of time that a certifiate is allowed good before it is actually
00953 ** good. This is used for pending certificates, ones that are about to be
00954 ** valid. The slop is designed to allow for some variance in the clocks
00955 ** of the machine checking the certificate.
00956 */
00957 #define PENDING_SLOP (24L*60L*60L)        /* seconds per day */
00958 static PRInt32 pendingSlop = PENDING_SLOP;       /* seconds */
00959 
00960 PRInt32
00961 CERT_GetSlopTime(void)
00962 {
00963     return pendingSlop;                   /* seconds */
00964 }
00965 
00966 SECStatus
00967 CERT_SetSlopTime(PRInt32 slop)            /* seconds */
00968 {
00969     if (slop < 0)
00970        return SECFailure;
00971     pendingSlop = slop;
00972     return SECSuccess;
00973 }
00974 
00975 SECStatus
00976 CERT_GetCertTimes(CERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
00977 {
00978     SECStatus rv;
00979 
00980     if (!c || !notBefore || !notAfter) {
00981         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00982         return SECFailure;
00983     }
00984     
00985     /* convert DER not-before time */
00986     rv = DER_DecodeTimeChoice(notBefore, &c->validity.notBefore);
00987     if (rv) {
00988        return(SECFailure);
00989     }
00990     
00991     /* convert DER not-after time */
00992     rv = DER_DecodeTimeChoice(notAfter, &c->validity.notAfter);
00993     if (rv) {
00994        return(SECFailure);
00995     }
00996 
00997     return(SECSuccess);
00998 }
00999 
01000 /*
01001  * Check the validity times of a certificate
01002  */
01003 SECCertTimeValidity
01004 CERT_CheckCertValidTimes(CERTCertificate *c, PRTime t, PRBool allowOverride)
01005 {
01006     PRTime notBefore, notAfter, llPendingSlop, tmp1;
01007     SECStatus rv;
01008 
01009     if (!c) {
01010         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01011         return(secCertTimeUndetermined);
01012     }
01013     /* if cert is already marked OK, then don't bother to check */
01014     if ( allowOverride && c->timeOK ) {
01015        return(secCertTimeValid);
01016     }
01017 
01018     rv = CERT_GetCertTimes(c, &notBefore, &notAfter);
01019     
01020     if (rv) {
01021        return(secCertTimeExpired); /*XXX is this the right thing to do here?*/
01022     }
01023     
01024     LL_I2L(llPendingSlop, pendingSlop);
01025     /* convert to micro seconds */
01026     LL_UI2L(tmp1, PR_USEC_PER_SEC);
01027     LL_MUL(llPendingSlop, llPendingSlop, tmp1);
01028     LL_SUB(notBefore, notBefore, llPendingSlop);
01029     if ( LL_CMP( t, <, notBefore ) ) {
01030        PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
01031        return(secCertTimeNotValidYet);
01032     }
01033     if ( LL_CMP( t, >, notAfter) ) {
01034        PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
01035        return(secCertTimeExpired);
01036     }
01037 
01038     return(secCertTimeValid);
01039 }
01040 
01041 SECStatus
01042 SEC_GetCrlTimes(CERTCrl *date, PRTime *notBefore, PRTime *notAfter)
01043 {
01044     int rv;
01045     
01046     /* convert DER not-before time */
01047     rv = DER_DecodeTimeChoice(notBefore, &date->lastUpdate);
01048     if (rv) {
01049        return(SECFailure);
01050     }
01051     
01052     /* convert DER not-after time */
01053     if (date->nextUpdate.data) {
01054        rv = DER_DecodeTimeChoice(notAfter, &date->nextUpdate);
01055        if (rv) {
01056            return(SECFailure);
01057        }
01058     }
01059     else {
01060        LL_I2L(*notAfter, 0L);
01061     }
01062     return(SECSuccess);
01063 }
01064 
01065 /* These routines should probably be combined with the cert
01066  * routines using an common extraction routine.
01067  */
01068 SECCertTimeValidity
01069 SEC_CheckCrlTimes(CERTCrl *crl, PRTime t) {
01070     PRTime notBefore, notAfter, llPendingSlop, tmp1;
01071     SECStatus rv;
01072 
01073     rv = SEC_GetCrlTimes(crl, &notBefore, &notAfter);
01074     
01075     if (rv) {
01076        return(secCertTimeExpired); 
01077     }
01078 
01079     LL_I2L(llPendingSlop, pendingSlop);
01080     /* convert to micro seconds */
01081     LL_I2L(tmp1, PR_USEC_PER_SEC);
01082     LL_MUL(llPendingSlop, llPendingSlop, tmp1);
01083     LL_SUB(notBefore, notBefore, llPendingSlop);
01084     if ( LL_CMP( t, <, notBefore ) ) {
01085        return(secCertTimeNotValidYet);
01086     }
01087 
01088     /* If next update is omitted and the test for notBefore passes, then
01089        we assume that the crl is up to date.
01090      */
01091     if ( LL_IS_ZERO(notAfter) ) {
01092        return(secCertTimeValid);
01093     }
01094 
01095     if ( LL_CMP( t, >, notAfter) ) {
01096        return(secCertTimeExpired);
01097     }
01098 
01099     return(secCertTimeValid);
01100 }
01101 
01102 PRBool
01103 SEC_CrlIsNewer(CERTCrl *inNew, CERTCrl *old) {
01104     PRTime newNotBefore, newNotAfter;
01105     PRTime oldNotBefore, oldNotAfter;
01106     SECStatus rv;
01107 
01108     /* problems with the new CRL? reject it */
01109     rv = SEC_GetCrlTimes(inNew, &newNotBefore, &newNotAfter);
01110     if (rv) return PR_FALSE;
01111 
01112     /* problems with the old CRL? replace it */
01113     rv = SEC_GetCrlTimes(old, &oldNotBefore, &oldNotAfter);
01114     if (rv) return PR_TRUE;
01115 
01116     /* Question: what about the notAfter's? */
01117     return ((PRBool)LL_CMP(oldNotBefore, <, newNotBefore));
01118 }
01119    
01120 /*
01121  * return required key usage and cert type based on cert usage 
01122  */
01123 SECStatus
01124 CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage,
01125                              PRBool ca,
01126                              unsigned int *retKeyUsage,
01127                              unsigned int *retCertType)
01128 {
01129     unsigned int requiredKeyUsage = 0;
01130     unsigned int requiredCertType = 0;
01131     
01132     if ( ca ) {
01133        switch ( usage ) {
01134          case certUsageSSLServerWithStepUp:
01135            requiredKeyUsage = KU_NS_GOVT_APPROVED | KU_KEY_CERT_SIGN;
01136            requiredCertType = NS_CERT_TYPE_SSL_CA;
01137            break;
01138          case certUsageSSLClient:
01139            requiredKeyUsage = KU_KEY_CERT_SIGN;
01140            requiredCertType = NS_CERT_TYPE_SSL_CA;
01141            break;
01142          case certUsageSSLServer:
01143            requiredKeyUsage = KU_KEY_CERT_SIGN;
01144            requiredCertType = NS_CERT_TYPE_SSL_CA;
01145            break;
01146          case certUsageSSLCA:
01147            requiredKeyUsage = KU_KEY_CERT_SIGN;
01148            requiredCertType = NS_CERT_TYPE_SSL_CA;
01149            break;
01150          case certUsageEmailSigner:
01151            requiredKeyUsage = KU_KEY_CERT_SIGN;
01152            requiredCertType = NS_CERT_TYPE_EMAIL_CA;
01153            break;
01154          case certUsageEmailRecipient:
01155            requiredKeyUsage = KU_KEY_CERT_SIGN;
01156            requiredCertType = NS_CERT_TYPE_EMAIL_CA;
01157            break;
01158          case certUsageObjectSigner:
01159            requiredKeyUsage = KU_KEY_CERT_SIGN;
01160            requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA;
01161            break;
01162          case certUsageAnyCA:
01163          case certUsageVerifyCA:
01164          case certUsageStatusResponder:
01165            requiredKeyUsage = KU_KEY_CERT_SIGN;
01166            requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA |
01167               NS_CERT_TYPE_EMAIL_CA |
01168                   NS_CERT_TYPE_SSL_CA;
01169            break;
01170          default:
01171            PORT_Assert(0);
01172            goto loser;
01173        }
01174     } else {
01175        switch ( usage ) {
01176          case certUsageSSLClient:
01177            requiredKeyUsage = KU_DIGITAL_SIGNATURE;
01178            requiredCertType = NS_CERT_TYPE_SSL_CLIENT;
01179            break;
01180          case certUsageSSLServer:
01181            requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
01182            requiredCertType = NS_CERT_TYPE_SSL_SERVER;
01183            break;
01184          case certUsageSSLServerWithStepUp:
01185            requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT |
01186               KU_NS_GOVT_APPROVED;
01187            requiredCertType = NS_CERT_TYPE_SSL_SERVER;
01188            break;
01189          case certUsageSSLCA:
01190            requiredKeyUsage = KU_KEY_CERT_SIGN;
01191            requiredCertType = NS_CERT_TYPE_SSL_CA;
01192            break;
01193          case certUsageEmailSigner:
01194            requiredKeyUsage = KU_DIGITAL_SIGNATURE;
01195            requiredCertType = NS_CERT_TYPE_EMAIL;
01196            break;
01197          case certUsageEmailRecipient:
01198            requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
01199            requiredCertType = NS_CERT_TYPE_EMAIL;
01200            break;
01201          case certUsageObjectSigner:
01202            requiredKeyUsage = KU_DIGITAL_SIGNATURE;
01203            requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING;
01204            break;
01205          case certUsageStatusResponder:
01206            requiredKeyUsage = KU_DIGITAL_SIGNATURE;
01207            requiredCertType = EXT_KEY_USAGE_STATUS_RESPONDER;
01208            break;
01209          default:
01210            PORT_Assert(0);
01211            goto loser;
01212        }
01213     }
01214 
01215     if ( retKeyUsage != NULL ) {
01216        *retKeyUsage = requiredKeyUsage;
01217     }
01218     if ( retCertType != NULL ) {
01219        *retCertType = requiredCertType;
01220     }
01221 
01222     return(SECSuccess);
01223 loser:
01224     return(SECFailure);
01225 }
01226 
01227 /*
01228  * check the key usage of a cert against a set of required values
01229  */
01230 SECStatus
01231 CERT_CheckKeyUsage(CERTCertificate *cert, unsigned int requiredUsage)
01232 {
01233     unsigned int certKeyUsage;
01234 
01235     if (!cert) {
01236         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01237        return SECFailure;
01238     }
01239     /* choose between key agreement or key encipherment based on key
01240      * type in cert
01241      */
01242     if ( requiredUsage & KU_KEY_AGREEMENT_OR_ENCIPHERMENT ) {
01243        KeyType keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
01244        /* turn off the special bit */
01245        requiredUsage &= (~KU_KEY_AGREEMENT_OR_ENCIPHERMENT);
01246 
01247        switch (keyType) {
01248        case rsaKey:
01249            requiredUsage |= KU_KEY_ENCIPHERMENT;
01250            break;
01251        case dsaKey:
01252            requiredUsage |= KU_DIGITAL_SIGNATURE;
01253            break;
01254        case fortezzaKey:
01255        case keaKey:
01256        case dhKey:
01257            requiredUsage |= KU_KEY_AGREEMENT;
01258            break;
01259        case ecKey:
01260            /* Accept either signature or agreement. */
01261            if (!(cert->keyUsage & (KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT)))
01262                goto loser;
01263            break;
01264        default:
01265            goto loser;
01266        }
01267     }
01268 
01269     certKeyUsage = cert->keyUsage;
01270     if (certKeyUsage & KU_NON_REPUDIATION)
01271         certKeyUsage |= KU_DIGITAL_SIGNATURE;
01272     if ( (certKeyUsage & requiredUsage) == requiredUsage ) 
01273        return SECSuccess;
01274 
01275 loser:
01276     PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
01277     return SECFailure;
01278 }
01279 
01280 
01281 CERTCertificate *
01282 CERT_DupCertificate(CERTCertificate *c)
01283 {
01284     if (c) {
01285 #ifdef NSS_CLASSIC
01286        CERT_LockCertRefCount(c);
01287        ++c->referenceCount;
01288        CERT_UnlockCertRefCount(c);
01289 #else
01290        NSSCertificate *tmp = STAN_GetNSSCertificate(c);
01291        nssCertificate_AddRef(tmp);
01292 #endif
01293     }
01294     return c;
01295 }
01296 
01297 /*
01298  * Allow use of default cert database, so that apps(such as mozilla) don't
01299  * have to pass the handle all over the place.
01300  */
01301 static CERTCertDBHandle *default_cert_db_handle = 0;
01302 
01303 void
01304 CERT_SetDefaultCertDB(CERTCertDBHandle *handle)
01305 {
01306     default_cert_db_handle = handle;
01307     
01308     return;
01309 }
01310 
01311 CERTCertDBHandle *
01312 CERT_GetDefaultCertDB(void)
01313 {
01314     return(default_cert_db_handle);
01315 }
01316 
01317 /* XXX this would probably be okay/better as an xp routine? */
01318 static void
01319 sec_lower_string(char *s)
01320 {
01321     if ( s == NULL ) {
01322        return;
01323     }
01324     
01325     while ( *s ) {
01326        *s = PORT_Tolower(*s);
01327        s++;
01328     }
01329     
01330     return;
01331 }
01332 
01333 /*
01334 ** Add a domain name to the list of names that the user has explicitly
01335 ** allowed (despite cert name mismatches) for use with a server cert.
01336 */
01337 SECStatus
01338 CERT_AddOKDomainName(CERTCertificate *cert, const char *hn)
01339 {
01340     CERTOKDomainName *domainOK;
01341     int              newNameLen;
01342 
01343     if (!hn || !(newNameLen = strlen(hn))) {
01344        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01345        return SECFailure;
01346     }
01347     domainOK = (CERTOKDomainName *)PORT_ArenaZAlloc(cert->arena, 
01348                               (sizeof *domainOK) + newNameLen);
01349     if (!domainOK) 
01350        return SECFailure;   /* error code is already set. */
01351 
01352     PORT_Strcpy(domainOK->name, hn);
01353     sec_lower_string(domainOK->name);
01354 
01355     /* put at head of list. */
01356     domainOK->next = cert->domainOK;
01357     cert->domainOK = domainOK;
01358     return SECSuccess;
01359 }
01360 
01361 /* returns SECSuccess if hn matches pattern cn,
01362 ** returns SECFailure with SSL_ERROR_BAD_CERT_DOMAIN if no match,
01363 ** returns SECFailure with some other error code if another error occurs.
01364 **
01365 ** may modify cn, so caller must pass a modifiable copy.
01366 */
01367 static SECStatus
01368 cert_TestHostName(char * cn, const char * hn)
01369 {
01370     int regvalid = PORT_RegExpValid(cn);
01371     if (regvalid != NON_SXP) {
01372        SECStatus rv;
01373        /* cn is a regular expression, try to match the shexp */
01374        int match = PORT_RegExpCaseSearch(hn, cn);
01375 
01376        if ( match == 0 ) {
01377            rv = SECSuccess;
01378        } else {
01379            PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
01380            rv = SECFailure;
01381        }
01382        return rv;
01383     } 
01384     /* cn is not a regular expression */
01385 
01386     /* compare entire hn with cert name */
01387     if (PORT_Strcasecmp(hn, cn) == 0) {
01388        return SECSuccess;
01389     }
01390            
01391     PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
01392     return SECFailure;
01393 }
01394 
01395 
01396 SECStatus
01397 cert_VerifySubjectAltName(CERTCertificate *cert, const char *hn)
01398 {
01399     PRArenaPool *     arena          = NULL;
01400     CERTGeneralName * nameList       = NULL;
01401     CERTGeneralName * current;
01402     char *            cn;
01403     int               cnBufLen;
01404     unsigned int      hnLen;
01405     int               DNSextCount    = 0;
01406     int               IPextCount     = 0;
01407     PRBool            isIPaddr;
01408     SECStatus         rv             = SECFailure;
01409     SECItem           subAltName;
01410     PRNetAddr         netAddr;
01411     char              cnbuf[128];
01412 
01413     subAltName.data = NULL;
01414     hnLen    = strlen(hn);
01415     cn       = cnbuf;
01416     cnBufLen = sizeof cnbuf;
01417 
01418     rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 
01419                             &subAltName);
01420     if (rv != SECSuccess) {
01421        goto finish;
01422     }
01423     isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
01424     rv = SECFailure;
01425     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01426     if (!arena) 
01427        goto finish;
01428 
01429     nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
01430     if (!current)
01431        goto finish;
01432 
01433     do {
01434        switch (current->type) {
01435        case certDNSName:
01436            if (!isIPaddr) {
01437               /* DNS name current->name.other.data is not null terminated.
01438               ** so must copy it.  
01439               */
01440               int cnLen = current->name.other.len;
01441               if (cnLen + 1 > cnBufLen) {
01442                   cnBufLen = cnLen + 1;
01443                   cn = (char *)PORT_ArenaAlloc(arena, cnBufLen);
01444                   if (!cn)
01445                      goto finish;
01446               }
01447               PORT_Memcpy(cn, current->name.other.data, cnLen);
01448               cn[cnLen] = 0;
01449               rv = cert_TestHostName(cn ,hn);
01450               if (rv == SECSuccess)
01451                   goto finish;
01452            }
01453            DNSextCount++;
01454            break;
01455        case certIPAddress:
01456            if (isIPaddr) {
01457               int match = 0;
01458               PRIPv6Addr v6Addr;
01459               if (current->name.other.len == 4 &&         /* IP v4 address */
01460                   netAddr.inet.family == PR_AF_INET) {
01461                   match = !memcmp(&netAddr.inet.ip, 
01462                                   current->name.other.data, 4);
01463               } else if (current->name.other.len == 16 && /* IP v6 address */
01464                   netAddr.ipv6.family == PR_AF_INET6) {
01465                   match = !memcmp(&netAddr.ipv6.ip,
01466                                    current->name.other.data, 16);
01467               } else if (current->name.other.len == 16 && /* IP v6 address */
01468                   netAddr.inet.family == PR_AF_INET) {
01469                   /* convert netAddr to ipv6, then compare. */
01470                   /* ipv4 must be in Network Byte Order on input. */
01471                   PR_ConvertIPv4AddrToIPv6(netAddr.inet.ip, &v6Addr);
01472                   match = !memcmp(&v6Addr, current->name.other.data, 16);
01473               } else if (current->name.other.len == 4 &&  /* IP v4 address */
01474                   netAddr.inet.family == PR_AF_INET6) {
01475                   /* convert netAddr to ipv6, then compare. */
01476                   PRUint32 ipv4 = (current->name.other.data[0] << 24) |
01477                                   (current->name.other.data[1] << 16) |
01478                                 (current->name.other.data[2] <<  8) |
01479                                  current->name.other.data[3];
01480                   /* ipv4 must be in Network Byte Order on input. */
01481                   PR_ConvertIPv4AddrToIPv6(PR_htonl(ipv4), &v6Addr);
01482                   match = !memcmp(&netAddr.ipv6.ip, &v6Addr, 16);
01483               } 
01484               if (match) {
01485                   rv = SECSuccess;
01486                   goto finish;
01487               }
01488            }
01489            IPextCount++;
01490            break;
01491        default:
01492            break;
01493        }
01494        current = CERT_GetNextGeneralName(current);
01495     } while (current != nameList);
01496 
01497     if ((!isIPaddr && !DNSextCount) || (isIPaddr && !IPextCount)) {
01498        /* no relevant value in the extension was found. */
01499        PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
01500     } else {
01501        PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
01502     }
01503     rv = SECFailure;
01504 
01505 finish:
01506 
01507     /* Don't free nameList, it's part of the arena. */
01508     if (arena) {
01509        PORT_FreeArena(arena, PR_FALSE);
01510     }
01511 
01512     if (subAltName.data) {
01513        SECITEM_FreeItem(&subAltName, PR_FALSE);
01514     }
01515 
01516     return rv;
01517 }
01518 
01519 
01520 /* Make sure that the name of the host we are connecting to matches the
01521  * name that is incoded in the common-name component of the certificate
01522  * that they are using.
01523  */
01524 SECStatus
01525 CERT_VerifyCertName(CERTCertificate *cert, const char *hn)
01526 {
01527     char *    cn;
01528     SECStatus rv;
01529     CERTOKDomainName *domainOK;
01530 
01531     if (!hn || !strlen(hn)) {
01532        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01533        return SECFailure;
01534     }
01535 
01536     /* if the name is one that the user has already approved, it's OK. */
01537     for (domainOK = cert->domainOK; domainOK; domainOK = domainOK->next) {
01538        if (0 == PORT_Strcasecmp(hn, domainOK->name)) {
01539            return SECSuccess;
01540        }
01541     }
01542 
01543     /* Per RFC 2818, if the SubjectAltName extension is present, it must
01544     ** be used as the cert's identity.
01545     */
01546     rv = cert_VerifySubjectAltName(cert, hn);
01547     if (rv == SECSuccess || PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND)
01548        return rv;
01549 
01550     /* try the cert extension first, then the common name */
01551     cn = CERT_FindNSStringExtension(cert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
01552     if ( !cn ) {
01553        cn = CERT_GetCommonName(&cert->subject);
01554     }
01555     if ( cn ) {
01556        rv = cert_TestHostName(cn, hn);
01557        PORT_Free(cn);
01558     } else 
01559        PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
01560     return rv;
01561 }
01562 
01563 PRBool
01564 CERT_CompareCerts(CERTCertificate *c1, CERTCertificate *c2)
01565 {
01566     SECComparison comp;
01567     
01568     comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
01569     if ( comp == SECEqual ) { /* certs are the same */
01570        return(PR_TRUE);
01571     } else {
01572        return(PR_FALSE);
01573     }
01574 }
01575 
01576 static SECStatus
01577 StringsEqual(char *s1, char *s2) {
01578     if ( ( s1 == NULL ) || ( s2 == NULL ) ) {
01579        if ( s1 != s2 ) { /* only one is null */
01580            return(SECFailure);
01581        }
01582        return(SECSuccess); /* both are null */
01583     }
01584        
01585     if ( PORT_Strcmp( s1, s2 ) != 0 ) {
01586        return(SECFailure); /* not equal */
01587     }
01588 
01589     return(SECSuccess); /* strings are equal */
01590 }
01591 
01592 
01593 PRBool
01594 CERT_CompareCertsForRedirection(CERTCertificate *c1, CERTCertificate *c2)
01595 {
01596     SECComparison comp;
01597     char *c1str, *c2str;
01598     SECStatus eq;
01599     
01600     comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
01601     if ( comp == SECEqual ) { /* certs are the same */
01602        return(PR_TRUE);
01603     }
01604        
01605     /* check if they are issued by the same CA */
01606     comp = SECITEM_CompareItem(&c1->derIssuer, &c2->derIssuer);
01607     if ( comp != SECEqual ) { /* different issuer */
01608        return(PR_FALSE);
01609     }
01610 
01611     /* check country name */
01612     c1str = CERT_GetCountryName(&c1->subject);
01613     c2str = CERT_GetCountryName(&c2->subject);
01614     eq = StringsEqual(c1str, c2str);
01615     PORT_Free(c1str);
01616     PORT_Free(c2str);
01617     if ( eq != SECSuccess ) {
01618        return(PR_FALSE);
01619     }
01620 
01621     /* check locality name */
01622     c1str = CERT_GetLocalityName(&c1->subject);
01623     c2str = CERT_GetLocalityName(&c2->subject);
01624     eq = StringsEqual(c1str, c2str);
01625     PORT_Free(c1str);
01626     PORT_Free(c2str);
01627     if ( eq != SECSuccess ) {
01628        return(PR_FALSE);
01629     }
01630        
01631     /* check state name */
01632     c1str = CERT_GetStateName(&c1->subject);
01633     c2str = CERT_GetStateName(&c2->subject);
01634     eq = StringsEqual(c1str, c2str);
01635     PORT_Free(c1str);
01636     PORT_Free(c2str);
01637     if ( eq != SECSuccess ) {
01638        return(PR_FALSE);
01639     }
01640 
01641     /* check org name */
01642     c1str = CERT_GetOrgName(&c1->subject);
01643     c2str = CERT_GetOrgName(&c2->subject);
01644     eq = StringsEqual(c1str, c2str);
01645     PORT_Free(c1str);
01646     PORT_Free(c2str);
01647     if ( eq != SECSuccess ) {
01648        return(PR_FALSE);
01649     }
01650 
01651 #ifdef NOTDEF 
01652     /* check orgUnit name */
01653     /*
01654      * We need to revisit this and decide which fields should be allowed to be
01655      * different
01656      */
01657     c1str = CERT_GetOrgUnitName(&c1->subject);
01658     c2str = CERT_GetOrgUnitName(&c2->subject);
01659     eq = StringsEqual(c1str, c2str);
01660     PORT_Free(c1str);
01661     PORT_Free(c2str);
01662     if ( eq != SECSuccess ) {
01663        return(PR_FALSE);
01664     }
01665 #endif
01666 
01667     return(PR_TRUE); /* all fields but common name are the same */
01668 }
01669 
01670 
01671 /* CERT_CertChainFromCert and CERT_DestroyCertificateList moved
01672    to certhigh.c */
01673 
01674 
01675 CERTIssuerAndSN *
01676 CERT_GetCertIssuerAndSN(PRArenaPool *arena, CERTCertificate *cert)
01677 {
01678     CERTIssuerAndSN *result;
01679     SECStatus rv;
01680 
01681     if ( arena == NULL ) {
01682        arena = cert->arena;
01683     }
01684     
01685     result = (CERTIssuerAndSN*)PORT_ArenaZAlloc(arena, sizeof(*result));
01686     if (result == NULL) {
01687        PORT_SetError (SEC_ERROR_NO_MEMORY);
01688        return NULL;
01689     }
01690 
01691     rv = SECITEM_CopyItem(arena, &result->derIssuer, &cert->derIssuer);
01692     if (rv != SECSuccess)
01693        return NULL;
01694 
01695     rv = CERT_CopyName(arena, &result->issuer, &cert->issuer);
01696     if (rv != SECSuccess)
01697        return NULL;
01698 
01699     rv = SECITEM_CopyItem(arena, &result->serialNumber, &cert->serialNumber);
01700     if (rv != SECSuccess)
01701        return NULL;
01702 
01703     return result;
01704 }
01705 
01706 char *
01707 CERT_MakeCANickname(CERTCertificate *cert)
01708 {
01709     char *firstname = NULL;
01710     char *org = NULL;
01711     char *nickname = NULL;
01712     int count;
01713     CERTCertificate *dummycert;
01714     CERTCertDBHandle *handle;
01715     
01716     handle = cert->dbhandle;
01717     
01718     nickname = CERT_GetNickName(cert, handle, cert->arena);
01719     if (nickname == NULL) {
01720        firstname = CERT_GetCommonName(&cert->subject);
01721        if ( firstname == NULL ) {
01722            firstname = CERT_GetOrgUnitName(&cert->subject);
01723        }
01724 
01725        org = CERT_GetOrgName(&cert->issuer);
01726        if (org == NULL) {
01727            org = CERT_GetDomainComponentName(&cert->issuer);
01728            if (org == NULL) {
01729               if (firstname) {
01730                   org = firstname;
01731                   firstname = NULL;
01732               } else {
01733                   org = PORT_Strdup("Unknown CA");
01734               }
01735            }
01736        }
01737 
01738        /* can only fail if PORT_Strdup fails, in which case
01739         * we're having memory problems. */
01740        if (org == NULL) {
01741            goto loser;
01742        }
01743 
01744     
01745        count = 1;
01746        while ( 1 ) {
01747 
01748            if ( firstname ) {
01749               if ( count == 1 ) {
01750                   nickname = PR_smprintf("%s - %s", firstname, org);
01751               } else {
01752                   nickname = PR_smprintf("%s - %s #%d", firstname, org, count);
01753               }
01754            } else {
01755               if ( count == 1 ) {
01756                   nickname = PR_smprintf("%s", org);
01757               } else {
01758                   nickname = PR_smprintf("%s #%d", org, count);
01759               }
01760            }
01761            if ( nickname == NULL ) {
01762               goto loser;
01763            }
01764 
01765            /* look up the nickname to make sure it isn't in use already */
01766            dummycert = CERT_FindCertByNickname(handle, nickname);
01767 
01768            if ( dummycert == NULL ) {
01769               goto done;
01770            }
01771        
01772            /* found a cert, destroy it and loop */
01773            CERT_DestroyCertificate(dummycert);
01774 
01775            /* free the nickname */
01776            PORT_Free(nickname);
01777 
01778            count++;
01779        }
01780     }
01781 loser:
01782     if ( nickname ) {
01783        PORT_Free(nickname);
01784     }
01785 
01786     nickname = "";
01787     
01788 done:
01789     if ( firstname ) {
01790        PORT_Free(firstname);
01791     }
01792     if ( org ) {
01793        PORT_Free(org);
01794     }
01795     
01796     return(nickname);
01797 }
01798 
01799 /* CERT_Import_CAChain moved to certhigh.c */
01800 
01801 void
01802 CERT_DestroyCrl (CERTSignedCrl *crl)
01803 {
01804     SEC_DestroyCrl (crl);
01805 }
01806 
01807 
01808 
01809 /*
01810  * Does a cert belong to a CA?  We decide based on perm database trust
01811  * flags, Netscape Cert Type Extension, and KeyUsage Extension.
01812  */
01813 PRBool
01814 CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype)
01815 {
01816     CERTCertTrust *trust;
01817     SECStatus rv;
01818     unsigned int type;
01819     PRBool ret;
01820 
01821     ret = PR_FALSE;
01822     type = 0;
01823 
01824     if ( cert->trust && (cert->trust->sslFlags|cert->trust->emailFlags|
01825                             cert->trust->objectSigningFlags)) {
01826        trust = cert->trust;
01827        if ( ( ( trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA ) ||
01828           ( ( trust->sslFlags & CERTDB_TRUSTED_CA ) == CERTDB_TRUSTED_CA ) ) {
01829            ret = PR_TRUE;
01830            type |= NS_CERT_TYPE_SSL_CA;
01831        }
01832        
01833        if ( ( ( trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA ) ||
01834          ( ( trust->emailFlags & CERTDB_TRUSTED_CA ) == CERTDB_TRUSTED_CA ) ) {
01835            ret = PR_TRUE;
01836            type |= NS_CERT_TYPE_EMAIL_CA;
01837        }
01838        
01839        if ( ( ( trust->objectSigningFlags & CERTDB_VALID_CA ) 
01840                                           == CERTDB_VALID_CA ) ||
01841           ( ( trust->objectSigningFlags & CERTDB_TRUSTED_CA ) 
01842                                           == CERTDB_TRUSTED_CA ) ) {
01843            ret = PR_TRUE;
01844            type |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
01845        }
01846     } else {
01847        if ( cert->nsCertType &
01848            ( NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
01849             NS_CERT_TYPE_OBJECT_SIGNING_CA ) ) {
01850            ret = PR_TRUE;
01851            type = (cert->nsCertType & NS_CERT_TYPE_CA);
01852        } else {
01853            CERTBasicConstraints constraints;
01854            rv = CERT_FindBasicConstraintExten(cert, &constraints);
01855            if ( rv == SECSuccess ) {
01856               if ( constraints.isCA ) {
01857                   ret = PR_TRUE;
01858                   type = (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
01859               }
01860            } 
01861        } 
01862 
01863        /* finally check if it's a FORTEZZA V1 CA */
01864        if (ret == PR_FALSE) {
01865            if (fortezzaIsCA(cert)) {
01866               ret = PR_TRUE;
01867               type = (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
01868            }
01869        }
01870     }
01871 
01872     /* the isRoot flag trumps all */
01873     if (cert->isRoot) {
01874        ret = PR_TRUE;
01875        /* set only these by default, same as above */
01876        type = (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
01877     }
01878 
01879     if ( rettype != NULL ) {
01880        *rettype = type;
01881     }
01882     
01883     return(ret);
01884 }
01885 
01886 PRBool
01887 CERT_IsCADERCert(SECItem *derCert, unsigned int *type) {
01888     CERTCertificate *cert;
01889     PRBool isCA;
01890 
01891     /* This is okay -- only looks at extensions */
01892     cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
01893     if (cert == NULL) return PR_FALSE;
01894 
01895     isCA = CERT_IsCACert(cert,type);
01896     CERT_DestroyCertificate (cert);
01897     return isCA;
01898 }
01899 
01900 PRBool
01901 CERT_IsRootDERCert(SECItem *derCert)
01902 {
01903     CERTCertificate *cert;
01904     PRBool isRoot;
01905 
01906     /* This is okay -- only looks at extensions */
01907     cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
01908     if (cert == NULL) return PR_FALSE;
01909 
01910     isRoot = cert->isRoot;
01911     CERT_DestroyCertificate (cert);
01912     return isRoot;
01913 }
01914 
01915 CERTCompareValidityStatus
01916 CERT_CompareValidityTimes(CERTValidity* val_a, CERTValidity* val_b)
01917 {
01918     PRTime notBeforeA, notBeforeB, notAfterA, notAfterB;
01919 
01920     if (!val_a || !val_b)
01921     {
01922         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01923         return certValidityUndetermined;
01924     }
01925 
01926     if ( SECSuccess != DER_DecodeTimeChoice(&notBeforeA, &val_a->notBefore) ||
01927          SECSuccess != DER_DecodeTimeChoice(&notBeforeB, &val_b->notBefore) ||
01928          SECSuccess != DER_DecodeTimeChoice(&notAfterA, &val_a->notAfter) ||
01929          SECSuccess != DER_DecodeTimeChoice(&notAfterB, &val_b->notAfter) ) {
01930         return certValidityUndetermined;
01931     }
01932 
01933     /* sanity check */
01934     if (LL_CMP(notBeforeA,>,notAfterA) || LL_CMP(notBeforeB,>,notAfterB)) {
01935         PORT_SetError(SEC_ERROR_INVALID_TIME);
01936         return certValidityUndetermined;
01937     }
01938 
01939     if (LL_CMP(notAfterA,!=,notAfterB)) {
01940         /* one cert validity goes farther into the future, select it */
01941         return LL_CMP(notAfterA,<,notAfterB) ?
01942             certValidityChooseB : certValidityChooseA;
01943     }
01944     /* the two certs have the same expiration date */
01945     PORT_Assert(LL_CMP(notAfterA, == , notAfterB));
01946     /* do they also have the same start date ? */
01947     if (LL_CMP(notBeforeA,==,notBeforeB)) {
01948        return certValidityEqual;
01949     }
01950     /* choose cert with the later start date */
01951     return LL_CMP(notBeforeA,<,notBeforeB) ?
01952         certValidityChooseB : certValidityChooseA;
01953 }
01954 
01955 /*
01956  * is certa newer than certb?  If one is expired, pick the other one.
01957  */
01958 PRBool
01959 CERT_IsNewer(CERTCertificate *certa, CERTCertificate *certb)
01960 {
01961     PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
01962     SECStatus rv;
01963     PRBool newerbefore, newerafter;
01964     
01965     rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
01966     if ( rv != SECSuccess ) {
01967        return(PR_FALSE);
01968     }
01969     
01970     rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
01971     if ( rv != SECSuccess ) {
01972        return(PR_TRUE);
01973     }
01974 
01975     newerbefore = PR_FALSE;
01976     if ( LL_CMP(notBeforeA, >, notBeforeB) ) {
01977        newerbefore = PR_TRUE;
01978     }
01979 
01980     newerafter = PR_FALSE;
01981     if ( LL_CMP(notAfterA, >, notAfterB) ) {
01982        newerafter = PR_TRUE;
01983     }
01984     
01985     if ( newerbefore && newerafter ) {
01986        return(PR_TRUE);
01987     }
01988     
01989     if ( ( !newerbefore ) && ( !newerafter ) ) {
01990        return(PR_FALSE);
01991     }
01992 
01993     /* get current time */
01994     now = PR_Now();
01995 
01996     if ( newerbefore ) {
01997        /* cert A was issued after cert B, but expires sooner */
01998        /* if A is expired, then pick B */
01999        if ( LL_CMP(notAfterA, <, now ) ) {
02000            return(PR_FALSE);
02001        }
02002        return(PR_TRUE);
02003     } else {
02004        /* cert B was issued after cert A, but expires sooner */
02005        /* if B is expired, then pick A */
02006        if ( LL_CMP(notAfterB, <, now ) ) {
02007            return(PR_TRUE);
02008        }
02009        return(PR_FALSE);
02010     }
02011 }
02012 
02013 void
02014 CERT_DestroyCertArray(CERTCertificate **certs, unsigned int ncerts)
02015 {
02016     unsigned int i;
02017     
02018     if ( certs ) {
02019        for ( i = 0; i < ncerts; i++ ) {
02020            if ( certs[i] ) {
02021               CERT_DestroyCertificate(certs[i]);
02022            }
02023        }
02024 
02025        PORT_Free(certs);
02026     }
02027     
02028     return;
02029 }
02030 
02031 char *
02032 CERT_FixupEmailAddr(char *emailAddr)
02033 {
02034     char *retaddr;
02035     char *str;
02036 
02037     if ( emailAddr == NULL ) {
02038        return(NULL);
02039     }
02040     
02041     /* copy the string */
02042     str = retaddr = PORT_Strdup(emailAddr);
02043     if ( str == NULL ) {
02044        return(NULL);
02045     }
02046     
02047     /* make it lower case */
02048     while ( *str ) {
02049        *str = tolower( *str );
02050        str++;
02051     }
02052     
02053     return(retaddr);
02054 }
02055 
02056 /*
02057  * NOTE - don't allow encode of govt-approved or invisible bits
02058  */
02059 SECStatus
02060 CERT_DecodeTrustString(CERTCertTrust *trust, char *trusts)
02061 {
02062     unsigned int i;
02063     unsigned int *pflags;
02064     
02065     if (!trust) {
02066        PORT_SetError(SEC_ERROR_INVALID_ARGS);
02067        return SECFailure;
02068     }
02069     trust->sslFlags = 0;
02070     trust->emailFlags = 0;
02071     trust->objectSigningFlags = 0;
02072     if (!trusts) {
02073        PORT_SetError(SEC_ERROR_INVALID_ARGS);
02074        return SECFailure;
02075     }
02076 
02077     pflags = &trust->sslFlags;
02078     
02079     for (i=0; i < PORT_Strlen(trusts); i++) {
02080        switch (trusts[i]) {
02081          case 'p':
02082              *pflags = *pflags | CERTDB_VALID_PEER;
02083              break;
02084 
02085          case 'P':
02086              *pflags = *pflags | CERTDB_TRUSTED | CERTDB_VALID_PEER;
02087              break;
02088 
02089          case 'w':
02090              *pflags = *pflags | CERTDB_SEND_WARN;
02091              break;
02092 
02093          case 'c':
02094              *pflags = *pflags | CERTDB_VALID_CA;
02095              break;
02096 
02097          case 'T':
02098              *pflags = *pflags | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA;
02099              break;
02100 
02101          case 'C' :
02102              *pflags = *pflags | CERTDB_TRUSTED_CA | CERTDB_VALID_CA;
02103              break;
02104 
02105          case 'u':
02106              *pflags = *pflags | CERTDB_USER;
02107              break;
02108 
02109          case 'i':
02110              *pflags = *pflags | CERTDB_INVISIBLE_CA;
02111              break;
02112          case 'g':
02113              *pflags = *pflags | CERTDB_GOVT_APPROVED_CA;
02114              break;
02115 
02116          case ',':
02117              if ( pflags == &trust->sslFlags ) {
02118                 pflags = &trust->emailFlags;
02119              } else {
02120                 pflags = &trust->objectSigningFlags;
02121              }
02122              break;
02123          default:
02124              return SECFailure;
02125        }
02126     }
02127 
02128     return SECSuccess;
02129 }
02130 
02131 static void
02132 EncodeFlags(char *trusts, unsigned int flags)
02133 {
02134     if (flags & CERTDB_VALID_CA)
02135        if (!(flags & CERTDB_TRUSTED_CA) &&
02136            !(flags & CERTDB_TRUSTED_CLIENT_CA))
02137            PORT_Strcat(trusts, "c");
02138     if (flags & CERTDB_VALID_PEER)
02139        if (!(flags & CERTDB_TRUSTED))
02140            PORT_Strcat(trusts, "p");
02141     if (flags & CERTDB_TRUSTED_CA)
02142        PORT_Strcat(trusts, "C");
02143     if (flags & CERTDB_TRUSTED_CLIENT_CA)
02144        PORT_Strcat(trusts, "T");
02145     if (flags & CERTDB_TRUSTED)
02146        PORT_Strcat(trusts, "P");
02147     if (flags & CERTDB_USER)
02148        PORT_Strcat(trusts, "u");
02149     if (flags & CERTDB_SEND_WARN)
02150        PORT_Strcat(trusts, "w");
02151     if (flags & CERTDB_INVISIBLE_CA)
02152        PORT_Strcat(trusts, "I");
02153     if (flags & CERTDB_GOVT_APPROVED_CA)
02154        PORT_Strcat(trusts, "G");
02155     return;
02156 }
02157 
02158 char *
02159 CERT_EncodeTrustString(CERTCertTrust *trust)
02160 {
02161     char tmpTrustSSL[32];
02162     char tmpTrustEmail[32];
02163     char tmpTrustSigning[32];
02164     char *retstr = NULL;
02165 
02166     if ( trust ) {
02167        tmpTrustSSL[0] = '\0';
02168        tmpTrustEmail[0] = '\0';
02169        tmpTrustSigning[0] = '\0';
02170     
02171        EncodeFlags(tmpTrustSSL, trust->sslFlags);
02172        EncodeFlags(tmpTrustEmail, trust->emailFlags);
02173        EncodeFlags(tmpTrustSigning, trust->objectSigningFlags);
02174     
02175        retstr = PR_smprintf("%s,%s,%s", tmpTrustSSL, tmpTrustEmail,
02176                           tmpTrustSigning);
02177     }
02178     
02179     return(retstr);
02180 }
02181 
02182 /* in 3.4, this will only set trust */
02183 SECStatus
02184 CERT_SaveImportedCert(CERTCertificate *cert, SECCertUsage usage,
02185                     PRBool caOnly, char *nickname)
02186 {
02187     SECStatus rv;
02188     PRBool saveit;
02189     CERTCertTrust trust;
02190     PRBool isCA;
02191     unsigned int certtype;
02192     
02193     isCA = CERT_IsCACert(cert, NULL);
02194     if ( caOnly && ( !isCA ) ) {
02195        return(SECSuccess);
02196     }
02197     /* In NSS 3.4, certs are given zero trust upon import.  However, this
02198     * function needs to set up default CA trust (CERTDB_VALID_CA), or
02199     * PKCS#12 imported certs will not show up correctly.  In the case of a
02200     * CA cert with zero trust, continue with this function.  But if the cert
02201     * does already have some trust bits, exit and do not change them.
02202     */
02203     if (isCA && cert->trust && 
02204         (cert->trust->sslFlags |
02205          cert->trust->emailFlags |
02206          cert->trust->objectSigningFlags)) {
02207        return(SECSuccess);
02208     }
02209 
02210     saveit = PR_TRUE;
02211     
02212     PORT_Memset((void *)&trust, 0, sizeof(trust));
02213 
02214     certtype = cert->nsCertType;
02215 
02216     /* if no CA bits in cert type, then set all CA bits */
02217     if ( isCA && ( ! ( certtype & NS_CERT_TYPE_CA ) ) ) {
02218        certtype |= NS_CERT_TYPE_CA;
02219     }
02220 
02221     /* if no app bits in cert type, then set all app bits */
02222     if ( ( !isCA ) && ( ! ( certtype & NS_CERT_TYPE_APP ) ) ) {
02223        certtype |= NS_CERT_TYPE_APP;
02224     }
02225 
02226     switch ( usage ) {
02227       case certUsageEmailSigner:
02228       case certUsageEmailRecipient:
02229        if ( isCA ) {
02230            if ( certtype & NS_CERT_TYPE_EMAIL_CA ) {
02231               trust.emailFlags = CERTDB_VALID_CA;
02232            }
02233        } else {
02234            if ( !cert->emailAddr || !cert->emailAddr[0] ) {
02235               saveit = PR_FALSE;
02236            }
02237            
02238            if ( certtype & NS_CERT_TYPE_EMAIL ) {
02239               trust.emailFlags = CERTDB_VALID_PEER;
02240               if ( ! ( cert->rawKeyUsage & KU_KEY_ENCIPHERMENT ) ) {
02241                   /* don't save it if KeyEncipherment is not allowed */
02242                   saveit = PR_FALSE;
02243               }
02244            }
02245        }
02246        break;
02247       case certUsageUserCertImport:
02248        if ( isCA ) {
02249            if ( certtype & NS_CERT_TYPE_SSL_CA ) {
02250               trust.sslFlags = CERTDB_VALID_CA;
02251            }
02252            
02253            if ( certtype & NS_CERT_TYPE_EMAIL_CA ) {
02254               trust.emailFlags = CERTDB_VALID_CA;
02255            }
02256            
02257            if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) {
02258               trust.objectSigningFlags = CERTDB_VALID_CA;
02259            }
02260            
02261        } else {
02262            if ( certtype & NS_CERT_TYPE_SSL_CLIENT ) {
02263               trust.sslFlags = CERTDB_VALID_PEER;
02264            }
02265            
02266            if ( certtype & NS_CERT_TYPE_EMAIL ) {
02267               trust.emailFlags = CERTDB_VALID_PEER;
02268            }
02269            
02270            if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING ) {
02271               trust.objectSigningFlags = CERTDB_VALID_PEER;
02272            }
02273        }
02274        break;
02275       case certUsageAnyCA:
02276        trust.sslFlags = CERTDB_VALID_CA;
02277        break;
02278       case certUsageSSLCA:
02279        trust.sslFlags = CERTDB_VALID_CA | 
02280                      CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA;
02281        break;
02282       default:       /* XXX added to quiet warnings; no other cases needed? */
02283        break;
02284     }
02285 
02286     if ( saveit ) {
02287        rv = CERT_ChangeCertTrust(cert->dbhandle, cert, &trust);
02288        if ( rv != SECSuccess ) {
02289            goto loser;
02290        }
02291     }
02292 
02293     rv = SECSuccess;
02294     goto done;
02295 
02296 loser:
02297     rv = SECFailure;
02298 done:
02299 
02300     return(rv);
02301 }
02302 
02303 SECStatus
02304 CERT_ImportCerts(CERTCertDBHandle *certdb, SECCertUsage usage,
02305                unsigned int ncerts, SECItem **derCerts,
02306                CERTCertificate ***retCerts, PRBool keepCerts,
02307                PRBool caOnly, char *nickname)
02308 {
02309     unsigned int i;
02310     CERTCertificate **certs = NULL;
02311     SECStatus rv;
02312     unsigned int fcerts = 0;
02313 
02314     if ( ncerts ) {
02315        certs = PORT_ZNewArray(CERTCertificate*, ncerts);
02316        if ( certs == NULL ) {
02317            return(SECFailure);
02318        }
02319     
02320        /* decode all of the certs into the temporary DB */
02321        for ( i = 0, fcerts= 0; i < ncerts; i++) {
02322            certs[fcerts] = CERT_NewTempCertificate(certdb,
02323                                                    derCerts[i],
02324                                                    NULL,
02325                                                    PR_FALSE,
02326                                                    PR_TRUE);
02327            if (certs[fcerts]) fcerts++;
02328        }
02329 
02330        if ( keepCerts ) {
02331            for ( i = 0; i < fcerts; i++ ) {
02332                 char* canickname = NULL;
02333                 PRBool freeNickname = PR_FALSE;
02334 
02335               SECKEY_UpdateCertPQG(certs[i]);
02336                 
02337                 if ( CERT_IsCACert(certs[i], NULL) ) {
02338                     canickname = CERT_MakeCANickname(certs[i]);
02339                     if ( canickname != NULL ) {
02340                         freeNickname = PR_TRUE;
02341                     }
02342                 }
02343 
02344               if(CERT_IsCACert(certs[i], NULL) && (fcerts > 1)) {
02345                   /* if we are importing only a single cert and specifying
02346                    * a nickname, we want to use that nickname if it a CA,
02347                    * otherwise if there are more than one cert, we don't
02348                    * know which cert it belongs to. But we still may try
02349                      * the individual canickname from the cert itself.
02350                    */
02351                   rv = CERT_AddTempCertToPerm(certs[i], canickname, NULL);
02352               } else {
02353                   rv = CERT_AddTempCertToPerm(certs[i],
02354                                                 nickname?nickname:canickname, NULL);
02355               }
02356               if (rv == SECSuccess) {
02357                   CERT_SaveImportedCert(certs[i], usage, caOnly, NULL);
02358               }
02359 
02360                 if (PR_TRUE == freeNickname) {
02361                     PORT_Free(canickname);
02362                 }
02363               /* don't care if it fails - keep going */
02364            }
02365        }
02366     }
02367 
02368     if ( retCerts ) {
02369        *retCerts = certs;
02370     } else {
02371        if (certs) {
02372            CERT_DestroyCertArray(certs, fcerts);
02373        }
02374     }
02375 
02376     return ((fcerts || !ncerts) ? SECSuccess : SECFailure);
02377 }
02378 
02379 /*
02380  * a real list of certificates - need to convert CERTCertificateList
02381  * stuff and ASN 1 encoder/decoder over to using this...
02382  */
02383 CERTCertList *
02384 CERT_NewCertList(void)
02385 {
02386     PRArenaPool *arena = NULL;
02387     CERTCertList *ret = NULL;
02388     
02389     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02390     if ( arena == NULL ) {
02391        goto loser;
02392     }
02393     
02394     ret = (CERTCertList *)PORT_ArenaZAlloc(arena, sizeof(CERTCertList));
02395     if ( ret == NULL ) {
02396        goto loser;
02397     }
02398     
02399     ret->arena = arena;
02400     
02401     PR_INIT_CLIST(&ret->list);
02402     
02403     return(ret);
02404 
02405 loser:
02406     if ( arena != NULL ) {
02407        PORT_FreeArena(arena, PR_FALSE);
02408     }
02409     
02410     return(NULL);
02411 }
02412 
02413 void
02414 CERT_DestroyCertList(CERTCertList *certs)
02415 {
02416     PRCList *node;
02417 
02418     while( !PR_CLIST_IS_EMPTY(&certs->list) ) {
02419        node = PR_LIST_HEAD(&certs->list);
02420        CERT_DestroyCertificate(((CERTCertListNode *)node)->cert);
02421        PR_REMOVE_LINK(node);
02422     }
02423     
02424     PORT_FreeArena(certs->arena, PR_FALSE);
02425     
02426     return;
02427 }
02428 
02429 void
02430 CERT_RemoveCertListNode(CERTCertListNode *node)
02431 {
02432     CERT_DestroyCertificate(node->cert);
02433     PR_REMOVE_LINK(&node->links);
02434     return;
02435 }
02436 
02437 
02438 SECStatus
02439 CERT_AddCertToListTailWithData(CERTCertList *certs, 
02440                             CERTCertificate *cert, void *appData)
02441 {
02442     CERTCertListNode *node;
02443     
02444     node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
02445                                           sizeof(CERTCertListNode));
02446     if ( node == NULL ) {
02447        goto loser;
02448     }
02449     
02450     PR_INSERT_BEFORE(&node->links, &certs->list);
02451     /* certs->count++; */
02452     node->cert = cert;
02453     node->appData = appData;
02454     return(SECSuccess);
02455     
02456 loser:
02457     return(SECFailure);
02458 }
02459 
02460 SECStatus
02461 CERT_AddCertToListTail(CERTCertList *certs, CERTCertificate *cert)
02462 {
02463     return CERT_AddCertToListTailWithData(certs, cert, NULL);
02464 }
02465 
02466 SECStatus
02467 CERT_AddCertToListHeadWithData(CERTCertList *certs, 
02468                                    CERTCertificate *cert, void *appData)
02469 {
02470     CERTCertListNode *node;
02471     CERTCertListNode *head;
02472     
02473     head = CERT_LIST_HEAD(certs);
02474 
02475     if (head == NULL) return CERT_AddCertToListTail(certs,cert);
02476 
02477     node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
02478                                           sizeof(CERTCertListNode));
02479     if ( node == NULL ) {
02480        goto loser;
02481     }
02482     
02483     PR_INSERT_BEFORE(&node->links, &head->links);
02484     /* certs->count++; */
02485     node->cert = cert;
02486     node->appData = appData;
02487     return(SECSuccess);
02488     
02489 loser:
02490     return(SECFailure);
02491 }
02492 
02493 SECStatus
02494 CERT_AddCertToListHead(CERTCertList *certs, CERTCertificate *cert)
02495 {
02496     return CERT_AddCertToListHeadWithData(certs, cert, NULL);
02497 }
02498 
02499 /*
02500  * Sort callback function to determine if cert a is newer than cert b.
02501  * Not valid certs are considered older than valid certs.
02502  */
02503 PRBool
02504 CERT_SortCBValidity(CERTCertificate *certa,
02505                   CERTCertificate *certb,
02506                   void *arg)
02507 {
02508     PRTime sorttime;
02509     PRTime notBeforeA, notAfterA, notBeforeB, notAfterB;
02510     SECStatus rv;
02511     PRBool newerbefore, newerafter;
02512     PRBool aNotValid = PR_FALSE, bNotValid = PR_FALSE;
02513 
02514     sorttime = *(PRTime *)arg;
02515     
02516     rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
02517     if ( rv != SECSuccess ) {
02518        return(PR_FALSE);
02519     }
02520     
02521     rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
02522     if ( rv != SECSuccess ) {
02523        return(PR_TRUE);
02524     }
02525     newerbefore = PR_FALSE;
02526     if ( LL_CMP(notBeforeA, >, notBeforeB) ) {
02527        newerbefore = PR_TRUE;
02528     }
02529     newerafter = PR_FALSE;
02530     if ( LL_CMP(notAfterA, >, notAfterB) ) {
02531        newerafter = PR_TRUE;
02532     }
02533 
02534     /* check if A is valid at sorttime */
02535     if ( CERT_CheckCertValidTimes(certa, sorttime, PR_FALSE)
02536        != secCertTimeValid ) {
02537        aNotValid = PR_TRUE;
02538     }
02539 
02540     /* check if B is valid at sorttime */
02541     if ( CERT_CheckCertValidTimes(certb, sorttime, PR_FALSE)
02542        != secCertTimeValid ) {
02543        bNotValid = PR_TRUE;
02544     }
02545 
02546     /* a is valid, b is not */
02547     if ( bNotValid && ( ! aNotValid ) ) {
02548        return(PR_TRUE);
02549     }
02550 
02551     /* b is valid, a is not */
02552     if ( aNotValid && ( ! bNotValid ) ) {
02553        return(PR_FALSE);
02554     }
02555     
02556     /* a and b are either valid or not valid */
02557     if ( newerbefore && newerafter ) {
02558        return(PR_TRUE);
02559     }
02560     
02561     if ( ( !newerbefore ) && ( !newerafter ) ) {
02562        return(PR_FALSE);
02563     }
02564 
02565     if ( newerbefore ) {
02566        /* cert A was issued after cert B, but expires sooner */
02567        return(PR_TRUE);
02568     } else {
02569        /* cert B was issued after cert A, but expires sooner */
02570        return(PR_FALSE);
02571     }
02572 }
02573 
02574 
02575 SECStatus
02576 CERT_AddCertToListSorted(CERTCertList *certs,
02577                       CERTCertificate *cert,
02578                       CERTSortCallback f,
02579                       void *arg)
02580 {
02581     CERTCertListNode *node;
02582     CERTCertListNode *head;
02583     PRBool ret;
02584     
02585     node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
02586                                           sizeof(CERTCertListNode));
02587     if ( node == NULL ) {
02588        goto loser;
02589     }
02590     
02591     head = CERT_LIST_HEAD(certs);
02592     
02593     while ( !CERT_LIST_END(head, certs) ) {
02594 
02595        /* if cert is already in the list, then don't add it again */
02596        if ( cert == head->cert ) {
02597            /*XXX*/
02598            /* don't keep a reference */
02599            CERT_DestroyCertificate(cert);
02600            goto done;
02601        }
02602        
02603        ret = (* f)(cert, head->cert, arg);
02604        /* if sort function succeeds, then insert before current node */
02605        if ( ret ) {
02606            PR_INSERT_BEFORE(&node->links, &head->links);
02607            goto done;
02608        }
02609 
02610        head = CERT_LIST_NEXT(head);
02611     }
02612     /* if we get to the end, then just insert it at the tail */
02613     PR_INSERT_BEFORE(&node->links, &certs->list);
02614 
02615 done:    
02616     /* certs->count++; */
02617     node->cert = cert;
02618     return(SECSuccess);
02619     
02620 loser:
02621     return(SECFailure);
02622 }
02623 
02624 /* This routine is here because pcertdb.c still has a call to it.
02625  * The SMIME profile code in pcertdb.c should be split into high (find
02626  * the email cert) and low (store the profile) code.  At that point, we
02627  * can move this to certhigh.c where it belongs.
02628  *
02629  * remove certs from a list that don't have keyUsage and certType
02630  * that match the given usage.
02631  */
02632 SECStatus
02633 CERT_FilterCertListByUsage(CERTCertList *certList, SECCertUsage usage,
02634                         PRBool ca)
02635 {
02636     unsigned int requiredKeyUsage;
02637     unsigned int requiredCertType;
02638     CERTCertListNode *node, *savenode;
02639     SECStatus rv;
02640     
02641     if (certList == NULL) goto loser;
02642 
02643     rv = CERT_KeyUsageAndTypeForCertUsage(usage, ca, &requiredKeyUsage,
02644                                      &requiredCertType);
02645     if ( rv != SECSuccess ) {
02646        goto loser;
02647     }
02648 
02649     node = CERT_LIST_HEAD(certList);
02650        
02651     while ( !CERT_LIST_END(node, certList) ) {
02652 
02653        PRBool bad = (PRBool)(!node->cert);
02654 
02655        /* bad key usage ? */
02656        if ( !bad && 
02657             CERT_CheckKeyUsage(node->cert, requiredKeyUsage) != SECSuccess ) {
02658            bad = PR_TRUE;
02659        }
02660        /* bad cert type ? */
02661        if ( !bad ) {
02662            unsigned int certType = 0;
02663            if ( ca ) {
02664               /* This function returns a more comprehensive cert type that
02665                * takes trust flags into consideration.  Should probably
02666                * fix the cert decoding code to do this.
02667                */
02668               (void)CERT_IsCACert(node->cert, &certType);
02669            } else {
02670               certType = node->cert->nsCertType;
02671            }
02672            if ( !( certType & requiredCertType ) ) {
02673               bad = PR_TRUE;
02674            }
02675        }
02676 
02677        if ( bad ) {
02678            /* remove the node if it is bad */
02679            savenode = CERT_LIST_NEXT(node);
02680            CERT_RemoveCertListNode(node);
02681            node = savenode;
02682        } else {
02683            node = CERT_LIST_NEXT(node);
02684        }
02685     }
02686     return(SECSuccess);
02687     
02688 loser:
02689     return(SECFailure);
02690 }
02691 
02692 PRBool CERT_IsUserCert(CERTCertificate* cert)
02693 {
02694     if ( cert->trust &&
02695         ((cert->trust->sslFlags & CERTDB_USER ) ||
02696          (cert->trust->emailFlags & CERTDB_USER ) ||
02697          (cert->trust->objectSigningFlags & CERTDB_USER )) ) {
02698         return PR_TRUE;
02699     } else {
02700         return PR_FALSE;
02701     }
02702 }
02703 
02704 SECStatus
02705 CERT_FilterCertListForUserCerts(CERTCertList *certList)
02706 {
02707     CERTCertListNode *node, *freenode;
02708     CERTCertificate *cert;
02709 
02710     if (!certList) {
02711         return SECFailure;
02712     }
02713 
02714     node = CERT_LIST_HEAD(certList);
02715     
02716     while ( ! CERT_LIST_END(node, certList) ) {
02717        cert = node->cert;
02718        if ( PR_TRUE != CERT_IsUserCert(cert) ) {
02719            /* Not a User Cert, so remove this cert from the list */
02720            freenode = node;
02721            node = CERT_LIST_NEXT(node);
02722            CERT_RemoveCertListNode(freenode);
02723        } else {
02724            /* Is a User cert, so leave it in the list */
02725            node = CERT_LIST_NEXT(node);
02726        }
02727     }
02728 
02729     return(SECSuccess);
02730 }
02731 
02732 static PZLock *certRefCountLock = NULL;
02733 
02734 /*
02735  * Acquire the cert reference count lock
02736  * There is currently one global lock for all certs, but I'm putting a cert
02737  * arg here so that it will be easy to make it per-cert in the future if
02738  * that turns out to be necessary.
02739  */
02740 void
02741 CERT_LockCertRefCount(CERTCertificate *cert)
02742 {
02743     if ( certRefCountLock == NULL ) {
02744        nss_InitLock(&certRefCountLock, nssILockRefLock);
02745        PORT_Assert(certRefCountLock != NULL);
02746     }
02747     
02748     PZ_Lock(certRefCountLock);
02749     return;
02750 }
02751 
02752 /*
02753  * Free the cert reference count lock
02754  */
02755 void
02756 CERT_UnlockCertRefCount(CERTCertificate *cert)
02757 {
02758     PRStatus prstat;
02759 
02760     PORT_Assert(certRefCountLock != NULL);
02761     
02762     prstat = PZ_Unlock(certRefCountLock);
02763     
02764     PORT_Assert(prstat == PR_SUCCESS);
02765 
02766     return;
02767 }
02768 
02769 static PZLock *certTrustLock = NULL;
02770 
02771 /*
02772  * Acquire the cert trust lock
02773  * There is currently one global lock for all certs, but I'm putting a cert
02774  * arg here so that it will be easy to make it per-cert in the future if
02775  * that turns out to be necessary.
02776  */
02777 void
02778 CERT_LockCertTrust(CERTCertificate *cert)
02779 {
02780     if ( certTrustLock == NULL ) {
02781        nss_InitLock(&certTrustLock, nssILockCertDB);
02782        PORT_Assert(certTrustLock != NULL);
02783     }
02784     
02785     PZ_Lock(certTrustLock);
02786     return;
02787 }
02788 
02789 /*
02790  * Free the cert trust lock
02791  */
02792 void
02793 CERT_UnlockCertTrust(CERTCertificate *cert)
02794 {
02795     PRStatus prstat;
02796 
02797     PORT_Assert(certTrustLock != NULL);
02798     
02799     prstat = PZ_Unlock(certTrustLock);
02800     
02801     PORT_Assert(prstat == PR_SUCCESS);
02802 
02803     return;
02804 }
02805 
02806 
02807 /*
02808  * Get the StatusConfig data for this handle
02809  */
02810 CERTStatusConfig *
02811 CERT_GetStatusConfig(CERTCertDBHandle *handle)
02812 {
02813   return handle->statusConfig;
02814 }
02815 
02816 /*
02817  * Set the StatusConfig data for this handle.  There
02818  * should not be another configuration set.
02819  */
02820 void
02821 CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig)
02822 {
02823   PORT_Assert(handle->statusConfig == NULL);
02824   handle->statusConfig = statusConfig;
02825 }
02826 
02827 /*
02828  * Code for dealing with subjKeyID to cert mappings.
02829  */
02830 
02831 static PLHashTable *gSubjKeyIDHash = NULL;
02832 static PRLock      *gSubjKeyIDLock = NULL;
02833 
02834 static void *cert_AllocTable(void *pool, PRSize size)
02835 {
02836     return PORT_Alloc(size);
02837 }
02838 
02839 static void cert_FreeTable(void *pool, void *item)
02840 {
02841     PORT_Free(item);
02842 }
02843 
02844 static PLHashEntry* cert_AllocEntry(void *pool, const void *key)
02845 {
02846     return PORT_New(PLHashEntry);
02847 }
02848 
02849 static void cert_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
02850 {
02851     SECITEM_FreeItem((SECItem*)(he->value), PR_TRUE);
02852     if (flag == HT_FREE_ENTRY) {
02853         SECITEM_FreeItem((SECItem*)(he->key), PR_TRUE);
02854         PORT_Free(he);
02855     }
02856 }
02857 
02858 static PLHashAllocOps cert_AllocOps = {
02859     cert_AllocTable, cert_FreeTable, cert_AllocEntry, cert_FreeEntry
02860 };
02861 
02862 SECStatus
02863 cert_CreateSubjectKeyIDHashTable(void)
02864 {
02865     gSubjKeyIDHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
02866                                     SECITEM_HashCompare,
02867                                     &cert_AllocOps, NULL);
02868     if (!gSubjKeyIDHash) {
02869         PORT_SetError(SEC_ERROR_NO_MEMORY);
02870         return SECFailure;
02871     }
02872     gSubjKeyIDLock = PR_NewLock();
02873     if (!gSubjKeyIDLock) {
02874         PL_HashTableDestroy(gSubjKeyIDHash);
02875         gSubjKeyIDHash = NULL;
02876         PORT_SetError(SEC_ERROR_NO_MEMORY);
02877         return SECFailure;
02878     }
02879     return SECSuccess;
02880 
02881 }
02882 
02883 SECStatus
02884 cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert)
02885 {
02886     SECItem *newKeyID, *oldVal, *newVal;
02887     SECStatus rv = SECFailure;
02888 
02889     if (!gSubjKeyIDLock) {
02890        /* If one is created, then both are there.  So only check for one. */
02891        return SECFailure;
02892     }
02893 
02894     newVal = SECITEM_DupItem(&cert->derCert);
02895     if (!newVal) {
02896         PORT_SetError(SEC_ERROR_NO_MEMORY);
02897         goto done;
02898     }
02899     newKeyID = SECITEM_DupItem(subjKeyID);
02900     if (!newKeyID) {
02901         SECITEM_FreeItem(newVal, PR_TRUE);
02902         PORT_SetError(SEC_ERROR_NO_MEMORY);
02903         goto done;
02904     }
02905 
02906     PR_Lock(gSubjKeyIDLock);
02907     /* The hash table implementation does not free up the memory 
02908      * associated with the key of an already existing entry if we add a 
02909      * duplicate, so we would wind up leaking the previously allocated 
02910      * key if we don't remove before adding.
02911      */
02912     oldVal = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
02913     if (oldVal) {
02914         PL_HashTableRemove(gSubjKeyIDHash, subjKeyID);
02915     }
02916 
02917     rv = (PL_HashTableAdd(gSubjKeyIDHash, newKeyID, newVal)) ? SECSuccess :
02918                                                                SECFailure;
02919     PR_Unlock(gSubjKeyIDLock);
02920 done:
02921     return rv;
02922 }
02923 
02924 SECStatus
02925 cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID)
02926 {
02927     SECStatus rv;
02928     if (!gSubjKeyIDLock)
02929         return SECFailure;
02930 
02931     PR_Lock(gSubjKeyIDLock);
02932     rv = (PL_HashTableRemove(gSubjKeyIDHash, subjKeyID)) ? SECSuccess :
02933                                                            SECFailure;
02934     PR_Unlock(gSubjKeyIDLock);
02935     return rv;
02936 }
02937 
02938 SECStatus
02939 cert_DestroySubjectKeyIDHashTable(void)
02940 {
02941     if (gSubjKeyIDHash) {
02942         PR_Lock(gSubjKeyIDLock);
02943         PL_HashTableDestroy(gSubjKeyIDHash);
02944         gSubjKeyIDHash = NULL;
02945         PR_Unlock(gSubjKeyIDLock);
02946         PR_DestroyLock(gSubjKeyIDLock);
02947         gSubjKeyIDLock = NULL;
02948     }
02949     return SECSuccess;
02950 }
02951 
02952 SECItem*
02953 cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID)
02954 {
02955     SECItem   *val;
02956  
02957     if (!gSubjKeyIDLock)
02958         return NULL;
02959 
02960     PR_Lock(gSubjKeyIDLock);
02961     val = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
02962     if (val) {
02963         val = SECITEM_DupItem(val);
02964     }
02965     PR_Unlock(gSubjKeyIDLock);
02966     return val;
02967 }
02968 
02969 CERTCertificate*
02970 CERT_FindCertBySubjectKeyID(CERTCertDBHandle *handle, SECItem *subjKeyID)
02971 {
02972     CERTCertificate *cert = NULL;
02973     SECItem *derCert;
02974 
02975     derCert = cert_FindDERCertBySubjectKeyID(subjKeyID);
02976     if (derCert) {
02977         cert = CERT_FindCertByDERCert(handle, derCert);
02978         SECITEM_FreeItem(derCert, PR_TRUE);
02979     }
02980     return cert;
02981 }