📄 pkcs15_wr.c
字号:
sizeofObject( \
sizeofObject( \
sizeofObject( pubKeyDataSize ) + \
extraDataSize ) ) );
if( ( pkcs15info->pubKeyData = \
clAlloc( "addCert", pkcs15info->pubKeyDataSize ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
}
if( cryptStatusError( status ) )
return( status );
/* Write the public key data */
sMemOpen( &stream, pkcs15info->pubKeyData,
pkcs15info->pubKeyDataSize );
writeConstructed( &stream, pubKeyAttributeSize + \
( int ) sizeofObject( \
sizeofObject( \
sizeofObject( pubKeyDataSize ) + \
extraDataSize ) ),
keyTypeTag );
swrite( &stream, pubKeyAttributes, pubKeyAttributeSize );
writeConstructed( &stream,
( int ) sizeofObject( \
sizeofObject( pubKeyDataSize ) + \
extraDataSize ),
CTAG_OB_TYPEATTR );
writeSequence( &stream, ( int ) sizeofObject( pubKeyDataSize ) + \
extraDataSize );
writeConstructed( &stream, pubKeyDataSize, CTAG_OV_DIRECT );
pkcs15info->pubKeyOffset = stell( &stream );
status = exportAttributeToStream( &stream, cryptHandle,
CRYPT_IATTRIBUTE_KEY_SPKI,
CRYPT_USE_DEFAULT );
if( cryptStatusOK( status ) && pkcCryptAlgo == CRYPT_ALGO_RSA )
{
/* When using the SPKI option for storing key components, the RSA
components require a [1] tag since the basic (non-SPKI) option is
also a SEQUENCE, so if it's an RSA key we modify the tag. This is
easier than passing the tag requirement down through the kernel
call to the context. In addition RSA keys have an extra element
for PKCS #11 compatibility */
#if 0 /* Disabled until 3.1 is widespread, since 3.0 used readSequence() */
sMemBufPtr( &stream )[ 0 ] = MAKE_CTAG( 1 );
#endif /* 0 */
status = writeShortInteger( &stream, modulusSize, DEFAULT_TAG );
}
sMemDisconnect( &stream );
return( status );
}
/* Add a private key to a PKCS #15 collection */
static int addPrivateKey( PKCS15_INFO *pkcs15info,
const CRYPT_HANDLE cryptHandle,
const CRYPT_HANDLE ownerHandle,
const char *password, const int passwordLength,
const void *privKeyAttributes,
const int privKeyAttributeSize,
const CRYPT_ALGO_TYPE pkcCryptAlgo,
const int modulusSize )
{
CRYPT_ALGO_TYPE wrapCryptAlgo;
CRYPT_CONTEXT iSessionKeyContext;
MECHANISM_WRAP_INFO mechanismInfo;
MESSAGE_CREATEOBJECT_INFO createInfo;
STREAM stream;
void *headerPtr, *dataPtr;
const int keyTypeTag = getKeyTypeTag( cryptHandle );
int privKeyInfoSize, privKeyDataSize;
int value, status;
/* Create a session key context and generate a key and IV into it. The IV
would be generated automatically later on when we encrypt data for the
first time, but we do it explicitly here to catch any possible errors
at a point where recovery is easier. 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( ownerHandle, IMESSAGE_GETATTRIBUTE, &wrapCryptAlgo,
CRYPT_OPTION_ENCR_ALGO );
if( isWeakCryptAlgo( wrapCryptAlgo ) ||
cryptStatusError( sizeofAlgoIDex( wrapCryptAlgo,
( CRYPT_ALGO_TYPE ) CRYPT_MODE_CBC, 0 ) ) )
wrapCryptAlgo = CRYPT_ALGO_3DES;
setMessageCreateObjectInfo( &createInfo, wrapCryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusOK( status ) )
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_GENKEY,
NULL, FALSE );
if( cryptStatusOK( status ) )
status = krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_CTX_GENIV );
if( cryptStatusError( status ) )
{
if( createInfo.cryptHandle != CRYPT_ERROR )
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
iSessionKeyContext = createInfo.cryptHandle;
/* Calculate the eventual encrypted key size and allocate storage for it */
setMechanismWrapInfo( &mechanismInfo, NULL, 0, NULL, 0, cryptHandle,
iSessionKeyContext, CRYPT_UNUSED );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT,
&mechanismInfo, MECHANISM_PRIVATEKEYWRAP );
privKeyInfoSize = mechanismInfo.wrappedDataLength;
clearMechanismInfo( &mechanismInfo );
if( cryptStatusOK( status ) )
{
pkcs15info->privKeyDataSize = privKeyAttributeSize +
privKeyInfoSize + 512;
if( ( pkcs15info->privKeyData = \
clAlloc( "addPrivateKey", \
pkcs15info->privKeyDataSize ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iSessionKeyContext, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Since we can't write the header and attributes until we write the
encrypted private key, we leave enough space at the start to contain
this information and write the private key after that */
sMemOpen( &stream, pkcs15info->privKeyData, pkcs15info->privKeyDataSize );
sseek( &stream, 200 + privKeyAttributeSize );
dataPtr = sMemBufPtr( &stream );
/* Write the encryption information with a gap at the start for the CMS
header. Since we're using KEKRecipientInfo, we use a version of 2
rather than 0 */
writeShortInteger( &stream, 2, DEFAULT_TAG );
status = writeWrappedSessionKey( &stream, iSessionKeyContext,
ownerHandle, password, passwordLength );
if( cryptStatusOK( status ) )
status = writeCMSencrHeader( &stream, OID_CMS_DATA, privKeyInfoSize,
iSessionKeyContext );
if( cryptStatusError( status ) )
{
sMemClose( &stream );
krnlSendNotifier( iSessionKeyContext, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Export the encrypted private key */
setMechanismWrapInfo( &mechanismInfo, sMemBufPtr( &stream ),
privKeyInfoSize, NULL, 0, cryptHandle,
iSessionKeyContext, CRYPT_UNUSED );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT,
&mechanismInfo, MECHANISM_PRIVATEKEYWRAP );
if( cryptStatusOK( status ) && pkcCryptAlgo == CRYPT_ALGO_RSA )
{
STREAM encDataStream;
int length;
/* Check that the wrapped key data no longer contains identifiable
structured data. We can only do this for RSA keys since the
amount of information present for DLP keys is too small to
reliably check. For RSA keys the data would be:
SEQUENCE {
[0] INTEGER | [3] INTEGER,
...
}
This check is performed in addition to checks already performed by
the encryption code and the key wrap code */
sMemConnect( &encDataStream, mechanismInfo.wrappedData,
mechanismInfo.wrappedDataLength );
status = readSequence( &encDataStream, &length );
if( cryptStatusOK( status ) )
{
/* The data must contain at least p and q, or at most all key
components */
if( length < ( bitsToBytes( MIN_PKCSIZE_BITS ) * 2 ) || \
length > MAX_PRIVATE_KEYSIZE )
status = CRYPT_ERROR;
else
{
/* The first value is either n or p */
value = peekTag( &encDataStream );
if( value == MAKE_CTAG( 0 ) || value == MAKE_CTAG( 3 ) )
{
status = readIntegerTag( &encDataStream, NULL,
&length, CRYPT_MAX_PKCSIZE,
value );
if( cryptStatusOK( status ) && \
( length < bitsToBytes( MIN_PKCSIZE_BITS ) || \
length > CRYPT_MAX_PKCSIZE ) )
status = CRYPT_ERROR;
}
}
}
sMemDisconnect( &encDataStream );
status = ( cryptStatusError( status ) ) ? \
CRYPT_OK : CRYPT_ERROR_FAILED;
}
if( cryptStatusOK( status ) )
status = sSkip( &stream, mechanismInfo.wrappedDataLength );
clearMechanismInfo( &mechanismInfo );
krnlSendNotifier( iSessionKeyContext, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
{
sMemClose( &stream );
return( status );
}
privKeyDataSize = stell( &stream ) - ( 200 + privKeyAttributeSize );
/* Kludge the CMS header onto the start of the data */
sseek( &stream, 100 + privKeyAttributeSize );
headerPtr = sMemBufPtr( &stream );
writeConstructed( &stream, privKeyDataSize, CTAG_OV_DIRECTPROTECTED );
memmove( sMemBufPtr( &stream ), dataPtr, privKeyDataSize );
privKeyDataSize += stell( &stream ) - ( 100 + privKeyAttributeSize );
/* Now that we've written the private key data and know how long it is,
move back to the start and write the attributes and outer header, then
move the private key information down to the end. Finally, adjust the
private key size value to reflect its true size (rather than the
allocated buffer size) */
sseek( &stream, 0 );
if( pkcCryptAlgo == CRYPT_ALGO_RSA )
/* RSA keys have an extra element for PKCS #11 compatibility */
privKeyDataSize += sizeofShortInteger( modulusSize );
writeConstructed( &stream, privKeyAttributeSize + \
( int ) sizeofObject( sizeofObject( privKeyDataSize ) ),
keyTypeTag );
swrite( &stream, privKeyAttributes, privKeyAttributeSize );
writeConstructed( &stream, ( int ) sizeofObject( privKeyDataSize ),
CTAG_OB_TYPEATTR );
writeSequence( &stream, privKeyDataSize );
pkcs15info->privKeyOffset = stell( &stream );
if( pkcCryptAlgo == CRYPT_ALGO_RSA )
{
/* RSA keys have an extra element for PKCS #11 compability that we
need to kludge onto the end of the private-key data */
privKeyDataSize -= sizeofShortInteger( modulusSize );
memmove( sMemBufPtr( &stream ), headerPtr, privKeyDataSize );
sSkip( &stream, privKeyDataSize );
status = writeShortInteger( &stream, modulusSize, DEFAULT_TAG );
}
else
{
memmove( sMemBufPtr( &stream ), headerPtr, privKeyDataSize );
status = sSkip( &stream, privKeyDataSize );
}
pkcs15info->privKeyDataSize = stell( &stream );
assert( sStatusOK( &stream ) );
sMemDisconnect( &stream );
return( status );
}
/* Add configuration data to a PKCS #15 collection */
static int addConfigData( PKCS15_INFO *pkcs15info, const char *data,
const int dataLength, const int flags )
{
int i;
assert( flags == CRYPT_IATTRIBUTE_CONFIGDATA || \
flags == CRYPT_IATTRIBUTE_USERINDEX || \
flags == CRYPT_IATTRIBUTE_USERID || \
flags == CRYPT_IATTRIBUTE_USERINFO );
/* If it's a user ID, set all object IDs to this value. This is needed
for user keysets where there usually isn't any key ID present (there
is one for SO keysets since they have public/private keys attached to
them, but they're not identified by key ID so it's not much use). In
this case the caller has to explicitly set an ID, which is the user
ID */
if( flags == CRYPT_IATTRIBUTE_USERID )
{
for( i = 0; i < MAX_PKCS15_OBJECTS; i++ )
{
memcpy( pkcs15info[ i ].iD, data, dataLength );
pkcs15info[ i ].iDlength = dataLength;
}
return( CRYPT_OK );
}
/* Find either the first free entry or an entry that contains data
identical to what we're adding now, which we'll replace with the new
data */
for( i = 0; i < MAX_PKCS15_OBJECTS; i++ )
if( ( pkcs15info[ i ].type == PKCS15_SUBTYPE_DATA && \
pkcs15info[ i ].dataType == flags ) || \
pkcs15info[ i ].type == PKCS15_SUBTYPE_NONE )
break;
if( i == MAX_PKCS15_OBJECTS )
return( CRYPT_ERROR_OVERFLOW );
pkcs15info = &pkcs15info[ i ];
/* If there's existing data present which was read from a keyset that
was opened for update, clear and free it */
if( pkcs15info->dataData != NULL )
{
assert( pkcs15info->dataType == flags );
zeroise( pkcs15info->dataData, pkcs15info->dataDataSize );
clFree( "addConfigData", pkcs15info->dataData );
pkcs15info->type = PKCS15_SUBTYPE_NONE;
/* If we're being sent empty data (corresponding to an empty
SEQUENCE), it means the caller wants to clear this entry */
if( dataLength < 8 )
{
zeroise( pkcs15info, sizeof( PKCS15_INFO ) );
return( CRYPT_OK );
}
}
/* Remember the pre-encoded config data */
assert( pkcs15info->type == PKCS15_SUBTYPE_NONE );
if( ( pkcs15info->dataData = \
clAlloc( "addConfigData", dataLength ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memcpy( pkcs15info->dataData, data, dataLength );
pkcs15info->dataDataSize = dataLength;
/* Set the type information for the data */
pkcs15info->type = PKCS15_SUBTYPE_DATA;
pkcs15info->dataType = flags;
return( CRYPT_OK );
}
/* Add a secret key to a PKCS #15 collection */
static int addSecretKey( PKCS15_INFO *pkcs15info,
const CRYPT_HANDLE cryptHandle )
{
RESOURCE_DATA msgData;
char label[ CRYPT_MAX_TEXTSIZE + 1 ];
int i, status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -