📄 dev_pk11.c
字号:
int i;
if( pkcs11Initialised )
for( i = 0; i < MAX_PKCS11_DRIVERS; i++ )
{
if( pkcs11InfoTbl[ i ].hPKCS11 != NULL_INSTANCE )
{
pkcs11InfoTbl[ i ].pC_Finalize( NULL_PTR );
DynamicUnload( pkcs11InfoTbl[ i ].hPKCS11 );
}
pkcs11InfoTbl[ i ].hPKCS11 = NULL_INSTANCE;
}
pkcs11Initialised = FALSE;
}
int deviceInitPKCS11( void )
{
int tblIndex = 0, optionIndex;
/* If we've previously tried to init the drivers, don't try it again */
if( pkcs11Initialised )
return( CRYPT_OK );
memset( pkcs11InfoTbl, 0, sizeof( pkcs11InfoTbl ) );
/* Try and link in each driver specified in the config options. Since
this is a general systemwide config option, we always query the built-
in default user object */
for( optionIndex = 0; optionIndex < MAX_PKCS11_DRIVERS; optionIndex++ )
{
RESOURCE_DATA msgData;
char deviceDriverName[ MAX_PATH_LENGTH + 1 ];
int status;
setMessageData( &msgData, deviceDriverName, MAX_PATH_LENGTH );
status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
optionIndex + CRYPT_OPTION_DEVICE_PKCS11_DVR01 );
if( cryptStatusError( status ) )
continue;
deviceDriverName[ msgData.length ] = '\0';
status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ],
deviceDriverName );
if( cryptStatusOK( status ) )
{
tblIndex++;
pkcs11Initialised = TRUE;
}
}
return( CRYPT_OK );
}
#else
int deviceInitPKCS11( void )
{
/* If we've previously tried to init the drivers, don't try it again */
if( pkcs11Initialised )
return( CRYPT_OK );
if( C_Initialize( NULL_PTR ) != CKR_OK )
return( CRYPT_ERROR );
pkcs11Initialised = TRUE;
return( CRYPT_OK );
}
void deviceEndPKCS11( void )
{
if( pkcs11Initialised )
C_Finalize( NULL_PTR );
pkcs11Initialised = FALSE;
}
#endif /* DYNAMIC_LOAD */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Map a PKCS #11-specific error to a cryptlib error */
static int mapError( PKCS11_INFO *pkcs11Info, const CK_RV errorCode,
const int defaultError )
{
pkcs11Info->errorCode = ( int ) errorCode;
switch( ( int ) errorCode )
{
case CKR_OK:
return( CRYPT_OK );
case CKR_HOST_MEMORY:
case CKR_DEVICE_MEMORY:
return( CRYPT_ERROR_MEMORY );
case CKR_DEVICE_ERROR:
case CKR_DEVICE_REMOVED:
case CKR_TOKEN_NOT_PRESENT:
case CKR_TOKEN_NOT_RECOGNIZED:
return( CRYPT_ERROR_SIGNALLED );
case CKR_PIN_INCORRECT:
case CKR_PIN_INVALID:
case CKR_PIN_LEN_RANGE:
case CKR_PIN_EXPIRED:
case CKR_PIN_LOCKED:
return( CRYPT_ERROR_WRONGKEY );
case CKR_DATA_INVALID:
case CKR_ENCRYPTED_DATA_INVALID:
case CKR_WRAPPED_KEY_INVALID:
return( CRYPT_ERROR_BADDATA );
case CKR_SIGNATURE_INVALID:
return( CRYPT_ERROR_SIGNATURE );
case CKR_KEY_NOT_WRAPPABLE:
case CKR_KEY_UNEXTRACTABLE:
case CKR_TOKEN_WRITE_PROTECTED:
case CKR_INFORMATION_SENSITIVE:
return( CRYPT_ERROR_PERMISSION );
case CKR_DATA_LEN_RANGE:
case CKR_ENCRYPTED_DATA_LEN_RANGE:
case CKR_SIGNATURE_LEN_RANGE:
case CKR_UNWRAPPING_KEY_SIZE_RANGE:
case CKR_WRAPPING_KEY_SIZE_RANGE:
case CKR_WRAPPED_KEY_LEN_RANGE:
return( CRYPT_ERROR_OVERFLOW );
case CKR_SESSION_EXISTS:
case CKR_SESSION_READ_ONLY_EXISTS:
case CKR_SESSION_READ_WRITE_SO_EXISTS:
case CKR_USER_ALREADY_LOGGED_IN:
case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
case CKR_CRYPTOKI_NOT_INITIALIZED:
return( CRYPT_ERROR_INITED );
case CKR_USER_NOT_LOGGED_IN:
case CKR_USER_PIN_NOT_INITIALIZED:
case CKR_CRYPTOKI_ALREADY_INITIALIZED:
return( CRYPT_ERROR_NOTINITED );
case CKR_RANDOM_NO_RNG:
return( CRYPT_ERROR_RANDOM );
case CKR_OPERATION_ACTIVE:
return( CRYPT_ERROR_TIMEOUT );
}
return( defaultError );
}
/* Extract the time from a PKCS #11 tokenInfo structure */
static time_t getTokenTime( CK_TOKEN_INFO *tokenInfo )
{
STREAM stream;
BYTE buffer[ 32 ];
time_t theTime = MIN_TIME_VALUE + 1;
int length, status;
/* Convert the token time to an ASN.1 time string that we can read using
the standard ASN.1 routines by writing a dummy time value and inserting
the token's time string in its place */
sMemOpen( &stream, buffer, 32 );
writeGeneralizedTime( &stream, theTime, DEFAULT_TAG );
length = stell( &stream );
sMemDisconnect( &stream );
memcpy( buffer + 2, tokenInfo->utcTime, 14 );
sMemConnect( &stream, buffer, length );
status = readGeneralizedTime( &stream, &theTime );
sMemDisconnect( &stream );
return( ( cryptStatusOK( status ) ) ? theTime : 0 );
}
/* Find an object based on a given template. There are two variations of
this, one that finds one and only one object, and the other that returns
the first object it finds without treating the presence of multiple
objects as an error.
The way in which this call works has special significance, there are PKCS
#11 implementations that don't allow any other calls during the init/find/
final sequence, so the code is structured to always call them one after
the other without any intervening calls. In addition some drivers are
confused over whether they're 1.x or 2.x and may or may not implement
C_FindObjectsFinal(). Because of this we call it if it exists, if it
doesn't we assume that the driver can handle cleanup itself (this
situation shouldn't occur because we've checked for 1.x drivers earlier,
but there are one or two drivers where it does happen) */
static int findDeviceObjects( PKCS11_INFO *pkcs11Info,
CK_OBJECT_HANDLE *hObject,
const CK_ATTRIBUTE *objectTemplate,
const CK_ULONG templateCount,
const BOOLEAN onlyOne )
{
CK_OBJECT_HANDLE hObjectArray[ 2 ];
CK_ULONG ulObjectCount;
CK_RV status;
status = C_FindObjectsInit( pkcs11Info->hSession,
( CK_ATTRIBUTE_PTR ) objectTemplate,
templateCount );
if( status == CKR_OK )
{
status = C_FindObjects( pkcs11Info->hSession, hObjectArray,
2, &ulObjectCount );
if( C_FindObjectsFinal != NULL )
C_FindObjectsFinal( pkcs11Info->hSession );
}
if( status != CKR_OK )
return( mapError( pkcs11Info, status, CRYPT_ERROR_NOTFOUND ) );
if( ulObjectCount <= 0 )
return( CRYPT_ERROR_NOTFOUND );
if( ulObjectCount > 1 && onlyOne )
return( CRYPT_ERROR_DUPLICATE );
if( hObject != NULL )
*hObject = hObjectArray[ 0 ];
return( CRYPT_OK );
}
static int findObject( PKCS11_INFO *pkcs11Info, CK_OBJECT_HANDLE *hObject,
const CK_ATTRIBUTE *objectTemplate,
const CK_ULONG templateCount )
{
return( findDeviceObjects( pkcs11Info, hObject,
objectTemplate, templateCount, TRUE ) );
}
static int findObjectEx( PKCS11_INFO *pkcs11Info, CK_OBJECT_HANDLE *hObject,
const CK_ATTRIBUTE *objectTemplate,
const CK_ULONG templateCount )
{
return( findDeviceObjects( pkcs11Info, hObject,
objectTemplate, templateCount, FALSE ) );
}
/* Set up certificate information and load it into the card */
static int updateCertificate( PKCS11_INFO *pkcs11Info,
const CRYPT_HANDLE iCryptHandle )
{
static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
static const CK_OBJECT_CLASS privkeyClass = CKO_PRIVATE_KEY;
static const CK_OBJECT_CLASS pubkeyClass = CKO_PUBLIC_KEY;
static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
static const CK_BBOOL bTrue = TRUE;
CK_ATTRIBUTE certTemplate[] = {
{ CKA_CLASS, ( CK_VOID_PTR ) &certClass, sizeof( CK_OBJECT_CLASS ) },
{ CKA_CERTIFICATE_TYPE, ( CK_VOID_PTR ) &certType, sizeof( CK_CERTIFICATE_TYPE ) },
{ CKA_TOKEN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_ID, NULL_PTR, 0 },
{ CKA_SUBJECT, NULL_PTR, 0 },
{ CKA_ISSUER, NULL_PTR, 0 },
{ CKA_SERIAL_NUMBER, NULL_PTR, 0 },
{ CKA_VALUE, NULL_PTR, 0 },
};
CK_ATTRIBUTE keyTemplate[] = {
{ CKA_CLASS, ( CK_VOID_PTR ) &privkeyClass, sizeof( CK_OBJECT_CLASS ) },
{ CKA_ID, NULL_PTR, 0 }
};
CK_OBJECT_HANDLE hObject;
CK_RV status;
RESOURCE_DATA msgData;
STREAM stream;
DYNBUF subjectDB, iAndSDB, certDB;
BYTE keyID[ CRYPT_MAX_HASHSIZE ];
int length, cryptStatus;
/* Get the key ID for the cert and use it to locate the corresponding
public or private key object. This is used as a check to ensure that
the certificate corresponds to a key in the device. In theory this
would allow us to read the label from the key so that we can reuse it
for the cert, but there doesn't seem to be any good reason for this
and it could lead to problems with multiple certs with the same
labels so we don't do it */
setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID );
if( cryptStatusError( cryptStatus ) )
return( CRYPT_ARGERROR_NUM1 );
keyTemplate[ 1 ].pValue = msgData.data;
keyTemplate[ 1 ].ulValueLen = msgData.length;
cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
if( cryptStatusError( cryptStatus ) )
{
/* Couldn't find a private key with this ID, try for a public key */
keyTemplate[ 0 ].pValue = ( CK_VOID_PTR ) &pubkeyClass;
cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
}
if( cryptStatusError( cryptStatus ) )
return( CRYPT_ARGERROR_NUM1 );
certTemplate[ 3 ].pValue = msgData.data;
certTemplate[ 3 ].ulValueLen = msgData.length;
/* Get the subjectName from the cert */
cryptStatus = dynCreate( &subjectDB, iCryptHandle,
CRYPT_IATTRIBUTE_SUBJECT );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
certTemplate[ 4 ].pValue = dynData( subjectDB );
certTemplate[ 4 ].ulValueLen = dynLength( subjectDB );
/* Get the issuerAndSerialNumber from the cert */
cryptStatus = dynCreate( &iAndSDB, iCryptHandle,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusError( cryptStatus ) )
{
dynDestroy( &subjectDB );
return( cryptStatus );
}
sMemConnect( &stream, dynData( iAndSDB ), dynLength( iAndSDB ) );
readSequence( &stream, NULL );
certTemplate[ 5 ].pValue = sMemBufPtr( &stream );
readSequence( &stream, &length ); /* Issuer DN */
certTemplate[ 5 ].ulValueLen = ( int ) sizeofObject( length );
sSkip( &stream, length );
certTemplate[ 6 ].pValue = sMemBufPtr( &stream );
readGenericHole( &stream, &length, BER_INTEGER );/* Serial number */
certTemplate[ 6 ].ulValueLen = ( int ) sizeofObject( length );
assert( sStatusOK( &stream ) );
sMemDisconnect( &stream );
/* Get the certificate data */
cryptStatus = dynCreate( &certDB, iCryptHandle,
CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusError( cryptStatus ) )
{
dynDestroy( &subjectDB );
dynDestroy( &iAndSDB );
return( cryptStatus );
}
certTemplate[ 7 ].pValue = dynData( certDB );
certTemplate[ 7 ].ulValueLen = dynLength( certDB );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -