📄 chk_cert.c
字号:
/****************************************************************************
* *
* Certificate Checking Routines *
* Copyright Peter Gutmann 1997-2007 *
* *
****************************************************************************/
#include <ctype.h>
#if defined( INC_ALL )
#include "cert.h"
#include "certattr.h"
#include "asn1.h"
#include "asn1_ext.h"
#else
#include "cert/cert.h"
#include "cert/certattr.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Check whether a policy is the wildcard anyPolicy */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN isAnyPolicy( INOUT const ATTRIBUTE_LIST *attributeListPtr )
{
assert( isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
return( ( attributeListPtr->valueLength == sizeofOID( OID_ANYPOLICY ) && \
!memcmp( attributeListPtr->value, OID_ANYPOLICY,
sizeofOID( OID_ANYPOLICY ) ) ) ? TRUE : FALSE );
}
/* Check whether a set of policies contains an instance of the anyPolicy
wildcard */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN containsAnyPolicy( const ATTRIBUTE_LIST *attributeListPtr,
IN_ATTRIBUTE \
const CRYPT_ATTRIBUTE_TYPE attributeType )
{
int iterationCount;
assert( isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
REQUIRES_B( attributeType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
attributeType <= CRYPT_CERTINFO_LAST );
for( attributeListPtr = findAttributeField( attributeListPtr, \
attributeType, CRYPT_ATTRIBUTE_NONE ), \
iterationCount = 0;
attributeListPtr != NULL && \
iterationCount < FAILSAFE_ITERATIONS_MAX;
attributeListPtr = findNextFieldInstance( attributeListPtr ), \
iterationCount++ )
{
if( isAnyPolicy( attributeListPtr ) )
return( TRUE );
}
ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MAX );
return( FALSE );
}
/* Check the type of policy present in a certificate */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 2, 3 ) ) \
static BOOLEAN checkPolicyType( IN_OPT const ATTRIBUTE_LIST *attributeListPtr,
OUT_BOOL BOOLEAN *hasPolicy,
OUT_BOOL BOOLEAN *hasAnyPolicy,
const BOOLEAN inhibitAnyPolicy )
{
int iterationCount;
assert( attributeListPtr == NULL || \
isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
assert( isWritePtr( hasPolicy, sizeof( BOOLEAN ) ) );
assert( isWritePtr( hasAnyPolicy, sizeof( BOOLEAN ) ) );
/* Clear return values */
*hasPolicy = *hasAnyPolicy = FALSE;
/* Make sure that there's a policy present and that it's a specific
policy if an explicit policy is required (the ability to disallow the
wildcard policy via inhibitAnyPolicy was introduced in RFC 3280 along
with the introduction of anyPolicy) */
if( attributeListPtr == NULL )
return( FALSE );
for( iterationCount = 0;
attributeListPtr != NULL && \
iterationCount < FAILSAFE_ITERATIONS_MAX;
attributeListPtr = findNextFieldInstance( attributeListPtr ), \
iterationCount++ )
{
ENSURES_B( attributeListPtr->fieldID == CRYPT_CERTINFO_CERTPOLICYID );
if( isAnyPolicy( attributeListPtr ) )
*hasAnyPolicy = TRUE;
else
*hasPolicy = TRUE;
}
ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MAX );
if( inhibitAnyPolicy )
{
/* The wildcard anyPolicy isn't valid for the subject, if there's no
other policy set then this is an error, otherwise we continue
without the wildcard match allowed */
if( !*hasPolicy )
return( FALSE );
*hasAnyPolicy = FALSE;
}
return( TRUE );
}
/* Check whether disallowed CA-only attributes are present in a (non-CA)
attribute list. We report the error as a constraint derived from the CA
flag rather than the attribute itself, since it's the absence of the flag
that renders the presence of the attribute invalid */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 4, 5 ) ) \
static BOOLEAN invalidAttributePresent( const ATTRIBUTE_LIST *attributeListPtr,
IN_ATTRIBUTE \
const CRYPT_ATTRIBUTE_TYPE attributeType,
const BOOLEAN isIssuer,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
BOOLEAN attributePresent;
assert( isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
REQUIRES_B( attributeType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
attributeType <= CRYPT_CERTINFO_LAST );
/* Clear return values */
*errorLocus = CRYPT_ATTRIBUTE_NONE;
*errorType = CRYPT_ERRTYPE_NONE;
/* In some cases only a particular field of an attribute is invalid
rather than the entire attribute. We use a per-field check if this
is the case (the specific exclusion of path-length constraints in
basicConstraints was introduced in RFC 3280) */
if( attributeType == CRYPT_CERTINFO_PATHLENCONSTRAINT )
{
attributePresent = \
findAttributeField( attributeListPtr,
CRYPT_CERTINFO_PATHLENCONSTRAINT,
CRYPT_ATTRIBUTE_NONE ) != NULL ? \
TRUE : FALSE;
}
else
{
attributePresent = \
checkAttributePresent( attributeListPtr,
CRYPT_CERTINFO_NAMECONSTRAINTS );
}
if( attributePresent )
{
setErrorValues( CRYPT_CERTINFO_CA, isIssuer ? \
CRYPT_ERRTYPE_ISSUERCONSTRAINT : \
CRYPT_ERRTYPE_CONSTRAINT );
}
return( attributePresent );
}
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
static BOOLEAN invalidAttributesPresent( const ATTRIBUTE_LIST *attributeListPtr,
const BOOLEAN isIssuer,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
assert( isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
return( invalidAttributePresent( attributeListPtr,
CRYPT_CERTINFO_NAMECONSTRAINTS,
FALSE, errorLocus, errorType ) || \
invalidAttributePresent( attributeListPtr,
CRYPT_CERTINFO_POLICYCONSTRAINTS,
FALSE, errorLocus, errorType ) || \
invalidAttributePresent( attributeListPtr,
CRYPT_CERTINFO_INHIBITANYPOLICY,
FALSE, errorLocus, errorType ) || \
invalidAttributePresent( attributeListPtr,
CRYPT_CERTINFO_POLICYMAPPINGS,
FALSE, errorLocus, errorType ) || \
invalidAttributePresent( attributeListPtr,
CRYPT_CERTINFO_PATHLENCONSTRAINT,
FALSE, errorLocus, errorType ) ? \
TRUE : FALSE );
}
/* Check whether a certificate is a PKIX path-kludge certificate, which
allows extra certificates to be kludged into the path without violating
any constraints */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN isPathKludge( const CERT_INFO *certInfoPtr )
{
const ATTRIBUTE_LIST *attributeListPtr;
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
/* Perform a quick-reject check for certificates that haven't been
identified by the certificate chain processing code as path-kludge
certificates */
if( !( certInfoPtr->flags & CERT_FLAG_PATHKLUDGE ) )
return( FALSE );
/* Only CA path-kludge certificates are exempt from constraint
enforcement. Non-CA path kludges shouldn't ever occur, but who knows
what other weirdness future RFCs will dream up so we perform an
explicit check here */
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_CA,
CRYPT_ATTRIBUTE_NONE );
return( ( attributeListPtr != NULL && attributeListPtr->intValue ) ? \
TRUE : FALSE );
}
/****************************************************************************
* *
* Name Comparison Routines *
* *
****************************************************************************/
/* Perform a wildcarded compare of two strings in attributes. Certificates
don't use standard ? and * regular-expression wildcards but instead
specify the constraint as a form of longest-suffix filter that's applied
to the string (with the usual pile of special-case exceptions that apply
to any certificate-related rules) so that e.g. www.foo.com would be
constrained using foo.com (or more usually .foo.com to avoid erroneous
matches for strings like www.barfoo.com) */
typedef enum {
MATCH_NONE, /* No special-case matching rules */
MATCH_EMAIL, /* Match using email address mailbox exception */
MATCH_URI, /* Match only DNS name portion of URI */
MATCH_LAST /* Last valid match rule type */
} MATCH_TYPE;
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static BOOLEAN wildcardMatch( const ATTRIBUTE_LIST *constrainedAttribute,
const ATTRIBUTE_LIST *attribute,
IN_ENUM_OPT( MATCH ) const MATCH_TYPE matchType )
{
const char *string = attribute->value;
const char *constrainedString = constrainedAttribute->value;
const int stringLength = attribute->valueLength;
const int constrainedStringLength = constrainedAttribute->valueLength;
const BOOLEAN isWildcardMatch = ( *string == '.' ) ? TRUE : FALSE;
int startPos;
assert( isReadPtr( constrainedAttribute, sizeof( ATTRIBUTE_LIST ) ) );
assert( isReadPtr( attribute, sizeof( ATTRIBUTE_LIST ) ) );
REQUIRES_B( matchType >= MATCH_NONE && matchType < MATCH_LAST );
/* Determine the start position of the constraining string within the
constrained string:
xxxxxyyyyy - Constrained string
yyyyy - Constraining string
^
|
startPos
If the constraining string is longer than the constrained string
(making startPos negative), it can never match */
startPos = constrainedStringLength - stringLength;
if( startPos < 0 || startPos > MAX_INTLENGTH_SHORT )
return( FALSE );
/* Handle special-case match requirements (PKIX section 4.2.1.11) */
switch( matchType )
{
case MATCH_EMAIL:
/* Email addresses have a special-case requirement where the
absence of a wildcard-match indicator (the leading dot)
indicates that the mailbox has to be located directly on the
constraining hostname rather than merely within that domain,
i.e. user@foo.bar.com is a valid match for .bar.com but not
for bar.com, which would require user@bar.com to match */
ENSURES_B( startPos <= constrainedStringLength );
if( !isWildcardMatch && \
( startPos < 1 || constrainedString[ startPos - 1 ] != '@' ) )
return( FALSE );
break;
case MATCH_URI:
{
URL_INFO urlInfo;
int status;
/* URIs can contain trailing location information that isn't
regarded as part of the URI for matching purposes so before
performing the match we have to parse the URL and only use
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -