📄 trustmgr.c
字号:
/****************************************************************************
* *
* Certificate Trust Management Routines *
* Copyright Peter Gutmann 1998-2008 *
* *
****************************************************************************/
/* The following code is actually part of the user rather than certificate
routines but it pertains to certificates so we include it here. Trust
information mutex handling is done in the user object so there are no
mutexes required here.
The interpretation of what represents a "trusted certificate" is somewhat
complex and open-ended, it's not clear whether what's being trusted is
the key in the certificate, the certificate, or the owner of the
certificate (corresponding to subjectKeyIdentifier, issuerAndSerialNumber/
certHash, or subject DN). The generally accepted form is to trust the
subject so we check for this in the certificate. The modification for
trusting the key is fairly simple to make if required */
#if defined( INC_ALL )
#include "cert.h"
#include "trustmgr.h"
#include "asn1.h"
#else
#include "cert/cert.h"
#include "cert/trustmgr.h"
#include "misc/asn1.h"
#endif /* Compiler-specific includes */
/* The size of the table of trust information. This must be a power of 2 */
#define TRUSTINFO_SIZE 256
/* Trusted certificate information */
typedef struct TI {
/* Identification information, the checksum and hash of the
certificate's subjectName and subjectKeyIdentifier */
int sCheck;
BYTE sHash[ HASH_DATA_SIZE + 4 ];
#if 0 /* sKID lookup isn't used at present */
int kCheck;
BYTE kHash[ HASH_DATA_SIZE + 4 ];
#endif /* 0 */
/* The trusted certificate. When we read trusted certificates from a
configuration file the certificate is stored in the encoded form to
save creating a pile of certificate objects that'll never be used.
When it's needed the certificate is created on the fly from the
encoded form. Conversely, when we get the trust information directly
from the user the certificate object already exists and the encoded
form isn't used */
BUFFER_OPT_FIXED( certObjectLength ) \
void *certObject;
int certObjectLength;
CRYPT_CERTIFICATE iCryptCert;
/* Pointer to the next entry */
struct TI *next; /* Next trustInfo record in the chain */
} TRUST_INFO;
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Extract ID fields from an encoded certificate. Since this isn't a
certificate object we have to parse the encoded data to locate the fields
that we're interested in */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
static int getCertIdInfo( IN_BUFFER( certObjectLength ) const void *certObject,
IN_LENGTH_SHORT_MIN( MIN_CRYPT_OBJECTSIZE ) \
const int certObjectLength,
OUT_PTR void **subjectDNptrPtr,
OUT_LENGTH_SHORT_Z int *subjectDNsizePtr )
{
STREAM stream;
void *subjectDNptr = DUMMY_INIT_PTR;
int subjectDNsize, status;
assert( isReadPtr( certObject, certObjectLength ) );
assert( isWritePtr( subjectDNptrPtr, sizeof( void * ) ) );
assert( isWritePtr( subjectDNsizePtr, sizeof( int ) ) );
REQUIRES( certObjectLength >= MIN_CRYPT_OBJECTSIZE && \
certObjectLength < MAX_INTLENGTH_SHORT );
/* Clear return values */
*subjectDNptrPtr = NULL;
*subjectDNsizePtr = 0;
/* Parse the certificate to locate the start of the encoded subject DN
and certificate extensions (if present) */
sMemConnect( &stream, certObject, certObjectLength );
readSequence( &stream, NULL ); /* Outer wrapper */
readSequence( &stream, NULL ); /* Inner wrapper */
if( peekTag( &stream ) == MAKE_CTAG( 0 ) )
readUniversal( &stream ); /* Version */
readUniversal( &stream ); /* Serial number */
readUniversal( &stream ); /* Signature algo */
readUniversal( &stream ); /* Issuer DN */
readUniversal( &stream ); /* Validity */
status = getStreamObjectLength( &stream, &subjectDNsize );
if( cryptStatusOK( status ) )
status = sMemGetDataBlock( &stream, &subjectDNptr, subjectDNsize );
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
*subjectDNptrPtr = subjectDNptr;
*subjectDNsizePtr = subjectDNsize;
status = sSkip( &stream, subjectDNsize );/* Subject DN */
#if 0 /* sKID lookup isn't used at present. Also this code should use the
parsing mechanism from dbx_rd.c to provide better checking */
const BYTE *extensionPtr;
int extensionSize = 0;
status = readUniversal( &stream ); /* Public key */
if( cryptStatusOK( status ) && \
peekTag( &stream ) == MAKE_CTAG( 3 ) )
{
status = readConstructed( &stream, &extensionSize, 3 );
if( cryptStatusOK( status ) )
{
extensionPtr = sMemBufPtr( &stream );
sSkip( &stream, extensionSize );
}
}
if( cryptStatusOK( status ) ) /* Signature */
status = readUniversal( &stream );
#endif /* 0 */
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
#if 0 /* sKID lookup isn't used at present. Also this code should use the
parsing mechanism from dbx_rd.c to provide better checking */
/* Look for the subjectKeyID in the extensions. It's easier to do a
pattern match than to try and parse the extensions */
subjectKeyIDptr = NULL;
subjectKeyIDsize = 0;
for( i = 0; i < extensionSize - 64; i++ )
{
/* Look for the OID. This potentially skips two bytes at a time,
but this is safe since the preceding bytes can never contain
either of these two values (they're 0x30, len) */
if( extensionPtr[ i++ ] != BER_OBJECT_IDENTIFIER || \
extensionPtr[ i++ ] != 3 )
continue;
if( memcmp( extensionPtr + i, "\x55\x1D\x0E", 3 ) )
continue;
i += 3;
/* We've found the OID (with 1.1e-12 error probability), skip the
critical flag if necessary */
if( extensionPtr[ i ] == BER_BOOLEAN )
i += 3;
/* Check for the OCTET STRING and a reasonable length */
if( extensionPtr[ i++ ] != BER_OCTETSTRING || \
extensionPtr[ i ] & 0x80 )
continue;
/* Extract the key ID */
if( i + extensionPtr[ i ] <= extensionSize )
{
subjectKeyIDsize = extensionPtr[ i++ ];
subjectKeyIDptr = extensionPtr + i;
}
}
#endif /* 0 */
return( CRYPT_OK );
}
/****************************************************************************
* *
* Retrieve Trusted Certificate Information *
* *
****************************************************************************/
/* Find the trust information entry for a given certificate. Since this
function is called from external code that doesn't know about trust
information internals the pointer is a void *, as it is for all other
externally-accessible trust management functions */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
void *findTrustEntry( INOUT TYPECAST( TRUST_INFO ** ) void *trustInfoPtrPtr,
IN_HANDLE const CRYPT_CERTIFICATE iCryptCert,
const BOOLEAN getIssuerEntry )
{
TRUST_INFO **trustInfoIndex = ( TRUST_INFO ** ) trustInfoPtrPtr;
const TRUST_INFO *trustInfoCursor;
DYNBUF nameDB;
BYTE sHash[ HASH_DATA_SIZE + 8 ];
BOOLEAN nameHashed = FALSE;
int sCheck, trustInfoEntry, iterationCount, status;
assert( isWritePtr( trustInfoPtrPtr, \
sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE ) );
REQUIRES_N( isHandleRangeValid( iCryptCert ) );
/* If we're trying to get a trusted issuer certificate and we're already
at a self-signed (CA root) certificate, don't return it. This check
is necessary because self-signed certificates have issuer name ==
subject name so once we get to a self-signed certificate's subject DN
an attempt to fetch its issuer would just repeatedly fetch the same
certificate */
if( getIssuerEntry )
{
int value;
status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_SELFSIGNED );
if( cryptStatusError( status ) || value )
return( NULL );
}
/* Set up the information needed to find the trusted certificate */
status = dynCreate( &nameDB, iCryptCert, getIssuerEntry ? \
CRYPT_IATTRIBUTE_ISSUER : CRYPT_IATTRIBUTE_SUBJECT );
if( cryptStatusError( status ) )
return( NULL );
sCheck = checksumData( dynData( nameDB ), dynLength( nameDB ) );
trustInfoEntry = sCheck & ( TRUSTINFO_SIZE - 1 );
ENSURES_N( trustInfoEntry >= 0 && trustInfoEntry < TRUSTINFO_SIZE );
/* Check to see whether something with the requested DN is present */
for( trustInfoCursor = trustInfoIndex[ trustInfoEntry ], \
iterationCount = 0; \
trustInfoCursor != NULL && \
iterationCount < FAILSAFE_ITERATIONS_MED; \
trustInfoCursor = trustInfoCursor->next, iterationCount++ )
{
/* Perform a quick check using a checksum of the name to weed out
most entries */
if( trustInfoCursor->sCheck == sCheck )
{
if( !nameHashed )
{
hashData( sHash, HASH_DATA_SIZE, dynData( nameDB ),
dynLength( nameDB ) );
nameHashed = TRUE;
}
if( !memcmp( trustInfoCursor->sHash, sHash, HASH_DATA_SIZE ) )
{
dynDestroy( &nameDB );
return( ( TRUST_INFO * ) trustInfoCursor );
}
}
}
ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MED );
dynDestroy( &nameDB );
return( NULL );
}
/* Retrieve trusted certificates */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
CRYPT_CERTIFICATE getTrustedCert( INOUT TYPECAST( TRUST_INFO ** ) \
void *trustInfoPtrPtr )
{
TRUST_INFO *trustInfo = trustInfoPtrPtr;
int status;
assert( isWritePtr( trustInfoPtrPtr, sizeof( TRUST_INFO ) ) );
/* If the certificate hasn't already been instantiated yet, do so now */
if( trustInfo->iCryptCert == CRYPT_ERROR )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
/* Instantiate the certificate */
setMessageCreateObjectIndirectInfo( &createInfo, trustInfo->certObject,
trustInfo->certObjectLength,
CRYPT_CERTTYPE_CERTIFICATE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
{
assert( DEBUG_WARN );
return( status );
}
/* The certificate was successfully instantiated, free its stored
encoded form */
zeroise( trustInfo->certObject, trustInfo->certObjectLength );
clFree( "getTrustedCert", trustInfo->certObject );
trustInfo->certObject = NULL;
trustInfo->certObjectLength = 0;
trustInfo->iCryptCert = createInfo.cryptHandle;
}
/* Return the trusted certificate */
return( trustInfo->iCryptCert );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int enumTrustedCerts( INOUT TYPECAST( TRUST_INFO ** ) void *trustInfoPtrPtr,
IN_HANDLE_OPT const CRYPT_CERTIFICATE iCryptCtl,
IN_HANDLE_OPT const CRYPT_KEYSET iCryptKeyset )
{
TRUST_INFO **trustInfoIndex = ( TRUST_INFO ** ) trustInfoPtrPtr;
int i;
assert( isWritePtr( trustInfoPtrPtr, \
sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE ) );
REQUIRES( ( iCryptCtl == CRYPT_UNUSED && \
iCryptKeyset == CRYPT_UNUSED ) || \
( iCryptCtl == CRYPT_UNUSED && \
isHandleRangeValid( iCryptKeyset ) ) || \
( isHandleRangeValid( iCryptCtl ) && \
iCryptKeyset == CRYPT_UNUSED ) );
/* If there's no destination for the trusted certificates supplied, it's
a presence check only */
if( iCryptCtl == CRYPT_UNUSED && iCryptKeyset == CRYPT_UNUSED )
{
for( i = 0; i < TRUSTINFO_SIZE; i++ )
{
if( trustInfoIndex[ i ] != NULL )
return( CRYPT_OK );
}
return( CRYPT_ERROR_NOTFOUND );
}
/* Send each trusted certificate to the given object, either a
certificate trust list or a keyset */
for( i = 0; i < TRUSTINFO_SIZE; i++ )
{
TRUST_INFO *trustInfoCursor;
int iterationCount;
for( trustInfoCursor = trustInfoIndex[ i ], iterationCount = 0; \
trustInfoCursor != NULL && \
iterationCount < FAILSAFE_ITERATIONS_MED; \
trustInfoCursor = trustInfoCursor->next, iterationCount++ )
{
const CRYPT_CERTIFICATE iCryptCert = \
getTrustedCert( trustInfoCursor );
int status;
if( cryptStatusError( iCryptCert ) )
return( iCryptCert );
if( iCryptCtl != CRYPT_UNUSED )
{
/* We're sending trusted certificates to a certificate trust
list */
status = krnlSendMessage( iCryptCtl, IMESSAGE_SETATTRIBUTE,
( void * ) &iCryptCert,
CRYPT_IATTRIBUTE_CERTCOLLECTION );
}
else
{
MESSAGE_KEYMGMT_INFO setkeyInfo;
/* We're sending trusted certificates to a keyset */
setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
NULL, 0, KEYMGMT_FLAG_NONE );
setkeyInfo.cryptHandle = iCryptCert;
status = krnlSendMessage( iCryptKeyset, IMESSAGE_KEY_SETKEY,
&setkeyInfo,
KEYMGMT_ITEM_PUBLICKEY );
}
if( cryptStatusError( status ) )
return( status );
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Add/Update Trusted Certificate Information *
* *
****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -