📄 certchn.c
字号:
length */
attributeListPtr = findAttributeField( issuerCertInfoPtr->attributes,
CRYPT_CERTINFO_PATHLENCONSTRAINT, CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
!( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) && \
attributeListPtr->value <= certIndex )
{
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_PATHLENCONSTRAINT,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If there's a name or policy constraint present, check that it's
satisfied for all certs below this one. We don't have to perform this
check if the constraint appears in the 0-th cert since the check for
(leaf, [0]) is performed by checkCert() */
if( certIndex >= 0 && \
!( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) && \
( ( nameAttributeListPtr = findAttribute( issuerCertInfoPtr->attributes, \
CRYPT_CERTINFO_NAMECONSTRAINTS ) ) != NULL ) || \
( ( policyAttributeListPtr = findAttribute( issuerCertInfoPtr->attributes, \
CRYPT_CERTINFO_POLICYCONSTRAINTS ) ) != NULL ) )
{
const BOOLEAN hasExcludedSubtrees = findAttribute( nameAttributeListPtr, \
CRYPT_CERTINFO_EXCLUDEDSUBTREES ) != NULL;
const BOOLEAN hasPermittedSubtrees = findAttribute( nameAttributeListPtr, \
CRYPT_CERTINFO_PERMITTEDSUBTREES ) != NULL;
const BOOLEAN hasPolicy = findAttribute( policyAttributeListPtr, \
CRYPT_CERTINFO_CERTPOLICYID ) != NULL;
BOOLEAN requireExplicitPolicyPresent = FALSE;
int requireExplicitPolicyLevel = CRYPT_ERROR;
CERT_INFO *subjectCertInfoPtr;
/* Check whether there's a requireExplicitPolicy attribute. The
handling of this is very ambiguous since other parts of the path
validation requirements stipulate that policies should be checked
anyway (even if requireExplicitPolicy isn't set), and no-one knows
what to do if multiple requireExplicitPolicy settings are present
in a chain (for example due to reparenting). This implementation
handles it by returning an error if a second requireExplicitPolicy
attribute which contradicts the first one is encountered */
attributeListPtr = findAttribute( policyAttributeListPtr,
CRYPT_CERTINFO_REQUIREEXPLICITPOLICY );
if( attributeListPtr != NULL )
{
requireExplicitPolicyLevel = ( int ) attributeListPtr->value;
requireExplicitPolicyPresent = TRUE;
}
/* Walk down the chain checking each cert against the issuer */
do
{
/* Get the next cert in the chain */
certIndex--;
status = getNextCert( certInfoPtr, &subjectCertInfoPtr,
certIndex );
if( status == OK_SPECIAL )
/* We've reached the end of the chain, exit */
break;
/* If there's a second policy constraint present further down the
chain, make sure it doesn't contradict the current one */
attributeListPtr = findAttribute( certInfoPtr->attributes,
CRYPT_CERTINFO_REQUIREEXPLICITPOLICY );
if( attributeListPtr != NULL && requireExplicitPolicyPresent && \
attributeListPtr->value != requireExplicitPolicyLevel )
{
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_REQUIREEXPLICITPOLICY,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
status = CRYPT_ERROR_INVALID;
break;
}
/* If there's a requireExplicitPolicy skip count, decrement it
for each cert */
if( requireExplicitPolicyLevel != CRYPT_ERROR )
requireExplicitPolicyLevel--;
/* Check that the current cert obeys the constraints set by the
issuer */
if( hasExcludedSubtrees && \
cryptStatusError( checkNameConstraints( subjectCertInfoPtr,
nameAttributeListPtr, TRUE ) ) )
status = CRYPT_ERROR_INVALID;
if( hasPermittedSubtrees && \
cryptStatusError( checkNameConstraints( subjectCertInfoPtr,
nameAttributeListPtr, FALSE ) ) )
status = CRYPT_ERROR_INVALID;
if( hasPolicy && requireExplicitPolicyLevel == CRYPT_ERROR && \
cryptStatusError( checkPolicyConstraints( subjectCertInfoPtr,
policyAttributeListPtr ) ) )
status = CRYPT_ERROR_INVALID;
unlockResource( subjectCertInfoPtr );
}
while( cryptStatusOK( status ) );
}
if( status == CRYPT_OK || status == OK_SPECIAL )
return( CRYPT_OK );
/* Remember which cert in the chain caused the problem */
*subjectCertIndex = certIndex;
return( status );
}
/* Walk down a chain checking each certificate */
int checkCertChain( CERT_INFO *certInfoPtr )
{
CRYPT_CONTEXT iCryptContext;
CERT_INFO *issuerCertInfoPtr = certInfoPtr, *subjectCertInfoPtr;
BOOLEAN isTrusted = TRUE;
int certIndex = certInfoPtr->certChainEnd - 1, i, status = CRYPT_OK;
assert( isWritePtr( certInfoPtr, CERT_INFO ) );
/* If the leaf cert is implicitly trusted, there's nothing to do */
if( checkCertTrusted( certInfoPtr ) )
return( CRYPT_OK );
/* If the leaf cert's issuer is implicitly trusted, we only need to check
the signature on the leaf cert */
iCryptContext = findTrustedCert( certInfoPtr->issuerDNptr,
certInfoPtr->issuerDNsize );
if( !cryptStatusError( iCryptContext ) )
certIndex = CRYPT_ERROR; /* No need to check the cert chain */
else
{
/* Walk up the chain from the leaf cert's issuer to the root checking
for an implicitly trusted cert */
for( i = 0; i <= certIndex; i++ )
{
getCheckInternalResource( certInfoPtr->certChain[ i ],
issuerCertInfoPtr, OBJECT_TYPE_CERTIFICATE );
iCryptContext = findTrustedCert( issuerCertInfoPtr->issuerDNptr,
issuerCertInfoPtr->issuerDNsize );
if( !cryptStatusError( iCryptContext ) )
break;
if( i != certIndex )
unlockResource( issuerCertInfoPtr );
}
certIndex = i; /* Remember how far we got */
/* If we didn't end up at an implicitly trusted cert, check whether
we should implicitly trust a self-signed root */
if( cryptStatusError( iCryptContext ) )
{
int trustChainRoot;
krnlSendMessage( certInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE, &trustChainRoot,
CRYPT_OPTION_CERT_TRUSTCHAINROOT );
if( ( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) && \
trustChainRoot )
/* There's a self-signed root present but it's not implicitly
trusted, continue without the trust flag set */
isTrusted = FALSE;
else
{
/* We didn't end up at an implicitly or explicitly trusted
key, either there's a missing link in the chain
(CRYPT_ERROR_STUART) and it was truncated before we got
to a trusted cert, or it goes to a root cert but it isn't
trusted */
certInfoPtr->certChainPos = certInfoPtr->certChainEnd - 1;
if( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED )
{
/* We got a root cert but it's not trusted */
setErrorInfo( issuerCertInfoPtr, CRYPT_CERTINFO_TRUSTED_IMPLICIT,
CRYPT_ERRTYPE_ATTR_ABSENT );
}
else
/* There's a missing link in the chain and it stops at
this cert */
setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
CRYPT_ERRTYPE_ATTR_ABSENT );
unlockResource( issuerCertInfoPtr );
return( CRYPT_ERROR_INVALID );
}
}
}
/* Walk down the chain from the trusted cert checking each link in turn */
subjectCertInfoPtr = ( CERT_INFO * ) issuerCertInfoPtr;
do
{
/* If the issuing cert for this one isn't implicitly trusted, check
the chaining from issuer to subject */
if( !isTrusted )
{
iCryptContext = issuerCertInfoPtr->iCryptContext;
status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr );
}
isTrusted = FALSE;
/* Check the signature on the subject cert unless it's a data-only
cert for which there isn't a context present. This is OK since
the only time we can have a data-only chain is when we're reading
from an (implicitly trusted) private key store */
if( cryptStatusOK( status ) && !cryptStatusError( iCryptContext ) )
status = checkX509signature( subjectCertInfoPtr->certificate,
subjectCertInfoPtr->certificateSize,
NULL, NULL, iCryptContext );
/* Check any constraints the issuer cert may place on the rest of the
chain */
if( cryptStatusOK( status ) && issuerCertInfoPtr != subjectCertInfoPtr )
status = checkConstraints( certInfoPtr, issuerCertInfoPtr,
&certIndex );
/* Move on to the next cert */
if( issuerCertInfoPtr != subjectCertInfoPtr )
unlockResource( issuerCertInfoPtr );
issuerCertInfoPtr = subjectCertInfoPtr;
certIndex--;
}
while( cryptStatusOK( status ) && \
( status = getNextCert( certInfoPtr, &subjectCertInfoPtr,
certIndex ) ) == CRYPT_OK );
if( status != OK_SPECIAL )
{
/* We stopped before we processed all the certs in the chain, if
the last cert we processed wasn't the leaf, unlock it and
select the one which caused the problem */
if( issuerCertInfoPtr != certInfoPtr )
unlockResource( issuerCertInfoPtr );
certInfoPtr->certChainPos = certIndex + 1;
}
else
/* We successfully reached the end of the chain */
status = CRYPT_OK;
return( status );
}
/****************************************************************************
* *
* Read Certificate-bagging Records *
* *
****************************************************************************/
/* Read a collection of certs in a cert chain into a cert object */
static int buildCertChain( CRYPT_CERTIFICATE *iLeafCert,
CRYPT_CERTIFICATE *iCertChain, int certChainEnd,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength )
{
CERTCHAIN_INFO certChainInfo[ MAX_CHAINLENGTH ];
CERT_INFO *certChainPtr;
CHAINING_INFO chainingInfo;
int leafNodePos, selfSigned, status;
assert( certChainEnd > 0 && certChainEnd < MAX_CHAINLENGTH );
assert( isWritePtrEx( certChainInfo, CERTCHAIN_INFO, certChainEnd ) );
assert( isReadPtrEx( iCertChain, CRYPT_CERTIFICATE, certChainEnd ) );
/* We've now got a collection of certs in unknown order (although in most
cases the first cert is the leaf). Extract the chaining info and
search the chain for the leaf node */
status = buildCertChainInfo( certChainInfo, iCertChain, certChainEnd );
if( cryptStatusError( status ) )
{
freeCertChain( iCertChain, certChainEnd );
return( status );
}
if( keyID != NULL )
leafNodePos = findIdentifiedLeafNode( certChainInfo, certChainEnd,
keyIDtype, keyID,keyIDlength );
else
leafNodePos = findLeafNode( certChainInfo, certChainEnd );
if( cryptStatusError( leafNodePos ) )
return( leafNodePos );
/* Now that we have the leaf node, clear its entry in the chain (to make
sure it isn't used for further processing), order the remaining certs
up to the root, and discard any unneeded certs */
*iLeafCert = iCertChain[ leafNodePos ];
getIssuerChainingInfo( &chainingInfo, &certChainInfo[ leafNodePos ] );
memset( &certChainInfo[ leafNodePos ], 0, sizeof( CERTCHAIN_INFO ) );
status = sortCertChain( iCertChain, certChainInfo, certChainEnd,
CRYPT_UNUSED, &chainingInfo );
if( cryptStatusError( status ) )
{
krnlSendNotifier( *iLeafCert, RESOURCE_IMESSAGE_DECREFCOUNT );
freeCertChain( iCertChain, certChainEnd );
return( status );
}
certChainEnd = status;
if( !certChainEnd )
/* There's only one cert in the chain, either due to it only having
one cert to begin with or due to all other certs being discarded,
leave it as a standalone cert rather than turning it into a
chain */
return( CRYPT_OK );
/* Finally, we've got the leaf cert and a chain up to the root. Make the
leaf a cert-chain type and copy in the chain. */
getCheckInternalResource( *iLeafCert, certChainPtr,
OBJECT_TYPE_CERTIFICATE );
memcpy( certChainPtr->certChain, iCertChain,
certChainEnd * sizeof( CRYPT_CERTIFICATE ) );
certChainPtr->certChainEnd = certChainEnd;
certChainPtr->type = CRYPT_CERTTYPE_CERTCHAIN;
/* If the root is self-signed, the entire chain counts as self-
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -