certvfy.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,576 行 · 第 1/3 页
C
1,576 行
SECStatusCERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool checkSig, SECCertUsage certUsage, int64 t, void *wincx, CERTVerifyLog *log){ SECTrustType trustType; CERTBasicConstraints basicConstraint; CERTCertificate *issuerCert = NULL; CERTCertificate *subjectCert = NULL; CERTCertificate *badCert = NULL; PRBool isca; PRBool isFortezzaV1 = PR_FALSE; SECStatus rv; SECComparison rvCompare; SECStatus rvFinal = SECSuccess; int count; int currentPathLen = -1; int flags; unsigned int caCertType; unsigned int requiredCAKeyUsage; unsigned int requiredFlags; PRArenaPool *arena = NULL; CERTGeneralName *namesList = NULL; CERTGeneralName *subjectNameList = NULL; SECItem *namesIndex = NULL; int namesIndexLen = 10; int namesCount = 0; enum { cbd_None, cbd_User, cbd_CA } last_type = cbd_None; SECKEYPublicKey *key; if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE, &requiredCAKeyUsage, &caCertType) != SECSuccess ) { PORT_Assert(0); EXIT_IF_NOT_LOGGING(log); requiredCAKeyUsage = 0; caCertType = 0; } switch ( certUsage ) { case certUsageSSLClient: case certUsageSSLServer: case certUsageSSLCA: case certUsageSSLServerWithStepUp: case certUsageEmailSigner: case certUsageEmailRecipient: case certUsageObjectSigner: case certUsageVerifyCA: case certUsageStatusResponder: if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, &trustType) != SECSuccess ) { PORT_Assert(0); EXIT_IF_NOT_LOGGING(log); requiredFlags = 0; trustType = trustSSL; } break; default: PORT_Assert(0); EXIT_IF_NOT_LOGGING(log); requiredFlags = 0; trustType = trustSSL;/* This used to be 0, but we need something * that matches the enumeration type. */ caCertType = 0; } subjectCert = CERT_DupCertificate(cert); if ( subjectCert == NULL ) { goto loser; } /* determine if the cert is fortezza. Getting the key is an easy * way to determine it, especially since we need to get the privillege * from the key anyway. */ key = CERT_ExtractPublicKey(cert); if (key != NULL) { isFortezzaV1 = (PRBool)(key->keyType == fortezzaKey); /* find out what type of cert we are starting with */ if (isFortezzaV1) { unsigned char priv = 0;; rv = SEC_CheckKRL(handle, key, NULL, t, wincx); if (rv == SECFailure) { /**** PORT_SetError is already set by SEC_CheckKRL **/ SECKEY_DestroyPublicKey(key); /**** Bob - should we log and continue when logging? **/ LOG_ERROR(log,subjectCert,0,0); goto loser; } if (key->u.fortezza.DSSpriviledge.len > 0) { priv = key->u.fortezza.DSSpriviledge.data[0]; } last_type = (priv & 0x30) ? cbd_CA : cbd_User; } SECKEY_DestroyPublicKey(key); } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { goto loser; } namesIndex = (SECItem *) PORT_ZAlloc(sizeof(SECItem) * namesIndexLen); if (namesIndex == NULL) { goto loser; } for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) { int subjectNameListLen; int i; /* Construct a list of names for the current and all previous certifcates to be verified against the name constraints extension of the issuer certificate. */ subjectNameList = CERT_GetCertificateNames(subjectCert, arena); subjectNameListLen = CERT_GetNamesLength(subjectNameList); for (i = 0; i < subjectNameListLen; i++) { if (namesIndexLen < namesCount + i) { namesIndexLen = namesIndexLen * 2; namesIndex = (SECItem *) PORT_Realloc(namesIndex, namesIndexLen * sizeof(SECItem)); if (namesIndex == NULL) { goto loser; } } rv = SECITEM_CopyItem(arena, &(namesIndex[namesCount + i]), &(subjectCert->derSubject)); } namesCount += subjectNameListLen; namesList = cert_CombineNamesLists(namesList, subjectNameList); /* find the certificate of the issuer */ issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage); if ( ! issuerCert ) { PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); LOG_ERROR(log,subjectCert,count,0); goto loser; } /* verify the signature on the cert */ if ( checkSig ) { rv = CERT_VerifySignedData(&subjectCert->signatureWrap, issuerCert, t, wincx); if ( rv != SECSuccess ) { if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) { PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); } else { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); LOG_ERROR_OR_EXIT(log,subjectCert,count,0); } } } /* * XXX - fortezza may need error logging stuff added */ if (isFortezzaV1) { unsigned char priv = 0; /* read the key */ key = CERT_ExtractPublicKey(issuerCert); /* Cant' get Key? fail. */ if (key == NULL) { PORT_SetError(SEC_ERROR_BAD_KEY); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); goto fortezzaDone; } /* if the issuer is not an old fortezza cert, we bail */ if (key->keyType != fortezzaKey) { SECKEY_DestroyPublicKey(key); /* CA Cert not fortezza */ PORT_SetError(SEC_ERROR_NOT_FORTEZZA_ISSUER); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); goto fortezzaDone; } /* get the privilege mask */ if (key->u.fortezza.DSSpriviledge.len > 0) { priv = key->u.fortezza.DSSpriviledge.data[0]; } /* * make sure the CA's keys are OK */ rv = SEC_CheckKRL(handle, key, NULL, t, wincx); if (rv != SECSuccess) { SECKEY_DestroyPublicKey(key); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); goto fortezzaDone; /** fall through looking for more stuff **/ } else { SECKEY_DestroyPublicKey(key); } switch (last_type) { case cbd_User: /* first check for subordination */ /*rv = FortezzaSubordinateCheck(cert,issuerCert);*/ rv = SECSuccess; /* now check for issuer privilege */ if ((rv != SECSuccess) || ((priv & 0x10) == 0)) { /* bail */ PORT_SetError (SEC_ERROR_CA_CERT_INVALID); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); } break; case cbd_CA: case cbd_None: if ((priv & 0x20) == 0) { /* bail */ PORT_SetError (SEC_ERROR_CA_CERT_INVALID); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); } break; default: /* bail */ /* shouldn't ever happen */ PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); }fortezzaDone: last_type = cbd_CA; } /* If the basicConstraint extension is included in an immediate CA * certificate, make sure that the isCA flag is on. If the * pathLenConstraint component exists, it must be greater than the * number of CA certificates we have seen so far. If the extension * is omitted, we will assume that this is a CA certificate with * an unlimited pathLenConstraint (since it already passes the * netscape-cert-type extension checking). * * In the fortezza (V1) case, we've already checked the CA bits * in the key, so we're presumed to be a CA; however we really don't * want to bypass Basic constraint or netscape extension parsing. * * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA */ rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint); if ( rv != SECSuccess ) { if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) { LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); } else { currentPathLen = CERT_UNLIMITED_PATH_CONSTRAINT; } /* no basic constraints found, if we're fortezza, CA bit is already * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca * isca = PR_FALSE */ isca = isFortezzaV1; } else { if ( basicConstraint.isCA == PR_FALSE ) { PORT_SetError (SEC_ERROR_CA_CERT_INVALID); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); } /* make sure that the path len constraint is properly set. */ if ( basicConstraint.pathLenConstraint == CERT_UNLIMITED_PATH_CONSTRAINT ) { currentPathLen = CERT_UNLIMITED_PATH_CONSTRAINT; } else if ( currentPathLen == CERT_UNLIMITED_PATH_CONSTRAINT ) { /* error if the previous CA's path length constraint is * unlimited but its CA's path is not. */ PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,basicConstraint.pathLenConstraint); } else if (basicConstraint.pathLenConstraint > currentPathLen) { currentPathLen = basicConstraint.pathLenConstraint; } else { PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,basicConstraint.pathLenConstraint); } isca = PR_TRUE; } /* XXX - the error logging may need to go down into CRL stuff at some * point */ /* check revoked list (issuer) */ rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx); if (rv == SECFailure) { LOG_ERROR_OR_EXIT(log,subjectCert,count,0); } else if (rv == SECWouldBlock) { /* We found something fishy, so we intend to issue an * error to the user, but the user may wish to continue * processing, in which case we better make sure nothing * worse has happened... so keep cranking the loop */ rvFinal = SECFailure; LOG_ERROR(log,subjectCert,count,0); } if ( issuerCert->trust ) { /* * check the trust parms of the issuer */ if ( certUsage == certUsageVerifyCA ) { if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) { trustType = trustEmail; } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) { trustType = trustSSL; } else { trustType = trustObjectSigning; } } flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType); if ( (flags & CERTDB_VALID_CA) || (certUsage == certUsageStatusResponder)) { if ( ( flags & requiredFlags ) == requiredFlags || certUsage == certUsageStatusResponder ) { /* we found a trusted one, so return */ rv = rvFinal; goto done; } } } /* * Make sure that if this is an intermediate CA in the chain that * it was given permission by its signer to be a CA. */ if ( isca ) { /* * if basicConstraints says it is a ca, then we check the * nsCertType. If the nsCertType has any CA bits set, then * it must have the right one. */ if ( issuerCert->nsCertType & NS_CERT_TYPE_CA ) { if ( issuerCert->nsCertType & caCertType ) { isca = PR_TRUE; } else { isca = PR_FALSE; } } } else { if ( issuerCert->nsCertType & caCertType ) { isca = PR_TRUE; } else { isca = PR_FALSE; } } if ( !isca ) { PORT_SetError(SEC_ERROR_CA_CERT_INVALID); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); } /* make sure key usage allows cert signing */ if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) { PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage); } /* make sure that the entire chain is within the name space of the current issuer * certificate. */ badCert = CERT_CompareNameSpace(issuerCert, namesList, namesIndex, arena, handle); if (badCert != NULL) { PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE); LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0); goto loser; } /* 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_SetError(SEC_ERROR_UNTRUSTED_ISSUER); LOG_ERROR(log, issuerCert, count+1, 0); goto loser; } CERT_DestroyCertificate(subjectCert); subjectCert = issuerCert; } subjectCert = NULL; PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); LOG_ERROR(log,issuerCert,count,0);loser: rv = SECFailure;done: if (namesIndex != NULL) { PORT_Free(namesIndex); } if ( issuerCert ) { CERT_DestroyCertificate(issuerCert); } if ( subjectCert ) { CERT_DestroyCertificate(subjectCert); } if ( arena != NULL ) { PORT_FreeArena(arena, PR_FALSE); } return rv;} /* * verify a certificate by checking if its valid and that we * trust the issuer. * Note that this routine does not verify the signature of the certificate. */SECStatusCERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool checkSig, SECCertUsage certUsage, int64 t, void *wincx, CERTVerifyLog *log){ SECStatus rv; unsigned int requiredKeyUsage; unsigned int requiredCertType; unsigned int flags; unsigned int certType; PRBool allowOverride; SECCertTimeValidity validity; CERTStatusConfig *statusConfig; /* check if this cert is in the Evil list */ rv = CERT_CheckForEvilCert(cert); if ( rv != SECSuccess ) { PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); LOG_ERROR_OR_EXIT(log,cert,0,0); } /* make sure that the cert is valid at time t */ allowOverride = (PRBool)((certUsage == certUsageSSLServer) || (certUsage == certUsageSSLServerWithStepUp)); validity = CERT_CheckCertValidTimes(cert, t, allowOverride); if ( validity != secCertTimeValid ) { LOG_ERROR_OR_EXIT(log,cert,0,validity); } /* check key usage and netscape cert type */ CERT_GetCertType(cert); certType = cert->nsCertType; switch ( certUsage ) { case certUsageSSLClient: case certUsageSSLServer: case certUsageSSLServerWithStepUp: case certUsageSSLCA: case certUsageEmailSigner: case certUsageEmailRecipient: case certUsageObjectSigner: case certUsageStatusResponder: rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE, &requiredKeyUsage, &requiredCertType); if ( rv != SECSuccess ) { PORT_Assert(0); EXIT_IF_NOT_LOGGING(log); requiredKeyUsage = 0; requiredCertType = 0; } break; case certUsageVerifyCA: requiredKeyUsage = KU_KEY_CERT_SIGN; requiredCertType = NS_CERT_TYPE_CA; if ( ! ( certType & NS_CERT_TYPE_CA ) ) { certType |= NS_CERT_TYPE_CA; } break; default: PORT_Assert(0); EXIT_IF_NOT_LOGGING(log); requiredKeyUsage = 0; requiredCertType = 0; } if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) { PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage); } if ( !( certType & requiredCertType ) ) { PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE); LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType); } /* check trust flags to see if this cert is directly trusted */ if ( cert->trust ) { /* the cert is in the DB */ switch ( certUsage ) { case certUsageSSLClient: case certUsageSSLServer: flags = cert->trust->sslFlags; /* is the cert directly trusted or not trusted ? */ if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/ if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ goto winner; } else { /* don't trust this cert */ PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); LOG_ERROR_OR_EXIT(log,cert,0,flags); } } break; case certUsageSSLServerWithStepUp: /* XXX - step up certs can't be directly trusted */ break; case certUsageSSLCA: break; case certUsageEmailSigner: case certUsageEmailRecipient: flags = cert->trust->emailFlags;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?