📄 pkcs11_rw.c
字号:
isLeafCert = FALSE;
}
/* Add each certificate in the chain to the device */
do
{
CK_OBJECT_HANDLE hObject;
DYNBUF iAndSDB;
/* If the certificate is already present, don't do anything */
cryptStatus = addIAndSToTemplate( &certTemplate[ 2 ], NULL, 0,
&iAndSDB, iCryptCert );
if( cryptStatusError( cryptStatus ) )
{
/* In theory we could also simply skip any certificates for
which we can't decode the iAndS, but in practice it's
probably better to fail and warn the user than to continue
with only some certificates added */
return( cryptStatus );
}
cryptStatus = findObject( pkcs11Info, &hObject, certTemplate, 4 );
dynDestroy( &iAndSDB );
if( cryptStatusOK( cryptStatus ) )
{
/* The certificate is already present, we don't need to add it
again */
continue;
}
/* Write the new certificate */
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 && \
iterationCount++ < FAILSAFE_ITERATIONS_MED );
if( iterationCount >= FAILSAFE_ITERATIONS_MED )
retIntError();
return( seenNonDuplicate ? CRYPT_OK : CRYPT_ERROR_DUPLICATE );
}
/****************************************************************************
* *
* Read an Item from a Device *
* *
****************************************************************************/
/* Instantiate an object in a device. This works like the create context
function but instantiates a cryptlib object using data already contained
in the device (for example a stored private key or certificate) */
int rsaSetPublicComponents( PKCS11_INFO *pkcs11Info,
const CRYPT_CONTEXT iCryptContext,
const CK_OBJECT_HANDLE hRsaKey,
const BOOLEAN nativeContext );
int dsaSetPublicComponents( PKCS11_INFO *pkcs11Info,
const CRYPT_CONTEXT iCryptContext,
const CK_OBJECT_HANDLE hDsaKey );
static int createNativeObject( PKCS11_INFO *pkcs11Info,
CRYPT_CONTEXT *iCryptContext,
const CK_OBJECT_HANDLE hObject,
const KEYMGMT_ITEM_TYPE itemType,
const CRYPT_ALGO_TYPE cryptAlgo )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
int actionFlags, cryptStatus;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
itemType == KEYMGMT_ITEM_PRIVATEKEY || \
itemType == KEYMGMT_ITEM_SECRETKEY );
assert( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
cryptAlgo <= CRYPT_ALGO_LAST_MAC );
/* Get the permitted-action flags for the object. If no usage is
allowed we can't do anything with the object so we don't even try and
create it */
actionFlags = getActionFlags( pkcs11Info, hObject, itemType, cryptAlgo );
if( actionFlags == 0 )
return( CRYPT_ERROR_PERMISSION );
/* We're creating a public-key context, make it a native context instead
of a device one. This solves a variety of problems including the
fact that some devices (which function purely as key stores coupled
to modexp accelerators) only support private-key operations, that
performing public-key operations natively is much, much faster than
on any device (around 150us for a 1Kbit RSA key on a 1.7GHz CPU,
which doesn't even cover the device communication overhead), and
finally that if we do it ourselves we can defend against a variety
of RSA padding and timing attacks that have come up since the
device firmware was done */
setMessageCreateObjectInfo( &createInfo, cryptAlgo );
cryptStatus = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
*iCryptContext = createInfo.cryptHandle;
/* Send the keying info to the context and set the action flags */
if( cryptAlgo == CRYPT_ALGO_RSA )
cryptStatus = rsaSetPublicComponents( pkcs11Info, *iCryptContext,
hObject, TRUE );
else
cryptStatus = dsaSetPublicComponents( pkcs11Info, *iCryptContext,
hObject );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = krnlSendMessage( *iCryptContext, IMESSAGE_SETATTRIBUTE,
&actionFlags,
CRYPT_IATTRIBUTE_ACTIONPERMS );
if( cryptStatusError( cryptStatus ) )
{
krnlSendNotifier( *iCryptContext, IMESSAGE_DECREFCOUNT );
return( cryptStatus );
}
return( CRYPT_OK );
}
static int createDeviceObject( PKCS11_INFO *pkcs11Info,
CRYPT_CONTEXT *iCryptContext,
const CK_OBJECT_HANDLE hObject,
const CRYPT_CERTIFICATE iCryptCert,
const CRYPT_USER iOwnerHandle,
const CRYPT_DEVICE iDeviceHandle,
const CAPABILITY_INFO *capabilityInfoPtr,
const KEYMGMT_ITEM_TYPE itemType,
const CRYPT_ALGO_TYPE cryptAlgo,
const int keySize )
{
MESSAGE_DATA msgData;
char label[ CRYPT_MAX_TEXTSIZE + 8 ];
int createFlags = CREATEOBJECT_FLAG_DUMMY;
int actionFlags, labelLength, cryptStatus;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
assert( ( iCryptCert == CRYPT_UNUSED ) || \
isHandleRangeValid( iCryptCert ) );
assert( iOwnerHandle == DEFAULTUSER_OBJECT_HANDLE || \
isHandleRangeValid( iOwnerHandle ) );
assert( isHandleRangeValid( iDeviceHandle ) );
assert( isReadPtr( capabilityInfoPtr, sizeof( CAPABILITY_INFO ) ) );
assert( itemType == KEYMGMT_ITEM_PRIVATEKEY || \
itemType == KEYMGMT_ITEM_SECRETKEY );
assert( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
cryptAlgo <= CRYPT_ALGO_LAST_MAC );
assert( keySize >= MIN_KEYSIZE && keySize <= CRYPT_MAX_PKCSIZE );
/* Check whether this is a persistent object */
if( readFlag( pkcs11Info, hObject, CKA_TOKEN ) )
createFlags |= CREATEOBJECT_FLAG_PERSISTENT;
/* Get the permitted-action flags for the object */
actionFlags = getActionFlags( pkcs11Info, hObject, itemType, cryptAlgo );
if( actionFlags == 0 )
{
/* If no usage is allowed, we can't do anything with the object so
we don't even try to create it */
if( iCryptCert != CRYPT_UNUSED )
krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT );
return( CRYPT_ERROR_PERMISSION );
}
/* Create a dummy context for the key, remember the device that it's
contained in, and record the handle for the device-internal key */
cryptStatus = getObjectLabel( pkcs11Info, hObject, label,
CRYPT_MAX_TEXTSIZE, &labelLength );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = createContextFromCapability( iCryptContext,
iOwnerHandle, capabilityInfoPtr, createFlags );
if( cryptStatusError( cryptStatus ) )
{
if( iCryptCert != CRYPT_UNUSED )
krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT );
return( cryptStatus );
}
cryptStatus = krnlSendMessage( *iCryptContext, IMESSAGE_SETDEPENDENT,
( void * ) &iDeviceHandle,
SETDEP_OPTION_INCREF );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = krnlSendMessage( *iCryptContext, IMESSAGE_SETATTRIBUTE,
( void * ) &hObject,
CRYPT_IATTRIBUTE_DEVICEOBJECT );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = krnlSendMessage( *iCryptContext, IMESSAGE_SETATTRIBUTE,
&actionFlags,
CRYPT_IATTRIBUTE_ACTIONPERMS );
if( cryptStatusError( cryptStatus ) )
{
krnlSendNotifier( *iCryptContext, IMESSAGE_DECREFCOUNT );
if( iCryptCert != CRYPT_UNUSED )
krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT );
return( cryptStatus );
}
/* Set the object's label and mark it as initialised (i.e. with a key
loaded). Setting the label requires special care because the label
that we're setting matches that of an existing object, so trying to
set it as a standard CRYPT_CTXINFO_LABEL will return a
CRYPT_ERROR_DUPLICATE error when the context code checks for the
existence of an existing label. To handle this, we use the
attribute CRYPT_IATTRIBUTE_EXISTINGLABEL to indicate that we're
setting a label that matches an existing object in the device */
if( labelLength <= 0 )
{
/* If there's no label present, use a dummy value */
strlcpy_s( label, CRYPT_MAX_TEXTSIZE, "Label-less PKCS #11 key" );
labelLength = strlen( label );
}
setMessageData( &msgData, label, min( labelLength, CRYPT_MAX_TEXTSIZE ) );
cryptStatus = krnlSendMessage( *iCryptContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_EXISTINGLABEL );
if( cryptStatusOK( cryptStatus ) )
{
/* Send the keying info to the context. For non-PKC contexts we
only need to set the key length to let the user query the key
size, for PKC contexts we also have to set the key components so
they can be written into certificates. Unfortunately we can't do
this for DLP private keys since we can't read y from a DLP
private key object (see the comments in the DSA code for more on
this), however the only time this is necessary is when a
certificate is being generated for a key that was pre-generated
in the device by someone else, which is typically done in Europe
where DSA isn't used so this shouldn't be a problem */
if( cryptAlgo == CRYPT_ALGO_RSA )
cryptStatus = rsaSetPublicComponents( pkcs11Info, *iCryptContext,
hObject, FALSE );
else
cryptStatus = krnlSendMessage( *iCryptContext,
IMESSAGE_SETATTRIBUTE,
( void * ) &keySize,
CRYPT_IATTRIBUTE_KEYSIZE );
}
if( cryptStatusOK( cryptStatus ) )
cryptStatus = krnlSendMessage( *iCryptContext, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_IATTRIBUTE_INITIALISED );
if( cryptStatusOK( cryptStatus ) && ( iCryptCert != CRYPT_UNUSED ) )
{
/* If it's a public key and there's a certificate present, attach it
to the context. The certificate is an internal object used only
by the context so we tell the kernel to mark it as owned by the
context only */
cryptStatus = krnlSendMessage( *iCryptContext, IMESSAGE_SETDEPENDENT,
( void * ) &iCryptCert,
SETDEP_OPTION_NOINCREF );
}
if( cryptStatusError( cryptStatus ) )
{
krnlSendNotifier( *iCryptContext, IMESSAGE_DECREFCOUNT );
if( iCryptCert != CRYPT_UNUSED )
krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT );
}
return( cryptStatus );
}
/* Get an item from a device and instantiate either a native or a device
object from it */
static int getItemFunction( DEVICE_INFO *deviceInfo,
CRYPT_CONTEXT *iCryptContext,
const KEYMGMT_ITEM_TYPE itemType,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
void *auxInfo, int *auxInfoLength,
const int flags )
{
static const CK_OBJECT_CLASS pubkeyClass = CKO_PUBLIC_KEY;
static const CK_OBJECT_CLASS privkeyClass = CKO_PRIVATE_KEY;
static const CK_OBJECT_CLASS secKeyClass = CKO_SECRET_KEY;
static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
const CAPABILITY_INFO *capabilityInfoPtr;
CK_ATTRIBUTE iAndSTemplate[] = {
{ 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 }
}, iAndSTemplateAlt[ 4 ];
CK_ATTRIBUTE keyTemplate[] = {
{ CKA_CLASS, NULL_PTR, sizeof( CK_OBJECT_CLASS ) },
{ CKA_LABEL, NULL_PTR, 0 }
};
CK_ATTRIBUTE keySizeTemplate = { 0, NULL, 0 };
CK_OBJECT_HANDLE hObject = CK_OBJECT_NONE, hCertificate = CK_OBJECT_NONE;
CRYPT_CERTIFICATE iCryptCert;
CRYPT_ALGO_TYPE cryptAlgo;
PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;
BOOLEAN certViaPrivateKey = FALSE, privateKeyViaCert = FALSE;
BOOLEAN certPresent = FALSE;
int keySize, cryptStatus;
assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
itemType == KEYMGMT_ITEM_PRIVATEKEY || \
itemType == KEYMGMT_ITEM_SECRETKEY );
assert( keyIDtype == CRYPT_KEYID_NAME || \
keyIDtype == CRYPT_KEYID_URI || \
keyIDtype == CRYPT_IKEYID_KEYID || \
keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER );
assert( isReadPtr( keyID, keyIDlength ) );
assert( ( auxInfo == NULL && *auxInfoLength == 0 ) || \
isReadPtr( auxInfo, *auxInfoLength ) );
/* If we're looking for a secret key it's fairly straightforward, we
can only have a label as an ID */
if( itemType == KEYMGMT_ITEM_SECRETKEY )
{
CK_ULONG keySize;
CK_ATTRIBUTE keySizeTemplate = \
{ CKA_VALUE_LEN, &keySize, sizeof( CK_ULONG ) };
int status;
assert( keyIDtype == CRYPT_KEYID_NAME || \
keyIDtype == CRYPT_IKEYID_KEYID );
/* Try and find the object with the given label/ID */
keyTemplate[ 0 ].pValue = ( CK_VOID_PTR ) &secKeyClass;
if( keyIDtype == CRYPT_IKEYID_KEYID )
keyTemplate[ 1 ].type = CKA_ID;
keyTemplate[ 1 ].pValue = ( CK_VOID_PTR ) keyID;
keyTemplate[ 1 ].ulValueLen = keyIDlength;
cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
if( cryptStatus == CRYPT_ERROR_NOTFOUND )
{
/* Some devices use the iD in place of the label, if a search by
label fails we try again with the label as the iD */
keyTemplate[ 1 ].type = CKA_ID;
cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
keyTemplate[ 1 ].type = CKA_LABEL;
}
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -