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, ¬Before, ¬After); 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 + -
显示快捷键?