Back to index

lightning-sunbird  0.9+nobinonly
certvfy.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  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 #include "nspr.h"
00037 #include "secerr.h"
00038 #include "secport.h"
00039 #include "seccomon.h"
00040 #include "secoid.h"
00041 #include "sslerr.h"
00042 #include "genname.h"
00043 #include "keyhi.h"
00044 #include "cert.h"
00045 #include "certdb.h"
00046 #include "cryptohi.h"
00047 
00048 #ifndef NSS_3_4_CODE
00049 #define NSS_3_4_CODE
00050 #endif /* NSS_3_4_CODE */
00051 #include "nsspki.h"
00052 #include "pkitm.h"
00053 #include "pkim.h"
00054 #include "pki3hack.h"
00055 #include "base.h"
00056 
00057 #define PENDING_SLOP (24L*60L*60L)
00058 
00059 /*
00060  * WARNING - this function is depricated, and will go away in the near future.
00061  *     It has been superseded by CERT_CheckCertValidTimes().
00062  *
00063  * Check the validity times of a certificate
00064  */
00065 SECStatus
00066 CERT_CertTimesValid(CERTCertificate *c)
00067 {
00068     int64 now, notBefore, notAfter, pendingSlop;
00069     SECStatus rv;
00070     
00071     /* if cert is already marked OK, then don't bother to check */
00072     if ( c->timeOK ) {
00073        return(SECSuccess);
00074     }
00075     
00076     /* get current time */
00077     now = PR_Now();
00078     rv = CERT_GetCertTimes(c, &notBefore, &notAfter);
00079     
00080     if (rv) {
00081        return(SECFailure);
00082     }
00083     
00084     LL_I2L(pendingSlop, PENDING_SLOP);
00085     LL_SUB(notBefore, notBefore, pendingSlop);
00086 
00087     if (LL_CMP(now, <, notBefore) || LL_CMP(now, >, notAfter)) {
00088        PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
00089        return(SECFailure);
00090     }
00091 
00092     return(SECSuccess);
00093 }
00094 
00095 /*
00096  * verify the signature of a signed data object with the given DER publickey
00097  */
00098 SECStatus
00099 CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd, 
00100                                    SECKEYPublicKey *pubKey,
00101                                  void *wincx)
00102 {
00103     SECStatus        rv;
00104     SECItem          sig;
00105 
00106     if ( !pubKey || !sd ) {
00107        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
00108        return SECFailure;
00109     }
00110 
00111     /* check the signature */
00112     sig = sd->signature;
00113     /* convert sig->len from bit counts to byte count. */
00114     DER_ConvertBitString(&sig);
00115 
00116     rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey, 
00117                      &sig, &sd->signatureAlgorithm, NULL, wincx);
00118 
00119     return rv ? SECFailure : SECSuccess;
00120 }
00121 
00122 /*
00123  * verify the signature of a signed data object with the given DER publickey
00124  */
00125 SECStatus
00126 CERT_VerifySignedDataWithPublicKeyInfo(CERTSignedData *sd, 
00127                                        CERTSubjectPublicKeyInfo *pubKeyInfo,
00128                                      void *wincx)
00129 {
00130     SECKEYPublicKey *pubKey;
00131     SECStatus        rv            = SECFailure;
00132 
00133     /* get cert's public key */
00134     pubKey = SECKEY_ExtractPublicKey(pubKeyInfo);
00135     if (pubKey) {
00136        rv =  CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx);
00137        SECKEY_DestroyPublicKey(pubKey);
00138     }
00139     return rv;
00140 }
00141 
00142 /*
00143  * verify the signature of a signed data object with the given certificate
00144  */
00145 SECStatus
00146 CERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert,
00147                     int64 t, void *wincx)
00148 {
00149     SECKEYPublicKey *pubKey = 0;
00150     SECStatus        rv     = SECFailure;
00151     SECCertTimeValidity validity;
00152 
00153     /* check the certificate's validity */
00154     validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE);
00155     if ( validity != secCertTimeValid ) {
00156        return rv;
00157     }
00158 
00159     /* get cert's public key */
00160     pubKey = CERT_ExtractPublicKey(cert);
00161     if (pubKey) {
00162        rv =  CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx);
00163        SECKEY_DestroyPublicKey(pubKey);
00164     }
00165     return rv;
00166 }
00167 
00168 
00169 /* Software FORTEZZA installation hack. The software fortezza installer does
00170  * not have access to the krl and cert.db file. Accept FORTEZZA Certs without
00171  * KRL's in this case. 
00172  */
00173 static int dont_use_krl = 0;
00174 /* not a public exposed function... */
00175 void sec_SetCheckKRLState(int value) { dont_use_krl = value; }
00176 
00177 SECStatus
00178 SEC_CheckKRL(CERTCertDBHandle *handle,SECKEYPublicKey *key,
00179             CERTCertificate *rootCert, int64 t, void * wincx)
00180 {
00181     CERTSignedCrl *crl = NULL;
00182     SECStatus rv = SECFailure;
00183     SECStatus rv2;
00184     CERTCrlEntry **crlEntry;
00185     SECCertTimeValidity validity;
00186     CERTCertificate *issuerCert = NULL;
00187 
00188     if (dont_use_krl) return SECSuccess;
00189 
00190     /* first look up the KRL */
00191     crl = SEC_FindCrlByName(handle,&rootCert->derSubject, SEC_KRL_TYPE);
00192     if (crl == NULL) {
00193        PORT_SetError(SEC_ERROR_NO_KRL);
00194        goto done;
00195     }
00196 
00197     /* get the issuing certificate */
00198     issuerCert = CERT_FindCertByName(handle, &crl->crl.derName);
00199     if (issuerCert == NULL) {
00200         PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
00201         goto done;
00202     }
00203 
00204 
00205     /* now verify the KRL signature */
00206     rv2 = CERT_VerifySignedData(&crl->signatureWrap, issuerCert, t, wincx);
00207     if (rv2 != SECSuccess) {
00208        PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
00209        goto done;
00210     }
00211 
00212     /* Verify the date validity of the KRL */
00213     validity = SEC_CheckCrlTimes(&crl->crl, t);
00214     if (validity == secCertTimeExpired) {
00215        PORT_SetError(SEC_ERROR_KRL_EXPIRED);
00216        goto done;
00217     }
00218 
00219     /* now make sure the key in this cert is still valid */
00220     if (key->keyType != fortezzaKey) {
00221        PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
00222        goto done; /* This should be an assert? */
00223     }
00224 
00225     /* now make sure the key is not on the revocation list */
00226     for (crlEntry = crl->crl.entries; crlEntry && *crlEntry; crlEntry++) {
00227        if (PORT_Memcmp((*crlEntry)->serialNumber.data,
00228                             key->u.fortezza.KMID,
00229                                 (*crlEntry)->serialNumber.len) == 0) {
00230            PORT_SetError(SEC_ERROR_REVOKED_KEY);
00231            goto done;
00232        }
00233     }
00234     rv = SECSuccess;
00235 
00236 done:
00237     if (issuerCert) CERT_DestroyCertificate(issuerCert);
00238     if (crl) SEC_DestroyCrl(crl);
00239     return rv;
00240 }
00241 
00242 SECStatus
00243 SEC_CheckCRL(CERTCertDBHandle *handle,CERTCertificate *cert,
00244             CERTCertificate *caCert, int64 t, void * wincx)
00245 {
00246     return CERT_CheckCRL(cert, caCert, NULL, t, wincx);
00247 }
00248 
00249 /*
00250  * Find the issuer of a cert.  Use the authorityKeyID if it exists.
00251  */
00252 CERTCertificate *
00253 CERT_FindCertIssuer(CERTCertificate *cert, int64 validTime, SECCertUsage usage)
00254 {
00255 #ifdef NSS_CLASSIC
00256     CERTAuthKeyID *   authorityKeyID = NULL;  
00257     CERTCertificate * issuerCert     = NULL;
00258     SECItem *         caName;
00259     PRArenaPool       *tmpArena = NULL;
00260 
00261     tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00262     
00263     if ( !tmpArena ) {
00264        goto loser;
00265     }
00266     authorityKeyID = CERT_FindAuthKeyIDExten(tmpArena,cert);
00267 
00268     if ( authorityKeyID != NULL ) {
00269        /* has the authority key ID extension */
00270        if ( authorityKeyID->keyID.data != NULL ) {
00271            /* extension contains a key ID, so lookup based on it */
00272            issuerCert = CERT_FindCertByKeyID(cert->dbhandle, &cert->derIssuer,
00273                                          &authorityKeyID->keyID);
00274            if ( issuerCert == NULL ) {
00275               PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
00276               goto loser;
00277            }
00278            
00279        } else if ( authorityKeyID->authCertIssuer != NULL ) {
00280            /* no key ID, so try issuer and serial number */
00281            caName = (SECItem*)CERT_GetGeneralNameByType(authorityKeyID->authCertIssuer,
00282                                                          certDirectoryName, PR_TRUE);
00283 
00284            /*
00285             * caName is NULL when the authCertIssuer field is not
00286             * being used, or other name form is used instead.
00287             * If the directoryName format and serialNumber fields are
00288             * used, we use them to find the CA cert.
00289             * Note:
00290             * By the time it gets here, we known for sure that if the
00291             * authCertIssuer exists, then the authCertSerialNumber
00292             * must also exists (CERT_DecodeAuthKeyID() ensures this).
00293             * We don't need to check again. 
00294             */
00295 
00296            if (caName != NULL) {
00297               CERTIssuerAndSN issuerSN;
00298 
00299               issuerSN.derIssuer.data = caName->data;
00300               issuerSN.derIssuer.len = caName->len;
00301               issuerSN.serialNumber.data = 
00302                      authorityKeyID->authCertSerialNumber.data;
00303               issuerSN.serialNumber.len = 
00304                      authorityKeyID->authCertSerialNumber.len;
00305               issuerCert = CERT_FindCertByIssuerAndSN(cert->dbhandle,
00306                                                         &issuerSN);
00307               if ( issuerCert == NULL ) {
00308                   PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
00309                   goto loser;
00310               }
00311            }
00312        }
00313     }
00314     if ( issuerCert == NULL ) {
00315        /* if there is not authorityKeyID, then try to find the issuer */
00316        /* find a valid CA cert with correct usage */
00317        issuerCert = CERT_FindMatchingCert(cert->dbhandle,
00318                                       &cert->derIssuer,
00319                                       certOwnerCA, usage, PR_TRUE,
00320                                       validTime, PR_TRUE);
00321 
00322        /* if that fails, then fall back to grabbing any cert with right name*/
00323        if ( issuerCert == NULL ) {
00324            issuerCert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer);
00325            if ( issuerCert == NULL ) {
00326               PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
00327            }
00328        }
00329     }
00330 
00331 loser:
00332     if (tmpArena != NULL) {
00333        PORT_FreeArena(tmpArena, PR_FALSE);
00334        tmpArena = NULL;
00335     }
00336 
00337     return(issuerCert);
00338 #else
00339     NSSCertificate *me;
00340     NSSTime *nssTime;
00341     NSSTrustDomain *td;
00342     NSSCryptoContext *cc;
00343     NSSCertificate *chain[3];
00344     NSSUsage nssUsage;
00345     PRStatus status;
00346 
00347     me = STAN_GetNSSCertificate(cert);
00348     if (!me) {
00349         PORT_SetError(SEC_ERROR_NO_MEMORY);
00350        return NULL;
00351     }
00352     nssTime = NSSTime_SetPRTime(NULL, validTime);
00353     nssUsage.anyUsage = PR_FALSE;
00354     nssUsage.nss3usage = usage;
00355     nssUsage.nss3lookingForCA = PR_TRUE;
00356     memset(chain, 0, 3*sizeof(NSSCertificate *));
00357     td   = STAN_GetDefaultTrustDomain();
00358     cc = STAN_GetDefaultCryptoContext();
00359     (void)NSSCertificate_BuildChain(me, nssTime, &nssUsage, NULL, 
00360                                     chain, 2, NULL, &status, td, cc);
00361     nss_ZFreeIf(nssTime);
00362     if (status == PR_SUCCESS) {
00363        PORT_Assert(me == chain[0]);
00364        /* if it's a root, the chain will only have one cert */
00365        if (!chain[1]) {
00366            /* already has a reference from the call to BuildChain */
00367            return cert;
00368        } 
00369        NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
00370        return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */
00371     } 
00372     if (chain[0]) {
00373        PORT_Assert(me == chain[0]);
00374        NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
00375     }
00376     PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
00377     return NULL;
00378 #endif
00379 }
00380 
00381 /*
00382  * return required trust flags for various cert usages for CAs
00383  */
00384 SECStatus
00385 CERT_TrustFlagsForCACertUsage(SECCertUsage usage,
00386                            unsigned int *retFlags,
00387                            SECTrustType *retTrustType)
00388 {
00389     unsigned int requiredFlags;
00390     SECTrustType trustType;
00391 
00392     switch ( usage ) {
00393       case certUsageSSLClient:
00394        requiredFlags = CERTDB_TRUSTED_CLIENT_CA;
00395        trustType = trustSSL;
00396         break;
00397       case certUsageSSLServer:
00398       case certUsageSSLCA:
00399        requiredFlags = CERTDB_TRUSTED_CA;
00400        trustType = trustSSL;
00401         break;
00402       case certUsageSSLServerWithStepUp:
00403        requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA;
00404        trustType = trustSSL;
00405         break;
00406       case certUsageEmailSigner:
00407       case certUsageEmailRecipient:
00408        requiredFlags = CERTDB_TRUSTED_CA;
00409        trustType = trustEmail;
00410        break;
00411       case certUsageObjectSigner:
00412        requiredFlags = CERTDB_TRUSTED_CA;
00413        trustType = trustObjectSigning;
00414        break;
00415       case certUsageVerifyCA:
00416       case certUsageAnyCA:
00417       case certUsageStatusResponder:
00418        requiredFlags = CERTDB_TRUSTED_CA;
00419        trustType = trustTypeNone;
00420        break;
00421       default:
00422        PORT_Assert(0);
00423        goto loser;
00424     }
00425     if ( retFlags != NULL ) {
00426        *retFlags = requiredFlags;
00427     }
00428     if ( retTrustType != NULL ) {
00429        *retTrustType = trustType;
00430     }
00431     
00432     return(SECSuccess);
00433 loser:
00434     return(SECFailure);
00435 }
00436 
00437 
00438 
00439 
00440 
00441 static void
00442 AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, unsigned long error,
00443               unsigned int depth, void *arg)
00444 {
00445     CERTVerifyLogNode *node, *tnode;
00446 
00447     PORT_Assert(log != NULL);
00448     
00449     node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena,
00450                                           sizeof(CERTVerifyLogNode));
00451     if ( node != NULL ) {
00452        node->cert = CERT_DupCertificate(cert);
00453        node->error = error;
00454        node->depth = depth;
00455        node->arg = arg;
00456        
00457        if ( log->tail == NULL ) {
00458            /* empty list */
00459            log->head = log->tail = node;
00460            node->prev = NULL;
00461            node->next = NULL;
00462        } else if ( depth >= log->tail->depth ) {
00463            /* add to tail */
00464            node->prev = log->tail;
00465            log->tail->next = node;
00466            log->tail = node;
00467            node->next = NULL;
00468        } else if ( depth < log->head->depth ) {
00469            /* add at head */
00470            node->prev = NULL;
00471            node->next = log->head;
00472            log->head->prev = node;
00473            log->head = node;
00474        } else {
00475            /* add in middle */
00476            tnode = log->tail;
00477            while ( tnode != NULL ) {
00478               if ( depth >= tnode->depth ) {
00479                   /* insert after tnode */
00480                   node->prev = tnode;
00481                   node->next = tnode->next;
00482                   tnode->next->prev = node;
00483                   tnode->next = node;
00484                   break;
00485               }
00486 
00487               tnode = tnode->prev;
00488            }
00489        }
00490 
00491        log->count++;
00492     }
00493     return;
00494 }
00495 
00496 #define EXIT_IF_NOT_LOGGING(log) \
00497     if ( log == NULL ) { \
00498        goto loser; \
00499     }
00500 
00501 #define LOG_ERROR_OR_EXIT(log,cert,depth,arg) \
00502     if ( log != NULL ) { \
00503        AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \
00504     } else { \
00505        goto loser; \
00506     }
00507 
00508 #define LOG_ERROR(log,cert,depth,arg) \
00509     if ( log != NULL ) { \
00510        AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \
00511     }
00512 
00513 
00514 typedef enum { cbd_None, cbd_User, cbd_CA } cbd_FortezzaType;
00515 
00516 static SECStatus
00517 cert_VerifyFortezzaV1Cert(CERTCertDBHandle *handle, CERTCertificate *cert,
00518        cbd_FortezzaType *next_type, cbd_FortezzaType last_type,
00519        int64 t, void *wincx)
00520 {
00521     unsigned char priv = 0;
00522     SECKEYPublicKey *key;
00523     SECStatus rv;
00524 
00525     *next_type = cbd_CA;
00526 
00527     /* read the key */
00528     key = CERT_ExtractPublicKey(cert);
00529 
00530     /* Cant' get Key? fail. */
00531     if (key == NULL) {
00532        PORT_SetError(SEC_ERROR_BAD_KEY);
00533        return SECFailure;
00534     }
00535 
00536 
00537     /* if the issuer is not an old fortezza cert, we bail */
00538     if (key->keyType != fortezzaKey) {
00539        SECKEY_DestroyPublicKey(key);
00540        /* CA Cert not fortezza */
00541        PORT_SetError(SEC_ERROR_NOT_FORTEZZA_ISSUER);
00542        return SECFailure;
00543     }
00544 
00545     /* get the privilege mask */
00546     if (key->u.fortezza.DSSpriviledge.len > 0) {
00547        priv = key->u.fortezza.DSSpriviledge.data[0];
00548     }
00549 
00550     /*
00551      * make sure the CA's keys are OK
00552      */
00553             
00554     rv = SEC_CheckKRL(handle, key, NULL, t, wincx);
00555     SECKEY_DestroyPublicKey(key);
00556     if (rv != SECSuccess) {
00557        return rv;
00558     }
00559 
00560     switch (last_type) {
00561       case cbd_User:
00562        /* first check for subordination */
00563        /*rv = FortezzaSubordinateCheck(cert,issuerCert);*/
00564        rv = SECSuccess;
00565 
00566        /* now check for issuer privilege */
00567        if ((rv != SECSuccess) || ((priv & 0x10) == 0)) {
00568            /* bail */
00569            PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
00570            return SECFailure;
00571        }
00572        break;
00573       case cbd_CA:
00574        if ((priv & 0x20) == 0) {
00575            /* bail */
00576            PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
00577            return SECFailure;
00578        }
00579        break;
00580       case cbd_None:
00581        *next_type = (priv & 0x30) ? cbd_CA : cbd_User;
00582        break;
00583       default:
00584        /* bail */ /* shouldn't ever happen */
00585        PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
00586        return SECFailure;
00587     }
00588     return SECSuccess;
00589 }
00590 
00591 
00592 static SECStatus
00593 cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
00594                    PRBool checkSig, PRBool* sigerror,
00595                      SECCertUsage certUsage, int64 t, void *wincx,
00596                      CERTVerifyLog *log, PRBool* revoked)
00597 {
00598     SECTrustType trustType;
00599     CERTBasicConstraints basicConstraint;
00600     CERTCertificate *issuerCert = NULL;
00601     CERTCertificate *subjectCert = NULL;
00602     CERTCertificate *badCert = NULL;
00603     PRBool isca;
00604     PRBool isFortezzaV1 = PR_FALSE;
00605     SECStatus rv;
00606     SECStatus rvFinal = SECSuccess;
00607     int count;
00608     int currentPathLen = 0;
00609     int pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;
00610     int flags;
00611     unsigned int caCertType;
00612     unsigned int requiredCAKeyUsage;
00613     unsigned int requiredFlags;
00614     PRArenaPool *arena = NULL;
00615     CERTGeneralName *namesList = NULL;
00616     CERTCertificate **certsList      = NULL;
00617     int certsListLen = 16;
00618     int namesCount = 0;
00619     PRBool subjectCertIsSelfIssued;
00620 
00621     cbd_FortezzaType last_type = cbd_None;
00622 
00623     if (revoked) {
00624         *revoked = PR_FALSE;
00625     }
00626 
00627     if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
00628                                     &requiredCAKeyUsage,
00629                                     &caCertType)
00630        != SECSuccess ) {
00631        PORT_Assert(0);
00632        EXIT_IF_NOT_LOGGING(log);
00633        requiredCAKeyUsage = 0;
00634        caCertType = 0;
00635     }
00636 
00637     switch ( certUsage ) {
00638       case certUsageSSLClient:
00639       case certUsageSSLServer:
00640       case certUsageSSLCA:
00641       case certUsageSSLServerWithStepUp:
00642       case certUsageEmailSigner:
00643       case certUsageEmailRecipient:
00644       case certUsageObjectSigner:
00645       case certUsageVerifyCA:
00646       case certUsageStatusResponder:
00647        if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
00648                                       &trustType) != SECSuccess ) {
00649            PORT_Assert(0);
00650            EXIT_IF_NOT_LOGGING(log);
00651            requiredFlags = 0;
00652            trustType = trustSSL;
00653        }
00654        break;
00655       default:
00656        PORT_Assert(0);
00657        EXIT_IF_NOT_LOGGING(log);
00658        requiredFlags = 0;
00659        trustType = trustSSL;/* This used to be 0, but we need something
00660                            * that matches the enumeration type.
00661                            */
00662        caCertType = 0;
00663     }
00664     
00665     subjectCert = CERT_DupCertificate(cert);
00666     if ( subjectCert == NULL ) {
00667        goto loser;
00668     }
00669 
00670     /* determine if the cert is fortezza.
00671      */
00672     isFortezzaV1 = (PRBool)
00673        (CERT_GetCertKeyType(&subjectCert->subjectPublicKeyInfo) 
00674                                                  == fortezzaKey);
00675 
00676     if (isFortezzaV1) {
00677        rv = cert_VerifyFortezzaV1Cert(handle, subjectCert, &last_type, 
00678                                           cbd_None, t, wincx);
00679        if (rv == SECFailure) {
00680            /**** PORT_SetError is already set by cert_VerifyFortezzaV1Cert **/
00681            LOG_ERROR_OR_EXIT(log,subjectCert,0,0);
00682        }
00683     }
00684 
00685     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00686     if (arena == NULL) {
00687        goto loser;
00688     }
00689 
00690     certsList = PORT_ZNewArray(CERTCertificate *, certsListLen);
00691     if (certsList == NULL)
00692        goto loser;
00693 
00694     /* RFC 3280 says that the name constraints will apply to the names
00695     ** in the leaf (EE) cert, whether it is self issued or not, so
00696     ** we pretend that it is not.
00697     */
00698     subjectCertIsSelfIssued = PR_FALSE;
00699     for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) {
00700        PRBool validCAOverride = PR_FALSE;
00701 
00702        /* Construct a list of names for the current and all previous 
00703         * certifcates (except leaf (EE) certs, root CAs, and self-issued
00704         * intermediate CAs) to be verified against the name constraints 
00705         * extension of the issuer certificate. 
00706         */
00707        if (subjectCertIsSelfIssued == PR_FALSE) {
00708            CERTGeneralName *subjectNameList;
00709            int subjectNameListLen;
00710            int i;
00711            subjectNameList    = CERT_GetCertificateNames(subjectCert, arena);
00712            subjectNameListLen = CERT_GetNamesLength(subjectNameList);
00713            if (certsListLen <= namesCount + subjectNameListLen) {
00714               CERTCertificate **tmpCertsList;
00715               certsListLen = (namesCount + subjectNameListLen) * 2;
00716               tmpCertsList = 
00717                   (CERTCertificate **)PORT_Realloc(certsList, 
00718                                    certsListLen * sizeof(CERTCertificate *));
00719               if (tmpCertsList == NULL) {
00720                   goto loser;
00721               }
00722               certsList = tmpCertsList;
00723            }
00724            for (i = 0; i < subjectNameListLen; i++) {
00725               certsList[namesCount + i] = subjectCert;
00726            }
00727            namesCount += subjectNameListLen;
00728            namesList = cert_CombineNamesLists(namesList, subjectNameList);
00729        }
00730 
00731         /* check if the cert has an unsupported critical extension */
00732        if ( subjectCert->options.bits.hasUnsupportedCriticalExt ) {
00733            PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
00734            LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
00735        }
00736 
00737        /* find the certificate of the issuer */
00738        issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage);
00739        if ( ! issuerCert ) {
00740            PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
00741            LOG_ERROR(log,subjectCert,count,0);
00742            goto loser;
00743        }
00744 
00745        /* verify the signature on the cert */
00746        if ( checkSig ) {
00747            rv = CERT_VerifySignedData(&subjectCert->signatureWrap,
00748                                    issuerCert, t, wincx);
00749     
00750            if ( rv != SECSuccess ) {
00751                 if (sigerror) {
00752                     *sigerror = PR_TRUE;
00753                 }
00754               if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) {
00755                   PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
00756                   LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
00757               } else {
00758                   PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
00759                   LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
00760               }
00761            }
00762        }
00763 
00764        /*
00765         * XXX - fortezza may need error logging stuff added
00766         */
00767        if (isFortezzaV1) {
00768            rv = cert_VerifyFortezzaV1Cert(handle, issuerCert, &last_type, 
00769                                    last_type, t, wincx);
00770            if (rv == SECFailure) {
00771               /**** PORT_SetError is already set by *
00772                * cert_VerifyFortezzaV1Cert **/
00773               LOG_ERROR_OR_EXIT(log,subjectCert,0,0);
00774            }
00775        }
00776 
00777        /* If the basicConstraint extension is included in an immediate CA
00778         * certificate, make sure that the isCA flag is on.  If the
00779         * pathLenConstraint component exists, it must be greater than the
00780         * number of CA certificates we have seen so far.  If the extension
00781         * is omitted, we will assume that this is a CA certificate with
00782         * an unlimited pathLenConstraint (since it already passes the
00783         * netscape-cert-type extension checking).
00784         *
00785         * In the fortezza (V1) case, we've already checked the CA bits
00786         * in the key, so we're presumed to be a CA; however we really don't
00787         * want to bypass Basic constraint or netscape extension parsing.
00788          * 
00789          * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA
00790         */
00791 
00792        rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint);
00793        if ( rv != SECSuccess ) {
00794            if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
00795               LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
00796            } 
00797            pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;
00798            /* no basic constraints found, if we're fortezza, CA bit is already
00799             * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca
00800             * isca = PR_FALSE */
00801            isca = isFortezzaV1;
00802        } else  {
00803            if ( basicConstraint.isCA == PR_FALSE ) {
00804               PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
00805               LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
00806            }
00807            pathLengthLimit = basicConstraint.pathLenConstraint;
00808            isca = PR_TRUE;
00809        }    
00810        /* make sure that the path len constraint is properly set.*/
00811        if (pathLengthLimit >= 0 && currentPathLen > pathLengthLimit) {
00812            PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
00813            LOG_ERROR_OR_EXIT(log, issuerCert, count+1, pathLengthLimit);
00814        }
00815        
00816        /* XXX - the error logging may need to go down into CRL stuff at some
00817         * point
00818         */
00819        /* check revoked list (issuer) */
00820         rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx);
00821         if (rv == SECFailure) {
00822             if (revoked) {
00823                 *revoked = PR_TRUE;
00824             }
00825             LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
00826         } else if (rv == SECWouldBlock) {
00827             /* We found something fishy, so we intend to issue an
00828              * error to the user, but the user may wish to continue
00829              * processing, in which case we better make sure nothing
00830              * worse has happened... so keep cranking the loop */
00831             rvFinal = SECFailure;
00832             if (revoked) {
00833                 *revoked = PR_TRUE;
00834             }
00835             LOG_ERROR(log,subjectCert,count,0);
00836         }
00837 
00838        if ( issuerCert->trust ) {
00839            /* we have some trust info, but this does NOT imply that this
00840             * cert is actually trusted for any purpose.  The cert may be
00841             * explicitly UNtrusted.  We won't know until we examine the
00842             * trust bits.
00843             */
00844            if (certUsage == certUsageStatusResponder) {
00845               /* XXX NSS has done this for years, but it seems incorrect. */
00846               rv = rvFinal;
00847               goto done;
00848            }
00849 
00850            /*
00851             * check the trust parms of the issuer
00852             */
00853            if ( certUsage == certUsageVerifyCA ) {
00854               if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) {
00855                   trustType = trustEmail;
00856               } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) {
00857                   trustType = trustSSL;
00858               } else {
00859                   trustType = trustObjectSigning;
00860               }
00861            }
00862            
00863            flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType);
00864            
00865            if (flags & CERTDB_VALID_CA) {
00866               if ( ( flags & requiredFlags ) == requiredFlags) {
00867                   /* we found a trusted one, so return */
00868                   rv = rvFinal; 
00869                   goto done;
00870               }
00871               validCAOverride = PR_TRUE;
00872            }
00873        }
00874 
00875        if (!validCAOverride) {
00876            /*
00877             * Make sure that if this is an intermediate CA in the chain that
00878             * it was given permission by its signer to be a CA.
00879             */
00880            /*
00881             * if basicConstraints says it is a ca, then we check the
00882             * nsCertType.  If the nsCertType has any CA bits set, then
00883             * it must have the right one.
00884             */
00885            if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) {
00886               isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;
00887            }
00888        
00889            if (  !isca  ) {
00890               PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
00891               LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);
00892            }
00893 
00894            /* make sure key usage allows cert signing */
00895            if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) {
00896               PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
00897               LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage);
00898            }
00899        }
00900 
00901        /* make sure that the entire chain is within the name space of the 
00902        ** current issuer certificate.
00903        */
00904        rv = CERT_CompareNameSpace(issuerCert, namesList, certsList, 
00905                                   arena, &badCert);
00906        if (rv != SECSuccess || badCert != NULL) {
00907            PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE);
00908             LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0);
00909            goto loser;
00910        }
00911        /* make sure that the issuer is not self signed.  If it is, then
00912         * stop here to prevent looping.
00913         */
00914        if (issuerCert->isRoot) {
00915            PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
00916            LOG_ERROR(log, issuerCert, count+1, 0);
00917            goto loser;
00918        } 
00919        /* The issuer cert will be the subject cert in the next loop.
00920         * A cert is self-issued if its subject and issuer are equal and
00921         * both are of non-zero length. 
00922         */
00923        subjectCertIsSelfIssued = (PRBool)
00924            SECITEM_ItemsAreEqual(&issuerCert->derIssuer, 
00925                               &issuerCert->derSubject) &&
00926            issuerCert->derSubject.len > 0;
00927        if (subjectCertIsSelfIssued == PR_FALSE) {
00928            /* RFC 3280 says only non-self-issued intermediate CA certs 
00929             * count in path length.
00930             */
00931            ++currentPathLen;
00932        }
00933 
00934        CERT_DestroyCertificate(subjectCert);
00935        subjectCert = issuerCert;
00936        issuerCert = NULL;
00937     }
00938 
00939     PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
00940     LOG_ERROR(log,subjectCert,count,0);
00941 loser:
00942     rv = SECFailure;
00943 done:
00944     if (certsList != NULL) {
00945        PORT_Free(certsList);
00946     }
00947     if ( issuerCert ) {
00948        CERT_DestroyCertificate(issuerCert);
00949     }
00950     
00951     if ( subjectCert ) {
00952        CERT_DestroyCertificate(subjectCert);
00953     }
00954 
00955     if ( arena != NULL ) {
00956        PORT_FreeArena(arena, PR_FALSE);
00957     }
00958     return rv;
00959 }
00960 
00961 SECStatus
00962 CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
00963                    PRBool checkSig, SECCertUsage certUsage, int64 t,
00964                    void *wincx, CERTVerifyLog *log)
00965 {
00966     return cert_VerifyCertChain(handle, cert, checkSig, NULL, certUsage, t,
00967                       wincx, log, NULL);
00968 }
00969 
00970 /*
00971  * verify that a CA can sign a certificate with the requested usage.
00972  * XXX This function completely ignores cert path length constraints!
00973  */
00974 SECStatus
00975 CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert,
00976               PRBool checkSig, SECCertUsage certUsage, int64 t,
00977               void *wincx, CERTVerifyLog *log)
00978 {
00979     SECTrustType trustType;
00980     CERTBasicConstraints basicConstraint;
00981     PRBool isca;
00982     PRBool validCAOverride = PR_FALSE;
00983     SECStatus rv;
00984     SECComparison rvCompare;
00985     SECStatus rvFinal = SECSuccess;
00986     int flags;
00987     unsigned int caCertType;
00988     unsigned int requiredCAKeyUsage;
00989     unsigned int requiredFlags;
00990     CERTCertificate *issuerCert;
00991 
00992 
00993     if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
00994                                     &requiredCAKeyUsage,
00995                                     &caCertType) != SECSuccess ) {
00996        PORT_Assert(0);
00997        EXIT_IF_NOT_LOGGING(log);
00998        requiredCAKeyUsage = 0;
00999        caCertType = 0;
01000     }
01001 
01002     switch ( certUsage ) {
01003       case certUsageSSLClient:
01004       case certUsageSSLServer:
01005       case certUsageSSLCA:
01006       case certUsageSSLServerWithStepUp:
01007       case certUsageEmailSigner:
01008       case certUsageEmailRecipient:
01009       case certUsageObjectSigner:
01010       case certUsageVerifyCA:
01011       case certUsageStatusResponder:
01012        if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
01013                                       &trustType) != SECSuccess ) {
01014            PORT_Assert(0);
01015            EXIT_IF_NOT_LOGGING(log);
01016            requiredFlags = 0;
01017            trustType = trustSSL;
01018        }
01019        break;
01020       default:
01021        PORT_Assert(0);
01022        EXIT_IF_NOT_LOGGING(log);
01023        requiredFlags = 0;
01024        trustType = trustSSL;/* This used to be 0, but we need something
01025                            * that matches the enumeration type.
01026                            */
01027        caCertType = 0;
01028     }
01029     
01030     /* If the basicConstraint extension is included in an intermmediate CA
01031      * certificate, make sure that the isCA flag is on.  If the
01032      * pathLenConstraint component exists, it must be greater than the
01033      * number of CA certificates we have seen so far.  If the extension
01034      * is omitted, we will assume that this is a CA certificate with
01035      * an unlimited pathLenConstraint (since it already passes the
01036      * netscape-cert-type extension checking).
01037      *
01038      * In the fortezza (V1) case, we've already checked the CA bits
01039      * in the key, so we're presumed to be a CA; however we really don't
01040      * want to bypass Basic constraint or netscape extension parsing.
01041      * 
01042      * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA
01043      */
01044 
01045     rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
01046     if ( rv != SECSuccess ) {
01047        if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
01048            LOG_ERROR_OR_EXIT(log,cert,0,0);
01049        } 
01050        /* no basic constraints found, if we're fortezza, CA bit is already
01051         * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca
01052         * isca = PR_FALSE */
01053        isca = PR_FALSE;
01054     } else  {
01055        if ( basicConstraint.isCA == PR_FALSE ) {
01056            PORT_SetError (SEC_ERROR_CA_CERT_INVALID);
01057            LOG_ERROR_OR_EXIT(log,cert,0,0);
01058        }
01059 
01060        /* can't check path length if we don't know the previous path */
01061        isca = PR_TRUE;
01062     }
01063        
01064     if ( cert->trust ) {
01065        /* we have some trust info, but this does NOT imply that this
01066         * cert is actually trusted for any purpose.  The cert may be
01067         * explicitly UNtrusted.  We won't know until we examine the
01068         * trust bits.
01069         */
01070         if (certUsage == certUsageStatusResponder) {
01071            /* Check the special case of certUsageStatusResponder */
01072             issuerCert = CERT_FindCertIssuer(cert, t, certUsage);
01073             if (issuerCert) {
01074                 if (SEC_CheckCRL(handle, cert, issuerCert, t, wincx) 
01075                   != SECSuccess) {
01076                     PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
01077                     CERT_DestroyCertificate(issuerCert);
01078                     goto loser;
01079                 }
01080                 CERT_DestroyCertificate(issuerCert);
01081             }
01082            /* XXX We have NOT determined that this cert is trusted.
01083             * For years, NSS has treated this as trusted, 
01084             * but it seems incorrect.
01085             */
01086            rv = rvFinal; 
01087            goto done;
01088         }
01089 
01090        /*
01091         * check the trust parms of the issuer
01092         */
01093        flags = SEC_GET_TRUST_FLAGS(cert->trust, trustType);
01094            
01095        if (flags & CERTDB_VALID_CA) {
01096            if ( ( flags & requiredFlags ) == requiredFlags) {
01097               /* we found a trusted one, so return */
01098               rv = rvFinal; 
01099               goto done;
01100            }
01101            validCAOverride = PR_TRUE;
01102        }
01103     }
01104     if (!validCAOverride) {
01105        /*
01106         * Make sure that if this is an intermediate CA in the chain that
01107         * it was given permission by its signer to be a CA.
01108         */
01109        /*
01110         * if basicConstraints says it is a ca, then we check the
01111         * nsCertType.  If the nsCertType has any CA bits set, then
01112         * it must have the right one.
01113         */
01114        if (!isca || (cert->nsCertType & NS_CERT_TYPE_CA)) {
01115            isca = (cert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;
01116        }
01117        
01118        if (!isca) {
01119            PORT_SetError(SEC_ERROR_CA_CERT_INVALID);
01120            LOG_ERROR_OR_EXIT(log,cert,0,0);
01121        }
01122            
01123        /* make sure key usage allows cert signing */
01124        if (CERT_CheckKeyUsage(cert, requiredCAKeyUsage) != SECSuccess) {
01125            PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
01126            LOG_ERROR_OR_EXIT(log,cert,0,requiredCAKeyUsage);
01127        }
01128     }
01129     /* make sure that the issuer is not self signed.  If it is, then
01130      * stop here to prevent looping.
01131      */
01132     rvCompare = SECITEM_CompareItem(&cert->derSubject, &cert->derIssuer);
01133     if (rvCompare == SECEqual) {
01134            PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);
01135            LOG_ERROR(log, cert, 0, 0);
01136            goto loser;
01137     }
01138 
01139     return CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t, 
01140                                                  wincx, log);
01141 loser:
01142     rv = SECFailure;
01143 done:
01144     return rv;
01145 }
01146 
01147 #define NEXT_USAGE() { \
01148     i*=2; \
01149     certUsage++; \
01150     continue; \
01151 }
01152 
01153 #define VALID_USAGE() { \
01154     NEXT_USAGE(); \
01155 }
01156 
01157 #define INVALID_USAGE() { \
01158     if (returnedUsages) { \
01159         *returnedUsages &= (~i); \
01160     } \
01161     if (PR_TRUE == requiredUsage) { \
01162         valid = SECFailure; \
01163     } \
01164     NEXT_USAGE(); \
01165 }
01166 
01167 /*
01168  * verify a certificate by checking if it's valid and that we
01169  * trust the issuer.
01170  *
01171  * certificateUsage contains a bitfield of all cert usages that are
01172  * required for verification to succeed
01173  *
01174  * a bitfield of cert usages is returned in *returnedUsages
01175  * if requiredUsages is non-zero, the returned bitmap is only
01176  * for those required usages, otherwise it is for all usages
01177  *
01178  */
01179 SECStatus
01180 CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
01181               PRBool checkSig, SECCertificateUsage requiredUsages, int64 t,
01182               void *wincx, CERTVerifyLog *log, SECCertificateUsage* returnedUsages)
01183 {
01184     SECStatus rv;
01185     SECStatus valid;
01186     unsigned int requiredKeyUsage;
01187     unsigned int requiredCertType;
01188     unsigned int flags;
01189     unsigned int certType;
01190     PRBool       allowOverride;
01191     SECCertTimeValidity validity;
01192     CERTStatusConfig *statusConfig;
01193     PRInt32 i;
01194     SECCertUsage certUsage = 0;
01195     PRBool checkedOCSP = PR_FALSE;
01196     PRBool checkAllUsages = PR_FALSE;
01197     PRBool revoked = PR_FALSE;
01198     PRBool sigerror = PR_FALSE;
01199 
01200     if (!requiredUsages) {
01201         /* there are no required usages, so the user probably wants to
01202            get status for all usages */
01203         checkAllUsages = PR_TRUE;
01204     }
01205 
01206     if (returnedUsages) {
01207         *returnedUsages = 0;
01208     } else {
01209         /* we don't have a place to return status for all usages,
01210            so we can skip checks for usages that aren't required */
01211         checkAllUsages = PR_FALSE;
01212     }
01213     valid = SECSuccess ; /* start off assuming cert is valid */
01214    
01215     /* make sure that the cert is valid at time t */
01216     allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) ||
01217                              (requiredUsages & certificateUsageSSLServerWithStepUp));
01218     validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
01219     if ( validity != secCertTimeValid ) {
01220         valid = SECFailure;
01221         LOG_ERROR_OR_EXIT(log,cert,0,validity);
01222     }
01223 
01224     /* check key usage and netscape cert type */
01225     cert_GetCertType(cert);
01226     certType = cert->nsCertType;
01227 
01228     for (i=1; i<=certificateUsageHighest && 
01229               (SECSuccess == valid || returnedUsages || log) ; ) {
01230         PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE;
01231         if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) {
01232             NEXT_USAGE();
01233         }
01234         if (returnedUsages) {
01235             *returnedUsages |= i; /* start off assuming this usage is valid */
01236         }
01237         switch ( certUsage ) {
01238           case certUsageSSLClient:
01239           case certUsageSSLServer:
01240           case certUsageSSLServerWithStepUp:
01241           case certUsageSSLCA:
01242           case certUsageEmailSigner:
01243           case certUsageEmailRecipient:
01244           case certUsageObjectSigner:
01245           case certUsageStatusResponder:
01246             rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
01247                                                   &requiredKeyUsage,
01248                                                   &requiredCertType);
01249             if ( rv != SECSuccess ) {
01250                 PORT_Assert(0);
01251                 /* EXIT_IF_NOT_LOGGING(log); XXX ??? */
01252                 requiredKeyUsage = 0;
01253                 requiredCertType = 0;
01254                 INVALID_USAGE();
01255             }
01256             break;
01257 
01258           case certUsageAnyCA:
01259           case certUsageProtectedObjectSigner:
01260           case certUsageUserCertImport:
01261           case certUsageVerifyCA:
01262               /* these usages cannot be verified */
01263               NEXT_USAGE();
01264 
01265           default:
01266             PORT_Assert(0);
01267             requiredKeyUsage = 0;
01268             requiredCertType = 0;
01269             INVALID_USAGE();
01270         }
01271         if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
01272             if (PR_TRUE == requiredUsage) {
01273                 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
01274             }
01275             LOG_ERROR(log,cert,0,requiredKeyUsage);
01276             INVALID_USAGE();
01277         }
01278         if ( !( certType & requiredCertType ) ) {
01279             if (PR_TRUE == requiredUsage) {
01280                 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
01281             }
01282             LOG_ERROR(log,cert,0,requiredCertType);
01283             INVALID_USAGE();
01284         }
01285 
01286         /* check trust flags to see if this cert is directly trusted */
01287         if ( cert->trust ) { /* the cert is in the DB */
01288             switch ( certUsage ) {
01289               case certUsageSSLClient:
01290               case certUsageSSLServer:
01291                 flags = cert->trust->sslFlags;
01292 
01293                 /* is the cert directly trusted or not trusted ? */
01294                 if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
01295                     if ( flags & CERTDB_TRUSTED ) {     /* trust this cert */
01296                         VALID_USAGE();
01297                     } else { /* don't trust this cert */
01298                         if (PR_TRUE == requiredUsage) {
01299                             PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
01300                         }
01301                         LOG_ERROR(log,cert,0,flags);
01302                         INVALID_USAGE();
01303                     }
01304                 }
01305                 break;
01306               case certUsageSSLServerWithStepUp:
01307                 /* XXX - step up certs can't be directly trusted */
01308                 break;
01309               case certUsageSSLCA:
01310                 break;
01311               case certUsageEmailSigner:
01312               case certUsageEmailRecipient:
01313                 flags = cert->trust->emailFlags;
01314 
01315                 /* is the cert directly trusted or not trusted ? */
01316                 if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) ==
01317                     ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) {
01318                     VALID_USAGE();
01319                 }
01320                 break;
01321               case certUsageObjectSigner:
01322                 flags = cert->trust->objectSigningFlags;
01323 
01324                 /* is the cert directly trusted or not trusted ? */
01325                 if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
01326                     if ( flags & CERTDB_TRUSTED ) {     /* trust this cert */
01327                         VALID_USAGE();
01328                     } else { /* don't trust this cert */
01329                         if (PR_TRUE == requiredUsage) {
01330                             PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
01331                         }
01332                         LOG_ERROR(log,cert,0,flags);
01333                         INVALID_USAGE();
01334                     }
01335                 }
01336                 break;
01337               case certUsageVerifyCA:
01338               case certUsageStatusResponder:
01339                 flags = cert->trust->sslFlags;
01340                 /* is the cert directly trusted or not trusted ? */
01341                 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
01342                     ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
01343                     VALID_USAGE();
01344                 }
01345                 flags = cert->trust->emailFlags;
01346                 /* is the cert directly trusted or not trusted ? */
01347                 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
01348                     ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
01349                     VALID_USAGE();
01350                 }
01351                 flags = cert->trust->objectSigningFlags;
01352                 /* is the cert directly trusted or not trusted ? */
01353                 if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
01354                     ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
01355                     VALID_USAGE();
01356                 }
01357                 break;
01358               case certUsageAnyCA:
01359               case certUsageProtectedObjectSigner:
01360               case certUsageUserCertImport:
01361                 /* XXX to make the compiler happy.  Should these be
01362                  * explicitly handled?
01363                  */
01364                 break;
01365             }
01366         }
01367 
01368         if (PR_TRUE == revoked || PR_TRUE == sigerror) {
01369             INVALID_USAGE();
01370         }
01371 
01372         rv = cert_VerifyCertChain(handle, cert,
01373             checkSig, &sigerror,
01374             certUsage, t, wincx, log,
01375             &revoked);
01376 
01377         if (rv != SECSuccess) {
01378             /* EXIT_IF_NOT_LOGGING(log); XXX ???? */
01379             INVALID_USAGE();
01380         }
01381 
01382         /*
01383          * Check OCSP revocation status, but only if the cert we are checking
01384          * is not a status reponder itself.  We only do this in the case
01385          * where we checked the cert chain (above); explicit trust "wins"
01386          * (avoids status checking, just as it avoids CRL checking) by
01387          * bypassing this code.
01388          */
01389 
01390         if (PR_FALSE == checkedOCSP) {
01391             checkedOCSP = PR_TRUE; /* only check OCSP once */
01392             statusConfig = CERT_GetStatusConfig(handle);
01393             if ( (! (requiredUsages == certificateUsageStatusResponder)) &&
01394                 statusConfig != NULL) {
01395                 if (statusConfig->statusChecker != NULL) {
01396                     rv = (* statusConfig->statusChecker)(handle, cert,
01397                                                                  t, wincx);
01398                     if (rv != SECSuccess) {
01399                         LOG_ERROR(log,cert,0,0);
01400                         revoked = PR_TRUE;
01401                         INVALID_USAGE();
01402                     }
01403                 }
01404             }
01405         }
01406 
01407         NEXT_USAGE();
01408     }
01409     
01410 loser:
01411     return(valid);
01412 }
01413                      
01414 /* obsolete, do not use for new code */
01415 SECStatus
01416 CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert,
01417               PRBool checkSig, SECCertUsage certUsage, int64 t,
01418               void *wincx, CERTVerifyLog *log)
01419 {
01420     SECStatus rv;
01421     unsigned int requiredKeyUsage;
01422     unsigned int requiredCertType;
01423     unsigned int flags;
01424     unsigned int certType;
01425     PRBool       allowOverride;
01426     SECCertTimeValidity validity;
01427     CERTStatusConfig *statusConfig;
01428    
01429 #ifdef notdef 
01430     /* check if this cert is in the Evil list */
01431     rv = CERT_CheckForEvilCert(cert);
01432     if ( rv != SECSuccess ) {
01433        PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
01434        LOG_ERROR_OR_EXIT(log,cert,0,0);
01435     }
01436 #endif
01437     
01438     /* make sure that the cert is valid at time t */
01439     allowOverride = (PRBool)((certUsage == certUsageSSLServer) ||
01440                              (certUsage == certUsageSSLServerWithStepUp));
01441     validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
01442     if ( validity != secCertTimeValid ) {
01443        LOG_ERROR_OR_EXIT(log,cert,0,validity);
01444     }
01445 
01446     /* check key usage and netscape cert type */
01447     cert_GetCertType(cert);
01448     certType = cert->nsCertType;
01449     switch ( certUsage ) {
01450       case certUsageSSLClient:
01451       case certUsageSSLServer:
01452       case certUsageSSLServerWithStepUp:
01453       case certUsageSSLCA:
01454       case certUsageEmailSigner:
01455       case certUsageEmailRecipient:
01456       case certUsageObjectSigner:
01457       case certUsageStatusResponder:
01458        rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
01459                                          &requiredKeyUsage,
01460                                          &requiredCertType);
01461        if ( rv != SECSuccess ) {
01462            PORT_Assert(0);
01463            EXIT_IF_NOT_LOGGING(log);
01464            requiredKeyUsage = 0;
01465            requiredCertType = 0;
01466        }
01467        break;
01468       case certUsageVerifyCA:
01469        requiredKeyUsage = KU_KEY_CERT_SIGN;
01470        requiredCertType = NS_CERT_TYPE_CA;
01471        if ( ! ( certType & NS_CERT_TYPE_CA ) ) {
01472            certType |= NS_CERT_TYPE_CA;
01473        }
01474        break;
01475       default:
01476        PORT_Assert(0);
01477        EXIT_IF_NOT_LOGGING(log);
01478        requiredKeyUsage = 0;
01479        requiredCertType = 0;
01480     }
01481     if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
01482        PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
01483        LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage);
01484     }
01485     if ( !( certType & requiredCertType ) ) {
01486        PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
01487        LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType);
01488     }
01489 
01490     /* check trust flags to see if this cert is directly trusted */
01491     if ( cert->trust ) { /* the cert is in the DB */
01492        switch ( certUsage ) {
01493          case certUsageSSLClient:
01494          case certUsageSSLServer:
01495            flags = cert->trust->sslFlags;
01496            
01497            /* is the cert directly trusted or not trusted ? */
01498            if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
01499               if ( flags & CERTDB_TRUSTED ) {    /* trust this cert */
01500                   goto winner;
01501               } else { /* don't trust this cert */
01502                   PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
01503                   LOG_ERROR_OR_EXIT(log,cert,0,flags);
01504               }
01505            }
01506            break;
01507          case certUsageSSLServerWithStepUp:
01508            /* XXX - step up certs can't be directly trusted */
01509            break;
01510          case certUsageSSLCA:
01511            break;
01512          case certUsageEmailSigner:
01513          case certUsageEmailRecipient:
01514            flags = cert->trust->emailFlags;
01515            
01516            /* is the cert directly trusted or not trusted ? */
01517            if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) ==
01518               ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) {
01519               goto winner;
01520            }
01521            break;
01522          case certUsageObjectSigner:
01523            flags = cert->trust->objectSigningFlags;
01524 
01525            /* is the cert directly trusted or not trusted ? */
01526            if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
01527               if ( flags & CERTDB_TRUSTED ) {    /* trust this cert */
01528                   goto winner;
01529               } else { /* don't trust this cert */
01530                   PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
01531                   LOG_ERROR_OR_EXIT(log,cert,0,flags);
01532               }
01533            }
01534            break;
01535          case certUsageVerifyCA:
01536          case certUsageStatusResponder:
01537            flags = cert->trust->sslFlags;
01538            /* is the cert directly trusted or not trusted ? */
01539            if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
01540               ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
01541               goto winner;
01542            }
01543            flags = cert->trust->emailFlags;
01544            /* is the cert directly trusted or not trusted ? */
01545            if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
01546               ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
01547               goto winner;
01548            }
01549            flags = cert->trust->objectSigningFlags;
01550            /* is the cert directly trusted or not trusted ? */
01551            if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
01552               ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
01553               goto winner;
01554            }
01555            break;
01556          case certUsageAnyCA:
01557          case certUsageProtectedObjectSigner:
01558          case certUsageUserCertImport:
01559            /* XXX to make the compiler happy.  Should these be
01560             * explicitly handled?
01561             */
01562            break;
01563        }
01564     }
01565 
01566     rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage,
01567                            t, wincx, log);
01568     if (rv != SECSuccess) {
01569        EXIT_IF_NOT_LOGGING(log);
01570     }
01571 
01572     /*
01573      * Check revocation status, but only if the cert we are checking
01574      * is not a status reponder itself.  We only do this in the case
01575      * where we checked the cert chain (above); explicit trust "wins"
01576      * (avoids status checking, just as it avoids CRL checking, which
01577      * is all done inside VerifyCertChain) by bypassing this code.
01578      */
01579     statusConfig = CERT_GetStatusConfig(handle);
01580     if (certUsage != certUsageStatusResponder && statusConfig != NULL) {
01581        if (statusConfig->statusChecker != NULL) {
01582            rv = (* statusConfig->statusChecker)(handle, cert,
01583                                                   t, wincx);
01584            if (rv != SECSuccess) {
01585               LOG_ERROR_OR_EXIT(log,cert,0,0);
01586            }
01587        }
01588     }
01589 
01590 winner:
01591     return(SECSuccess);
01592 
01593 loser:
01594     rv = SECFailure;
01595     
01596     return(rv);
01597 }
01598 
01599 /*
01600  * verify a certificate by checking if its valid and that we
01601  * trust the issuer.  Verify time against now.
01602  */
01603 SECStatus
01604 CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert,
01605                  PRBool checkSig, SECCertificateUsage requiredUsages,
01606                    void *wincx, SECCertificateUsage* returnedUsages)
01607 {
01608     return(CERT_VerifyCertificate(handle, cert, checkSig, 
01609                  requiredUsages, PR_Now(), wincx, NULL, returnedUsages));
01610 }
01611 
01612 /* obsolete, do not use for new code */
01613 SECStatus
01614 CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
01615                  PRBool checkSig, SECCertUsage certUsage, void *wincx)
01616 {
01617     return(CERT_VerifyCert(handle, cert, checkSig, 
01618                  certUsage, PR_Now(), wincx, NULL));
01619 }
01620 
01621 
01622 /* [ FROM pcertdb.c ] */
01623 /*
01624  * Supported usage values and types:
01625  *     certUsageSSLClient
01626  *     certUsageSSLServer
01627  *     certUsageSSLServerWithStepUp
01628  *     certUsageEmailSigner
01629  *     certUsageEmailRecipient
01630  *     certUsageObjectSigner
01631  */
01632 
01633 CERTCertificate *
01634 CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName,
01635                     CERTCertOwner owner, SECCertUsage usage,
01636                     PRBool preferTrusted, int64 validTime, PRBool validOnly)
01637 {
01638     CERTCertList *certList = NULL;
01639     CERTCertificate *cert = NULL;
01640     unsigned int requiredTrustFlags;
01641     SECTrustType requiredTrustType;
01642     unsigned int flags;
01643     
01644     PRBool lookingForCA = PR_FALSE;
01645     SECStatus rv;
01646     CERTCertListNode *node;
01647     CERTCertificate *saveUntrustedCA = NULL;
01648     
01649     /* if preferTrusted is set, must be a CA cert */
01650     PORT_Assert( ! ( preferTrusted && ( owner != certOwnerCA ) ) );
01651     
01652     if ( owner == certOwnerCA ) {
01653        lookingForCA = PR_TRUE;
01654        if ( preferTrusted ) {
01655            rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags,
01656                                           &requiredTrustType);
01657            if ( rv != SECSuccess ) {
01658               goto loser;
01659            }
01660            requiredTrustFlags |= CERTDB_VALID_CA;
01661        }
01662     }
01663 
01664     certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime,
01665                                      validOnly);
01666     if ( certList != NULL ) {
01667        rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA);
01668        if ( rv != SECSuccess ) {
01669            goto loser;
01670        }
01671        
01672        node = CERT_LIST_HEAD(certList);
01673        
01674        while ( !CERT_LIST_END(node, certList) ) {
01675            cert = node->cert;
01676 
01677            /* looking for a trusted CA cert */
01678            if ( ( owner == certOwnerCA ) && preferTrusted &&
01679               ( requiredTrustType != trustTypeNone ) ) {
01680 
01681               if ( cert->trust == NULL ) {
01682                   flags = 0;
01683               } else {
01684                   flags = SEC_GET_TRUST_FLAGS(cert->trust, requiredTrustType);
01685               }
01686 
01687               if ( ( flags & requiredTrustFlags ) != requiredTrustFlags ) {
01688                   /* cert is not trusted */
01689                   /* if this is the first cert to get this far, then save
01690                    * it, so we can use it if we can't find a trusted one
01691                    */
01692                   if ( saveUntrustedCA == NULL ) {
01693                      saveUntrustedCA = cert;
01694                   }
01695                   goto endloop;
01696               }
01697            }
01698            /* if we got this far, then this cert meets all criteria */
01699            break;
01700            
01701 endloop:
01702            node = CERT_LIST_NEXT(node);
01703            cert = NULL;
01704        }
01705 
01706        /* use the saved one if we have it */
01707        if ( cert == NULL ) {
01708            cert = saveUntrustedCA;
01709        }
01710 
01711        /* if we found one then bump the ref count before freeing the list */
01712        if ( cert != NULL ) {
01713            /* bump the ref count */
01714            cert = CERT_DupCertificate(cert);
01715        }
01716        
01717        CERT_DestroyCertList(certList);
01718     }
01719 
01720     return(cert);
01721 
01722 loser:
01723     if ( certList != NULL ) {
01724        CERT_DestroyCertList(certList);
01725     }
01726 
01727     return(NULL);
01728 }
01729 
01730 
01731 /* [ From certdb.c ] */
01732 /*
01733  * Filter a list of certificates, removing those certs that do not have
01734  * one of the named CA certs somewhere in their cert chain.
01735  *
01736  *     "certList" - the list of certificates to filter
01737  *     "nCANames" - number of CA names
01738  *     "caNames" - array of CA names in string(rfc 1485) form
01739  *     "usage" - what use the certs are for, this is used when
01740  *            selecting CA certs
01741  */
01742 SECStatus
01743 CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames,
01744                           char **caNames, SECCertUsage usage)
01745 {
01746     CERTCertificate *issuerCert = NULL;
01747     CERTCertificate *subjectCert;
01748     CERTCertListNode *node, *freenode;
01749     CERTCertificate *cert;
01750     int n;
01751     char **names;
01752     PRBool found;
01753     int64 time;
01754     
01755     if ( nCANames <= 0 ) {
01756        return(SECSuccess);
01757     }
01758 
01759     time = PR_Now();
01760     
01761     node = CERT_LIST_HEAD(certList);
01762     
01763     while ( ! CERT_LIST_END(node, certList) ) {
01764        cert = node->cert;
01765        
01766        subjectCert = CERT_DupCertificate(cert);
01767 
01768        /* traverse the CA certs for this cert */
01769        found = PR_FALSE;
01770        while ( subjectCert != NULL ) {
01771            n = nCANames;
01772            names = caNames;
01773           
01774             if (subjectCert->issuerName != NULL) { 
01775                while ( n > 0 ) {
01776                   if ( PORT_Strcmp(*names, subjectCert->issuerName) == 0 ) {
01777                       found = PR_TRUE;
01778                       break;
01779                   }
01780 
01781                   n--;
01782                   names++;
01783                 }
01784            }
01785 
01786            if ( found ) {
01787               break;
01788            }
01789            
01790            issuerCert = CERT_FindCertIssuer(subjectCert, time, usage);
01791            if ( issuerCert == subjectCert ) {
01792               CERT_DestroyCertificate(issuerCert);
01793               issuerCert = NULL;
01794               break;
01795            }
01796            CERT_DestroyCertificate(subjectCert);
01797            subjectCert = issuerCert;
01798 
01799        }
01800        CERT_DestroyCertificate(subjectCert);
01801        if ( !found ) {
01802            /* CA was not found, so remove this cert from the list */
01803            freenode = node;
01804            node = CERT_LIST_NEXT(node);
01805            CERT_RemoveCertListNode(freenode);
01806        } else {
01807            /* CA was found, so leave it in the list */
01808            node = CERT_LIST_NEXT(node);
01809        }
01810     }
01811     
01812     return(SECSuccess);
01813 }
01814 
01815 /*
01816  * Given a certificate, return a string containing the nickname, and possibly
01817  * one of the validity strings, based on the current validity state of the
01818  * certificate.
01819  *
01820  * "arena" - arena to allocate returned string from.  If NULL, then heap
01821  *     is used.
01822  * "cert" - the cert to get nickname from
01823  * "expiredString" - the string to append to the nickname if the cert is
01824  *            expired.
01825  * "notYetGoodString" - the string to append to the nickname if the cert is
01826  *            not yet good.
01827  */
01828 char *
01829 CERT_GetCertNicknameWithValidity(PRArenaPool *arena, CERTCertificate *cert,
01830                              char *expiredString, char *notYetGoodString)
01831 {
01832     SECCertTimeValidity validity;
01833     char *nickname = NULL, *tmpstr = NULL;
01834     
01835     validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE);
01836 
01837     /* if the cert is good, then just use the nickname directly */
01838     if ( validity == secCertTimeValid ) {
01839        if ( arena == NULL ) {
01840            nickname = PORT_Strdup(cert->nickname);
01841        } else {
01842            nickname = PORT_ArenaStrdup(arena, cert->nickname);
01843        }
01844        
01845        if ( nickname == NULL ) {
01846            goto loser;
01847        }
01848     } else {
01849            
01850        /* if the cert is not valid, then tack one of the strings on the
01851         * end
01852         */
01853        if ( validity == secCertTimeExpired ) {
01854            tmpstr = PR_smprintf("%s%s", cert->nickname,
01855                              expiredString);
01856        } else if ( validity == secCertTimeNotValidYet ) {
01857            /* not yet valid */
01858            tmpstr = PR_smprintf("%s%s", cert->nickname,
01859                              notYetGoodString);
01860         } else {
01861             /* undetermined */
01862            tmpstr = PR_smprintf("%s",
01863                         "(NULL) (Validity Unknown)");
01864         }
01865 
01866        if ( tmpstr == NULL ) {
01867            goto loser;
01868        }
01869 
01870        if ( arena ) {
01871            /* copy the string into the arena and free the malloc'd one */
01872            nickname = PORT_ArenaStrdup(arena, tmpstr);
01873            PORT_Free(tmpstr);
01874        } else {
01875            nickname = tmpstr;
01876        }
01877        if ( nickname == NULL ) {
01878            goto loser;
01879        }
01880     }    
01881     return(nickname);
01882 
01883 loser:
01884     return(NULL);
01885 }
01886 
01887 /*
01888  * Collect the nicknames from all certs in a CertList.  If the cert is not
01889  * valid, append a string to that nickname.
01890  *
01891  * "certList" - the list of certificates
01892  * "expiredString" - the string to append to the nickname of any expired cert
01893  * "notYetGoodString" - the string to append to the nickname of any cert
01894  *            that is not yet valid
01895  */
01896 CERTCertNicknames *
01897 CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString,
01898                              char *notYetGoodString)
01899 {
01900     CERTCertNicknames *names;
01901     PRArenaPool *arena;
01902     CERTCertListNode *node;
01903     char **nn;
01904     
01905     /* allocate an arena */
01906     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01907     if ( arena == NULL ) {
01908        return(NULL);
01909     }
01910     
01911     /* allocate the structure */
01912     names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
01913     if ( names == NULL ) {
01914        goto loser;
01915     }
01916 
01917     /* init the structure */
01918     names->arena = arena;
01919     names->head = NULL;
01920     names->numnicknames = 0;
01921     names->nicknames = NULL;
01922     names->totallen = 0;
01923 
01924     /* count the certs in the list */
01925     node = CERT_LIST_HEAD(certList);
01926     while ( ! CERT_LIST_END(node, certList) ) {
01927        names->numnicknames++;
01928        node = CERT_LIST_NEXT(node);
01929     }
01930     
01931     /* allocate nicknames array */
01932     names->nicknames = PORT_ArenaAlloc(arena,
01933                                    sizeof(char *) * names->numnicknames);
01934     if ( names->nicknames == NULL ) {
01935        goto loser;
01936     }
01937 
01938     /* just in case printf can't deal with null strings */
01939     if (expiredString == NULL ) {
01940        expiredString = "";
01941     }
01942 
01943     if ( notYetGoodString == NULL ) {
01944        notYetGoodString = "";
01945     }
01946     
01947     /* traverse the list of certs and collect the nicknames */
01948     nn = names->nicknames;
01949     node = CERT_LIST_HEAD(certList);
01950     while ( ! CERT_LIST_END(node, certList) ) {
01951        *nn = CERT_GetCertNicknameWithValidity(arena, node->cert,
01952                                           expiredString,
01953                                           notYetGoodString);
01954        if ( *nn == NULL ) {
01955            goto loser;
01956        }
01957 
01958        names->totallen += PORT_Strlen(*nn);
01959        
01960        nn++;
01961        node = CERT_LIST_NEXT(node);
01962     }
01963 
01964     return(names);
01965 
01966 loser:
01967     PORT_FreeArena(arena, PR_FALSE);
01968     return(NULL);
01969 }
01970 
01971 /*
01972  * Extract the nickname from a nickmake string that may have either
01973  * expiredString or notYetGoodString appended.
01974  *
01975  * Args:
01976  *     "namestring" - the string containing the nickname, and possibly
01977  *            one of the validity label strings
01978  *     "expiredString" - the expired validity label string
01979  *     "notYetGoodString" - the not yet good validity label string
01980  *
01981  * Returns the raw nickname
01982  */
01983 char *
01984 CERT_ExtractNicknameString(char *namestring, char *expiredString,
01985                         char *notYetGoodString)
01986 {
01987     int explen, nyglen, namelen;
01988     int retlen;
01989     char *retstr;
01990     
01991     namelen = PORT_Strlen(namestring);
01992     explen = PORT_Strlen(expiredString);
01993     nyglen = PORT_Strlen(notYetGoodString);
01994     
01995     if ( namelen > explen ) {
01996        if ( PORT_Strcmp(expiredString, &namestring[namelen-explen]) == 0 ) {
01997            retlen = namelen - explen;
01998            retstr = (char *)PORT_Alloc(retlen+1);
01999            if ( retstr == NULL ) {
02000               goto loser;
02001            }
02002            
02003            PORT_Memcpy(retstr, namestring, retlen);
02004            retstr[retlen] = '\0';
02005            goto done;
02006        }
02007     }
02008 
02009     if ( namelen > nyglen ) {
02010        if ( PORT_Strcmp(notYetGoodString, &namestring[namelen-nyglen]) == 0) {
02011            retlen = namelen - nyglen;
02012            retstr = (char *)PORT_Alloc(retlen+1);
02013            if ( retstr == NULL ) {
02014               goto loser;
02015            }
02016            
02017            PORT_Memcpy(retstr, namestring, retlen);
02018            retstr[retlen] = '\0';
02019            goto done;
02020        }
02021     }
02022 
02023     /* if name string is shorter than either invalid string, then it must
02024      * be a raw nickname
02025      */
02026     retstr = PORT_Strdup(namestring);
02027     
02028 done:
02029     return(retstr);
02030 
02031 loser:
02032     return(NULL);
02033 }
02034 
02035 CERTCertList *
02036 CERT_GetCertChainFromCert(CERTCertificate *cert, int64 time, SECCertUsage usage)
02037 {
02038     CERTCertList *chain = NULL;
02039 
02040     if (NULL == cert) {
02041         return NULL;
02042     }
02043     
02044     cert = CERT_DupCertificate(cert);
02045     if (NULL == cert) {
02046         PORT_SetError(SEC_ERROR_NO_MEMORY);
02047         return NULL;
02048     }
02049 
02050     chain = CERT_NewCertList();
02051     if (NULL == chain) {
02052         PORT_SetError(SEC_ERROR_NO_MEMORY);
02053         return NULL;
02054     }
02055 
02056     while (cert != NULL) {
02057        if (SECSuccess != CERT_AddCertToListTail(chain, cert)) {
02058             /* return partial chain */
02059             PORT_SetError(SEC_ERROR_NO_MEMORY);
02060             return chain;
02061         }
02062 
02063        if (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject)
02064            == SECEqual) {
02065             /* return complete chain */
02066            return chain;
02067        }
02068 
02069        cert = CERT_FindCertIssuer(cert, time, usage);
02070     }
02071 
02072     /* return partial chain */
02073     PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
02074     return chain;
02075 }