📄 chk_use.c
字号:
implicit/undefined */
if( certInfoPtr->version == 1 && \
( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
{
/* If it's claiming to be a CA cert by virtue of being a v1 self-
signed cert, there can't be any v3 CA attributes (or any v3
attributes for that matter) present. Unfortunately we can't just
check for the complete non-presence of attributes because the
cert-import code will have converted an email address in the DN
into the appropriate altName component, creating at least one
valid (in this case) attribute */
if( checkAttributePresent( certInfoPtr->attributes,
CRYPT_CERTINFO_BASICCONSTRAINTS ) || \
checkAttributePresent( certInfoPtr->attributes,
CRYPT_CERTINFO_KEYUSAGE ) || \
extKeyUsage != 0 )
{
setErrorValues( CRYPT_CERTINFO_VERSION,
CRYPT_ERRTYPE_ATTR_VALUE );
return( CRYPT_ERROR_INVALID );
}
/* It's a v1 self-signed cert with no keyUsage present, don't
perform any usage-specific checks */
return( CRYPT_OK );
}
/* Get the cert's keyUsage. If we're running at a reduced compliance
level and the CA flag is set and keyUsage isn't or vice versa, we
synthesise the required value from the other value in order to pass
the checks that follow */
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
keyUsage = attributeListPtr->intValue;
keyUsageCritical = \
( attributeListPtr->flags & ATTR_FLAG_CRITICAL ) ? TRUE : FALSE;
/* If the CA key usages are set, make sure that the CA flag is set in
an appropriate manner */
if( complianceLevel <= CRYPT_COMPLIANCELEVEL_STANDARD && \
( keyUsage & specificUsage & ( CRYPT_KEYUSAGE_CRLSIGN | \
CRYPT_KEYUSAGE_KEYCERTSIGN ) ) && \
!isCA )
isCA = TRUE;
}
else
{
/* There's no keyUsage information present, start with no usage
details */
keyUsage = 0;
/* If the CA flag is set, make sure that the keyUsage is set in an
appropriate manner */
if( complianceLevel <= CRYPT_COMPLIANCELEVEL_STANDARD && isCA )
keyUsage = CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN;
/* Some broken certs don't have any keyUsage present, which is meant
to imply that the cert can be used for any usage that the key is
capable of, modulo the magic usages keyCertSign and crlSign. To
handle this, we map the algorithm type to the matching usage
types. In theory the usage may be further modified by the cert
policy, extKeyUsage, and who knows what else, but in the presence
of a cert like that it's up to the user to sort out what they
want to do with it.
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,
fixAttributes() will have mapped the Netscape usage to the
equivalent X.509 usage, so there's always a keyUsage present */
if( isCryptAlgo( certInfoPtr->publicKeyAlgo ) )
keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
if( isSigAlgo( certInfoPtr->publicKeyAlgo ) )
keyUsage |= CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
CRYPT_KEYUSAGE_NONREPUDIATION;
if( isKeyxAlgo( certInfoPtr->publicKeyAlgo ) )
keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
}
caKeyUsage = keyUsage & ( CRYPT_KEYUSAGE_CRLSIGN | \
CRYPT_KEYUSAGE_KEYCERTSIGN );
/* Apply the trusted-usage restrictions if necessary */
rawKeyUsage = keyUsage;
rawExtKeyUsage = extKeyUsage;
if( trustedUsage != CRYPT_ERROR )
{
keyUsage &= trustedUsage;
extKeyUsage &= trustedUsage;
}
/* If we're looking for a CA cert, make sure that the basicConstraints
CA flag is set and the keyUsage indicates a CA usage (PKIX sections
4.2.1.3 and 4.2.1.10). RFC 2459 left this open, it was made explicit
in RFC 3280 */
if( isGeneralCheck && ( flags & CHECKKEY_FLAG_CA ) )
{
if( !isCA )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( !( caKeyUsage & specificUsage ) )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* There is one universal case in which a key is regarded as invalid for
the requested use and that's when it's explicitly not trusted for the
purpose */
if( specificUsage != CRYPT_UNUSED && trustedUsage != CRYPT_ERROR && \
!( specificUsage & keyUsage ) )
{
setErrorValues( CRYPT_CERTINFO_TRUSTED_USAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If we're doing a reduced level of checking, we're done */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_STANDARD )
return( CRYPT_OK );
/* 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. In other words this
check tests for an XOR relation, ( CA && kU ) || ( !CA && !kU ).
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 (PKIX sections 4.2.1.3 and 4.2.1.10). RFC 2459
left this open, it was made explicit in RFC 3280 */
if( isCA )
{
/* It's a CA cert, make sure that a CA keyUsage is set */
if( !( caKeyUsage | extKeyUsage ) )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
else
/* It's a non-CA cert, make sure that no CA keyUsage is set */
if( ( caKeyUsage | extKeyUsage ) & ( CRYPT_KEYUSAGE_CRLSIGN | \
CRYPT_KEYUSAGE_KEYCERTSIGN ) )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Check and enforce the keyUsage if required (PKIX section 4.2.1.3).
RFC 2459 included some waffly text about critical vs. non-critical
usage, RFC 3280 made this explicit regardless of criticality */
if( specificUsage != CRYPT_UNUSED )
{
BOOLEAN usageOK = FALSE;
/* If it's a key agreement usage the checking gets a bit complex
(PKIX-ALGS section 2.3.3), we have to make sure that it's both a
permitted usage and not an excluded usage */
if( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL && \
( specificUsage & ( CRYPT_KEYUSAGE_ENCIPHERONLY | \
CRYPT_KEYUSAGE_DECIPHERONLY ) ) )
{
const int excludedUsage = \
( specificUsage & CRYPT_KEYUSAGE_ENCIPHERONLY ) ? \
CRYPT_KEYUSAGE_DECIPHERONLY : CRYPT_KEYUSAGE_ENCIPHERONLY;
if( ( keyUsage & specificUsage ) && !( keyUsage & excludedUsage ) )
usageOK = TRUE;
}
else
/* Conventional usage flag, do a straight check */
if( keyUsage & specificUsage )
usageOK = TRUE;
if( !usageOK )
{
setErrorValues( ( rawKeyUsage & specificUsage ) ? \
CRYPT_CERTINFO_TRUSTED_USAGE : \
CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* Switch back to the original usage values (before adjustment by
trusted-usage values) because after this point we're performing
consistency checks on the values and need to check all of the bits */
keyUsage = rawKeyUsage;
extKeyUsage = rawExtKeyUsage;
/* Make sure that mutually exclusive flags aren't set (PKIX-ALGS section
2.3.3) */
if( isGeneralCheck && \
( 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. RFC 2459 included some waffly text
about critical vs. non-critical usage, RFC 3280 made this explicit
regardless of criticality, although the details were actually moved
into RFC 3279, which specifies the algorithms used in PKIX */
if( isGeneralCheck && \
( ( ( 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) */
keyUsage &= ~USAGE_MASK_NONRELEVANT;
extKeyUsage &= ~USAGE_MASK_NONRELEVANT;
/* If there's no key usage based on extended key usage present, there's
nothing further to check */
if( !extKeyUsage || complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
return( CRYPT_OK );
/* If we're not doing at least partial PKIX checking, we're done */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
return( CRYPT_OK );
/* If we're being asked to check for private-key constraints, check and
enforce the privateKeyUsage attribute if there's one present */
if( ( flags & CHECKKEY_FLAG_PRIVATEKEY ) && \
checkAttributePresent( certInfoPtr->attributes,
CRYPT_CERTINFO_PRIVATEKEYUSAGEPERIOD ) )
{
const time_t currentTime = getTime();
if( currentTime < MIN_TIME_VALUE )
{
/* Time is broken, we can't reliably check for expiry times */
setErrorValues( CRYPT_CERTINFO_PRIVATEKEY_NOTBEFORE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
attributeListPtr = \
findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_PRIVATEKEY_NOTBEFORE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
currentTime < *( ( time_t * ) attributeListPtr->value ) )
{
setErrorValues( CRYPT_CERTINFO_PRIVATEKEY_NOTBEFORE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
attributeListPtr = \
findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_PRIVATEKEY_NOTAFTER,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
currentTime > *( ( time_t * ) attributeListPtr->value ) )
{
setErrorValues( CRYPT_CERTINFO_PRIVATEKEY_NOTAFTER,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* If we're just performing a key-usability check rather than a general
check that the key usage is in order, we're done */
if( !isGeneralCheck )
return( CRYPT_OK );
/* If the CA key usages are set, an encryption key usage shouldn't be
set (PKIX-ALGS, section 2.3.1) */
if( isCA && \
( keyUsage & extKeyUsage & ( CRYPT_KEYUSAGE_KEYENCIPHERMENT | \
CRYPT_KEYUSAGE_DATAENCIPHERMENT ) ) )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* 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 (PKIX section 4.2.1.13). To
perform this check we first check for situations where we *don't*
have to perform the check, and only if none of these occur do we
perform the actual check.
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 there's no critical key usage present we can exit without
performing further checks */
if( !keyUsageCritical )
return( CRYPT_OK );
/* If we find an extended key usage and it's non-critical (which
means that all extended usages are non-critical since they're
all in the same extension), return */
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 ) )
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 );
}
/* If the encipherOnly or decipherOnly bits are set, the keyAgreement
bit most also be set (PKIX section 4.2.1.3). Actually the spec
merely says "undefined", but we interpret this to mean that they
should be consistent. This situation occurs because the encipher/
decipher-only usages were tacked on as modifiers long after
keyAgreement was defined and make it entirely redundant, in the same
way that the CA keyUsages make the basicConstraints CA flag
redundant */
if( ( keyUsage & ( CRYPT_KEYUSAGE_ENCIPHERONLY | \
CRYPT_KEYUSAGE_DECIPHERONLY ) ) && \
!( keyUsage & CRYPT_KEYUSAGE_KEYAGREEMENT ) )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE, CRYPT_ERRTYPE_ATTR_VALUE );
return( CRYPT_ERROR_INVALID );
}
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -