📄 pkcs11.c
字号:
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 device */
static int updateCertificate( PKCS11_INFO *pkcs11Info,
const CRYPT_HANDLE iCryptHandle,
const BOOLEAN isLeafCert )
{
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 keyID from the cert */
setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID );
if( cryptStatusError( cryptStatus ) )
return( CRYPT_ARGERROR_NUM1 );
certTemplate[ 3 ].pValue = msgData.data;
certTemplate[ 3 ].ulValueLen = msgData.length;
/* If it's a leaf cert, use the keyID 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 */
if( isLeafCert )
{
keyTemplate[ 1 ].pValue = certTemplate[ 3 ].pValue;
keyTemplate[ 1 ].ulValueLen = certTemplate[ 3 ].ulValueLen;
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 );
}
/* 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 );
/* We've finally got everything available, try and update the device with
the certificate data. In theory we should also set CKA_PRIVATE = FALSE
but the Dallas iButton driver doesn't allow this so we have to rely on
drivers doing the right thing with the default setting */
status = C_CreateObject( pkcs11Info->hSession,
( CK_ATTRIBUTE_PTR ) certTemplate, 8,
&hObject );
if( status != CKR_OK )
cryptStatus = mapError( pkcs11Info, status, CRYPT_ERROR_FAILED );
/* Clean up */
dynDestroy( &subjectDB );
dynDestroy( &iAndSDB );
dynDestroy( &certDB );
return( cryptStatus );
}
/* Update a device using the certs in a cert chain */
static int updateCertChain( PKCS11_INFO *pkcs11Info,
const CRYPT_CERTIFICATE iCryptCert )
{
static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
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_ISSUER, NULL_PTR, 0 },
{ CKA_SERIAL_NUMBER, NULL_PTR, 0 },
};
BOOLEAN isLeafCert = TRUE, seenNonDuplicate = FALSE;
int value, cryptStatus;
/* If we've been passed a standalone cert, check whether it's implicitly
trusted, which allows to be added without the presence of a
corresponding public/private key in the device */
cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusError( cryptStatus ) )
return( ( cryptStatus == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_NUM1 : cryptStatus );
if( value == CRYPT_CERTTYPE_CERTIFICATE )
{
cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE,
&value,
CRYPT_CERTINFO_TRUSTED_IMPLICIT );
if( cryptStatusError( cryptStatus ) )
return( CRYPT_ARGERROR_NUM1 );
/* If the cert is implicitly trusted we indicate that it's
(effectively) a non-leaf cert so that it can be added even if
there's no corresponding key already in the device */
if( value )
isLeafCert = FALSE;
}
/* Add each cert in the chain to the device */
do
{
CK_OBJECT_HANDLE hObject;
STREAM stream;
DYNBUF iAndSDB;
int length;
/* If the cert is already present, don't do anything */
cryptStatus = dynCreate( &iAndSDB, iCryptCert,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
sMemConnect( &stream, dynData( iAndSDB ), dynLength( iAndSDB ) );
readSequence( &stream, NULL );
certTemplate[ 2 ].pValue = sMemBufPtr( &stream );
readSequence( &stream, &length ); /* Issuer DN */
certTemplate[ 2 ].ulValueLen = ( int ) sizeofObject( length );
sSkip( &stream, length );
certTemplate[ 3 ].pValue = sMemBufPtr( &stream );
readGenericHole( &stream, &length, BER_INTEGER );/* Serial number */
certTemplate[ 3 ].ulValueLen = ( int ) sizeofObject( length );
assert( sStatusOK( &stream ) );
sMemDisconnect( &stream );
cryptStatus = findObject( pkcs11Info, &hObject, certTemplate, 4 );
dynDestroy( &iAndSDB );
if( cryptStatusOK( cryptStatus ) )
/* The cert is already present, we don't need to add it again */
continue;
/* Write the new cert */
cryptStatus = updateCertificate( pkcs11Info, iCryptCert, isLeafCert );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
isLeafCert = FALSE;
seenNonDuplicate = TRUE;
}
while( krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORNEXT,
CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK );
return( seenNonDuplicate ? CRYPT_OK : CRYPT_ERROR_DUPLICATE );
}
/****************************************************************************
* *
* Device Init/Shutdown/Device Control Routines *
* *
****************************************************************************/
/* Prototypes for functions to get and free device capability information */
static int getCapabilities( DEVICE_INFO *deviceInfo );
static void freeCapabilities( DEVICE_INFO *deviceInfo );
/* Prototypes for device-specific functions */
static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
const int length );
/* Close a previously-opened session with the device. We have to have this
before the init function since it may be called by it if the init process
fails */
static void shutdownFunction( DEVICE_INFO *deviceInfo )
{
PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;
/* Log out and close the session with the device */
if( deviceInfo->flags & DEVICE_LOGGEDIN )
C_Logout( pkcs11Info->hSession );
C_CloseSession( pkcs11Info->hSession );
pkcs11Info->hSession = CRYPT_ERROR;
deviceInfo->flags &= ~( DEVICE_ACTIVE | DEVICE_LOGGEDIN );
/* Free the device capability information */
freeCapabilities( deviceInfo );
}
/* Open a session with the device */
static int initFunction( DEVICE_INFO *deviceInfo, const char *name,
const int nameLength )
{
CK_SESSION_HANDLE hSession;
CK_SLOT_ID slotList[ MAX_PKCS11_SLOTS ];
CK_ULONG slotCount = MAX_PKCS11_SLOTS;
CK_SLOT_INFO slotInfo;
CK_TOKEN_INFO tokenInfo;
CK_RV status;
PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;
char *labelPtr;
int tokenSlot = DEFAULT_SLOT, i, labelLength, cryptStatus;
/* Get information on all available slots */
memset( slotList, 0, sizeof( slotList ) );
status = C_GetSlotList( TRUE, slotList, &slotCount );
if( status != CKR_OK )
return( mapError( pkcs11Info, status, CRYPT_ERROR_OPEN ) );
if( slotCount <= 0 )
/* There are token slots present but no tokens in the slots */
return( CRYPT_ERROR_OPEN );
/* Check whether a token name (used to select the slot) has been
specified */
for( i = 1; i < nameLength - 1; i++ )
if( name[ i ] == ':' && name[ i + 1 ] == ':' )
break;
if( i < nameLength - 1 )
{
const char *tokenName = name + i + 2; /* Skip '::' */
const int tokenNameLength = nameLength - ( i + 2 );
if( tokenNameLength <= 0 )
return( CRYPT_ARGERROR_STR1 );
/* Some tokens don't implement named slots, so we also allow them to
be specified using slot counts */
if( tokenNameLength == 1 && isDigit( *tokenName ) )
{
tokenSlot = *tokenName - '0';
if( tokenSlot < 0 || tokenSlot > 9 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -