📄 certsig.c
字号:
sMemDisconnect( &stream );
if( issuerCertPresent )
unlockResource( issuerCertInfoPtr );
if( cryptStatusError( status ) )
{
zeroise( certObjectPtr, certObjectLength );
if( certObjectPtr != certObjectBuffer )
free( certObjectPtr );
free( signedCertObject );
return( status );
}
/* If there's no signing key present, pseudo-sign the certificate
information by writing the outer wrapper and moving the object into
the initialised state */
if( nonSigningKey )
{
if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
certInfoPtr->type == CRYPT_CERTTYPE_PKIUSER )
{
/* It's an unsigned OCSP request or PKI user info, write the
outer wrapper */
signedCertObjectLength = sizeofObject( certObjectLength );
sMemOpen( &stream, signedCertObject, signedCertObjectLength );
writeSequence( &stream, certObjectLength );
swrite( &stream, certObjectPtr, certObjectLength );
sMemDisconnect( &stream );
}
else
{
const int dataSize = certObjectLength + \
sizeofObject( sizeofShortInteger( 0 ) );
long dataStart;
assert( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );
/* It's an encryption-only key, wrap up the cert data with an
indication that private key POP will be performed via out-of-
band means and remember where the encoded subject name
starts */
signedCertObjectLength = sizeofObject( dataSize );
sMemOpen( &stream, signedCertObject, signedCertObjectLength );
writeSequence( &stream, dataSize );
dataStart = stell( &stream );
swrite( &stream, certObjectPtr, certObjectLength );
writeConstructed( &stream, sizeofShortInteger( 0 ), 2 );
writeShortInteger( &stream, 0, 1 );
sseek( &stream, dataStart );
readSequence( &stream, NULL ); /* Wrapper */
readUniversal( &stream ); /* Request ID */
readSequence( &stream, NULL ); /* Inner wrapper */
if( peekTag( &stream ) == MAKE_CTAG( 4 ) )
readUniversal( &stream ); /* Validity */
readConstructed( &stream, NULL, 5 ); /* Subj.name wrapper */
certInfoPtr->subjectDNptr = sMemBufPtr( &stream );
assert( sGetStatus( &stream ) == CRYPT_OK );
sMemDisconnect( &stream );
/* The pseudo-signature has been checked (since we just created
it), this also avoids nasty semantic problems with not-really-
signed CRMF requests with encryption-only keys) */
certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
}
certInfoPtr->certificate = signedCertObject;
certInfoPtr->certificateSize = signedCertObjectLength;
/* The object is now (pseudo-)signed and initialised */
certInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
krnlSendMessage( certInfoPtr->objectHandle,
RESOURCE_IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED,
CRYPT_IATTRIBUTE_INITIALISED );
/* Clean up */
zeroise( certObjectPtr, certObjectLength );
if( certObjectPtr != certObjectBuffer )
free( certObjectPtr );
return( CRYPT_OK );
}
/* Sign the certificate information */
status = createX509signature( signedCertObject, &signedCertObjectLength,
certObjectPtr, certObjectLength, signContext,
CRYPT_ALGO_SHA );
if( cryptStatusError( status ) )
{
zeroise( certObjectPtr, certObjectLength );
if( certObjectPtr != certObjectBuffer )
free( certObjectPtr );
return( status );
}
certInfoPtr->certificate = signedCertObject;
certInfoPtr->certificateSize = signedCertObjectLength;
/* CRMF and OCSP use a signature format which is almost, but not quite,
right, so if it's a signed CRMF or OCSP request we have to rewrite the
signature slightly to use the nonstandard format. Rewriting it here is
easier than trying to pass different "use nonstandard signature format"
flags down 20 levels of function calls to have it done by the
signature-generation code */
if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT || \
certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST )
{
BYTE *dataStart;
int totalSize, sigSize, newSigSize, delta;
/* Rewrite the outer wrapper to account for the overhead of the
extra tag(s), copy down the payload, and re-wrap the signature in
an extra [1] or [0] SEQUENCE wrapper. This rewrites:
SEQ {
...,
AlgoID,
BIT STRING
}
to:
SEQ' { -- CRMF SEQ' { -- OCSP
... ...
[1] { [0] {
AlgoID, SEQUENCE {
BIT STRING AlgoID,
} BIT STRING
} }
}
}
First we read the data and get location and size information for
the header, payload, and signature */
sMemConnect( &stream, signedCertObject, signedCertObjectLength );
readSequence( &stream, &totalSize );
dataStart = sMemBufPtr( &stream );
sigSize = totalSize - certObjectLength;
newSigSize = ( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT ) ? \
( int ) sizeofObject( sigSize ) : \
( int ) sizeofObject( sizeofObject( sigSize ) );
sMemDisconnect( &stream );
/* Next we open up a gap at the start of the data, write the new
total size (SEQ') into the gap, and move the payload (but not the
sig) back down again */
memmove( dataStart + 16, dataStart, totalSize );
sMemOpen( &stream, signedCertObject, 16 );
writeSequence( &stream, certObjectLength + newSigSize );
memmove( sMemBufPtr( &stream ), dataStart + 16, certObjectLength );
delta = ( int ) stell( &stream );
sMemDisconnect( &stream );
/* Finally, we skip over the payload, write the extra headers around
the signature ([1]{...} or [0]{ SEQUENCE {...}}), and move the
signature into place at the end of the new header */
sMemOpen( &stream, ( BYTE * ) signedCertObject + delta + \
certObjectLength, 8 );
if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
writeConstructed( &stream, sigSize, 1 );
else
{
writeConstructed( &stream, ( int ) sizeofObject( sigSize ), 0 );
writeSequence( &stream, sigSize );
}
memmove( sMemBufPtr( &stream ), dataStart + 16 + certObjectLength,
sigSize );
sMemDisconnect( &stream );
/* Adjust the size of the cert object to account for the extra tag */
certInfoPtr->certificateSize = ( int ) \
sizeofObject( certObjectLength + newSigSize );
}
/* If it's a certification request, it's now self-signed. In addition
the signature has been checked, since we just created it */
if( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
certInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
/* If it's a cert chain and the root is self-signed, the entire chain
counts as self-signed */
if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
{
int selfSigned;
status = krnlSendMessage( \
certInfoPtr->certChain[ certInfoPtr->certChainEnd - 1 ],
RESOURCE_IMESSAGE_GETATTRIBUTE, &selfSigned,
CRYPT_CERTINFO_SELFSIGNED );
if( cryptStatusOK( status ) && selfSigned )
certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
}
/* If it's a certificate, parse the signed form to locate the start of
the encoded issuer and subject DN and public key (the length is
recorded when the cert data is written, but their position in the cert
can't be determined until the cert has been signed). If it's a CRMF
request, remember the start of the encoded DN if there is one (the
issuer DN is already set up when the issuer cert is added) */
if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
{
sMemConnect( &stream, signedCertObject, signedCertObjectLength );
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 */
certInfoPtr->issuerDNptr = sMemBufPtr( &stream );
readUniversal( &stream ); /* Issuer DN */
readUniversal( &stream ); /* Validity */
certInfoPtr->subjectDNptr = sMemBufPtr( &stream );
readUniversal( &stream ); /* Subject DN */
certInfoPtr->publicKeyInfo = sMemBufPtr( &stream );
assert( sGetStatus( &stream ) == CRYPT_OK );
sMemDisconnect( &stream );
}
if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
{
sMemConnect( &stream, signedCertObject, signedCertObjectLength );
readSequence( &stream, NULL ); /* Outer wrapper */
readSequence( &stream, NULL );
readUniversal( &stream ); /* Request ID */
readSequence( &stream, NULL ); /* Inner wrapper */
if( peekTag( &stream ) == MAKE_CTAG( 4 ) )
readUniversal( &stream ); /* Validity */
if( peekTag( &stream ) == MAKE_CTAG( 5 ) )
{
readConstructed( &stream, NULL, 5 ); /* Subj.name wrapper */
certInfoPtr->subjectDNptr = sMemBufPtr( &stream );
}
assert( sGetStatus( &stream ) == CRYPT_OK );
sMemDisconnect( &stream );
}
/* Clean up */
zeroise( certObjectPtr, certObjectLength );
if( certObjectPtr != certObjectBuffer )
free( certObjectPtr );
return( status );
}
/****************************************************************************
* *
* Certificate Checking Functions *
* *
****************************************************************************/
/* Generate a nameID or issuerID. These are needed when storing/retrieving a
cert to/from a RDBMS, which can't handle the awkward heirarchical ID's
usually used in certs. There are two types of ID's, the nameID, which is
an SHA-1 hash of the DistinguishedName and used for X.509, and the
issuerID, which is an SHA-1 hash of the IssuerAndSerialNumber and used for
CRL's and CMS */
static int generateCertID( const void *dnPtr, const void *serialNumber,
const int serialNumberLength, BYTE *certID )
{
HASHFUNCTION hashFunction;
STREAM stream;
BYTE buffer[ 1024 ], *bufPtr = buffer;
int length = sizeofDN( dnPtr ), payloadSize;
int hashSize, status;
/* If it's an issuerID, add the size of the serial number and evaluate
the total size */
if( serialNumber != NULL )
{
payloadSize = length + \
sizeofInteger( serialNumber, serialNumberLength );
length = ( int ) sizeofObject( payloadSize );
}
/* Get the hash algorithm information */
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
/* Allocate a buffer for the ID information if necessary */
if( length > 1024 && ( bufPtr = malloc( length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
/* Write the relevant information to a buffer and hash the data to get
the ID. Since there are an infinite number of ways to misrepresent
DN's and the like, we recode them into the canonical form before
generating the ID to ensure that even if other software suddenly
changes the way it represents a DN, or the software which generated
a message requiring a certain cert encodes the DN differently to the
way the software which created the cert encodes it, we still
(hopefully) end up with the same ID */
sMemOpen( &stream, bufPtr, length );
if( serialNumber == NULL )
status = writeDN( &stream, dnPtr, DEFAULT_TAG );
else
{
writeSequence( &stream, payloadSize );
status = writeDN( &stream, dnPtr, DEFAULT_TAG );
if( cryptStatusOK( status ) )
status = writeInteger( &stream, serialNumber,
serialNumberLength, DEFAULT_TAG );
}
if( cryptStatusOK( status ) )
hashFunction( NULL, certID, bufPtr, length, HASH_ALL );
sMemClose( &stream );
if( bufPtr != buffer )
free( bufPtr );
if( cryptStatusError( status ) )
return( status );
return( CRYPT_OK );
}
/* Check the entries in an OCSP response object against a cert store. The
semantics for this one are a bit odd, the source information for the
check is from a request, but the destination information is in a response,
since we don't have a copy-and-verify function we do the checking from
the response even though, technically, it's the request data which is
being checked */
int checkOCSPResponse( CERT_INFO *certInfoPtr,
const CRYPT_KEYSET cryptKeyset )
{
REVOCATION_INFO *revocationInfo;
BOOLEAN isRevoked = FALSE;
/* Walk down the list of revocation entries fetching status information
on each one from the cert store */
for( revocationInfo = certInfoPtr->revocations;
revocationInfo != NULL; revocationInfo = revocationInfo->next )
{
MESSAGE_KEYMGMT_INFO getkeyInfo;
int status;
/* Determine the revocation status of the object. Unfortunateley
because of the way OCSP returns status information we can't just
return a yes/no response but have to perform multiple queries to
determine whether a cert is not revoked, revoked, or unknown.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -