PRBool CERT_GovtApprovedBitSet(CERTCertificate *cert) { SECStatus rv; SECItem extItem; CERTOidSequence *oidSeq = NULL; PRBool ret; SECItem **oids; SECItem *oid; SECOidTag oidTag; extItem.data = NULL; rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem); if ( rv != SECSuccess ) { goto loser; } oidSeq = CERT_DecodeOidSequence(&extItem); if ( oidSeq == NULL ) { goto loser; } oids = oidSeq->oids; while ( oids != NULL && *oids != NULL ) { oid = *oids; oidTag = SECOID_FindOIDTag(oid); if ( oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED ) { goto success; } oids++; } loser: ret = PR_FALSE; goto done; success: ret = PR_TRUE; done: if ( oidSeq != NULL ) { CERT_DestroyOidSequence(oidSeq); } if (extItem.data != NULL) { PORT_Free(extItem.data); } return(ret); }
// 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage) // 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage) Result CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedEKUs, SECOidTag requiredEKU) { // TODO: Either do not allow anyExtendedKeyUsage to be passed as requiredEKU, // or require that callers pass anyExtendedKeyUsage instead of // SEC_OID_UNKNWON and disallow SEC_OID_UNKNWON. // XXX: We're using SEC_ERROR_INADEQUATE_CERT_TYPE here so that callers can // distinguish EKU mismatch from KU mismatch from basic constraints mismatch. // We should probably add a new error code that is more clear for this type // of problem. bool foundOCSPSigning = false; if (encodedEKUs) { ScopedPtr<CERTOidSequence, CERT_DestroyOidSequence> seq(CERT_DecodeOidSequence(encodedEKUs)); if (!seq) { PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); return RecoverableError; } bool found = false; // XXX: We allow duplicate entries. for (const SECItem* const* oids = seq->oids; oids && *oids; ++oids) { SECOidTag oidTag = SECOID_FindOIDTag(*oids); if (requiredEKU != SEC_OID_UNKNOWN && oidTag == requiredEKU) { found = true; } if (oidTag == SEC_OID_OCSP_RESPONDER) { foundOCSPSigning = true; } } // If the EKU extension was included, then the required EKU must be in the // list. if (!found) { PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); return RecoverableError; } } // pkixocsp.cpp depends on the following additional checks. if (foundOCSPSigning) { // When validating anything other than an delegated OCSP signing cert, // reject any cert that also claims to be an OCSP responder, because such // a cert does not make sense. For example, if an SSL certificate were to // assert id-kp-OCSPSigning then it could sign OCSP responses for itself, // if not for this check. if (requiredEKU != SEC_OID_OCSP_RESPONDER) { PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); return RecoverableError; } } else if (requiredEKU == SEC_OID_OCSP_RESPONDER && endEntityOrCA == MustBeEndEntity) { // http://tools.ietf.org/html/rfc6960#section-4.2.2.2: // "OCSP signing delegation SHALL be designated by the inclusion of // id-kp-OCSPSigning in an extended key usage certificate extension // included in the OCSP response signer's certificate." // // id-kp-OCSPSigning is the only EKU that isn't implicitly assumed when the // EKU extension is missing from an end-entity certificate. However, any CA // certificate can issue a delegated OCSP response signing certificate, so // we can't require the EKU be explicitly included for CA certificates. PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); return RecoverableError; } return Success; }
// 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage) // 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage) Result CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedEKUs, SECOidTag requiredEKU) { // TODO: Either do not allow anyExtendedKeyUsage to be passed as requiredEKU, // or require that callers pass anyExtendedKeyUsage instead of // SEC_OID_UNKNWON and disallow SEC_OID_UNKNWON. // XXX: We're using SEC_ERROR_INADEQUATE_CERT_TYPE here so that callers can // distinguish EKU mismatch from KU mismatch from basic constraints mismatch. // We should probably add a new error code that is more clear for this type // of problem. bool foundOCSPSigning = false; if (encodedEKUs) { ScopedPtr<CERTOidSequence, CERT_DestroyOidSequence> seq(CERT_DecodeOidSequence(encodedEKUs)); if (!seq) { PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); return RecoverableError; } bool found = false; // XXX: We allow duplicate entries. for (const SECItem* const* oids = seq->oids; oids && *oids; ++oids) { SECOidTag oidTag = SECOID_FindOIDTag(*oids); if (requiredEKU != SEC_OID_UNKNOWN && oidTag == requiredEKU) { found = true; } else { // Treat CA certs with step-up OID as also having SSL server type. // COMODO has issued certificates that require this behavior // that don't expire until June 2020! // TODO 982932: Limit this expection to old certificates if (endEntityOrCA == MustBeCA && requiredEKU == SEC_OID_EXT_KEY_USAGE_SERVER_AUTH && oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) { found = true; } } if (oidTag == SEC_OID_OCSP_RESPONDER) { foundOCSPSigning = true; } } // If the EKU extension was included, then the required EKU must be in the // list. if (!found) { PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); return RecoverableError; } } // pkixocsp.cpp depends on the following additional checks. if (endEntityOrCA == MustBeEndEntity) { // When validating anything other than an delegated OCSP signing cert, // reject any cert that also claims to be an OCSP responder, because such // a cert does not make sense. For example, if an SSL certificate were to // assert id-kp-OCSPSigning then it could sign OCSP responses for itself, // if not for this check. // That said, we accept CA certificates with id-kp-OCSPSigning because // some CAs in Mozilla's CA program have issued such intermediate // certificates, and because some CAs have reported some Microsoft server // software wrongly requires CA certificates to have id-kp-OCSPSigning. // Allowing this exception does not cause any security issues because we // require delegated OCSP response signing certificates to be end-entity // certificates. if (foundOCSPSigning && requiredEKU != SEC_OID_OCSP_RESPONDER) { PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); return RecoverableError; } // http://tools.ietf.org/html/rfc6960#section-4.2.2.2: // "OCSP signing delegation SHALL be designated by the inclusion of // id-kp-OCSPSigning in an extended key usage certificate extension // included in the OCSP response signer's certificate." // // id-kp-OCSPSigning is the only EKU that isn't implicitly assumed when the // EKU extension is missing from an end-entity certificate. However, any CA // certificate can issue a delegated OCSP response signing certificate, so // we can't require the EKU be explicitly included for CA certificates. if (!foundOCSPSigning && requiredEKU == SEC_OID_OCSP_RESPONDER) { PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); return RecoverableError; } } return Success; }