certvfy.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,576 行 · 第 1/3 页

C
1,576
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "nspr.h"#include "secerr.h"#include "secport.h"#include "seccomon.h"#include "secoid.h"#include "sslerr.h"#include "genname.h"#include "keyhi.h"#include "cert.h"#include "certdb.h"#include "cryptohi.h"#define PENDING_SLOP (24L*60L*60L)/* * WARNING - this function is depricated, and will go away in the near future. *	It has been superseded by CERT_CheckCertValidTimes(). * * Check the validity times of a certificate */SECStatusCERT_CertTimesValid(CERTCertificate *c){    int64 now, notBefore, notAfter, pendingSlop;    SECStatus rv;        /* if cert is already marked OK, then don't bother to check */    if ( c->timeOK ) {	return(SECSuccess);    }        /* get current UTC time */    now = PR_Now();    rv = CERT_GetCertTimes(c, &notBefore, &notAfter);        if (rv) {	return(SECFailure);    }        LL_I2L(pendingSlop, PENDING_SLOP);    LL_SUB(notBefore, notBefore, pendingSlop);    if (LL_CMP(now, <, notBefore) || LL_CMP(now, >, notAfter)) {	PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);	return(SECFailure);    }    return(SECSuccess);}/* * verify the signature of a signed data object with the given certificate */SECStatusCERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert,		      int64 t, void *wincx){    SECItem sig;    SECKEYPublicKey *pubKey = 0;    SECStatus rv;    SECCertTimeValidity validity;    SECOidTag algid;    /* check the certificate's validity */    validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE);    if ( validity != secCertTimeValid ) {	return(SECFailure);    }    /* get cert's public key */    pubKey = CERT_ExtractPublicKey(cert);    if ( !pubKey ) {	return(SECFailure);    }        /* check the signature */    sig = sd->signature;    DER_ConvertBitString(&sig);    algid = SECOID_GetAlgorithmTag(&sd->signatureAlgorithm);    rv = VFY_VerifyData(sd->data.data, sd->data.len, pubKey, &sig,			algid, wincx);    SECKEY_DestroyPublicKey(pubKey);    if ( rv ) {	return(SECFailure);    }    return(SECSuccess);}/* * This must only be called on a cert that is known to have an issuer * with an invalid time */CERTCertificate *CERT_FindExpiredIssuer(CERTCertDBHandle *handle, CERTCertificate *cert){    CERTCertificate *issuerCert = NULL;    CERTCertificate *subjectCert;    int              count;    SECStatus        rv;    SECComparison    rvCompare;        subjectCert = CERT_DupCertificate(cert);    if ( subjectCert == NULL ) {	goto loser;    }        for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) {	/* find the certificate of the issuer */	issuerCert = CERT_FindCertByName(handle, &subjectCert->derIssuer);    	if ( ! issuerCert ) {	    goto loser;	}	rv = CERT_CertTimesValid(issuerCert);	if ( rv == SECFailure ) {	    /* this is the invalid issuer */	    CERT_DestroyCertificate(subjectCert);	    return(issuerCert);	}	/* make sure that the issuer is not self signed.  If it is, then	 * stop here to prevent looping.	 */	rvCompare = SECITEM_CompareItem(&issuerCert->derSubject,				 &issuerCert->derIssuer);	if (rvCompare == SECEqual) {	    PORT_Assert(0);		/* No expired issuer! */	    goto loser;	}	CERT_DestroyCertificate(subjectCert);	subjectCert = issuerCert;    }loser:    if ( issuerCert ) {	CERT_DestroyCertificate(issuerCert);    }        if ( subjectCert ) {	CERT_DestroyCertificate(subjectCert);    }        return(NULL);}/* Software FORTEZZA installation hack. The software fortezza installer does * not have access to the krl and cert.db file. Accept FORTEZZA Certs without * KRL's in this case.  */static int dont_use_krl = 0;/* not a public exposed function... */void sec_SetCheckKRLState(int value) { dont_use_krl = value; }SECStatusSEC_CheckKRL(CERTCertDBHandle *handle,SECKEYPublicKey *key,	     CERTCertificate *rootCert, int64 t, void * wincx){    CERTSignedCrl *crl = NULL;    SECStatus rv = SECFailure;    SECStatus rv2;    CERTCrlEntry **crlEntry;    SECCertTimeValidity validity;    CERTCertificate *issuerCert = NULL;    if (dont_use_krl) return SECSuccess;    /* first look up the KRL */    crl = SEC_FindCrlByName(handle,&rootCert->derSubject, SEC_KRL_TYPE);    if (crl == NULL) {	PORT_SetError(SEC_ERROR_NO_KRL);	goto done;    }    /* get the issuing certificate */    issuerCert = CERT_FindCertByName(handle, &crl->crl.derName);    if (issuerCert == NULL) {        PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);        goto done;    }    /* now verify the KRL signature */    rv2 = CERT_VerifySignedData(&crl->signatureWrap, issuerCert, t, wincx);    if (rv2 != SECSuccess) {	PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);    	goto done;    }    /* Verify the date validity of the KRL */    validity = SEC_CheckCrlTimes(&crl->crl, t);    if (validity == secCertTimeExpired) {	PORT_SetError(SEC_ERROR_KRL_EXPIRED);	goto done;    }    /* now make sure the key in this cert is still valid */    if (key->keyType != fortezzaKey) {	PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);	goto done; /* This should be an assert? */    }    /* now make sure the key is not on the revocation list */    for (crlEntry = crl->crl.entries; crlEntry && *crlEntry; crlEntry++) {	if (PORT_Memcmp((*crlEntry)->serialNumber.data,				key->u.fortezza.KMID,				    (*crlEntry)->serialNumber.len) == 0) {	    PORT_SetError(SEC_ERROR_REVOKED_KEY);	    goto done;	}    }    rv = SECSuccess;done:    if (issuerCert) CERT_DestroyCertificate(issuerCert);    if (crl) SEC_DestroyCrl(crl);    return rv;}SECStatusSEC_CheckCRL(CERTCertDBHandle *handle,CERTCertificate *cert,	     CERTCertificate *caCert, int64 t, void * wincx){    CERTSignedCrl *crl = NULL;    SECStatus rv = SECSuccess;    CERTCrlEntry **crlEntry;    SECCertTimeValidity validity;    /* first look up the CRL */    crl = SEC_FindCrlByName(handle,&caCert->derSubject, SEC_CRL_TYPE);    if (crl == NULL) {	/* XXX for now no CRL is ok */	goto done;    }    /* now verify the CRL signature */    rv = CERT_VerifySignedData(&crl->signatureWrap, caCert, t, wincx);    if (rv != SECSuccess) {	PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);        rv = SECWouldBlock; /* Soft error, ask the user */    	goto done;    }    /* Verify the date validity of the KRL */    validity = SEC_CheckCrlTimes(&crl->crl,t);    if (validity == secCertTimeExpired) {	PORT_SetError(SEC_ERROR_CRL_EXPIRED);        rv = SECWouldBlock; /* Soft error, ask the user */    } else if (validity == secCertTimeNotValidYet) {	PORT_SetError(SEC_ERROR_CRL_NOT_YET_VALID);	rv = SECWouldBlock; /* Soft error, ask the user */    }    /* now make sure the key is not on the revocation list */    for (crlEntry = crl->crl.entries; crlEntry && *crlEntry; crlEntry++) {	if (SECITEM_CompareItem(&(*crlEntry)->serialNumber,&cert->serialNumber) == SECEqual) {	    PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);	    rv = SECFailure; /* cert is revoked */	    goto done;	}    }done:    if (crl) SEC_DestroyCrl(crl);    return rv;}/* * Find the issuer of a cert.  Use the authorityKeyID if it exists. */CERTCertificate *CERT_FindCertIssuer(CERTCertificate *cert, int64 validTime, SECCertUsage usage){    CERTAuthKeyID *   authorityKeyID = NULL;      CERTCertificate * issuerCert     = NULL;    SECItem *         caName;    PRArenaPool       *tmpArena = NULL;    SECItem           issuerCertKey;    SECStatus         rv;    tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);        if ( !tmpArena ) {	goto loser;    }    authorityKeyID = CERT_FindAuthKeyIDExten(tmpArena,cert);    if ( authorityKeyID != NULL ) {	/* has the authority key ID extension */	if ( authorityKeyID->keyID.data != NULL ) {	    /* extension contains a key ID, so lookup based on it */	    issuerCert = CERT_FindCertByKeyID(cert->dbhandle, &cert->derIssuer,					      &authorityKeyID->keyID);	    if ( issuerCert == NULL ) {		PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);		goto loser;	    }	    	} else if ( authorityKeyID->authCertIssuer != NULL ) {	    /* no key ID, so try issuer and serial number */	    caName = (SECItem*)CERT_GetGeneralNameByType(authorityKeyID->authCertIssuer,					       		 certDirectoryName, PR_TRUE);	    /*	     * caName is NULL when the authCertIssuer field is not	     * being used, or other name form is used instead.	     * If the directoryName format and serialNumber fields are	     * used, we use them to find the CA cert.	     * Note:	     *	By the time it gets here, we known for sure that if the	     *	authCertIssuer exists, then the authCertSerialNumber	     *	must also exists (CERT_DecodeAuthKeyID() ensures this).	     *	We don't need to check again. 	     */	    if (caName != NULL) {		rv = CERT_KeyFromIssuerAndSN(tmpArena, caName,					     &authorityKeyID->authCertSerialNumber,					     &issuerCertKey);		if ( rv == SECSuccess ) {		    issuerCert = CERT_FindCertByKey(cert->dbhandle,						    &issuerCertKey);		}				if ( issuerCert == NULL ) {		    PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);		    goto loser;		}	    }	}    }    if ( issuerCert == NULL ) {	/* if there is not authorityKeyID, then try to find the issuer */	/* find a valid CA cert with correct usage */	issuerCert = CERT_FindMatchingCert(cert->dbhandle,					   &cert->derIssuer,					   certOwnerCA, usage, PR_TRUE,					   validTime, PR_TRUE);	/* if that fails, then fall back to grabbing any cert with right name*/	if ( issuerCert == NULL ) {	    issuerCert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer);	    if ( issuerCert == NULL ) {		PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);	    }	}    }loser:    if (tmpArena != NULL) {	PORT_FreeArena(tmpArena, PR_FALSE);	tmpArena = NULL;    }    return(issuerCert);}/* * return required trust flags for various cert usages for CAs */SECStatusCERT_TrustFlagsForCACertUsage(SECCertUsage usage,			      unsigned int *retFlags,			      SECTrustType *retTrustType){    unsigned int requiredFlags;    SECTrustType trustType;    switch ( usage ) {      case certUsageSSLClient:	requiredFlags = CERTDB_TRUSTED_CLIENT_CA;	trustType = trustSSL;        break;      case certUsageSSLServer:      case certUsageSSLCA:	requiredFlags = CERTDB_TRUSTED_CA;	trustType = trustSSL;        break;      case certUsageSSLServerWithStepUp:	requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA;	trustType = trustSSL;        break;      case certUsageEmailSigner:      case certUsageEmailRecipient:	requiredFlags = CERTDB_TRUSTED_CA;	trustType = trustEmail;	break;      case certUsageObjectSigner:	requiredFlags = CERTDB_TRUSTED_CA;	trustType = trustObjectSigning;	break;      case certUsageVerifyCA:      case certUsageAnyCA:      case certUsageStatusResponder:	requiredFlags = CERTDB_TRUSTED_CA;	trustType = trustTypeNone;	break;      default:	PORT_Assert(0);	goto loser;    }    if ( retFlags != NULL ) {	*retFlags = requiredFlags;    }    if ( retTrustType != NULL ) {	*retTrustType = trustType;    }        return(SECSuccess);loser:    return(SECFailure);}static voidAddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, unsigned long error,	       unsigned int depth, void *arg){    CERTVerifyLogNode *node, *tnode;    PORT_Assert(log != NULL);        node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena,						sizeof(CERTVerifyLogNode));    if ( node != NULL ) {	node->cert = CERT_DupCertificate(cert);	node->error = error;	node->depth = depth;	node->arg = arg;		if ( log->tail == NULL ) {	    /* empty list */	    log->head = log->tail = node;	    node->prev = NULL;	    node->next = NULL;	} else if ( depth >= log->tail->depth ) {	    /* add to tail */	    node->prev = log->tail;	    log->tail->next = node;	    log->tail = node;	    node->next = NULL;	} else if ( depth < log->head->depth ) {	    /* add at head */	    node->prev = NULL;	    node->next = log->head;	    log->head->prev = node;	    log->head = node;	} else {	    /* add in middle */	    tnode = log->tail;	    while ( tnode != NULL ) {		if ( depth >= tnode->depth ) {		    /* insert after tnode */		    node->prev = tnode;		    node->next = tnode->next;		    tnode->next->prev = node;		    tnode->next = node;		    break;		}		tnode = tnode->prev;	    }	}	log->count++;    }    return;}#define EXIT_IF_NOT_LOGGING(log) \    if ( log == NULL ) { \	goto loser; \    }#define LOG_ERROR_OR_EXIT(log,cert,depth,arg) \    if ( log != NULL ) { \	AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \    } else { \	goto loser; \    }#define LOG_ERROR(log,cert,depth,arg) \    if ( log != NULL ) { \	AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?