📄 pkcs11_pkc.c
字号:
krnlReleaseObject( iCryptDevice );
return( cryptStatus );
}
/* Send the keying info to the context and set up the key ID info */
cryptStatus = dsaSetKeyInfo( pkcs11Info, contextInfoPtr->objectHandle,
hDsaKey, CK_OBJECT_NONE,
dsaKey->p, bitsToBytes( dsaKey->pLen ),
dsaKey->q, bitsToBytes( dsaKey->qLen ),
dsaKey->g, bitsToBytes( dsaKey->gLen ),
yValue, yValueLength, FALSE );
if( cryptStatusError( cryptStatus ) )
C_DestroyObject( pkcs11Info->hSession, hDsaKey );
else
/* Remember that this object is backed by a crypto device */
contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT;
krnlReleaseObject( iCryptDevice );
return( cryptStatus );
}
static int dsaGenerateKey( CONTEXT_INFO *contextInfoPtr, const int keysizeBits )
{
static const CK_MECHANISM mechanism = { CKM_DSA_KEY_PAIR_GEN, NULL_PTR, 0 };
static const CK_BBOOL bTrue = TRUE;
CK_ATTRIBUTE privateKeyTemplate[] = {
{ CKA_TOKEN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_PRIVATE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_SENSITIVE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_LABEL, contextInfoPtr->label, contextInfoPtr->labelSize },
{ CKA_SIGN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
};
CK_ATTRIBUTE publicKeyTemplate[] = {
{ CKA_TOKEN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_LABEL, contextInfoPtr->label, contextInfoPtr->labelSize },
{ CKA_VERIFY, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_PRIME, NULL, 0 },
{ CKA_SUBPRIME, NULL, 0 },
{ CKA_BASE, NULL, 0 },
};
CK_ATTRIBUTE yValueTemplate = { CKA_VALUE, NULL, CRYPT_MAX_PKCSIZE * 2 };
CK_OBJECT_HANDLE hPublicKey, hPrivateKey;
MESSAGE_CREATEOBJECT_INFO createInfo;
MESSAGE_DATA msgData;
CRYPT_DEVICE iCryptDevice;
PKCS11_INFO *pkcs11Info;
BYTE pubkeyBuffer[ ( CRYPT_MAX_PKCSIZE * 3 ) + 8 ], label[ 8 + 8 ];
CK_RV status;
STREAM stream;
void *dataPtr = DUMMY_INIT_PTR;
long length;
int cryptStatus;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( keysizeBits >= bytesToBits( MIN_PKCSIZE ) && \
keysizeBits <= bytesToBits( CRYPT_MAX_PKCSIZE ) );
/* CKM_DSA_KEY_PAIR_GEN is really a Clayton's key generation mechanism
since it doesn't actually generate the p, q, or g values (presumably
it dates back to the original FIPS 186 shared domain parameters idea).
Because of this we'd have to generate half the key ourselves in a
native context, then copy portions from the native context over in
flat form and complete the keygen via the device. The easiest way to
do this is to create a native DSA context, generate a key, grab the
public portions, and destroy the context again (i.e. generate a full
key on a superscalar 2GHz RISC CPU, then throw half of it away, and
regenerate it on a 5MHz 8-bit tinkertoy). Since the keygen can take
awhile and doesn't require the device, we do it before we grab the
device */
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 );
cryptStatus = krnlSendNotifier( createInfo.cryptHandle,
IMESSAGE_CTX_GENKEY );
if( cryptStatusOK( cryptStatus ) )
{
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 );
/* Set up the public key info by extracting the flat values from the
SubjectPublicKeyInfo. 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 q to be zero-padded
to make it exactly 20 bytes rather than (say) 19 bytes if the high
byte is zero) */
sMemConnect( &stream, pubkeyBuffer, msgData.length );
readSequence( &stream, NULL ); /* SEQUENCE */
readSequence( &stream, NULL ); /* SEQUENCE */
readUniversal( &stream ); /* OID */
readSequence( &stream, NULL ); /* SEQUENCE */
status = readGenericHole( &stream, &length, 16, BER_INTEGER ); /* p */
if( cryptStatusOK( status ) )
status = sMemGetDataBlock( &stream, &dataPtr, length );
if( cryptStatusError( status ) )
retIntError();
publicKeyTemplate[ 3 ].pValue = dataPtr;
publicKeyTemplate[ 3 ].ulValueLen = length;
sSkip( &stream, length );
status = readGenericHole( &stream, &length, 16, BER_INTEGER ); /* q */
if( cryptStatusOK( status ) )
status = sMemGetDataBlock( &stream, &dataPtr, length );
if( cryptStatusError( status ) )
retIntError();
publicKeyTemplate[ 4 ].pValue = dataPtr;
publicKeyTemplate[ 4 ].ulValueLen = length;
sSkip( &stream, length );
status = readGenericHole( &stream, &length, 16, BER_INTEGER ); /* g */
if( cryptStatusOK( status ) )
status = sMemGetDataBlock( &stream, &dataPtr, length );
if( cryptStatusError( status ) )
retIntError();
publicKeyTemplate[ 5 ].pValue = dataPtr;
publicKeyTemplate[ 5 ].ulValueLen = length;
sMemDisconnect( &stream );
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* Generate the keys */
status = C_GenerateKeyPair( pkcs11Info->hSession,
( CK_MECHANISM_PTR ) &mechanism,
( CK_ATTRIBUTE_PTR ) publicKeyTemplate, 6,
( CK_ATTRIBUTE_PTR ) privateKeyTemplate, 5,
&hPublicKey, &hPrivateKey );
cryptStatus = pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED );
if( cryptStatusError( cryptStatus ) )
{
krnlReleaseObject( iCryptDevice );
return( cryptStatus );
}
/* Read back the generated y value, send the public key info to the
context, and set up the key ID info. The odd two-phase y value read
is necessary for buggy implementations that fail if the given size
isn't exactly the same as the data size */
status = C_GetAttributeValue( pkcs11Info->hSession, hPublicKey,
&yValueTemplate, 1 );
if( status == CKR_OK )
{
yValueTemplate.pValue = pubkeyBuffer;
status = C_GetAttributeValue( pkcs11Info->hSession, hPublicKey,
&yValueTemplate, 1 );
}
cryptStatus = pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = dsaSetKeyInfo( pkcs11Info, contextInfoPtr->objectHandle,
hPrivateKey, hPublicKey,
publicKeyTemplate[ 3 ].pValue, publicKeyTemplate[ 3 ].ulValueLen,
publicKeyTemplate[ 4 ].pValue, publicKeyTemplate[ 4 ].ulValueLen,
publicKeyTemplate[ 5 ].pValue, publicKeyTemplate[ 5 ].ulValueLen,
yValueTemplate.pValue, yValueTemplate.ulValueLen, FALSE );
if( cryptStatusError( cryptStatus ) )
{
C_DestroyObject( pkcs11Info->hSession, hPublicKey );
C_DestroyObject( pkcs11Info->hSession, hPrivateKey );
}
else
/* Remember that this object is backed by a crypto device */
contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT;
krnlReleaseObject( iCryptDevice );
return( cryptStatus );
}
static int dsaSign( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int length )
{
static const CK_MECHANISM mechanism = { CKM_DSA, NULL_PTR, 0 };
CRYPT_DEVICE iCryptDevice;
PKCS11_INFO *pkcs11Info;
DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
PKC_INFO *dsaKey = contextInfoPtr->ctxPKC;
BIGNUM *r, *s;
BYTE signature[ 40 + 8 ];
int cryptStatus;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isWritePtr( buffer, length ) );
assert( length == sizeof( DLP_PARAMS ) );
assert( dlpParams->inParam1 != NULL && \
dlpParams->inLen1 == 20 );
assert( dlpParams->inParam2 == NULL && dlpParams->inLen2 == 0 );
assert( dlpParams->outParam != NULL && \
dlpParams->outLen >= ( 2 + 20 ) * 2 );
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
cryptStatus = genericSign( pkcs11Info, contextInfoPtr, &mechanism,
dlpParams->inParam1, dlpParams->inLen1,
signature, 40 );
krnlReleaseObject( iCryptDevice );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* Encode the result as a DL data block. We have to do this via bignums,
but this isn't a big deal since DSA signing via tokens is almost never
used */
r = BN_new();
if( r == NULL )
return( CRYPT_ERROR_MEMORY );
s = BN_new();
if( s == NULL )
{
BN_free( r );
return( CRYPT_ERROR_MEMORY );
}
cryptStatus = extractBignum( r, signature, 20,
bitsToBytes( 160 - 32 ), 20, NULL, FALSE );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = extractBignum( r, signature + 20, 20,
bitsToBytes( 160 - 32 ), 20, NULL, FALSE );
if( cryptStatusOK( cryptStatus ) )
{
cryptStatus = \
dsaKey->encodeDLValuesFunction( dlpParams->outParam,
dlpParams->outLen, &dlpParams->outLen,
r, s, dlpParams->formatType );
}
BN_clear_free( s );
BN_clear_free( r );
return( cryptStatus );
}
static int dsaVerify( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int length )
{
static const CK_MECHANISM mechanism = { CKM_DSA, NULL_PTR, 0 };
/* CRYPT_DEVICE iCryptDevice; */
DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
PKC_INFO *dsaKey = contextInfoPtr->ctxPKC;
BIGNUM r, s;
/* BYTE signature[ 40 + 8 ]; */
int cryptStatus;
/* This function is present but isn't used as part of any normal
operation because cryptlib does the same thing much faster in
software and because some tokens don't support public-key
operations */
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isWritePtr( buffer, length ) );
assert( length == sizeof( DLP_PARAMS ) );
assert( dlpParams->inParam1 != NULL && dlpParams->inLen1 == 20 );
assert( dlpParams->inParam2 != NULL && \
( ( dlpParams->formatType == CRYPT_FORMAT_CRYPTLIB && \
dlpParams->inLen2 >= 46 ) || \
( dlpParams->formatType == CRYPT_FORMAT_PGP && \
dlpParams->inLen2 == 44 ) || \
( dlpParams->formatType == CRYPT_IFORMAT_SSH && \
dlpParams->inLen2 == 40 ) ) );
assert( dlpParams->outParam == NULL && dlpParams->outLen == 0 );
/* Decode the values from a DL data block and make sure r and s are
valid */
BN_init( &r );
BN_init( &s );
cryptStatus = \
dsaKey->decodeDLValuesFunction( dlpParams->inParam2, dlpParams->inLen2,
&r, &s, NULL, dlpParams->formatType );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* This code can never be called since DSA public-key contexts are
always native contexts */
retIntError();
#if 0
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
cryptStatus = genericVerify( pkcs11Info, contextInfoPtr, &mechanism,
buffer, 20, signature, 40 );
krnlReleaseObject( iCryptDevice );
return( cryptStatus );
#endif /* 0 */
}
/****************************************************************************
* *
* Device Capability Routines *
* *
****************************************************************************/
/* PKC mechanism info */
static const PKCS11_MECHANISM_INFO mechanismInfoPKC[] = {
/* The handling of the RSA mechanism is a bit odd. Almost everyone
supports CKM_RSA_X_509 even though what's reported as being supported
is CKM_RSA_PKCS, however the PKCS mechanism is often implemented in a
buggy manner with all sorts of problems with handling the padding.
The safest option would be to use the raw RSA one and do the padding
ourselves, which means that it'll always be done right. Since some
implementations report raw RSA as being unavailable even though it's
present, we detect it by checking for the PKCS mechanism but using
raw RSA. However, some implementations genuinely don't do raw RSA, so
the code fakes it by removing/adding dummy PKCS padding as required
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -