📄 certchn.c
字号:
CRYPT_CERTINFO_SELFSIGNED );
if( cryptStatusOK( status ) && selfSigned )
certChainPtr->flags |= CERT_FLAG_SELFSIGNED;
krnlReleaseObject( certChainPtr->objectHandle );
return( CRYPT_OK );
}
/* Read certificate chain/sequence information */
int readCertChain( STREAM *stream, CRYPT_CERTIFICATE *iCryptCert,
const CRYPT_USER cryptOwner,
const CRYPT_CERTTYPE_TYPE type,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const BOOLEAN dataOnlyCert )
{
CRYPT_CERTIFICATE iCertChain[ MAX_CHAINLENGTH ];
int certSequenceLength, endPos, certChainEnd = 0, status = CRYPT_OK;
assert( type == CRYPT_CERTTYPE_CERTCHAIN || \
type == CRYPT_ICERTTYPE_CMS_CERTSET || \
type == CRYPT_ICERTTYPE_SSL_CERTCHAIN );
assert( ( keyIDtype == CRYPT_KEYID_NONE && keyID == NULL && \
keyIDlength == 0 ) || \
( ( keyIDtype == CRYPT_IKEYID_KEYID || \
keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ) && \
keyID != NULL && keyIDlength > 16 ) );
/* If it's a PKCS #7 chain, skip the contentType OID, read the content
encapsulation and header if necessary, and burrow down into the PKCS
#7 content */
if( type == CRYPT_CERTTYPE_CERTCHAIN )
{
long integer;
int length, oidLength;
/* Read the wrapper */
readUniversal( stream );
readConstructed( stream, NULL, 0 );
readSequence( stream, NULL );
/* Read the version number (1 = PKCS #7 v1.5, 2 = PKCS #7 v1.6,
3 = S/MIME with attribute certificate(s)), and (should be empty)
SET OF DigestAlgorithmIdentifier */
readShortInteger( stream, &integer );
status = readSet( stream, &length );
if( cryptStatusOK( status ) && ( integer < 1 || integer > 3 ) )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
return( status );
if( length > 0 )
sSkip( stream, length );
/* Read the ContentInfo header, contentType OID and the inner content
encapsulation. Sometimes we may (incorrectly) get passed actual
signed data (rather than degenerate zero-length data signifying a
pure cert chain), if there's data present we skip it */
readSequenceI( stream, &length );
status = readRawObject( stream, NULL, &oidLength, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
if( length == CRYPT_UNUSED )
/* It's an indefinite-length ContentInfo, check for the EOC */
status = checkEOC( stream );
else
/* If we've been fed signed data (i.e. the ContentInfo has the
content field present), skip the content to get to the cert
chain */
if( length > sizeofObject( oidLength ) )
status = readUniversal( stream );
}
if( type == CRYPT_CERTTYPE_CERTCHAIN || \
type == CRYPT_ICERTTYPE_CMS_CERTSET )
status = readConstructedI( stream, &certSequenceLength, 0 );
else
/* There's no outer wrapper to give us length information for an SSL
cert chain, however the length will be equal to the total stream
size */
certSequenceLength = sMemBufSize( stream );
if( cryptStatusError( status ) )
return( status );
/* If it's a definite-length chain, determine where it ends */
if( certSequenceLength != CRYPT_UNUSED )
endPos = stell( stream ) + certSequenceLength;
/* We've finally reached the certificate(s), read the collection of certs
into cert objects. We allow for a bit of slop for software that gets
the length encoding wrong by a few bytes */
while( certSequenceLength == CRYPT_UNUSED || \
stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
{
CRYPT_CERTIFICATE iNewCert;
/* Make sure that we don't overflow the chain */
if( certChainEnd >= MAX_CHAINLENGTH - 1 )
{
freeCertChain( iCertChain, certChainEnd );
return( CRYPT_ERROR_OVERFLOW );
}
/* If it's an SSL cert chain, there's a 24-bit length field between
certs */
if( type == CRYPT_ICERTTYPE_SSL_CERTCHAIN )
sSkip( stream, 3 );
/* Read the next cert and add it to the chain. When importing the
chain from an external (untrusted) source we create standard certs
so we can check the signatures on each link in the chain. When
importing from a trusted source we create data-only certs, once
we've got all the certs and know which cert is the leaf, we can
go back and decode the public key information for it */
status = importCert( sMemBufPtr( stream ), sMemDataLeft( stream ),
&iNewCert, cryptOwner, CRYPT_KEYID_NONE,
NULL, 0, dataOnlyCert ? \
CERTFORMAT_DATAONLY : \
CRYPT_CERTTYPE_CERTIFICATE );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
/* Add the newly-read cert to the chain and skip over its
encoded data. Unfortunately due to the mixing of stream and
non-stream functions we have to do this in a somewhat
roundabout manner by getting the length of the data in the
newly-created cert object and then skipping that far ahead in
the input stream */
iCertChain[ certChainEnd++ ] = iNewCert;
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iNewCert, IMESSAGE_CRT_EXPORT,
&msgData, CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusOK( status ) )
status = sSkip( stream, msgData.length );
}
if( cryptStatusError( status ) )
{
if( certChainEnd > 0 )
freeCertChain( iCertChain, certChainEnd );
return( status );
}
/* If it's encoded using the indefinite form and we find the EOC
octets, exit */
if( certSequenceLength == CRYPT_UNUSED )
{
status = checkEOC( stream );
if( cryptStatusError( status ) )
return( status );
if( status == TRUE )
/* We've seen EOC octets, we're done */
break;
}
}
/* We must have read at least one cert in order to create a chain */
if( certChainEnd <= 0 )
return( CRYPT_ERROR_BADDATA );
/* Build the complete chain from the individual certs */
return( buildCertChain( iCryptCert, iCertChain, certChainEnd,
keyIDtype, keyID, keyIDlength ) );
}
/* Fetch a sequence of certs from an object to create a cert chain */
int assembleCertChain( CRYPT_CERTIFICATE *iCertificate,
const CRYPT_HANDLE iCertSource,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const int options )
{
CRYPT_CERTIFICATE iCertChain[ MAX_CHAINLENGTH ], lastCert;
MESSAGE_KEYMGMT_INFO getnextcertInfo;
const int chainOptions = options & KEYMGMT_FLAG_DATAONLY_CERT;
int stateInfo = CRYPT_ERROR, certChainEnd = 1, status;
/* Get the initial cert based on the key ID */
setMessageKeymgmtInfo( &getnextcertInfo, keyIDtype, keyID, keyIDlength,
&stateInfo, sizeof( int ),
options & KEYMGMT_MASK_CERTOPTIONS );
status = krnlSendMessage( iCertSource, IMESSAGE_KEY_GETFIRSTCERT,
&getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusError( status ) )
return( status );
iCertChain[ 0 ] = lastCert = getnextcertInfo.cryptHandle;
/* Fetch subsequent certs that make up the chain based on the state
information. Since the basic options apply only to the leaf cert,
we only allow the data-only-cert flag at this point */
setMessageKeymgmtInfo( &getnextcertInfo, CRYPT_KEYID_NONE, NULL, 0,
&stateInfo, sizeof( int ), chainOptions );
do
{
int selfSigned;
/* If we've reached a self-signed cert, stop */
krnlSendMessage( lastCert, IMESSAGE_GETATTRIBUTE, &selfSigned,
CRYPT_CERTINFO_SELFSIGNED );
if( selfSigned )
break;
/* Get the next cert in the chain from the source, import it, and
add it to the collection */
getnextcertInfo.cryptHandle = CRYPT_ERROR; /* Reset result handle */
status = krnlSendMessage( iCertSource, IMESSAGE_KEY_GETNEXTCERT,
&getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusOK( status ) )
{
if( certChainEnd >= MAX_CHAINLENGTH - 1 )
status = CRYPT_ERROR_OVERFLOW;
else
iCertChain[ certChainEnd++ ] = \
lastCert = getnextcertInfo.cryptHandle;
}
if( status == CRYPT_ERROR_NOTFOUND )
{
status = CRYPT_OK;
break; /* End of chain reached */
}
}
while( cryptStatusOK( status ) );
if( cryptStatusError( status ) )
{
freeCertChain( iCertChain, certChainEnd );
return( status );
}
/* Build the complete chain from the individual certs */
return( buildCertChain( iCertificate, iCertChain, certChainEnd,
CRYPT_KEYID_NONE, NULL, 0 ) );
}
/****************************************************************************
* *
* Write Certificate-bagging Records *
* *
****************************************************************************/
/* Determine the size of and write a certificate path from a base cert up to
the root. If it's a cert collection, it's just a container for random
certs but not a cert in its own right, so we skip the leaf cert */
static int sizeofCertPath( const CERT_INFO *certInfoPtr )
{
int length = 0, i;
/* Evaluate the size of the current certificate and the issuer
certificates in the chain */
if( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) )
length = certInfoPtr->certificateSize;
for( i = 0; i < certInfoPtr->certChainEnd; i++ )
{
RESOURCE_DATA msgData;
int status;
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( certInfoPtr->certChain[ i ],
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
length += msgData.length;
}
return( length );
}
static int writeCertPath( STREAM *stream, const CERT_INFO *certInfoPtr )
{
int i, status = CRYPT_OK;
/* Write the current certificate and the associated cert chain up to the
root */
if( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) )
status = swrite( stream, certInfoPtr->certificate,
certInfoPtr->certificateSize );
for( i = 0; cryptStatusOK( status ) && \
i < certInfoPtr->certChainEnd; i++ )
{
CERT_INFO *certChainPtr;
status = krnlGetObject( certInfoPtr->certChain[ i ],
OBJECT_TYPE_CERTIFICATE,
( void ** ) &certChainPtr,
CRYPT_ERROR_SIGNALLED );
if( cryptStatusOK( status ) )
{
status = swrite( stream, certChainPtr->certificate,
certChainPtr->certificateSize );
krnlReleaseObject( certChainPtr->objectHandle );
}
}
return( status );
}
/* Write certificate chain/sequence information:
CertChain ::= SEQUENCE {
contentType OBJECT IDENTIFIER, -- signedData
content [ 0 ] EXPLICIT SEQUENCE {
version INTEGER (1),
digestAlgorithms SET OF AlgorithmIdentifier, -- SIZE(0)
contentInfo SEQUENCE {
signedData OBJECT IDENTIFIER -- data
}
certificates [ 0 ] IMPLICIT SET OF {
Certificate
}
}
signerInfos SET OF SignerInfo -- SIZE(0)
} */
int sizeofCertSet( const CERT_INFO *certInfoPtr )
{
return( ( int ) sizeofObject( sizeofCertPath( certInfoPtr ) ) );
}
int writeCertSet( STREAM *stream, const CERT_INFO *certInfoPtr )
{
writeConstructed( stream, sizeofCertPath( certInfoPtr ), 0 );
return( writeCertPath( stream, certInfoPtr ) );
}
int writeCertSequence( STREAM *stream, const CERT_INFO *certInfoPtr )
{
writeSequence( stream, sizeofCertPath( certInfoPtr ) );
return( writeCertPath( stream, certInfoPtr ) );
}
int writeCertChain( STREAM *stream, const CERT_INFO *certInfoPtr )
{
int innerLength;
/* Determine how big the encoded cert chain/sequence will be */
innerLength = sizeofShortInteger( 1 ) + ( int ) sizeofObject( 0 ) + \
( int ) sizeofObject( sizeofOID( OID_CMS_DATA ) ) + \
( int ) sizeofObject( sizeofCertPath( certInfoPtr ) ) + \
( int ) sizeofObject( 0 );
/* Write the outer SEQUENCE wrapper and contentType and content wrapper */
writeSequence( stream,
sizeofOID( OID_CMS_SIGNEDDATA ) + \
( int ) sizeofObject( sizeofObject( innerLength ) ) );
swrite( stream, OID_CMS_SIGNEDDATA, sizeofOID( OID_CMS_SIGNEDDATA ) );
writeConstructed( stream, sizeofObject( innerLength ), 0 );
writeSequence( stream, innerLength );
/* Write the inner content */
writeShortInteger( stream, 1, DEFAULT_TAG );
writeSet( stream, 0 );
writeSequence( stream, sizeofOID( OID_CMS_DATA ) );
swrite( stream, OID_CMS_DATA, sizeofOID( OID_CMS_DATA ) );
writeCertSet( stream, certInfoPtr );
return( writeSet( stream, 0 ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -