📄 pkcs15_adpr.c
字号:
/****************************************************************************
* *
* cryptlib PKCS #15 Private-key Add Interface *
* Copyright Peter Gutmann 1996-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "crypt.h"
#include "keyset.h"
#include "pkcs15.h"
#include "asn1.h"
#include "asn1_ext.h"
#else
#include "crypt.h"
#include "keyset/keyset.h"
#include "keyset/pkcs15.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
#ifdef USE_PKCS15
/* The minimum number of keying iterations to use when deriving a key wrap
key from a password */
#ifdef CONFIG_SLOW_CPU
#define MIN_KEYING_ITERATIONS 800
#else
#define MIN_KEYING_ITERATIONS 2500
#endif /* CONFIG_SLOW_CPU */
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Replace existing private-key data with updated information */
STDC_NONNULL_ARG( ( 1, 2 ) ) \
static void replacePrivkeyData( INOUT PKCS15_INFO *pkcs15infoPtr,
IN_BUFFER( newPrivKeyDataSize ) \
const void *newPrivKeyData,
IN_LENGTH_SHORT_MIN( 16 ) \
const int newPrivKeyDataSize,
IN_LENGTH_SHORT const int newPrivKeyOffset )
{
assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
assert( isReadPtr( newPrivKeyData, newPrivKeyDataSize ) );
REQUIRES_V( newPrivKeyDataSize >= 16 && \
newPrivKeyDataSize < MAX_INTLENGTH_SHORT );
REQUIRES_V( newPrivKeyOffset > 0 && \
newPrivKeyOffset < newPrivKeyDataSize && \
newPrivKeyOffset < MAX_INTLENGTH_SHORT );
/* If we've allocated new storage for the data rather than directly
replacing the existing entry, free the existing one and replace it
with the new one */
if( newPrivKeyData != pkcs15infoPtr->privKeyData )
{
if( pkcs15infoPtr->privKeyData != NULL )
{
zeroise( pkcs15infoPtr->privKeyData,
pkcs15infoPtr->privKeyDataSize );
clFree( "replacePrivkeyData", pkcs15infoPtr->privKeyData );
}
pkcs15infoPtr->privKeyData = ( void * ) newPrivKeyData;
}
/* Update the size information */
pkcs15infoPtr->privKeyDataSize = newPrivKeyDataSize;
pkcs15infoPtr->privKeyOffset = newPrivKeyOffset;
}
/* Calculate the size of and if necessary allocate storage for private-key
data. This function has to be accessible externally because adding or
changing a certificate for a private key can change the private-key
attributes */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
int calculatePrivkeyStorage( const PKCS15_INFO *pkcs15infoPtr,
OUT_PTR void **newPrivKeyDataPtr,
OUT_LENGTH_SHORT_Z int *newPrivKeyDataSize,
IN_LENGTH_SHORT const int privKeySize,
IN_LENGTH_SHORT const int privKeyAttributeSize,
IN_LENGTH_SHORT const int extraDataSize )
{
void *newPrivKeyData;
assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
assert( isWritePtr( newPrivKeyDataPtr, sizeof( void * ) ) );
assert( isWritePtr( newPrivKeyDataSize, sizeof( int ) ) );
REQUIRES( privKeySize > 0 && privKeySize < MAX_INTLENGTH_SHORT );
REQUIRES( privKeyAttributeSize > 0 && \
privKeyAttributeSize < MAX_INTLENGTH_SHORT );
REQUIRES( extraDataSize >= 0 && extraDataSize < MAX_INTLENGTH_SHORT );
/* Calculate the new private-key data size */
*newPrivKeyDataSize = sizeofObject( privKeyAttributeSize + \
sizeofObject( \
sizeofObject( privKeySize ) + \
extraDataSize ) );
/* If the new data will fit into the existing storage, we're done */
if( *newPrivKeyDataSize <= pkcs15infoPtr->privKeyDataSize )
return( CRYPT_OK );
/* Allocate storage for the new data */
newPrivKeyData = clAlloc( "calculatePrivkeyStorage", *newPrivKeyDataSize );
if( newPrivKeyData == NULL )
return( CRYPT_ERROR_MEMORY );
*newPrivKeyDataPtr = newPrivKeyData;
return( CRYPT_OK );
}
/* Update the private-key attributes while leaving the private key itself
untouched. This is necessary after updating a certificate associated
with a private key, which can affect the key's attributes */
STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
void updatePrivKeyAttributes( INOUT PKCS15_INFO *pkcs15infoPtr,
OUT_BUFFER_FIXED( newPrivKeyDataSize ) \
void *newPrivKeyData,
IN_LENGTH_SHORT_MIN( 16 ) \
const int newPrivKeyDataSize,
IN_BUFFER( privKeyAttributeSize ) \
const void *privKeyAttributes,
IN_LENGTH_SHORT const int privKeyAttributeSize,
IN_LENGTH_SHORT const int privKeyInfoSize,
IN_TAG const int keyTypeTag )
{
STREAM stream;
BYTE keyBuffer[ MAX_PRIVATE_KEYSIZE + 8 ];
int newPrivKeyOffset = DUMMY_INIT, status;
assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
assert( isWritePtr( newPrivKeyData, newPrivKeyDataSize ) );
assert( isReadPtr( privKeyAttributes, privKeyAttributeSize ) );
REQUIRES_V( newPrivKeyDataSize >= 16 && \
newPrivKeyDataSize < MAX_INTLENGTH_SHORT );
REQUIRES_V( privKeyAttributeSize > 0 && \
privKeyAttributeSize < MAX_INTLENGTH_SHORT );
REQUIRES_V( privKeyInfoSize > 0 && \
privKeyInfoSize < MAX_PRIVATE_KEYSIZE );
REQUIRES_V( keyTypeTag == DEFAULT_TAG || keyTypeTag >= 0 );
/* Since we may be doing an in-place update of the private-key
information we copy the wrapped key data out to a temporary buffer
while we make the changes */
ENSURES_V( rangeCheck( pkcs15infoPtr->privKeyOffset, privKeyInfoSize,
pkcs15infoPtr->privKeyDataSize ) );
memcpy( keyBuffer, ( BYTE * ) pkcs15infoPtr->privKeyData +
pkcs15infoPtr->privKeyOffset,
privKeyInfoSize );
/* The corresponding key is already present, we need to update the key
attributes since adding the certificate may have changed them. The
key data itself is unchanged so we just memcpy() it across verbatim */
sMemOpen( &stream, newPrivKeyData, newPrivKeyDataSize );
writeConstructed( &stream, privKeyAttributeSize + \
sizeofObject( \
sizeofObject( privKeyInfoSize ) ),
keyTypeTag );
swrite( &stream, privKeyAttributes, privKeyAttributeSize );
writeConstructed( &stream, ( int ) sizeofObject( privKeyInfoSize ),
CTAG_OB_TYPEATTR );
status = writeSequence( &stream, privKeyInfoSize );
if( cryptStatusOK( status ) )
{
newPrivKeyOffset = stell( &stream );
status = swrite( &stream, keyBuffer, privKeyInfoSize );
}
sMemDisconnect( &stream );
zeroise( keyBuffer, MAX_PRIVATE_KEYSIZE );
ENSURES_V( cryptStatusOK( status ) && \
!cryptStatusError( checkObjectEncoding( newPrivKeyData, \
newPrivKeyDataSize ) ) );
/* Replace the old data with the newly-written data */
replacePrivkeyData( pkcs15infoPtr, newPrivKeyData, newPrivKeyDataSize,
newPrivKeyOffset );
}
/****************************************************************************
* *
* Private-key Wrap Routines *
* *
****************************************************************************/
/* Create a strong encryption context to wrap a key */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int createStrongEncryptionContext( OUT_HANDLE_OPT \
CRYPT_CONTEXT *iCryptContext,
IN_HANDLE const CRYPT_USER iCryptOwner )
{
CRYPT_ALGO_TYPE cryptAlgo;
MESSAGE_CREATEOBJECT_INFO createInfo;
int status;
assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
REQUIRES( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
isHandleRangeValid( iCryptOwner ) );
/* Clear return value */
*iCryptContext = CRYPT_ERROR;
/* In the interests of luser-proofing we're rather 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 */
status = krnlSendMessage( iCryptOwner, IMESSAGE_GETATTRIBUTE, &cryptAlgo,
CRYPT_OPTION_ENCR_ALGO );
if( cryptStatusError( status ) || isWeakCryptAlgo( cryptAlgo ) || \
cryptStatusError( sizeofAlgoIDex( cryptAlgo, CRYPT_MODE_CBC, 0 ) ) )
cryptAlgo = CRYPT_ALGO_3DES;
/* Create the context */
setMessageCreateObjectInfo( &createInfo, cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
*iCryptContext = createInfo.cryptHandle;
return( CRYPT_OK );
}
/* Generate a session key and write the wrapped key in the form
SET OF { [ 0 ] (EncryptedKey) } */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
static int writeWrappedSessionKey( INOUT STREAM *stream,
IN_HANDLE \
const CRYPT_CONTEXT iSessionKeyContext,
IN_HANDLE const CRYPT_USER iCryptOwner,
IN_BUFFER( passwordLength ) \
const char *password,
IN_LENGTH_NAME const int passwordLength )
{
CRYPT_CONTEXT iCryptContext;
int iterations, exportedKeySize, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( password, passwordLength ) );
REQUIRES( isHandleRangeValid( iSessionKeyContext ) );
REQUIRES( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
isHandleRangeValid( iCryptOwner ) );
REQUIRES( passwordLength >= MIN_NAME_LENGTH && \
passwordLength < MAX_ATTRIBUTE_SIZE );
/* In the interests of luser-proofing we force the use of a safe minimum
number of iterations */
status = krnlSendMessage( iCryptOwner, IMESSAGE_GETATTRIBUTE, &iterations,
CRYPT_OPTION_KEYING_ITERATIONS );
if( cryptStatusError( status ) || iterations < MIN_KEYING_ITERATIONS )
iterations = MIN_KEYING_ITERATIONS;
/* Create an encryption context and derive the user password into it */
status = createStrongEncryptionContext( &iCryptContext, iCryptOwner );
if( cryptStatusError( status ) )
return( status );
status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
&iterations, CRYPT_CTXINFO_KEYING_ITERATIONS );
if( cryptStatusOK( status ) )
{
MESSAGE_DATA msgData;
setMessageData( &msgData, ( void * ) password, passwordLength );
status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEYING_VALUE );
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Determine the size of the exported key and write the encrypted data
content field */
status = iCryptExportKey( NULL, 0, &exportedKeySize, CRYPT_FORMAT_CMS,
iSessionKeyContext, iCryptContext );
if( cryptStatusOK( status ) )
{
void *dataPtr;
int length;
writeSet( stream, exportedKeySize );
status = sMemGetDataBlockRemaining( stream, &dataPtr, &length );
if( cryptStatusOK( status ) )
{
status = iCryptExportKey( dataPtr, length, &exportedKeySize,
CRYPT_FORMAT_CMS, iSessionKeyContext,
iCryptContext );
}
if( cryptStatusOK( status ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -