📄 pkcs11.c
字号:
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* Change the SSO PIN from the init PIN. Once we've done this we
clear the initial SSO PIN, since it's no longer valid in the new
state */
status = C_SetPIN( pkcs11Info->hSession, pkcs11Info->defaultSSOPin,
pkcs11Info->defaultSSOPinLen,
( CK_CHAR_PTR ) data, ( CK_ULONG ) dataLength );
zeroise( pkcs11Info->defaultSSOPin, CRYPT_MAX_TEXTSIZE );
pkcs11Info->defaultSSOPinLen = 0;
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
}
if( type == CRYPT_DEVINFO_SET_AUTHENT_USER )
{
/* Make sure that the PIN is within range */
if( dataLength < pkcs11Info->minPinSize || \
dataLength > pkcs11Info->maxPinSize )
return( CRYPT_ARGERROR_NUM1 );
status = C_InitPIN( pkcs11Info->hSession, ( CK_CHAR_PTR ) data,
( CK_ULONG ) dataLength );
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
}
/* Handle initialisation and zeroisation */
if( type == CRYPT_DEVINFO_INITIALISE || \
type == CRYPT_DEVINFO_ZEROISE )
{
CK_SESSION_HANDLE hSession;
CK_CHAR label[ 32 + 8 ];
/* Make sure that the PIN is within range */
if( dataLength < pkcs11Info->minPinSize || \
dataLength > pkcs11Info->maxPinSize )
return( CRYPT_ARGERROR_NUM1 );
/* If there's a session active with the device, log out and terminate
the session, since the token init will reset this */
if( pkcs11Info->hSession != CK_OBJECT_NONE )
{
C_Logout( pkcs11Info->hSession );
C_CloseSession( pkcs11Info->hSession );
pkcs11Info->hSession = CK_OBJECT_NONE;
}
/* Initialise/clear the device, setting the initial SSO PIN */
memset( label, ' ', 32 );
status = C_InitToken( pkcs11Info->slotID,
( CK_CHAR_PTR ) data,
( CK_ULONG ) dataLength, label );
if( status != CKR_OK )
return( pkcs11MapError( pkcs11Info, status,
CRYPT_ERROR_FAILED ) );
/* Reopen the session with the device */
status = C_OpenSession( pkcs11Info->slotID,
CKF_RW_SESSION | CKF_SERIAL_SESSION,
NULL_PTR, NULL_PTR, &hSession );
if( status != CKR_OK )
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_OPEN ) );
assert( hSession != CK_OBJECT_NONE );
pkcs11Info->hSession = hSession;
/* If it's a straight zeroise, we're done */
if( type == CRYPT_DEVINFO_ZEROISE )
return( CRYPT_OK );
/* We're initialising it, log in as supervisor. In theory we could
also set the initial user PIN to the same as the SSO PIN at this
point because the user usually won't be aware of the presence of
an SSO role or the need to set a PIN for it, but this can run into
problems with tokens that only allow the user PIN to be modified
by the SSO after they've set it for the first time, so if the user
*is* aware of the existence of an SSO role then once they log in
as SSO they can no longer set the user PIN */
status = C_Login( pkcs11Info->hSession, CKU_SO,
( CK_CHAR_PTR ) data, ( CK_ULONG ) dataLength );
if( status != CKR_OK )
{
C_Logout( pkcs11Info->hSession );
C_CloseSession( pkcs11Info->hSession );
pkcs11Info->hSession = CK_OBJECT_NONE;
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
}
/* Remember the default SSO PIN for use with a future C_SetPIN() */
memcpy( pkcs11Info->defaultSSOPin, data, dataLength );
pkcs11Info->defaultSSOPinLen = dataLength;
/* We're logged in and ready to go */
deviceInfo->flags |= DEVICE_LOGGEDIN;
return( CRYPT_OK );
}
/* Handle high-reliability time */
if( type == CRYPT_IATTRIBUTE_TIME )
{
CK_TOKEN_INFO tokenInfo;
time_t *timePtr = ( time_t * ) data, theTime;
/* Get the token's time, returned as part of the token info
structure */
status = C_GetTokenInfo( pkcs11Info->slotID, &tokenInfo );
if( status != CKR_OK )
return( pkcs11MapError( pkcs11Info, status,
CRYPT_ERROR_SIGNALLED ) );
if( ( theTime = getTokenTime( &tokenInfo ) ) <= MIN_TIME_VALUE )
return( CRYPT_ERROR_NOTAVAIL );
*timePtr = theTime;
return( CRYPT_OK );
}
retIntError();
}
/****************************************************************************
* *
* Capability Interface Routines *
* *
****************************************************************************/
/* Encrypt, decrypt */
static int genericEncrypt( PKCS11_INFO *pkcs11Info,
CONTEXT_INFO *contextInfoPtr,
const CK_MECHANISM *pMechanism, void *buffer,
const int length, const int outLength )
{
CK_ULONG resultLen = outLength;
CK_RV status;
status = C_EncryptInit( pkcs11Info->hSession,
( CK_MECHANISM_PTR ) pMechanism,
contextInfoPtr->deviceObject );
if( status == CKR_OK )
status = C_Encrypt( pkcs11Info->hSession, buffer, length,
buffer, &resultLen );
if( status != CKR_OK )
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
return( CRYPT_OK );
}
static int genericDecrypt( PKCS11_INFO *pkcs11Info,
CONTEXT_INFO *contextInfoPtr,
const CK_MECHANISM *pMechanism, void *buffer,
const int length )
{
CK_ULONG resultLen = length;
CK_RV status;
status = C_DecryptInit( pkcs11Info->hSession,
( CK_MECHANISM_PTR ) pMechanism,
contextInfoPtr->deviceObject );
if( status == CKR_OK )
status = C_Decrypt( pkcs11Info->hSession, buffer, length,
buffer, &resultLen );
if( status != CKR_OK )
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
return( CRYPT_OK );
}
/* Clean up the object associated with a context */
int genericEndFunction( CONTEXT_INFO *contextInfoPtr )
{
CRYPT_DEVICE iCryptDevice;
PKCS11_INFO *pkcs11Info;
int cryptStatus;
/* Since the device object that corresponds to the cryptlib object is
created on-demand, it may not exist yet if the action that triggers
the on-demand creation hasn't been taken yet. If no device object
exists, we're done */
if( contextInfoPtr->deviceObject == CRYPT_ERROR )
return( CRYPT_OK );
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* If we're deleting an object that's in the middle of a multi-stage
operation, record the fact that the operation has now ended. We
have to perform this tracking explicitly since PKCS #11 only allows
one multi-stage operation per session */
if( pkcs11Info->hActiveSignObject == contextInfoPtr->deviceObject )
pkcs11Info->hActiveSignObject = CK_OBJECT_NONE;
/* If this is a persistent object, we can't destroy it. This is a bit
problematic since PKCS #11 doesn't differentiate between releasing
an object handle and destroying (deleting) it, which means that
repeatedly instantiating a persistent object (via getItemFunction())
and then destroying it leaks a PKCS #11 handle each time.
Unfortunately there's nothing that we can do about this since the
problem lies at the PKCS #11 level */
if( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT )
{
krnlReleaseObject( iCryptDevice );
return( CRYPT_OK );
}
/* Destroy the object */
C_DestroyObject( pkcs11Info->hSession, contextInfoPtr->deviceObject );
if( contextInfoPtr->altDeviceObject != CK_OBJECT_NONE )
C_DestroyObject( pkcs11Info->hSession,
contextInfoPtr->altDeviceObject );
krnlReleaseObject( iCryptDevice );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Conventional Crypto/MAC Key Load Functions *
* *
****************************************************************************/
/* Get a PKCS #11 mechanism corresponding to a cryptlib algorithm and
optional mode */
typedef enum { MECH_NONE, MECH_CONV, MECH_MAC, MECH_CONV_KEYGEN,
MECH_MAC_KEYGEN, MECH_LAST } GETMECH_TYPE;
static CK_MECHANISM_TYPE getMechanism( const GETMECH_TYPE mechType,
const CRYPT_ALGO_TYPE cryptAlgo,
const CRYPT_MODE_TYPE cryptMode );
/* Set up a key template and context info in preparation for creating a
device object */
static void adjustKeyParity( BYTE *key, const int length )
{
int i;
assert( isWritePtr( key, length ) );
/* Adjust a key to have odd parity, needed for DES keys */
for( i = 0; i < length; i++ )
{
BYTE ch = key[ i ];
ch = ( ch & 0x55 ) + ( ( ch >> 1 ) & 0x55 );
ch = ( ch & 0x33 ) + ( ( ch >> 2 ) & 0x33 );
if( !( ( ch + ( ch >> 4 ) ) & 0x01 ) )
key[ i ] ^= 1;
}
}
/* Load a key into a device object */
static int initKey( CONTEXT_INFO *contextInfoPtr, CK_ATTRIBUTE *keyTemplate,
const int templateCount, const void *key,
const int keyLength )
{
CRYPT_DEVICE iCryptDevice;
const CRYPT_ALGO_TYPE cryptAlgo = \
contextInfoPtr->capabilityInfo->cryptAlgo;
PKCS11_INFO *pkcs11Info;
CK_OBJECT_HANDLE hObject;
CK_RV status;
BYTE *contextKeyPtr;
int *contextKeyLenPtr;
int keySize = \
( cryptAlgo == CRYPT_ALGO_DES || cryptAlgo == CRYPT_ALGO_3DES || \
cryptAlgo == CRYPT_ALGO_IDEA || cryptAlgo == CRYPT_ALGO_SKIPJACK ) ? \
contextInfoPtr->capabilityInfo->keySize : keyLength;
int cryptStatus;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isWritePtr( keyTemplate, \
templateCount * sizeof( CK_ATTRIBUTE ) ) );
assert( isReadPtr( key, keyLength ) );
/* Get the info for the device associated with this context */
cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle,
&iCryptDevice, &pkcs11Info );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* Set up pointers to the appropriate object sub-type data */
if( contextInfoPtr->type == CONTEXT_CONV )
{
contextKeyPtr = contextInfoPtr->ctxConv->userKey;
contextKeyLenPtr = &contextInfoPtr->ctxConv->userKeyLength;
}
else
{
assert( contextInfoPtr->type == CONTEXT_MAC );
contextKeyPtr = contextInfoPtr->ctxMAC->userKey;
contextKeyLenPtr = &contextInfoPtr->ctxMAC->userKeyLength;
}
/* Copy the key to internal storage */
if( contextKeyPtr != key )
memcpy( contextKeyPtr, key, keyLength );
*contextKeyLenPtr = keyLength;
/* Special-case handling for 2-key vs.3-key 3DES */
if( cryptAlgo == CRYPT_ALGO_3DES )
{
/* If the supplied key contains only two DES keys, adjust the key to
make it the equivalent of 3-key 3DES. In addition since the
nominal keysize is for 2-key 3DES, we have to make the actual
size the maximum size, corresponding to 3-key 3DES */
if( keyLength <= bitsToBytes( 64 * 2 ) )
memcpy( contextKeyPtr + bitsToBytes( 64 * 2 ),
contextKeyPtr, bitsToBytes( 64 ) );
keySize = contextInfoPtr->capabilityInfo->maxKeySize;
}
/* If we're using DES we have to adjust the key parity because the spec
says so, almost all implementations do this anyway but there's always
the odd one out that we have to cater for */
if( cryptAlgo == CRYPT_ALGO_DES || cryptAlgo == CRYPT_ALGO_3DES )
adjustKeyParity( contextKeyPtr, keySize );
/* Set up the key values. Since the key passed in by the user may be
smaller than the keysize required by algorithms that use fixed-size
keys, we use the (optionally) zero-padded key of the correct length
held in the context rather than the variable-length user-supplied
one */
keyTemplate[ 7 ].pValue = contextKeyPtr;
keyTemplate[ 7 ].ulValueLen = keySize;
/* Load the key into the token */
status = C_CreateObject( pkcs11Info->hSession, keyTemplate,
templateCount, &hObject );
cryptStatus = pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED );
if( cryptStatusOK( cryptStatus ) )
{
assert( hObject != CK_OBJECT_NONE );
contextInfoPtr->deviceObject = hObject;
}
else
{
zeroise( contextInfoPtr->ctxConv->userKey, keyLength );
contextInfoPtr->ctxConv->userKeyLength = 0;
}
zeroise( keyTemplate, sizeof( CK_ATTRIBUTE ) * templateCount );
krnlReleaseObject( iCryptDevice );
return( cryptStatus );
}
static int cipherInitKey( CONTEXT_INFO *contextInfoPtr, const void *key,
const int keyLength )
{
static const CK_OBJECT_CLASS class = CKO_SECRET_KEY;
static const CK_BBOOL bFalse = FALSE, bTrue = TRUE;
const CK_KEY_TYPE type = contextInfoPtr->capabilityInfo->paramKeyType;
CK_ATTRIBUTE keyTemplate[] = {
/* General-purpose fields */
{ CKA_CLASS, ( CK_VOID_PTR ) &class, sizeof( CK_OBJECT_CLASS ) },
{ CKA_KEY_TYPE, ( CK_VOID_PTR ) &type, sizeof( CK_KEY_TYPE ) },
{ CKA_TOKEN, ( CK_VOID_PTR ) &bFalse, sizeof( CK_BBOOL ) },
{ CKA_PRIVATE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_SENSITIVE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_ENCRYPT, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_DECRYPT, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_VALUE, NULL_PTR, 0 },
/* Persistent-object only fields */
{ CKA_LABEL, contextInfoPtr->label, contextInfoPtr->labelSize }
};
const int templateCount = \
( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT ) ? 9 : 8;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -