📄 pkcs11_pkc.c
字号:
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isWritePtr( buffer, length ) );
assert( length == keySize );
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
cryptStatus = genericDecrypt( pkcs11Info, contextInfoPtr, &mechanism,
buffer, keySize, &resultLen );
krnlReleaseObject( iCryptDevice );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* Redo the PKCS #1 padding to CKM_RSA_PKCS look like CKM_RSA_X_509.
Note that this doesn't have to be cryptographically strong since
it gets stripped as soon as we return to the caller, it just has
to be random:
bufPtr keySize
| |
+---+---+------------+---+----------+
| 0 | 1 | random | 0 | key |
+---+---+------------+---+----------+
| | | |
<------------> <---------->
keySize - resultLen
resultLen - 3
This gets a bit ugly because the random padding has to be nonzero,
which would require using the non-nonce RNG. To work around this,
we look for any zeroes in the data and fill them with some other
value */
memmove( bufPtr + keySize - resultLen, bufPtr, resultLen );
bufPtr[ 0 ] = 0;
bufPtr[ 1 ] = 2;
setMessageData( &msgData, bufPtr + 2, keySize - resultLen - 3 );
cryptStatus = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM_NONCE );
for( i = 2; i < keySize - resultLen - 1; i++ )
if( bufPtr[ i ] == 0 )
{
/* Create some sort of non-constant non-zero value to replace
the zero byte with, since PKCS #1 can't have zero bytes.
Note again that this doesn't have to be a strong random value,
it just has to vary a bit */
const int pad = 0xAA ^ ( i & 0xFF );
bufPtr[ i ] = pad ? pad : 0x21;
}
bufPtr[ keySize - resultLen - 1 ] = 0;
assert( 2 + ( keySize - resultLen - 3 ) + 1 + resultLen == keySize );
return( cryptStatus );
}
/****************************************************************************
* *
* DSA Mapping Functions *
* *
****************************************************************************/
/* DSA algorithm-specific mapping functions */
static int dsaSetKeyInfo( PKCS11_INFO *pkcs11Info,
const CRYPT_CONTEXT iCryptContext,
const CK_OBJECT_HANDLE hPrivateKey,
const CK_OBJECT_HANDLE hPublicKey,
const void *p, const int pLen,
const void *q, const int qLen,
const void *g, const int gLen,
const void *y, const int yLen,
const BOOLEAN nativeContext )
{
MESSAGE_DATA msgData;
BYTE keyDataBuffer[ ( CRYPT_MAX_PKCSIZE * 4 ) + 8 ];
BYTE idBuffer[ KEYID_SIZE + 8 ];
int keyDataSize, cryptStatus;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isHandleRangeValid( iCryptContext ) );
assert( isReadPtr( p, pLen ) );
assert( isReadPtr( q, qLen ) );
assert( isReadPtr( g, gLen ) );
assert( isReadPtr( y, yLen ) );
/* Send the public key data to the context. We send the keying info as
CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL rather than CRYPT_IATTRIBUTE_KEY_SPKI
since the latter transitions the context into the high state. We
don't want to do this because we're already in the middle of processing
a message that does this on completion, all we're doing here is
sending in encoded public key data for use by objects such as
certificates */
cryptStatus = writeFlatPublicKey( keyDataBuffer, CRYPT_MAX_PKCSIZE * 3,
&keyDataSize, CRYPT_ALGO_DSA,
p, pLen, q, qLen, g, gLen, y, yLen );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
setMessageData( &msgData, keyDataBuffer, keyDataSize );
if( nativeContext )
{
/* If we're just setting public key components for a native context,
we're done */
return( krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEY_SPKI ) );
}
cryptStatus = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL );
if( !cryptStatusError( cryptStatus ) )
cryptStatus = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
( void * ) &pLen,
CRYPT_IATTRIBUTE_KEYSIZE );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* Remember what we've set up */
krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
( void * ) &hPrivateKey, CRYPT_IATTRIBUTE_DEVICEOBJECT );
/* Get the key ID from the context and use it as the object ID. Since
some objects won't allow after-the-even ID updates, we don't treat a
failure to update as an error */
setMessageData( &msgData, idBuffer, KEYID_SIZE );
cryptStatus = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID );
if( cryptStatusOK( cryptStatus ) )
{
CK_ATTRIBUTE idTemplate = { CKA_ID, msgData.data, msgData.length };
if( hPublicKey != CRYPT_UNUSED )
C_SetAttributeValue( pkcs11Info->hSession, hPublicKey,
&idTemplate, 1 );
C_SetAttributeValue( pkcs11Info->hSession, hPrivateKey,
&idTemplate, 1 );
}
return( cryptStatus );
}
int dsaSetPublicComponents( PKCS11_INFO *pkcs11Info,
const CRYPT_CONTEXT iCryptContext,
const CK_OBJECT_HANDLE hDsaKey )
{
BYTE p[ CRYPT_MAX_PKCSIZE + 8 ], q[ CRYPT_MAX_PKCSIZE + 8 ];
BYTE g[ CRYPT_MAX_PKCSIZE + 8 ], y[ CRYPT_MAX_PKCSIZE + 8 ];
int pLen, qLen = DUMMY_INIT, gLen = DUMMY_INIT, yLen = DUMMY_INIT;
int cryptStatus;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isHandleRangeValid( iCryptContext ) );
/* Get the public key components from the device */
cryptStatus = readAttributeValue( pkcs11Info, hDsaKey, CKA_PRIME,
p, CRYPT_MAX_PKCSIZE, &pLen );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = readAttributeValue( pkcs11Info, hDsaKey, CKA_SUBPRIME,
q, CRYPT_MAX_PKCSIZE, &qLen );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = readAttributeValue( pkcs11Info, hDsaKey, CKA_BASE,
g, CRYPT_MAX_PKCSIZE, &gLen );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = readAttributeValue( pkcs11Info, hDsaKey, CKA_VALUE,
y, CRYPT_MAX_PKCSIZE, &yLen );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
return( dsaSetKeyInfo( pkcs11Info, iCryptContext, CK_OBJECT_NONE, hDsaKey,
p, pLen, q, qLen, g, gLen, y, yLen, TRUE ) );
}
static int dsaInitKey( CONTEXT_INFO *contextInfoPtr, const void *key,
const int keyLength )
{
static const CK_OBJECT_CLASS privKeyClass = CKO_PRIVATE_KEY;
static const CK_OBJECT_CLASS pubKeyClass = CKO_PUBLIC_KEY;
static const CK_KEY_TYPE type = CKK_DSA;
static const CK_BBOOL bTrue = TRUE;
CK_ATTRIBUTE dsaKeyTemplate[] = {
/* Shared fields */
{ CKA_CLASS, ( CK_VOID_PTR ) &privKeyClass, sizeof( CK_OBJECT_CLASS ) },
{ CKA_KEY_TYPE, ( CK_VOID_PTR ) &type, sizeof( CK_KEY_TYPE ) },
{ CKA_TOKEN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_SIGN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_LABEL, contextInfoPtr->label, contextInfoPtr->labelSize },
{ CKA_PRIME, NULL, 0 },
{ CKA_SUBPRIME, NULL, 0 },
{ CKA_BASE, NULL, 0 },
{ CKA_VALUE, NULL, 0 },
/* Private-key only fields */
{ CKA_PRIVATE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
};
const CRYPT_PKCINFO_DLP *dsaKey = ( CRYPT_PKCINFO_DLP * ) key;
CRYPT_DEVICE iCryptDevice;
PKCS11_INFO *pkcs11Info;
CK_OBJECT_HANDLE hDsaKey;
CK_RV status;
BYTE yValue[ CRYPT_MAX_PKCSIZE + 8 ];
const void *yValuePtr = yValue;
const int templateCount = dsaKey->isPublicKey ? 9 : 10;
int yValueLength, cryptStatus;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isReadPtr( key, keyLength ) );
assert( keyLength == sizeof( CRYPT_PKCINFO_DLP ) );
/* Creating a private-key object is somewhat problematic since the
PKCS #11 interpretation of DSA reuses CKA_VALUE for x in the private
key and y in the public key, so it's not possible to determine y from
a private key because the x value is sensitive and can't be extracted.
Because of this we have to create a native private-key context (which
will generate the y value from x), read out the y value, and destroy
it again (see the comments in the DSA generate key section for more on
this problem). Since this doesn't require the device, we do it before
we grab the device */
if( !dsaKey->isPublicKey )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
MESSAGE_DATA msgData;
STREAM stream;
BYTE pubkeyBuffer[ ( CRYPT_MAX_PKCSIZE * 3 ) + 8 ], label[ 8 + 8 ];
void *yValuePtr = DUMMY_INIT_PTR;
/* Create a native private-key DSA context, which generates the y
value internally */
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_DSA );
cryptStatus = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
setMessageData( &msgData, label, 8 );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_LABEL );
setMessageData( &msgData, ( void * ) dsaKey,
sizeof( CRYPT_PKCINFO_DLP ) );
cryptStatus = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEY_COMPONENTS );
if( cryptStatusError( cryptStatus ) )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( cryptStatus );
}
/* Get the public key data and extract the y value from it. Note
that the data used is represented in DER-canonical form, there may
be PKCS #11 implementations that can't handle this (for example
they may require y to be zero-padded to make it exactly 64 bytes
rather than (say) 63 bytes if the high byte is zero) */
setMessageData( &msgData, pubkeyBuffer, CRYPT_MAX_PKCSIZE * 3 );
cryptStatus = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_KEY_SPKI );
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
sMemConnect( &stream, msgData.data, msgData.length );
readSequence( &stream, NULL ); /* SEQUENCE { */
readUniversal( &stream ); /* AlgoID */
readBitStringHole( &stream, NULL, 16, DEFAULT_TAG );/* BIT STRING */
status = readGenericHole( &stream, &yValueLength, 16,
BER_INTEGER );/* INTEGER */
if( cryptStatusOK( status ) )
status = sMemGetDataBlock( &stream, &yValuePtr, yValueLength );
if( cryptStatusError( status ) )
retIntError();
memcpy( yValue, yValuePtr, yValueLength );
sMemDisconnect( &stream );
}
else
{
/* It's a public key, use the pre-generated y value */
yValuePtr = dsaKey->y,
yValueLength = bitsToBytes( dsaKey->yLen );
}
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* Set up the key values */
dsaKeyTemplate[ 5 ].pValue = ( CK_VOID_PTR ) dsaKey->p;
dsaKeyTemplate[ 5 ].ulValueLen = bitsToBytes( dsaKey->pLen );
dsaKeyTemplate[ 6 ].pValue = ( CK_VOID_PTR ) dsaKey->q;
dsaKeyTemplate[ 6 ].ulValueLen = bitsToBytes( dsaKey->qLen );
dsaKeyTemplate[ 7 ].pValue = ( CK_VOID_PTR ) dsaKey->g;
dsaKeyTemplate[ 7 ].ulValueLen = bitsToBytes( dsaKey->gLen );
if( !dsaKey->isPublicKey )
{
dsaKeyTemplate[ 8 ].pValue = ( CK_VOID_PTR ) dsaKey->x;
dsaKeyTemplate[ 8 ].ulValueLen = bitsToBytes( dsaKey->xLen );
}
else
{
dsaKeyTemplate[ 8 ].pValue = ( CK_VOID_PTR ) dsaKey->y;
dsaKeyTemplate[ 8 ].ulValueLen = bitsToBytes( dsaKey->yLen );
/* If it's a public key, we need to change the type and the
indication of the operations that it's allowed to perform */
dsaKeyTemplate[ 0 ].pValue = ( CK_VOID_PTR ) &pubKeyClass;
dsaKeyTemplate[ 3 ].type = CKA_VERIFY;
}
/* Load the key into the token */
status = C_CreateObject( pkcs11Info->hSession, dsaKeyTemplate,
templateCount, &hDsaKey );
zeroise( dsaKeyTemplate, sizeof( CK_ATTRIBUTE ) * templateCount );
cryptStatus = pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED );
if( cryptStatusError( cryptStatus ) )
{
/* If we're trying to set a public key and this is one of those
tinkertoy tokens that only does private-key ops, return a more
appropriate error code */
if( dsaKey->isPublicKey && \
contextInfoPtr->capabilityInfo->sigCheckFunction == NULL )
cryptStatus = CRYPT_ERROR_NOTAVAIL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -