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