📄 certchk.c
字号:
/****************************************************************************
* *
* Certificate Checking Routines *
* Copyright Peter Gutmann 1997-2003 *
* *
****************************************************************************/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) || defined( INC_CHILD )
#include "cert.h"
#include "certattr.h"
#include "../misc/asn1_rw.h"
#else
#include "cert/cert.h"
#include "cert/certattr.h"
#include "misc/asn1_rw.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* ExtKeyUsage to Key Usage Routines *
* *
****************************************************************************/
/* The following keyUsage settings are used based on extendedKeyUsage and
Netscape key usage extensions. In the following 'Y' = required, 'w' =
written but apparently not required, S = for signature keys only, E = for
encryption keys only, KA = for key agreement keys only.
dig non key dat key cer crl enc dec
sig rep enc enc agt sig sig onl onl
PKIX: -----------------------------------
serverAuth S E KA
clientAuth S
codeSign Y
email Y Y E
ipsecEndSys S E KA
ipsecTunnel S E KA
ipsecUser S E KA
timeStamping Y Y
ocsp Y
directoryService ?
MS: -----------------------------------
individualCodeSign Y
commercialCodeSign Y
ctlSign Y
tsa Y
sgc E
encryptedFS E
NS: -----------------------------------
sgc E
NS extensions: -----------------------------------
sslClient Y
sslServer Y
sMime S E
objectSign Y
sslCA Y w
sMimeCA Y w
objectSignCA Y w
-----------------------------------
dig non key dat key cer crl enc dec
sig rep enc enc agt sig sig onl onl */
/* Masks for various key usage types */
#define USAGE_SIGN_MASK ( CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
CRYPT_KEYUSAGE_NONREPUDIATION | \
CRYPT_KEYUSAGE_KEYCERTSIGN | \
CRYPT_KEYUSAGE_CRLSIGN )
#define USAGE_CRYPT_MASK ( CRYPT_KEYUSAGE_KEYENCIPHERMENT | \
CRYPT_KEYUSAGE_DATAENCIPHERMENT )
#define USAGE_KEYAGREEMENT_MASK ( CRYPT_KEYUSAGE_KEYAGREEMENT | \
CRYPT_KEYUSAGE_ENCIPHERONLY | \
CRYPT_KEYUSAGE_DECIPHERONLY )
/* Mask for key usage types that we don't check for consistency against
extended key usages. The two CA usages don't occur in extended key usage,
and non-repudiation has a somewhat peculiar status where no-one's quite
sure what it means and it can (in some interpretations) be transparently
replaced with the meaning of digitalSignature even if the two values are
dissimilar, so we don't check for consistency with this one */
#define USAGE_MASK_NONRELEVANT ( CRYPT_KEYUSAGE_NONREPUDIATION | \
CRYPT_KEYUSAGE_KEYCERTSIGN | \
CRYPT_KEYUSAGE_CRLSIGN )
/* Flags to denote the algorithm type */
#define ALGO_TYPE_SIGN 1
#define ALGO_TYPE_CRYPT 2
#define ALGO_TYPE_KEYAGREEMENT 4
/* Table mapping extended key usage values to key usage flags */
static const FAR_BSS struct {
const CRYPT_ATTRIBUTE_TYPE usageType;
const int keyUsageFlags;
} extendedUsageInfo[] = {
{ CRYPT_CERTINFO_EXTKEY_MS_INDIVIDUALCODESIGNING, /* individualCodeSigning */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_MS_COMMERCIALCODESIGNING, /* commercialCodeSigning */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_MS_CERTTRUSTLISTSIGNING, /* certTrustListSigning */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_MS_TIMESTAMPSIGNING, /* timeStampSigning */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_MS_SERVERGATEDCRYPTO, /* serverGatedCrypto */
CRYPT_KEYUSAGE_KEYENCIPHERMENT },
{ CRYPT_CERTINFO_EXTKEY_MS_ENCRYPTEDFILESYSTEM, /* encrypedFileSystem */
CRYPT_KEYUSAGE_KEYENCIPHERMENT },
{ CRYPT_CERTINFO_EXTKEY_SERVERAUTH, /* serverAuth */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_CLIENTAUTH, /* clientAuth */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_CODESIGNING, /* codeSigning */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_EMAILPROTECTION, /* emailProtection */
CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_NONREPUDIATION },
{ CRYPT_CERTINFO_EXTKEY_IPSECENDSYSTEM, /* ipsecEndSystem */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_IPSECTUNNEL, /* ipsecTunnel */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_IPSECUSER, /* ipsecUser */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_TIMESTAMPING, /* timeStamping */
CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_NONREPUDIATION },
{ CRYPT_CERTINFO_EXTKEY_OCSPSIGNING, /* ocspSigning */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_DIRECTORYSERVICE, /* directoryService */
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_CERTINFO_EXTKEY_NS_SERVERGATEDCRYPTO, /* serverGatedCrypto */
CRYPT_KEYUSAGE_KEYENCIPHERMENT },
{ CRYPT_ATTRIBUTE_NONE, 0 }
};
/* Table mapping Netscape cert-type flags to extended key usage flags */
static const FAR_BSS struct {
const int certType;
const int keyUsageFlags;
} certTypeInfo[] = {
{ CRYPT_NS_CERTTYPE_SSLCLIENT,
CRYPT_KEYUSAGE_DIGITALSIGNATURE },
{ CRYPT_NS_CERTTYPE_SSLSERVER,
CRYPT_KEYUSAGE_KEYENCIPHERMENT },
{ CRYPT_NS_CERTTYPE_SMIME,
CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_KEYENCIPHERMENT },
{ CRYPT_NS_CERTTYPE_OBJECTSIGNING,
CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_NONREPUDIATION },
{ CRYPT_NS_CERTTYPE_RESERVED, 0 },
{ CRYPT_NS_CERTTYPE_SSLCA,
CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
{ CRYPT_NS_CERTTYPE_SMIMECA,
CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
{ CRYPT_NS_CERTTYPE_OBJECTSIGNINGCA,
CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
{ 0, 0 }
};
/* Build up key usage flags consistent with the extended key usage purpose */
static int getExtendedKeyUsageFlags( const ATTRIBUTE_LIST *attributes,
const int algorithmType,
CRYPT_ATTRIBUTE_TYPE *errorLocus )
{
int keyUsage = 0, i;
for( i = 0; extendedUsageInfo[ i ].usageType != CRYPT_ATTRIBUTE_NONE; i++ )
{
const ATTRIBUTE_LIST *attributeListPtr = \
findAttributeField( attributes, extendedUsageInfo[ i ].usageType,
CRYPT_ATTRIBUTE_NONE );
int extendedUsage = 0;
/* If this usage isn't present, continue */
if( attributeListPtr == NULL )
continue;
/* If the usage is consistent with the algorithm type, add it */
if( algorithmType & ALGO_TYPE_SIGN )
extendedUsage |= extendedUsageInfo[ i ].keyUsageFlags & USAGE_SIGN_MASK;
if( algorithmType & ALGO_TYPE_CRYPT )
extendedUsage |= extendedUsageInfo[ i ].keyUsageFlags & USAGE_CRYPT_MASK;
if( algorithmType & ALGO_TYPE_KEYAGREEMENT )
extendedUsage |= extendedUsageInfo[ i ].keyUsageFlags & USAGE_KEYAGREEMENT_MASK;
/* If there's no key usage consistent with the extended usage and the
extended usage isn't some special-case usage, return an error */
if( !extendedUsage && extendedUsageInfo[ i ].keyUsageFlags )
{
*errorLocus = extendedUsageInfo[ i ].usageType;
return( CRYPT_ERROR_INVALID );
}
keyUsage |= extendedUsage;
}
return( keyUsage );
}
/* Build up key usage flags consistent with the Netscape cert-type purpose */
static int getNetscapeCertTypeFlags( const ATTRIBUTE_LIST *attributes,
const int algorithmType,
CRYPT_ATTRIBUTE_TYPE *errorLocus )
{
const ATTRIBUTE_LIST *attributeListPtr = \
findAttributeField( attributes, CRYPT_CERTINFO_NS_CERTTYPE,
CRYPT_ATTRIBUTE_NONE );
int nsCertType, keyUsage = 0, i;
/* If there isn't a Netscape cert-type extension present, exit */
if( attributeListPtr == NULL )
return( 0 );
nsCertType = ( int ) attributeListPtr->intValue;
/* The Netscape cert-type value is a bitfield containing the different
cert types. For each cert-type flag which is set, we set the
corresponding keyUsage flags */
for( i = 0; certTypeInfo[ i ].certType; i++ )
{
int nsUsage = 0;
/* If this isn't the currently-selected cert-type, continue */
if( !( nsCertType & certTypeInfo[ i ].certType ) )
continue;
/* If the usage is consistent with the algorithm type, add it */
if( algorithmType & ALGO_TYPE_SIGN )
nsUsage |= certTypeInfo[ i ].keyUsageFlags & USAGE_SIGN_MASK;
if( algorithmType & ALGO_TYPE_CRYPT )
nsUsage |= certTypeInfo[ i ].keyUsageFlags & USAGE_CRYPT_MASK;
if( algorithmType & ALGO_TYPE_KEYAGREEMENT )
nsUsage |= certTypeInfo[ i ].keyUsageFlags & USAGE_KEYAGREEMENT_MASK;
/* If there's no key usage consistent with the Netscape cert-type,
return an error */
if( !nsUsage )
{
*errorLocus = CRYPT_CERTINFO_NS_CERTTYPE;
return( CRYPT_ERROR_INVALID );
}
keyUsage |= nsUsage;
}
return( keyUsage );
}
/* Get key usage flags for a cert based on its extended key usage/Netscape
cert-type. Returns 0 if no extKeyUsage/cert-type values present */
int getKeyUsageFromExtKeyUsage( const CERT_INFO *certInfoPtr,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
int algorithmType = 0, keyUsage;
/* Determine the possible algorithm usage type(s) */
if( isCryptAlgo( certInfoPtr->publicKeyAlgo ) )
algorithmType |= ALGO_TYPE_CRYPT;
if( isSigAlgo( certInfoPtr->publicKeyAlgo ) )
algorithmType |= ALGO_TYPE_SIGN;
if( isKeyxAlgo( certInfoPtr->publicKeyAlgo ) )
algorithmType |= ALGO_TYPE_KEYAGREEMENT;
/* Get the key usage flags for the given extended/Netscape usage type(s)
and algorithm type */
keyUsage = getExtendedKeyUsageFlags( certInfoPtr->attributes,
algorithmType, errorLocus );
keyUsage |= getNetscapeCertTypeFlags( certInfoPtr->attributes,
algorithmType, errorLocus );
if( cryptStatusError( keyUsage ) )
{
*errorType = CRYPT_ERRTYPE_CONSTRAINT;
return( CRYPT_ERROR_INVALID );
}
return( keyUsage );
}
/****************************************************************************
* *
* Key Usage Routines *
* *
****************************************************************************/
/* Check that the key usage flags are consistent, checked if complianceLevel
>= CRYPT_COMPLIANCELEVEL_STANDARD */
static int checkKeyUsageFlags( const CERT_INFO *certInfoPtr,
const int complianceLevel,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
ATTRIBUTE_LIST *attributeListPtr;
BOOLEAN keyUsageCritical = 0;
BOOLEAN isCA = FALSE;
int extKeyUsage, keyUsage;
assert( isReadPtr( certInfoPtr, CERT_INFO ) );
assert( complianceLevel >= CRYPT_COMPLIANCELEVEL_STANDARD );
/* Obtain assorted cert information */
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_CA,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
isCA = attributeListPtr->intValue;
/* Get the key usage information. We recognise two distinct usage types,
the explicit (or implicit for v1 certs) keyUsage, and the extKeyUsage
based on any extended key usage extensions that may be present */
extKeyUsage = getKeyUsageFromExtKeyUsage( certInfoPtr, errorLocus,
errorType );
if( cryptStatusError( extKeyUsage ) )
return( extKeyUsage );
if( certInfoPtr->version == 1 && ( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
/* It's a v1 self-signed cert with no keyUsage present, any (normal)
key usage is permitted */
keyUsage = CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
CRYPT_KEYUSAGE_NONREPUDIATION | \
CRYPT_KEYUSAGE_KEYENCIPHERMENT;
else
{
/* It's not a v1 self-signed cert, get its keyUsage */
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
keyUsage = attributeListPtr->intValue;
keyUsageCritical = \
( attributeListPtr->flags & ATTR_FLAG_CRITICAL ) ? \
TRUE : FALSE;
}
else
{
int algorithmType = 0, netscapeUsage;
/* If we're doing a PKIX-compliant check, we need a keyUsage
(PKIX section 4.2.1.3) */
if( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_INVALID );
}
/* Some broken certs don't have any keyUsage present, if there's
nothing there allow at least some minimal usage. Note that
this is a non-CA usage, so setting it doesn't interfere with
the CA keyUsage checks below */
keyUsage = CRYPT_KEYUSAGE_DIGITALSIGNATURE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -