📄 certchk.c
字号:
/* Some even more broken certs indicate their usage via a
Netscape key usage (even though they use X.509 flags
everywhere else), which means that we fail them if we're
strictly applying the PKIX requirements at a higher compliance
level. At this lower level we try for Netscape usage if we
can't find anything else, and if there's one present, use the
translated values as if they were the X.509 usage */
if( isCryptAlgo( certInfoPtr->publicKeyAlgo ) )
algorithmType = ALGO_TYPE_CRYPT;
if( isSigAlgo( certInfoPtr->publicKeyAlgo ) )
algorithmType |= ALGO_TYPE_SIGN;
if( isKeyxAlgo( certInfoPtr->publicKeyAlgo ) )
algorithmType |= ALGO_TYPE_KEYAGREEMENT;
netscapeUsage = getNetscapeCertTypeFlags( certInfoPtr->attributes,
algorithmType, errorLocus );
if( netscapeUsage > 0 )
keyUsage = netscapeUsage;
}
}
/* If the CA flag is set, make sure that there's a keyUsage with one of
the CA usages present. Conversely, if there are CA key usages
present, make sure that the CA flag is set. The CA flag is actually a
leftover from an early v3 cert concept and is made entirely redundant
by the keyUsage flags, but we have to check it regardless */
if( isCA )
{
if( !( ( extKeyUsage | keyUsage ) & \
( CRYPT_KEYUSAGE_CRLSIGN | CRYPT_KEYUSAGE_KEYCERTSIGN ) ) )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
else
if( ( extKeyUsage | keyUsage ) & \
( CRYPT_KEYUSAGE_CRLSIGN | CRYPT_KEYUSAGE_KEYCERTSIGN ) )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Make sure that mutually exclusive flags aren't set */
if( ( keyUsage & CRYPT_KEYUSAGE_ENCIPHERONLY ) && \
( keyUsage & CRYPT_KEYUSAGE_DECIPHERONLY ) )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE, CRYPT_ERRTYPE_ATTR_VALUE );
return( CRYPT_ERROR_INVALID );
}
/* Make sure that the keyUsage flags represent capabilities that the
algorithm is actually capable of */
if( ( ( keyUsage & USAGE_CRYPT_MASK ) && \
!isCryptAlgo( certInfoPtr->publicKeyAlgo ) ) || \
( ( keyUsage & USAGE_SIGN_MASK ) && \
!isSigAlgo( certInfoPtr->publicKeyAlgo ) ) || \
( ( keyUsage & USAGE_KEYAGREEMENT_MASK ) && \
!isKeyxAlgo( certInfoPtr->publicKeyAlgo ) ) )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE, CRYPT_ERRTYPE_ATTR_VALUE );
return( CRYPT_ERROR_INVALID );
}
/* Mask out any non-relevant usages (e.g. cert signing, which doesn't
occur in extended key usages and has already been checked above) */
extKeyUsage &= ~USAGE_MASK_NONRELEVANT;
keyUsage &= ~USAGE_MASK_NONRELEVANT;
/* If there's no key usage based on extended key usage present or we're
not doing a PKIX-compliant check, there's nothing further to check */
if( !extKeyUsage || complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
return( CRYPT_OK );
/* If the usage and extended usage are critical (but only if both are
critical, because PKIX says so) make sure that the given usage is
consistent with the required usage. Checking whether the extended
usage is critical is a bit nontrivial, we have to check each possible
extended usage since only one of them may be present, so we check the
criticality of the basic key usage first to allow quick short-circuit
evaluation.
In addition to the explicit criticality checks, we also perform an
implicit check based on whether this is a freshly-generated, as-yet-
unsigned cryptlib cert. This is done for two reasons, firstly because
an unsigned cert won't have had the criticality flag set by the
signing/encoding process so the extension always appears non-critical,
and secondly because we don't want cryptlib to generate inconsistent
certs, whether the extensions are marked critical or not (cryptlib
always makes the keyUsage critical, so at least for key usage it's
no change from the standard behaviour) */
if( certInfoPtr->certificate != NULL )
{
int attributeID;
if( !keyUsageCritical )
/* No critical key usage, return */
return( CRYPT_OK );
for( attributeID = CRYPT_CERTINFO_EXTKEYUSAGE + 1;
attributeID < CRYPT_CERTINFO_NS_CERTTYPE; attributeID++ )
{
attributeListPtr = findAttributeField( certInfoPtr->attributes,
attributeID, CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
!( attributeListPtr->flags & ATTR_FLAG_CRITICAL ) )
/* We found an extended key usage and it's non-critical
(which means that all extended usages are non-critical),
return */
return( CRYPT_OK );
}
}
/* Make sure that the extended key usage-based key usage is consistent
with the actual key usage */
if( ( keyUsage & extKeyUsage ) != extKeyUsage )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Name Comparison Routines *
* *
****************************************************************************/
/* Compare two attribute components */
static BOOLEAN compareAttributeComponents( const ATTRIBUTE_LIST *attribute1ptr,
const ATTRIBUTE_LIST *attribute2ptr )
{
/* Make sure either both are absent or present */
if( attribute1ptr != NULL )
{
if( attribute2ptr == NULL )
return( FALSE ); /* Both must be present or absent */
}
else
{
if( attribute2ptr != NULL )
return( FALSE ); /* Both must be present or absent */
return( TRUE );
}
/* If it's an attribute containing a composite field, use a special-case
compare */
if( attribute1ptr->fieldType == FIELDTYPE_DN )
return( compareDN( attribute1ptr->value, attribute2ptr->value, FALSE ) );
/* Compare the data values */
if( attribute1ptr->valueLength != attribute2ptr->valueLength || \
memcmp( attribute1ptr->value, attribute2ptr->value,
attribute1ptr->valueLength ) )
return( FALSE );
return( TRUE );
}
/* Compare two altNames component by component */
static CRYPT_ATTRIBUTE_TYPE compareAltNames( const ATTRIBUTE_LIST *subjectAttributes,
const ATTRIBUTE_LIST *issuerAttributes )
{
ATTRIBUTE_LIST *subjectAttributeListPtr, *issuerAttributeListPtr;
/* Check the otherName */
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_OTHERNAME_TYPEID );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_OTHERNAME_TYPEID );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_OTHERNAME_TYPEID );
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_OTHERNAME_VALUE );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_OTHERNAME_VALUE );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_OTHERNAME_VALUE );
/* Check the email address */
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_RFC822NAME );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_RFC822NAME );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_RFC822NAME );
/* Check the DNS name */
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_DNSNAME );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_DNSNAME );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_DNSNAME );
/* Check the directory name */
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_DIRECTORYNAME );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_DIRECTORYNAME );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_DIRECTORYNAME );
/* Check the EDI party name */
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_EDIPARTYNAME_NAMEASSIGNER );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_EDIPARTYNAME_NAMEASSIGNER );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_EDIPARTYNAME_NAMEASSIGNER );
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_EDIPARTYNAME_PARTYNAME );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_EDIPARTYNAME_PARTYNAME );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_EDIPARTYNAME_PARTYNAME );
/* Check the URI */
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER );
/* Check the IP address */
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_IPADDRESS );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_IPADDRESS );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_IPADDRESS );
/* Check the registered ID */
subjectAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME, CRYPT_CERTINFO_REGISTEREDID );
issuerAttributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_REGISTEREDID );
if( !compareAttributeComponents( subjectAttributeListPtr,
issuerAttributeListPtr ) )
return( CRYPT_CERTINFO_REGISTEREDID );
return( CRYPT_ATTRIBUTE_NONE );
}
/* Perform a wildcarded compare of two strings in attributes */
static BOOLEAN wildcardStringMatch( const char *wildcardString,
const char *string )
{
while( *wildcardString && *string )
{
/* Match a wildcard */
if( *wildcardString == '*' )
{
BOOLEAN isMatch = FALSE;
/* Skip '*'s and exit if we've reached the end of the pattern */
while( *wildcardString == '*' )
wildcardString++;
if( !*wildcardString )
return( TRUE );
/* Match to the next literal, then match the next section with
backtracking in case of a mismatch */
while( *string && *wildcardString != *string )
string++;
while( *string && !isMatch )
{
isMatch = wildcardStringMatch( wildcardString, string );
if( !isMatch )
string++;
}
return( isMatch );
}
else
if( *wildcardString != *string )
return( FALSE );
wildcardString++;
string++;
}
/* If there are literals left in the wildcard or text string, we haven't
found a match yet */
if( *wildcardString && ( *wildcardString != '*' || *++wildcardString ) )
return( FALSE );
return( *string ? FALSE : TRUE );
}
static BOOLEAN wildcardMatch( const ATTRIBUTE_LIST *constrainedAttribute,
const ATTRIBUTE_LIST *attribute,
const BOOLEAN errorStatus )
{
const char *string = attribute->value;
int count = 0, i;
/* Perform a quick damage-control check to prevent excessive recursion:
There shouldn't be more than ten wildcard chars present (realistically
there shouldn't be more than one) */
for( i = 0; string[ i ]; i++ )
if( string[ i ] == '*' )
count++;
if( count > 10 )
return( errorStatus );
/* Pass the call on to the string matcher (this is recursive so we can't
do the match in this function) */
return( wildcardStringMatch( string, constrainedAttribute->value ) );
}
/* Check name constraints placed by an issuer, checked if complianceLevel >=
CRYPT_COMPLIANCELEVEL_PKIX_FULL. matchValue = TRUE for excluded subtrees
(fail on a match), FALSE for included subtrees (fail on a mismatch) */
int checkNameConstraints( const CERT_INFO *subjectCertInfoPtr,
const ATTRIBUTE_LIST *issuerAttributes,
const BOOLEAN matchValue,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
const ATTRIBUTE_LIST *subjectAttributes = subjectCertInfoPtr->attributes;
const CRYPT_ATTRIBUTE_TYPE constraintType = matchValue ? \
CRYPT_CERTINFO_EXCLUDEDSUBTREES : CRYPT_CERTINFO_PERMITTEDSUBTREES;
ATTRIBUTE_LIST *attributeListPtr, *constrainedAttributeListPtr;
int status = CRYPT_OK;
assert( isReadPtr( subjectCertInfoPtr, CERT_INFO ) );
assert( isReadPtr( issuerAttributes, ATTRIBUTE_LIST ) );
/* Compare the DN if a constraint exists */
attributeListPtr = findAttributeField( issuerAttributes,
constraintType, CRYPT_CERTINFO_DIRECTORYNAME );
if( compareDN( subjectCertInfoPtr->subjectName,
attributeListPtr->value, TRUE ) == matchValue )
{
setErrorValues( CRYPT_CERTINFO_SUBJECTNAME,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Compare the Internet-related names if constraints exist */
attributeListPtr = findAttributeField( issuerAttributes,
constraintType, CRYPT_CERTINFO_RFC822NAME );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -