crypt32: Only permit v1 or v2 CA certificates without a basic constraints extension if they're installed locally.
This commit is contained in:
parent
552fec4002
commit
33a6235053
|
@ -418,11 +418,18 @@ static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks element's basic constraints to see if it can act as a CA, with
|
/* Checks element's basic constraints to see if it can act as a CA, with
|
||||||
* remainingCAs CAs left in this chain. A root certificate is assumed to be
|
* remainingCAs CAs left in this chain. In general, a cert must include the
|
||||||
* allowed to be a CA whether or not the basic constraints extension is present,
|
* basic constraints extension, with the CA flag asserted, in order to be
|
||||||
* whereas an intermediate CA cert is not. This matches the expected usage in
|
* allowed to be a CA. A V1 or V2 cert, which has no extensions, is also
|
||||||
* RFC 3280: a conforming intermediate CA MUST contain the basic constraints
|
* allowed to be a CA if it's installed locally (in the engine's world store.)
|
||||||
* extension. It also appears to match Microsoft's implementation.
|
* This matches the expected usage in RFC 5280, section 4.2.1.9: a conforming
|
||||||
|
* CA MUST include the basic constraints extension in all certificates that are
|
||||||
|
* used to validate digital signatures on certificates. It also matches
|
||||||
|
* section 6.1.4(k): "If a certificate is a v1 or v2 certificate, then the
|
||||||
|
* application MUST either verify that the certificate is a CA certificate
|
||||||
|
* through out-of-band means or reject the certificate." Rejecting the
|
||||||
|
* certificate prohibits a large number of commonly used certificates, so
|
||||||
|
* accepting locally installed ones is a compromise.
|
||||||
* Updates chainConstraints with the element's constraints, if:
|
* Updates chainConstraints with the element's constraints, if:
|
||||||
* 1. chainConstraints doesn't have a path length constraint, or
|
* 1. chainConstraints doesn't have a path length constraint, or
|
||||||
* 2. element's path length constraint is smaller than chainConstraints's
|
* 2. element's path length constraint is smaller than chainConstraints's
|
||||||
|
@ -431,15 +438,36 @@ static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
|
||||||
* Returns TRUE if the element can be a CA, and the length of the remaining
|
* Returns TRUE if the element can be a CA, and the length of the remaining
|
||||||
* chain is valid.
|
* chain is valid.
|
||||||
*/
|
*/
|
||||||
static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
|
static BOOL CRYPT_CheckBasicConstraintsForCA(PCertificateChainEngine engine,
|
||||||
CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, DWORD remainingCAs,
|
PCCERT_CONTEXT cert, CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints,
|
||||||
BOOL isRoot, BOOL *pathLengthConstraintViolated)
|
DWORD remainingCAs, BOOL *pathLengthConstraintViolated)
|
||||||
{
|
{
|
||||||
BOOL validBasicConstraints;
|
BOOL validBasicConstraints, implicitCA = FALSE;
|
||||||
CERT_BASIC_CONSTRAINTS2_INFO constraints;
|
CERT_BASIC_CONSTRAINTS2_INFO constraints;
|
||||||
|
|
||||||
|
if (cert->pCertInfo->dwVersion == CERT_V1 ||
|
||||||
|
cert->pCertInfo->dwVersion == CERT_V2)
|
||||||
|
{
|
||||||
|
BYTE hash[20];
|
||||||
|
DWORD size = sizeof(hash);
|
||||||
|
|
||||||
|
if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
|
||||||
|
hash, &size))
|
||||||
|
{
|
||||||
|
CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
|
||||||
|
PCCERT_CONTEXT localCert = CertFindCertificateInStore(
|
||||||
|
engine->hWorld, cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH,
|
||||||
|
&blob, NULL);
|
||||||
|
|
||||||
|
if (localCert)
|
||||||
|
{
|
||||||
|
CertFreeCertificateContext(localCert);
|
||||||
|
implicitCA = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
|
if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
|
||||||
&constraints, isRoot)))
|
&constraints, implicitCA)))
|
||||||
{
|
{
|
||||||
chainConstraints->fCA = constraints.fCA;
|
chainConstraints->fCA = constraints.fCA;
|
||||||
if (!constraints.fCA)
|
if (!constraints.fCA)
|
||||||
|
@ -1210,9 +1238,9 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
|
||||||
if (pathLengthConstraintViolated)
|
if (pathLengthConstraintViolated)
|
||||||
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
|
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
|
||||||
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
|
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
|
||||||
else if (!CRYPT_CheckBasicConstraintsForCA(
|
else if (!CRYPT_CheckBasicConstraintsForCA(engine,
|
||||||
chain->rgpElement[i]->pCertContext, &constraints, i - 1,
|
chain->rgpElement[i]->pCertContext, &constraints, i - 1,
|
||||||
isRoot, &pathLengthConstraintViolated))
|
&pathLengthConstraintViolated))
|
||||||
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
|
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
|
||||||
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
|
CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
|
||||||
else if (constraints.fPathLenConstraint &&
|
else if (constraints.fPathLenConstraint &&
|
||||||
|
|
Loading…
Reference in New Issue