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