📄 certrust.c
字号:
/****************************************************************************
* *
* Certificate Trust Management Routines *
* Copyright Peter Gutmann 1998-2003 *
* *
****************************************************************************/
/* The following code is actually part of the user rather than certificate
routines, but it pertains to certificates so we include it here.
The interpretation of what represents a "trusted cert" is somewhat complex
and open-ended, it's not clear whether what's being trusted is the key
in the cert, the cert, or the owner of the cert (corresponding to
subjectKeyIdentifier, issuerAndSerialNumber/certHash, or subject DN). The
generally accepted form is to trust the subject, so we check for this in
the cert. The modification for trusting the key in the cert is fairly
simple to make if required */
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) || defined( INC_CHILD )
#include "cert.h"
#include "../misc/asn1_rw.h"
#else
#include "cert/cert.h"
#include "misc/asn1_rw.h"
#endif /* Compiler-specific includes */
/* The size of the table of trust information. This must be a power of 2 */
#define TRUSTINFO_SIZE 256
/* The size of the hashed identifier info */
#define HASH_SIZE 20
/* Trusted certificate information */
typedef struct TI {
/* Identification information, the checksum and hash of the cert
subjectName and subjectKeyIdentifier */
int sCheck, kCheck;
BYTE sHash[ HASH_SIZE ], kHash[ HASH_SIZE ];
/* The trusted certificate. When we read trusted certs from a config
file, the cert is stored in the encoded form to save creating a pile
of cert objects that will never be used, when it's needed the cert is
created on the fly from the encoded form. When we get the trust info
directly from the user, the cert object already exists and the
encoded form isn't used */
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 *
* *
****************************************************************************/
/* Hash data */
static void hashData( BYTE *hash, const void *data, const int dataLength )
{
static HASHFUNCTION hashFunction = NULL;
/* Get the hash algorithm information if necessary */
if( hashFunction == NULL )
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, NULL );
/* Hash the data */
if( dataLength <= 0 )
memset( hash, 0, HASH_SIZE );
else
hashFunction( NULL, hash, ( BYTE * ) data, dataLength, HASH_ALL );
}
/****************************************************************************
* *
* Trust Information Management Routines *
* *
****************************************************************************/
/* Find the trust info entry for a given cert */
void *findTrustEntry( void *trustInfoPtr, const CRYPT_CERTIFICATE iCryptCert,
const BOOLEAN getIssuerEntry )
{
TRUST_INFO **trustInfoIndex = ( TRUST_INFO ** ) trustInfoPtr;
const TRUST_INFO *trustInfoCursor;
DYNBUF nameDB;
BYTE sHash[ HASH_SIZE ];
BOOLEAN nameHashed = FALSE;
int sCheck, status;
status = dynCreate( &nameDB, iCryptCert, getIssuerEntry ? \
CRYPT_IATTRIBUTE_ISSUER : CRYPT_IATTRIBUTE_SUBJECT );
if( cryptStatusError( status ) )
return( NULL );
sCheck = checksumData( dynData( nameDB ), dynLength( nameDB ) );
trustInfoCursor = trustInfoIndex[ sCheck & ( TRUSTINFO_SIZE - 1 ) ];
/* Check to see whether something with the requested DN is present */
while( trustInfoCursor != NULL )
{
/* Perform a quick check using a checksum of the name to weed out
most entries */
if( trustInfoCursor->sCheck == sCheck )
{
if( !nameHashed )
{
hashData( sHash, dynData( nameDB ), dynLength( nameDB ) );
nameHashed = TRUE;
}
if( !memcmp( trustInfoCursor->sHash, sHash, HASH_SIZE ) )
{
dynDestroy( &nameDB );
return( ( TRUST_INFO * ) trustInfoCursor );
}
}
trustInfoCursor = trustInfoCursor->next;
}
dynDestroy( &nameDB );
return( NULL );
}
/* Add and delete a trust entry */
static int addEntry( void *trustInfoPtr, const CRYPT_CERTIFICATE iCryptCert,
const void *certObject, const int certObjectLength )
{
TRUST_INFO **trustInfoIndex = ( TRUST_INFO ** ) trustInfoPtr;
CRYPT_CONTEXT iCryptContext;
TRUST_INFO *newElement;
BOOLEAN recreateCert = FALSE;
int trustInfoEntry;
/* If we're adding a cert, check whether it has a context attached and
if it does, whether it's a public-key context. If there's no context
attached (it's a data-only cert) or the attached context is a
private-key context (which we don't want to leave hanging around in
memory, or which could be in a removable crypto device), we don't try
and use the cert but instead add the cert data and re-instantiate a
new cert with attached public-key context if required */
if( certObject == NULL )
{
int status;
status = krnlSendMessage( iCryptCert, IMESSAGE_GETDEPENDENT,
&iCryptContext, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
/* There's no context associated with this cert, we'll have to
recreate it later */
recreateCert = TRUE;
else
{
status = krnlSendMessage( iCryptCert, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_PRIVATE );
if( cryptStatusOK( status ) )
/* The context associated with the cert is a private-key
context, recreate it later as a public-key context */
recreateCert = TRUE;
}
}
/* Allocate memory for the new element and copy the information across */
if( ( newElement = ( TRUST_INFO * ) \
clAlloc( "addEntry", sizeof( TRUST_INFO ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memset( newElement, 0, sizeof( TRUST_INFO ) );
if( certObject == NULL )
{
DYNBUF subjectDB, subjectKeyDB;
BOOLEAN hasSKID = FALSE;
int status;
/* Generate the checksum and hash of the cert object's subject name and
key ID */
status = dynCreate( &subjectDB, iCryptCert, CRYPT_IATTRIBUTE_SUBJECT );
if( cryptStatusError( status ) )
return( status );
status = dynCreate( &subjectKeyDB, iCryptCert,
CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
if( cryptStatusOK( status ) )
hasSKID = TRUE;
newElement->sCheck = checksumData( dynData( subjectDB ),
dynLength( subjectDB ) );
hashData( newElement->sHash, dynData( subjectDB ),
dynLength( subjectDB ) );
if( hasSKID )
{
newElement->kCheck = checksumData( dynData( subjectKeyDB ),
dynLength( subjectKeyDB ) );
hashData( newElement->kHash, dynData( subjectKeyDB ),
dynLength( subjectKeyDB ) );
dynDestroy( &subjectKeyDB );
}
else
{
newElement->kCheck = 0;
hashData( newElement->kHash, NULL, 0 );
}
dynDestroy( &subjectDB );
}
if( certObject != NULL || recreateCert )
{
DYNBUF certDB;
int objectLength = certObjectLength, status;
/* If we're using the data from an existing cert object, all we still
need is the encoded data */
if( recreateCert )
{
/* Get the encoded cert */
status = dynCreate( &certDB, iCryptCert,
CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
certObject = dynData( certDB );
objectLength = dynLength( certDB );
}
else
{
STREAM stream;
const BYTE *extensionPtr;
const void *subjectDNptr, *subjectKeyIDptr;
int subjectDNsize, subjectKeyIDsize;
int extensionSize = 0, i;
/* Parse the certificate to locate the start of the encoded
subject DN and cert 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 ); /* Sig.algo */
readUniversal( &stream ); /* Issuer DN */
readUniversal( &stream ); /* Validity */
subjectDNptr = sMemBufPtr( &stream );
readSequence( &stream, &subjectDNsize );
subjectDNsize = sizeofObject( subjectDNsize );
readUniversal( &stream ); /* Subject DN */
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 );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
clFree( "addEntry", newElement );
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
/* Now 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -