📄 pkcs15_wr.c
字号:
/* Determine how big the public key attribute collections will be */
keyUsage &= PUBKEY_USAGE_MASK;
commonKeyAttributeSize = ( int ) sizeofObject( pkcs15info->iDlength ) + \
sizeofBitString( keyUsage ) + \
sizeofBitString( KEYATTR_ACCESS_PUBLIC );
if( pkcs15info->validFrom )
commonKeyAttributeSize += sizeofGeneralizedTime();
if( pkcs15info->validTo )
commonKeyAttributeSize += sizeofGeneralizedTime();
/* Write the public key attributes */
sMemOpen( &stream, pubKeyAttributes, KEYATTR_BUFFER_SIZE );
writeSequence( &stream, commonAttributeSize );
writeCharacterString( &stream, ( BYTE * ) pkcs15info->label,
pkcs15info->labelLength, BER_STRING_UTF8 );
writeSequence( &stream, commonKeyAttributeSize );
writeOctetString( &stream, pkcs15info->iD, pkcs15info->iDlength,
DEFAULT_TAG );
writeBitString( &stream, keyUsage, DEFAULT_TAG );
status = writeBitString( &stream, KEYATTR_ACCESS_PUBLIC, DEFAULT_TAG );
if( pkcs15info->validFrom )
status = writeGeneralizedTime( &stream, pkcs15info->validFrom, \
DEFAULT_TAG );
if( pkcs15info->validTo )
status = writeGeneralizedTime( &stream, pkcs15info->validTo, \
CTAG_KA_VALIDTO );
*pubKeyAttributeSize = stell( &stream );
assert( sStatusOK( &stream ) );
sMemDisconnect( &stream );
pkcs15info->pubKeyUsage = keyUsage; /* Update stored usage info */
return( status );
}
static int writeCertAttributes( void *certAttributes,
int *certAttributeSize,
PKCS15_INFO *pkcs15info,
const CRYPT_HANDLE cryptHandle )
{
STREAM stream;
BOOLEAN trustedImplicit = FALSE;
int isCA, trustedUsage, status;
int commonAttributeSize, commonCertAttributeSize;
int keyIdentifierDataSize, trustedUsageSize;
/* Get various pieces of information from the object. If we're adding a
standalone cert then the iD and keyID won't have been set up yet, so
we need to set these up as well. Since the cert could be a data-only
cert, we create the iD ourselves from the encoded public key
components rather than trying to read an associated context's keyID
attribute. For similar reasons we specifically don't try and read the
PGP ID information since for a cert chain it'll come from the context
of the leaf cert rather than the current cert (in any case they're not
necessary since none of the certs in the chain will be PGP keys */
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, &isCA,
CRYPT_CERTINFO_CA );
if( status == CRYPT_ERROR_NOTFOUND )
{
isCA = FALSE;
status = CRYPT_OK;
}
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
&trustedUsage, CRYPT_CERTINFO_TRUSTED_USAGE );
if( status == CRYPT_ERROR_NOTFOUND )
{
/* If there's no trusted usage defined, don't store a trust
setting */
trustedUsage = CRYPT_UNUSED;
status = CRYPT_OK;
}
}
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
&trustedImplicit, CRYPT_CERTINFO_TRUSTED_IMPLICIT );
if( status == CRYPT_ERROR_NOTFOUND )
{
/* If it's not implicitly trusted, don't store a trust setting */
trustedImplicit = FALSE;
status = CRYPT_OK;
}
}
if( cryptStatusOK( status ) )
status = getValidityInfo( pkcs15info, cryptHandle );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, pkcs15info->pgp2KeyID, PGP_KEYID_SIZE );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID_PGP );
if( cryptStatusOK( status ) )
/* Not present for all key types, so an error isn't fatal */
pkcs15info->pgp2KeyIDlength = msgData.length;
setMessageData( &msgData, pkcs15info->openPGPKeyID, PGP_KEYID_SIZE );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
pkcs15info->openPGPKeyIDlength = msgData.length;
}
if( cryptStatusError( status ) )
return( status );
if( !pkcs15info->iDlength )
{
status = getCertID( cryptHandle, CRYPT_IATTRIBUTE_SPKI,
pkcs15info->iD );
if( cryptStatusError( status ) )
return( status );
pkcs15info->iDlength = KEYID_SIZE;
}
if( !pkcs15info->keyIDlength )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, pkcs15info->keyID, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
if( cryptStatusOK( status ) )
pkcs15info->keyIDlength = msgData.length;
else
{
memcpy( pkcs15info->keyID, pkcs15info->iD, pkcs15info->iDlength );
pkcs15info->keyIDlength = pkcs15info->iDlength;
}
}
/* At this point we could create a pseudo-label by walking up the cert DN
from the CN until we find a component we can use, however label-less
items will only occur when adding a standalone (i.e. trusted,
implicitly-handled) cert. If we were to set labels for these, the
keyset would end up acting as a general-purpose certificate store
which it isn't meant to be, so we always leave implicitly handled
certs label-less */
/* Calculate the various IDs for the cert */
status = getCertID( cryptHandle, CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER,
pkcs15info->iAndSID );
if( cryptStatusOK( status ) )
status = getCertID( cryptHandle, CRYPT_IATTRIBUTE_SUBJECT,
pkcs15info->subjectNameID );
if( cryptStatusOK( status ) )
status = getCertID( cryptHandle, CRYPT_IATTRIBUTE_ISSUER,
pkcs15info->issuerNameID );
if( cryptStatusError( status ) )
return( status );
pkcs15info->iAndSIDlength = pkcs15info->subjectNameIDlength = \
pkcs15info->issuerNameIDlength = KEYID_SIZE;
trustedUsageSize = ( trustedUsage != CRYPT_UNUSED ) ? \
sizeofBitString( trustedUsage ) : 0;
keyIdentifierDataSize = sizeofObjectIDs( pkcs15info );
/* Determine how big the attribute collection will be */
commonAttributeSize = pkcs15info->labelLength ? \
( int) sizeofObject( pkcs15info->labelLength ) : 0;
commonCertAttributeSize = ( int ) \
sizeofObject( pkcs15info->iDlength ) + \
( isCA ? sizeofBoolean() : 0 ) + \
( ( trustedUsage != CRYPT_UNUSED ) ? \
sizeofObject( trustedUsageSize ) : 0 ) + \
sizeofObject( keyIdentifierDataSize ) + \
( trustedImplicit ? sizeofBoolean() : 0 ) + \
sizeofGeneralizedTime() + sizeofGeneralizedTime();
/* Write the cert attributes */
sMemOpen( &stream, certAttributes, KEYATTR_BUFFER_SIZE );
writeSequence( &stream, commonAttributeSize );
if( commonAttributeSize )
writeCharacterString( &stream, pkcs15info->label,
pkcs15info->labelLength, BER_STRING_UTF8 );
writeSequence( &stream, commonCertAttributeSize );
writeOctetString( &stream, pkcs15info->iD, pkcs15info->iDlength,
DEFAULT_TAG );
if( isCA )
writeBoolean( &stream, TRUE, DEFAULT_TAG );
if( trustedUsage != CRYPT_UNUSED )
{
writeConstructed( &stream, trustedUsageSize, CTAG_CA_TRUSTED_USAGE );
writeBitString( &stream, trustedUsage, DEFAULT_TAG );
}
writeObjectIDs( &stream, pkcs15info, keyIdentifierDataSize,
CTAG_CA_IDENTIFIERS );
if( trustedImplicit )
writeBoolean( &stream, TRUE, CTAG_CA_TRUSTED_IMPLICIT );
writeGeneralizedTime( &stream, pkcs15info->validFrom, DEFAULT_TAG );
status = writeGeneralizedTime( &stream, pkcs15info->validTo, \
CTAG_CA_VALIDTO );
*certAttributeSize = stell( &stream );
assert( sStatusOK( &stream ) );
sMemDisconnect( &stream );
return( status );
}
/****************************************************************************
* *
* Write a Key *
* *
****************************************************************************/
/* When adding key/cert data to a PKCS #15 collection, we have to be able to
cleanly handle the addition of arbitrary collections of objects, which
leads to some rather convoluted logic for deciding what needs updating
and under which conditions. The actions taken are:
key only: if present
return( CRYPT_ERROR_DUPLICATE )
else
add key;
cert only: if present
return( CRYPT_ERROR_DUPLICATE );
elif( matching key present )
#ifdef RETAIN_PUBKEY
add, update key data;
#else
add, delete key data;
#endif // RETAIN_PUBKEY
elif( trusted cert )
add as trusted cert;
else
error;
key+cert: if key present and cert present
return( CRYPT_ERROR_DUPLICATE );
#ifdef RETAIN_PUBKEY
if key present -> don't add key;
#else
delete key;
#endif // RETAIN_PUBKEY
if cert present -> don't add cert;
The following values specify the action to be taken when adding a cert */
typedef enum {
CERTADD_UPDATE_EXISTING,/* Update existing key info with a cert */
CERTADD_NORMAL, /* Add a cert for which no key info present */
CERTADD_STANDALONE_CERT /* Add a standalone cert not assoc'd with a key */
} CERTADD_TYPE;
/* Determine the tag to use when encoding a given key type. There isn't any
tag for Elgamal but the keys are the same as X9.42 DH keys and cryptlib
uses the OID rather than the tag to determine the key type, so the
following sleight-of-hand works */
static int getKeyTypeTag( const CRYPT_CONTEXT cryptContext )
{
CRYPT_ALGO_TYPE cryptAlgo;
int status;
status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
switch( cryptAlgo )
{
case CRYPT_ALGO_RSA:
return( DEFAULT_TAG );
case CRYPT_ALGO_DH:
case CRYPT_ALGO_ELGAMAL:
return( 1 );
case CRYPT_ALGO_DSA:
return( 2 );
case CRYPT_ALGO_KEA:
return( 3 );
}
assert( NOTREACHED );
return( 0 ); /* Get rid of compiler warning */
}
/* Generate a session key and write the wrapped key in the form
SET OF { [ 0 ] (EncryptedKey) } */
static int writeWrappedSessionKey( STREAM *stream,
CRYPT_CONTEXT iSessionKeyContext,
const CRYPT_USER cryptOwner,
const char *password,
const int passwordLength )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
CRYPT_ALGO_TYPE cryptAlgo;
int iterations, exportedKeySize, status;
/* In the interests of luser-proofing, we're really paranoid and force
the use of non-weak algorithms and modes of operation. In addition
since OIDs are only defined for a limited subset of algorithms, we
also default to a guaranteed available algorithm if no OID is defined
for the one requested */
krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE, &cryptAlgo,
CRYPT_OPTION_ENCR_ALGO );
if( isWeakCryptAlgo( cryptAlgo ) || \
cryptStatusError( sizeofAlgoIDex( cryptAlgo,
( CRYPT_ALGO_TYPE ) CRYPT_MODE_CBC, 0 ) ) )
cryptAlgo = CRYPT_ALGO_3DES;
krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE, &iterations,
CRYPT_OPTION_KEYING_ITERATIONS );
if( iterations < MIN_KEYING_ITERATIONS )
iterations = MIN_KEYING_ITERATIONS;
/* Create an encryption context and derive the user password into it */
setMessageCreateObjectInfo( &createInfo, cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
&iterations, CRYPT_CTXINFO_KEYING_ITERATIONS );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, ( void * ) password, passwordLength );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEYING_VALUE );
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Determine the size of the exported key and write the encrypted data
content field */
if( cryptStatusOK( status ) )
status = iCryptExportKeyEx( NULL, &exportedKeySize, 0,
CRYPT_FORMAT_CMS, iSessionKeyContext,
createInfo.cryptHandle, CRYPT_UNUSED );
if( cryptStatusOK( status ) )
{
writeSet( stream, exportedKeySize );
status = iCryptExportKeyEx( sMemBufPtr( stream ), &exportedKeySize,
sMemDataLeft( stream ), CRYPT_FORMAT_CMS,
iSessionKeyContext, createInfo.cryptHandle,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -