📄 certchn.c
字号:
}
/* If we're at the 0-th cert we don't have to perform any constraint
checking since the check for (leaf, [0]) is performed by checkCert().
If it's a self-signed cert, the constraints don't apply to itself (a
Smith and Wesson beats four aces) */
if( certIndex < 0 || ( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
return( CRYPT_OK );
/* If there aren't any name or policy constraint present, we're done */
if( !checkAttributePresent( issuerCertInfoPtr->attributes, \
CRYPT_CERTINFO_NAMECONSTRAINTS ) && \
!checkAttributePresent( issuerCertInfoPtr->attributes, \
CRYPT_CERTINFO_POLICYCONSTRAINTS ) )
return( CRYPT_OK );
/* Check that the name/policy constraints are satisfied for all certs
below this one */
nameAttributeListPtr = findAttribute( issuerCertInfoPtr->attributes, \
CRYPT_CERTINFO_NAMECONSTRAINTS, FALSE );
policyAttributeListPtr = findAttribute( issuerCertInfoPtr->attributes, \
CRYPT_CERTINFO_POLICYCONSTRAINTS, FALSE );
hasExcludedSubtrees = findAttributeField( nameAttributeListPtr, \
CRYPT_CERTINFO_EXCLUDEDSUBTREES,
CRYPT_ATTRIBUTE_NONE ) != NULL;
hasPermittedSubtrees = findAttributeField( nameAttributeListPtr, \
CRYPT_CERTINFO_PERMITTEDSUBTREES,
CRYPT_ATTRIBUTE_NONE ) != NULL;
hasPolicy = findAttributeField( policyAttributeListPtr, \
CRYPT_CERTINFO_CERTPOLICYID,
CRYPT_ATTRIBUTE_NONE ) != NULL;
/* 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 that contradicts the first one is encountered */
attributeListPtr = findAttributeField( policyAttributeListPtr,
CRYPT_CERTINFO_REQUIREEXPLICITPOLICY,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
requireExplicitPolicyLevel = ( int ) attributeListPtr->intValue;
requireExplicitPolicyPresent = TRUE;
}
/* Walk down the chain checking each cert against the issuer */
do
{
CERT_INFO *subjectCertInfoPtr;
/* 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 that it doesn't contradict the current one */
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_REQUIREEXPLICITPOLICY,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && requireExplicitPolicyPresent && \
attributeListPtr->intValue != 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,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType ) ) );
status = CRYPT_ERROR_INVALID;
if( hasPermittedSubtrees && \
cryptStatusError( checkNameConstraints( subjectCertInfoPtr,
nameAttributeListPtr, FALSE,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType ) ) );
status = CRYPT_ERROR_INVALID;
if( hasPolicy && requireExplicitPolicyLevel == CRYPT_ERROR && \
cryptStatusError( checkPolicyConstraints( subjectCertInfoPtr,
policyAttributeListPtr,
&subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType ) ) );
status = CRYPT_ERROR_INVALID;
krnlReleaseObject( subjectCertInfoPtr->objectHandle );
}
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 */
static int checkLeafCertTrust( CERT_INFO *certInfoPtr,
CRYPT_CERTIFICATE *iIssuerCert )
{
SELECTION_STATE savedState;
int status;
/* Clear return value */
*iIssuerCert = CRYPT_ERROR;
/* Explicitly select the leaf cert by making it appear that the cert
chain is empty. This is required in order to ensure that we check
the leaf rather than the currently-selected cert */
saveSelectionState( savedState, certInfoPtr );
certInfoPtr->certChainPos = CRYPT_ERROR;
/* If the leaf cert is implicitly trusted, there's nothing to do */
status = krnlSendMessage( certInfoPtr->ownerHandle, IMESSAGE_SETATTRIBUTE,
&certInfoPtr->objectHandle,
CRYPT_IATTRIBUTE_CERT_CHECKTRUST );
if( cryptStatusOK( status ) )
status = OK_SPECIAL;
else
{
/* If the leaf cert's issuer is implicitly trusted, we only need to
check the signature on the leaf cert */
*iIssuerCert = certInfoPtr->objectHandle;
status = krnlSendMessage( certInfoPtr->ownerHandle,
IMESSAGE_SETATTRIBUTE, iIssuerCert,
CRYPT_IATTRIBUTE_CERT_TRUSTEDISSUER );
}
/* Restore the cert chain info */
restoreSelectionState( savedState, certInfoPtr );
return( status );
}
int checkCertChain( CERT_INFO *certInfoPtr )
{
CRYPT_CERTIFICATE iIssuerCert;
CERT_INFO *issuerCertInfoPtr = certInfoPtr, *subjectCertInfoPtr;
BOOLEAN isTrusted = TRUE;
int certIndex = certInfoPtr->certChainEnd - 1, complianceLevel, i, status;
assert( isWritePtr( certInfoPtr, CERT_INFO ) );
krnlSendMessage( certInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
&complianceLevel, CRYPT_OPTION_CERT_COMPLIANCELEVEL );
/* Check whether the leaf cert is either implicitly trusted or signed by
a trusted cert */
status = checkLeafCertTrust( certInfoPtr, &iIssuerCert );
if( status == OK_SPECIAL )
/* The leaf is implicitly trusted, there's nothing more to do */
return( CRYPT_OK );
if( cryptStatusOK( status ) )
/* The leaf is signed by a trusted cert, no need to check the cert
chain */
certIndex = CRYPT_ERROR;
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++ )
{
status = krnlGetObject( certInfoPtr->certChain[ i ],
OBJECT_TYPE_CERTIFICATE,
( void ** ) &issuerCertInfoPtr,
CRYPT_ERROR_SIGNALLED );
if( cryptStatusError( status ) )
break;
iIssuerCert = issuerCertInfoPtr->objectHandle;
status = krnlSendMessage( certInfoPtr->ownerHandle,
IMESSAGE_SETATTRIBUTE, &iIssuerCert,
CRYPT_IATTRIBUTE_CERT_TRUSTEDISSUER );
if( cryptStatusOK( status ) )
break;
if( i != certIndex )
krnlReleaseObject( issuerCertInfoPtr->objectHandle );
}
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( status ) )
{
/* We didn't end up at a 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 );
krnlReleaseObject( issuerCertInfoPtr->objectHandle );
return( CRYPT_ERROR_INVALID );
}
}
/* Walk down the chain from the trusted cert checking each link in turn */
subjectCertInfoPtr = ( CERT_INFO * ) issuerCertInfoPtr;
do
{
CRYPT_CONTEXT iPubkeyContext = iIssuerCert;
/* If the issuing cert for this one isn't implicitly trusted, check
the chaining from issuer to subject */
if( !isTrusted )
{
iPubkeyContext = issuerCertInfoPtr->iPubkeyContext;
status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr,
TRUE, &subjectCertInfoPtr->errorLocus,
&subjectCertInfoPtr->errorType);
if( cryptStatusOK( status ) )
subjectCertInfoPtr->maxCheckLevel = complianceLevel;
}
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( iPubkeyContext ) )
status = checkX509signature( subjectCertInfoPtr->certificate,
subjectCertInfoPtr->certificateSize,
NULL, NULL, iPubkeyContext,
CRYPT_UNUSED );
/* Check any constraints that the issuer cert may place on the rest
of the chain */
if( cryptStatusOK( status ) && \
complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_FULL && \
issuerCertInfoPtr != subjectCertInfoPtr )
status = checkConstraints( certInfoPtr, issuerCertInfoPtr,
&certIndex );
/* Move on to the next cert */
if( issuerCertInfoPtr != subjectCertInfoPtr )
krnlReleaseObject( issuerCertInfoPtr->objectHandle );
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 that we processed wasn't the leaf, unlock it and
select the one that caused the problem */
if( issuerCertInfoPtr != certInfoPtr )
krnlReleaseObject( issuerCertInfoPtr->objectHandle );
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 that 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, IMESSAGE_DECREFCOUNT );
freeCertChain( iCertChain, certChainEnd );
return( status );
}
certChainEnd = status;
if( certChainEnd <= 0 )
/* There's only one cert in the chain, either due to the chain
containing only a single cert 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 */
status = krnlGetObject( *iLeafCert, OBJECT_TYPE_CERTIFICATE,
( void ** ) &certChainPtr,
CRYPT_ERROR_SIGNALLED );
if( cryptStatusError( status ) )
return( status );
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-
signed */
status = krnlSendMessage( certChainPtr->certChain[ certChainEnd - 1 ],
IMESSAGE_GETATTRIBUTE, &selfSigned,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -