/**************************************************************************** * * * cryptlib Generic Crypto HW Routines * * Copyright Peter Gutmann 1998-2009 * * * ****************************************************************************/ #define PKC_CONTEXT /* Indicate that we're working with PKC contexts */ #if defined( INC_ALL ) #include "crypt.h" #include "context.h" #include "device.h" #include "hardware.h" #include "dev_mech.h" #else #include "crypt.h" #include "context/context.h" #include "device/device.h" #include "device/hardware.h" #include "mechs/dev_mech.h" #endif /* Compiler-specific includes */ #ifdef USE_HARDWARE /**************************************************************************** * * * Utility Routines * * * ****************************************************************************/ /* Get access to the hardware device associated with a context */ static int getContextDeviceInfo( const CRYPT_HANDLE iCryptContext, CRYPT_DEVICE *iCryptDevice, HARDWARE_INFO **hwInfoPtrPtr ) { CRYPT_DEVICE iLocalDevice; DEVICE_INFO *deviceInfo; int status; assert( isWritePtr( iCryptDevice, sizeof( CRYPT_DEVICE ) ) ); assert( isWritePtr( hwInfoPtrPtr, sizeof( HARDWARE_INFO * ) ) ); REQUIRES( isHandleRangeValid( iCryptContext ) ); /* Clear return values */ *iCryptDevice = CRYPT_ERROR; *hwInfoPtrPtr = NULL; /* Get the the device associated with this context */ status = krnlSendMessage( iCryptContext, IMESSAGE_GETDEPENDENT, &iLocalDevice, OBJECT_TYPE_DEVICE ); if( cryptStatusError( status ) ) return( status ); /* Get the hardware information from the device information */ status = krnlAcquireObject( iLocalDevice, OBJECT_TYPE_DEVICE, ( void ** ) &deviceInfo, CRYPT_ERROR_SIGNALLED ); if( cryptStatusError( status ) ) return( status ); *iCryptDevice = iLocalDevice; *hwInfoPtrPtr = deviceInfo->deviceHardware; return( CRYPT_OK ); } /* Get a reference to the cryptographic hardware object that underlies a cryptlib object. This is used to connect a template object from a PKCS #15 storage object to the corresponding hardware object via the storageID that's recorded in the storage object */ static int getHardwareReference( const CRYPT_CONTEXT iCryptContext, int *keyHandle ) { MESSAGE_DATA msgData; BYTE storageID[ KEYID_SIZE + 8 ]; int status; assert( isWritePtr( keyHandle, sizeof( int ) ) ); REQUIRES( isHandleRangeValid( iCryptContext ) ); setMessageData( &msgData, storageID, KEYID_SIZE ); status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_DEVICESTORAGEID ); if( cryptStatusOK( status ) ) status = hwLookupItem( storageID, KEYID_SIZE, keyHandle ); if( cryptStatusError( status ) ) { /* In theory this is an internal error but in practice we shouldn't treat this as too fatal, what it really means is that the crypto hardware (which we don't control and therefore can't do too much about) is out of sync with the PKCS #15 storage object. This can happen for example during the development process when the hardware is reinitialised but the storage object isn't, or from any one of a number of other circumstances beyond our control. To deal with this we return a standard notfound error but also output a diagnostic message for developers to let them know that they need to check hardware/storage object synchronisation */ DEBUG_PRINT(( "Object held in PKCS #15 object store doesn't " "correspond to anything known to the crypto " "hardware HAL" )); return( CRYPT_ERROR_NOTFOUND ); } return( CRYPT_OK ); } /* Open the PKCS #15 storage object associated with this device */ static int openStorageObject( CRYPT_KEYSET *iCryptKeyset, const CRYPT_KEYOPT_TYPE options, const CRYPT_DEVICE iCryptDevice ) { MESSAGE_CREATEOBJECT_INFO createInfo; char storageFilePath[ MAX_PATH_LENGTH + 8 ]; int storageFilePathLen, status; assert( isWritePtr( iCryptKeyset, sizeof( CRYPT_KEYSET ) ) ); REQUIRES( options == CRYPT_KEYOPT_NONE || \ options == CRYPT_KEYOPT_CREATE ); REQUIRES( isHandleRangeValid( iCryptDevice ) ); /* Clear return value */ *iCryptKeyset = CRYPT_ERROR; /* Try and open/create the PKCS #15 storage object */ status = fileBuildCryptlibPath( storageFilePath, MAX_PATH_LENGTH, &storageFilePathLen, "CLKEYS", 6, BUILDPATH_GETPATH ); if( cryptStatusError( status ) ) return( status ); setMessageCreateObjectInfo( &createInfo, CRYPT_KEYSET_FILE ); if( options != CRYPT_KEYOPT_NONE ) createInfo.arg2 = options; createInfo.strArg1 = storageFilePath; createInfo.strArgLen1 = storageFilePathLen; status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT, &createInfo, OBJECT_TYPE_KEYSET ); if( cryptStatusError( status ) ) return( status ); /* Now that we've got the storage object we have to perform a somewhat awkward double-linked-list update of the keyset to give it the handle of the owning device since we need to create any contexts for keys fetched from the storage object via the hardware device rather than the default system device. In theory we could also do this via a new get-owning-object message but we still need to signal to the keyset that it's a storage object rather than a standard keyset so this action serves a second purpose anyway and we may as well use it to explicitly set the owning-device handle at the same time. Note that we don't set the storage object as a dependent object of the device because it's not necessarily constant across device sessions. In particular if we initialise or zeroise the device then the storage object will be reset, but there's no way to switch dependent objects without destroying and recreating the parent. In addition it's not certain whether the storage-object keyset should really be a dependent object or not, in theory it's nice because it allows keyset-specific messages/accesses to be sent to the device and automatically routed to the keyset (standard accesses will still go to the device, so for example a getItem() will be handled as a device-get rather than a keyset-get) but such unmediated access to the underlying keyset probably isn't a good idea anyway */ status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &iCryptDevice, CRYPT_IATTRIBUTE_HWSTORAGE ); if( cryptStatusError( status ) ) { krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); return( status ); } *iCryptKeyset = createInfo.cryptHandle; return( CRYPT_OK ); } /**************************************************************************** * * * Init/Shutdown Routines * * * ****************************************************************************/ /* Initialise the capability information */ #define MAX_DEVICE_CAPABILITIES 32 static CAPABILITY_INFO_LIST capabilityInfoList[ MAX_DEVICE_CAPABILITIES ]; /* Initialise the cryptographic hardware and its crypto capability interface */ CHECK_RETVAL \ int deviceInitHardware( void ) { CAPABILITY_INFO *capabilityInfo; static BOOLEAN initCalled = FALSE; int noCapabilities, i, status; /* If we've previously tried to initialise the hardware, don't try it again */ if( initCalled ) return( CRYPT_OK ); initCalled = TRUE; /* Get the hardware capability information */ status = hwGetCapabilities( &capabilityInfo, &noCapabilities ); if( cryptStatusError( status ) ) return( status ); ENSURES( noCapabilities > 0 && \ noCapabilities < MAX_DEVICE_CAPABILITIES ); /* Build the list of available capabilities */ memset( capabilityInfoList, 0, sizeof( CAPABILITY_INFO_LIST ) * MAX_DEVICE_CAPABILITIES ); for( i = 0; i < noCapabilities && \ capabilityInfo[ i ].cryptAlgo != CRYPT_ALGO_NONE; i++ ) { REQUIRES( sanityCheckCapability( &capabilityInfo[ i ] ) ); capabilityInfoList[ i ].info = &capabilityInfo[ i ]; capabilityInfoList[ i ].next = NULL; if( i > 0 ) capabilityInfoList[ i - 1 ].next = &capabilityInfoList[ i ]; } ENSURES( i < noCapabilities ); return( CRYPT_OK ); } void deviceEndHardware( void ) { } /**************************************************************************** * * * Device Init/Shutdown/Device Control Routines * * * ****************************************************************************/ /* Close a previously-opened session with the device. We have to have this before the initialisation function since it may be called by it if the initialisation process fails */ static void shutdownFunction( DEVICE_INFO *deviceInfo ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); /* Shut down access to the storage object */ if( hardwareInfo->iCryptKeyset != CRYPT_ERROR ) { krnlSendNotifier( hardwareInfo->iCryptKeyset, IMESSAGE_DECREFCOUNT ); hardwareInfo->iCryptKeyset = CRYPT_ERROR; } deviceInfo->flags &= ~( DEVICE_ACTIVE | DEVICE_LOGGEDIN ); } /* Open a session with the device */ static int initFunction( DEVICE_INFO *deviceInfo, const char *name, const int nameLength ) { CRYPT_KEYSET iCryptKeyset; HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; int status; UNUSED_ARG( name ); assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); /* Set up any internal objects to contain invalid handles */ hardwareInfo->iCryptKeyset = CRYPT_ERROR; /* Set up the device ID information */ memcpy( hardwareInfo->label, "Cryptographic hardware device", 29 ); hardwareInfo->labelLen = 29; deviceInfo->label = hardwareInfo->label; deviceInfo->labelLen = hardwareInfo->labelLen; /* Since this is a built-in hardware device it's always present and available */ deviceInfo->flags |= DEVICE_ACTIVE | DEVICE_LOGGEDIN; /* Try and open the PKCS #15 storage object. If we can't open it it means that either it doesn't exist (i.e. persistent key storage isn't supported) or the device hasn't been initialised yet. This isn't a fatal error, although it does mean that public-key operations will be severely restricted since these depend on storing key metadata in the storage object */ status = openStorageObject( &iCryptKeyset, CRYPT_KEYOPT_NONE, deviceInfo->objectHandle ); if( cryptStatusError( status ) ) return( CRYPT_OK ); /* Storage object not available */ hardwareInfo->iCryptKeyset = iCryptKeyset; return( CRYPT_OK ); } /* Handle device control functions */ static int controlFunction( DEVICE_INFO *deviceInfo, const CRYPT_ATTRIBUTE_TYPE type, const void *data, const int dataLength, MESSAGE_FUNCTION_EXTINFO *messageExtInfo ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; int status; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); REQUIRES( isAttribute( type ) || isInternalAttribute( type ) ); UNUSED_ARG( hardwareInfo ); UNUSED_ARG( messageExtInfo ); /* Handle user authorisation. Since this is a built-in hardware device it's always available for use so these are just dummy routines, although they can be expanded to call down into the HAL for actual authentication if any hardware with such a facility is ever used */ if( type == CRYPT_DEVINFO_AUTHENT_USER || \ type == CRYPT_DEVINFO_AUTHENT_SUPERVISOR ) { /* Authenticate the user */ /* ... */ /* The device is now ready for use */ deviceInfo->flags |= DEVICE_LOGGEDIN; krnlSendMessage( deviceInfo->objectHandle, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED, CRYPT_IATTRIBUTE_INITIALISED ); return( CRYPT_OK ); } /* Handle authorisation value change */ if( type == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR ) { /* Set SO PIN */ /* ... */ return( CRYPT_OK ); } if( type == CRYPT_DEVINFO_SET_AUTHENT_USER ) { /* Set user PIN */ /* ... */ return( CRYPT_OK ); } /* Handle initialisation and zeroisation */ if( type == CRYPT_DEVINFO_INITIALISE || \ type == CRYPT_DEVINFO_ZEROISE ) { CRYPT_KEYSET iCryptKeyset; /* Shut down any existing state if necessary in preparation for the zeroise/initialise. Since this clears all state we manually reset the device-active flag since we're still active, just with all information cleared */ if( hardwareInfo->iCryptKeyset != CRYPT_ERROR ) shutdownFunction( deviceInfo ); hwInitialise(); deviceInfo->flags |= DEVICE_ACTIVE; /* The only real difference between a zeroise and an initialise is that the zeroise only clears existing state and exits while the initialise resets the state with the device ready to be used again */ if( type == CRYPT_DEVINFO_ZEROISE ) { char storageFilePath[ MAX_PATH_LENGTH + 1 + 8 ]; int storageFilePathLen; /* Zeroise the device */ status = fileBuildCryptlibPath( storageFilePath, MAX_PATH_LENGTH, &storageFilePathLen, "CLKEYS", 6, BUILDPATH_GETPATH ); if( cryptStatusOK( status ) ) { storageFilePath[ storageFilePathLen ] = '\0'; fileErase( storageFilePath ); } deviceInfo->flags &= ~DEVICE_LOGGEDIN; return( status ); } /* Initialise the device. In theory we're already in the logged-in state but if the initialise was preceded by a zeroise then this will have been cleared, so we explicitly re-set it */ status = openStorageObject( &iCryptKeyset, CRYPT_KEYOPT_CREATE, deviceInfo->objectHandle ); if( cryptStatusError( status ) ) return( status ); hardwareInfo->iCryptKeyset = iCryptKeyset; deviceInfo->flags |= DEVICE_LOGGEDIN; return( CRYPT_OK ); } /* Handle high-reliability time */ if( type == CRYPT_IATTRIBUTE_TIME ) { time_t *timePtr = ( time_t * ) data; UNUSED_ARG( timePtr ); return( CRYPT_ERROR_NOTAVAIL ); } retIntError(); } /* Get random data from the device. The messageExtInfo parameter is used to handle recursive messages sent to the system device during the randomness-polling process and isn't used here */ static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer, const int length, MESSAGE_FUNCTION_EXTINFO *messageExtInfo ) { UNUSED_ARG( messageExtInfo ); assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isWritePtr( buffer, length ) ); REQUIRES( length > 0 && length < MAX_BUFFER_SIZE ); /* Fill the buffer with random data */ return( hwGetRandom( buffer, length ) ); } /**************************************************************************** * * * Get/Set/Delete Item Routines * * * ****************************************************************************/ /* 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). If the value being read is a public key and there's a certificate attached then the instantiated object is a native cryptlib object rather than a device object with a native certificate object attached because there doesn't appear to be any good reason to create the public-key object in the device, and the cryptlib native object will probably be faster anyway */ 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 ) { #if 0 const CRYPT_DEVICE cryptDevice = deviceInfo->objectHandle; CRYPT_CERTIFICATE iCryptCert = CRYPT_UNUSED; const CAPABILITY_INFO *capabilityInfoPtr; HW_KEYINFO keyInfo; MESSAGE_DATA msgData; const int extraFlags = ( itemType == KEYMGMT_ITEM_PRIVATEKEY ) ? \ KEYMGMT_FLAG_DATAONLY_CERT : 0; int keyHandle, p15status, status; #endif CRYPT_CONTEXT iLocalContext; HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO getkeyInfo; int keyHandle, status; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) ); assert( isReadPtr( keyID, keyIDlength ) ); REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \ itemType == KEYMGMT_ITEM_PRIVATEKEY ); REQUIRES( keyIDtype == CRYPT_KEYID_NAME || \ keyIDtype == CRYPT_KEYID_URI || \ keyIDtype == CRYPT_IKEYID_KEYID || \ keyIDtype == CRYPT_IKEYID_PGPKEYID || \ keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ); REQUIRES( auxInfo == NULL && *auxInfoLength == 0 ); REQUIRES( flags >= KEYMGMT_FLAG_NONE && flags < KEYMGMT_FLAG_MAX ); #if 1 /* Redirect the fetch down to the PKCS #15 storage object, which will create either a dummy context that we have to connect to the actual hardware for a private-key object or a native public-key/certificate object if it's a non-private-key item */ if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) return( CRYPT_ERROR_NOTINITED ); setMessageKeymgmtInfo( &getkeyInfo, keyIDtype, keyID, keyIDlength, NULL, 0, flags ); status = krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, itemType ); if( cryptStatusError( status ) ) return( status ); iLocalContext = getkeyInfo.cryptHandle; /* If it's a public-key fetch, we've created a native object and we're done */ if( itemType != KEYMGMT_ITEM_PRIVATEKEY ) { *iCryptContext = iLocalContext; return( CRYPT_OK ); } /* It was a private-key fetch, we need to connect the dummy context that was created with the underlying hardware. When this final step has been completed we can move the context to the initialised state */ status = getHardwareReference( iLocalContext, &keyHandle ); if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); return( status ); } status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, &keyHandle, CRYPT_IATTRIBUTE_DEVICEOBJECT ); if( cryptStatusOK( status ) ) { status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED, CRYPT_IATTRIBUTE_INITIALISED ); } if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); return( status ); } #else /* As a first step we redirect the fetch down to the PKCS #15 storage object to get any certificate that may be associated with the item. We always do this because if we're fetching a public key then this is all that we need and if we're fetching a private key then we'll associate the certificate with it if it's present */ if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) return( CRYPT_ERROR_NOTINITED ); setMessageKeymgmtInfo( &getkeyInfo, keyIDtype, keyID, keyIDlength, NULL, 0, flags | extraFlags ); p15status = krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, KEYMGMT_ITEM_PUBLICKEY ); if( cryptStatusOK( p15status ) ) { iCryptCert = getkeyInfo.cryptHandle; /* If we were after a public key, we're done */ if( itemType == KEYMGMT_ITEM_PUBLICKEY ) { *iCryptContext = iCryptCert; return( CRYPT_OK ); } /* If we were after a private key and the keyID is one that isn't stored locally, extract it from the returned private key */ // This won't work, there's no CRYPT_IKEYID_KEYID or // CRYPT_IKEYID_PGPKEYID with the cert, only an // CRYPT_IKEYID_ISSUERANDSERIALNUMBER } /* Look up the private key, which we may use directly or simply extract the public-key components from. If there's an error then we preferentially return the error code from the storage object, which is likely to be more informative than a generic CRYPT_ERROR_NOTFOUND from the hardware lookup */ status = hwLookupItemInfo( keyIDtype, keyID, keyIDlength, &keyHandle, &keyInfo ); if( cryptStatusError( status ) ) return( cryptStatusError( p15status ) ? p15status : status ); if( itemType == KEYMGMT_ITEM_PUBLICKEY ) { MESSAGE_CREATEOBJECT_INFO createInfo; /* There's no certificate present but we do have private-key components from which we can extract the public-key portion to create a native context instead of a device one. This solves a variety of problems including the fact that performing public-key operations natively is often much faster than the time it takes to marshall the data and get it to the crypto hardware, and 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, keyInfo.cryptAlgo ); status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT, &createInfo, OBJECT_TYPE_CONTEXT ); if( cryptStatusError( status ) ) return( status ); iLocalContext = createInfo.cryptHandle; /* Send the keying information to the context. We don't set the action flags because there are none recorded at the hardware level */ status = setPublicComponents( createInfo.cryptHandle, keyInfo.cryptAlgo, &keyInfo.publicKeyInfo ); if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); return( status ); } *iCryptContext = iLocalContext; return( CRYPT_OK ); } /* It's a private key, create a dummy context for the device object, remember the device that it's contained in, and record the handle for the device-internal key */ capabilityInfoPtr = findCapabilityInfo( deviceInfo->capabilityInfoList, keyInfo.cryptAlgo ); if( capabilityInfoPtr == NULL ) return( CRYPT_ERROR_NOTAVAIL ); status = createContextFromCapability( &iLocalContext, cryptDevice, capabilityInfoPtr, CREATEOBJECT_FLAG_DUMMY | \ CREATEOBJECT_FLAG_PERSISTENT ); if( cryptStatusError( status ) ) { if( iCryptCert != CRYPT_UNUSED ) krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT ); return( status ); } status = krnlSendMessage( iLocalContext, IMESSAGE_SETDEPENDENT, ( MESSAGE_CAST ) &cryptDevice, SETDEP_OPTION_INCREF ); if( cryptStatusOK( status ) ) status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &keyHandle, CRYPT_IATTRIBUTE_DEVICEOBJECT ); if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); if( iCryptCert != CRYPT_UNUSED ) krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT ); return( status ); } /* Set the object's label, send the keying information to the context, 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( keyInfo.labelLength <= 0 ) { /* If there's no label present, use a dummy value */ strlcpy_s( keyInfo.label, CRYPT_MAX_TEXTSIZE, "Label-less private key" ); keyInfo.labelLength = 22; } setMessageData( &msgData, keyInfo.label, keyInfo.labelLength ); status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_EXISTINGLABEL ); if( cryptStatusOK( status ) ) status = setPublicComponents( iLocalContext, keyInfo.cryptAlgo, &keyInfo.publicKeyInfo ); if( cryptStatusOK( status ) ) status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED, CRYPT_IATTRIBUTE_INITIALISED ); if( cryptStatusOK( status ) && ( iCryptCert != CRYPT_UNUSED ) ) { /* If 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 */ status = krnlSendMessage( iLocalContext, IMESSAGE_SETDEPENDENT, ( MESSAGE_CAST ) &iCryptCert, SETDEP_OPTION_NOINCREF ); } if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); if( iCryptCert != CRYPT_UNUSED ) krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT ); } #endif /* 1 */ *iCryptContext = iLocalContext; return( CRYPT_OK ); } /* Add an object to a device. This can only ever add a certificate (enforced by the kernel ACLs) so we don't have to perform any special-case handling */ static int setItemFunction( DEVICE_INFO *deviceInfo, const CRYPT_HANDLE iCryptHandle ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO setkeyInfo; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); REQUIRES( isHandleRangeValid( iCryptHandle ) ); /* Redirect the add down to the PKCS #15 storage object */ if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) return( CRYPT_ERROR_NOTINITED ); setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0, NULL, 0, KEYMGMT_FLAG_NONE ); setkeyInfo.cryptHandle = iCryptHandle; return( krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_SETKEY, &setkeyInfo, KEYMGMT_ITEM_PUBLICKEY ) ); } /* Delete an object in a device */ static int deleteItemFunction( DEVICE_INFO *deviceInfo, const KEYMGMT_ITEM_TYPE itemType, const CRYPT_KEYID_TYPE keyIDtype, const void *keyID, const int keyIDlength ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO getkeyInfo, deletekeyInfo; int status; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isReadPtr( keyID, keyIDlength ) ); REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \ itemType == KEYMGMT_ITEM_PRIVATEKEY ); REQUIRES( keyIDtype == CRYPT_KEYID_NAME ); REQUIRES( keyIDlength > 0 && keyIDlength <= CRYPT_MAX_TEXTSIZE ); /* Perform the delete both from the PKCS #15 storage object and the native storage. This gets a bit complicated because in order to find the hardware object we have to extract the storageID, and in order to get that we have to instantiate a dummy private-key object to contain it. In addition if the object that's stored isn't a private-key object then there's no associated cryptographic hardware object. To handle this we try and instantiate a dummy private-key object in order to get the storageID. If this succeeds, we locate the underlying hardware object and delete it. Finally, we delete the PKCS #15 object, either a pure public-key/certificate object or the private-key metadata for the cryptographic hardware object */ if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) return( CRYPT_ERROR_NOTINITED ); setMessageKeymgmtInfo( &getkeyInfo, keyIDtype, keyID, keyIDlength, NULL, 0, KEYMGMT_FLAG_NONE ); status = krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, KEYMGMT_ITEM_PRIVATEKEY ); if( cryptStatusOK( status ) ) { int keyHandle; /* It's a private-key object, get its hardware reference and delete it. If this fails we continue anyway because we know that there's also a PKCS #15 object to delete */ status = getHardwareReference( getkeyInfo.cryptHandle, &keyHandle ); if( cryptStatusOK( status ) ) ( void ) hwDeleteItem( keyHandle ); krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); } setMessageKeymgmtInfo( &deletekeyInfo, keyIDtype, keyID, keyIDlength, NULL, 0, KEYMGMT_FLAG_NONE ); return( krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_DELETEKEY, &deletekeyInfo, itemType ) ); } /* Get the sequence of certificates in a chain from a device. Since these functions operate only on certificates we can redirect them straight down to the underlying storage object */ static int getFirstItemFunction( DEVICE_INFO *deviceInfo, CRYPT_CERTIFICATE *iCertificate, int *stateInfo, const CRYPT_KEYID_TYPE keyIDtype, const void *keyID, const int keyIDlength, const KEYMGMT_ITEM_TYPE itemType, const int options ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO getnextcertInfo; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) ); assert( isReadPtr( keyID, keyIDlength ) ); assert( isWritePtr( stateInfo, sizeof( int ) ) ); REQUIRES( keyIDtype == CRYPT_IKEYID_KEYID ); REQUIRES( keyIDlength > 4 && keyIDlength < MAX_INTLENGTH_SHORT ); REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY ); /* Clear return values */ *iCertificate = CRYPT_ERROR; *stateInfo = CRYPT_ERROR; /* Get the first certificate */ setMessageKeymgmtInfo( &getnextcertInfo, keyIDtype, keyID, keyIDlength, stateInfo, sizeof( int ), options ); return( krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETFIRSTCERT, &getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY ) ); } static int getNextItemFunction( DEVICE_INFO *deviceInfo, CRYPT_CERTIFICATE *iCertificate, int *stateInfo, const int options ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO getnextcertInfo; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) ); assert( isWritePtr( stateInfo, sizeof( int ) ) ); REQUIRES( isHandleRangeValid( *stateInfo ) || \ *stateInfo == CRYPT_ERROR ); UNUSED_ARG( hardwareInfo ); /* Clear return value */ *iCertificate = CRYPT_ERROR; /* If the previous certificate was the last one, there's nothing left to fetch */ if( *stateInfo == CRYPT_ERROR ) return( CRYPT_ERROR_NOTFOUND ); /* Get the next certificate */ setMessageKeymgmtInfo( &getnextcertInfo, CRYPT_KEYID_NONE, NULL, 0, stateInfo, sizeof( int ), options ); return( krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETNEXTCERT, &getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY ) ); } /**************************************************************************** * * * Cryptographic HAL Assist Routines * * * ****************************************************************************/ /* The following helper routines provide common functionality needed by most cryptographic HALs, which avoids having to reimplement the same code in each HAL module. These are called from the HAL to provide services such as keygen assist and various context-management functions */ /* Set up a mapping from a context to its associated information in the underlying hardware. This generates a storageID for the information and records it and the hardware handle in the context. The caller has to record the storageID alongside the crypto information held by the hardware for later use to look up the information */ int setPersonalityMapping( CONTEXT_INFO *contextInfoPtr, const int keyHandle, void *storageID, const int storageIDlength ) { CRYPT_DEVICE iCryptDevice; HARDWARE_INFO *hardwareInfo; MESSAGE_KEYMGMT_INFO setkeyInfo; MESSAGE_DATA msgData; BYTE buffer[ KEYID_SIZE + 8 ]; int status; assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) ); assert( isWritePtr( storageID, storageIDlength ) ); REQUIRES( keyHandle >= 0 && keyHandle < INT_MAX ); REQUIRES( storageIDlength >= 4 && storageIDlength <= KEYID_SIZE ); /* Set up the mapping information in the context */ status = hwGetRandom( buffer, KEYID_SIZE ); if( cryptStatusError( status ) ) return( status ); setMessageData( &msgData, buffer, KEYID_SIZE ); status = krnlSendMessage( contextInfoPtr->objectHandle, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_DEVICESTORAGEID ); if( cryptStatusOK( status ) ) { status = krnlSendMessage( contextInfoPtr->objectHandle, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &keyHandle, CRYPT_IATTRIBUTE_DEVICEOBJECT ); } if( cryptStatusError( status ) ) return( status ); /* Copy the storageID back to the caller */ memcpy( storageID, buffer, storageIDlength ); /* If it's a non-PKC context then there's nothing further to do */ if( contextInfoPtr->type != CONTEXT_PKC ) return( CRYPT_OK ); /* As a variation of the above, if it's a public-key context then we don't want to persist it to the storage object because public-key contexts a bit of an anomaly, when generating our own keys we always have full private keys and when obtaining public keys from an external source they'll be in the form of certificates so there isn't really much need for persistent raw public keys. At the moment the only time they're used is for the self-test, and potentially polluting the (typically quite limited) crypto hardware storage with unneeded public keys doesn't seem like a good idea */ if( contextInfoPtr->flags & CONTEXT_FLAG_ISPUBLICKEY ) return( CRYPT_OK ); /* It's a PKC context, prepare to persist the key metadata to the underlying PKCS #15 object store */ status = getContextDeviceInfo( contextInfoPtr->objectHandle, &iCryptDevice, &hardwareInfo ); if( cryptStatusError( status ) ) return( status ); if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) { krnlReleaseObject( iCryptDevice ); return( CRYPT_ERROR_NOTINITED ); } /* Since this is a dummy context that contains no actual keying information (the key data is held in hardware) we set it as KEYMGMT_ITEM_KEYMETADATA */ setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0, NULL, 0, KEYMGMT_FLAG_NONE ); setkeyInfo.cryptHandle = contextInfoPtr->objectHandle; status = krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_SETKEY, &setkeyInfo, KEYMGMT_ITEM_KEYMETADATA ); krnlReleaseObject( iCryptDevice ); return( status ); } /* Many hardware devices have no native public/private key generation support or can only generate something like the DLP x value, which is just a raw string of random bits, but can't generate a full set of public/private key parameters since these require complex bignum operations not supported by the underlying cryptologic. To handle this we provide supplementary software support routines that generate the key parameters using native contexts and bignum code and then pass them back to the crypto HAL to load into the cryptlogic */ static int generateKeyComponents( CONTEXT_INFO *staticContextInfo, PKC_INFO *contextData, const CAPABILITY_INFO *capabilityInfoPtr, const int keySizeBits ) { int status; assert( isWritePtr( staticContextInfo, sizeof( CONTEXT_INFO ) ) ); assert( isWritePtr( contextData, sizeof( PKC_INFO ) ) ); assert( isReadPtr( capabilityInfoPtr, sizeof( CAPABILITY_INFO ) ) ); REQUIRES( keySizeBits >= bytesToBits( MIN_PKCSIZE ) && \ keySizeBits <= bytesToBits( CRYPT_MAX_PKCSIZE ) ); /* Initialise a static context to generate the key into */ status = staticInitContext( staticContextInfo, CONTEXT_PKC, capabilityInfoPtr, contextData, sizeof( PKC_INFO ), NULL ); if( cryptStatusError( status ) ) return( status ); /* Generate a key into the static context */ status = capabilityInfoPtr->generateKeyFunction( staticContextInfo, keySizeBits ); if( cryptStatusError( status ) ) { staticDestroyContext( staticContextInfo ); return( status ); } return( CRYPT_OK ); } static int rsaGenerateComponents( CRYPT_PKCINFO_RSA *rsaKeyInfo, const int keySizeBits ) { CONTEXT_INFO staticContextInfo; PKC_INFO contextData, *pkcInfo = &contextData; int length, status; assert( isWritePtr( rsaKeyInfo, sizeof( CRYPT_PKCINFO_RSA ) ) ); REQUIRES( keySizeBits >= bytesToBits( MIN_PKCSIZE ) && \ keySizeBits <= bytesToBits( CRYPT_MAX_PKCSIZE ) ); /* Clear return value */ cryptInitComponents( rsaKeyInfo, FALSE ); /* Generate the key components */ status = generateKeyComponents( &staticContextInfo, &contextData, getRSACapability(), keySizeBits ); if( cryptStatusError( status ) ) return( status ); /* Extract the newly-generated key components for the caller to use */ rsaKeyInfo->nLen = BN_num_bits( &pkcInfo->rsaParam_n ); length = BN_bn2bin( &pkcInfo->rsaParam_n, rsaKeyInfo->n ); ENSURES( length == bitsToBytes( rsaKeyInfo->nLen ) ); rsaKeyInfo->eLen = BN_num_bits( &pkcInfo->rsaParam_e ); length = BN_bn2bin( &pkcInfo->rsaParam_e, rsaKeyInfo->e ); ENSURES( length == bitsToBytes( rsaKeyInfo->eLen ) ); rsaKeyInfo->pLen = BN_num_bits( &pkcInfo->rsaParam_p ); length = BN_bn2bin( &pkcInfo->rsaParam_p, rsaKeyInfo->p ); ENSURES( length == bitsToBytes( rsaKeyInfo->pLen ) ); rsaKeyInfo->qLen = BN_num_bits( &pkcInfo->rsaParam_q ); length = BN_bn2bin( &pkcInfo->rsaParam_q, rsaKeyInfo->q ); ENSURES( length == bitsToBytes( rsaKeyInfo->qLen ) ); rsaKeyInfo->e1Len = BN_num_bits( &pkcInfo->rsaParam_exponent1 ); length = BN_bn2bin( &pkcInfo->rsaParam_exponent1, rsaKeyInfo->e1 ); ENSURES( length == bitsToBytes( rsaKeyInfo->e1Len ) ); rsaKeyInfo->e2Len = BN_num_bits( &pkcInfo->rsaParam_exponent2 ); length = BN_bn2bin( &pkcInfo->rsaParam_exponent2, rsaKeyInfo->e2 ); ENSURES( length == bitsToBytes( rsaKeyInfo->e2Len ) ); rsaKeyInfo->uLen = BN_num_bits( &pkcInfo->rsaParam_u ); length = BN_bn2bin( &pkcInfo->rsaParam_u, rsaKeyInfo->u ); ENSURES( length == bitsToBytes( rsaKeyInfo->uLen ) ); staticDestroyContext( &staticContextInfo ); return( status ); } #if defined( USE_DH ) || defined( USE_DSA ) || defined( USE_ELGAMAL ) static int dlpGenerateComponents( CRYPT_PKCINFO_DLP *dlpKeyInfo, const int keySizeBits, const CRYPT_ALGO_TYPE cryptAlgo ) { CONTEXT_INFO staticContextInfo; PKC_INFO contextData, *pkcInfo = &contextData; int length, status; assert( isWritePtr( dlpKeyInfo, sizeof( CRYPT_PKCINFO_DLP ) ) ); REQUIRES( keySizeBits >= bytesToBits( MIN_PKCSIZE ) && \ keySizeBits <= bytesToBits( CRYPT_MAX_PKCSIZE ) ); REQUIRES( cryptAlgo == CRYPT_ALGO_DH || \ cryptAlgo == CRYPT_ALGO_DSA || \ cryptAlgo == CRYPT_ALGO_ELGAMAL ); /* Clear return value */ cryptInitComponents( dlpKeyInfo, FALSE ); /* Generate the key components */ switch( cryptAlgo ) { #ifdef USE_DH case CRYPT_ALGO_DH: status = generateKeyComponents( &staticContextInfo, &contextData, getDHCapability(), keySizeBits ); break; #endif /* USE_DH */ #ifdef USE_DSA case CRYPT_ALGO_DSA: status = generateKeyComponents( &staticContextInfo, &contextData, getDSACapability(), keySizeBits ); break; #endif /* USE_DSA */ #ifdef USE_ELGAMAL case CRYPT_ALGO_ELGAMAL: status = generateKeyComponents( &staticContextInfo, &contextData, getElgamalCapability(), keySizeBits ); break; #endif /* USE_ELGAMAL */ default: retIntError(); } if( cryptStatusError( status ) ) return( status ); /* Extract the newly-generated key components for the caller to use */ dlpKeyInfo->pLen = BN_num_bits( &pkcInfo->dlpParam_p ); length = BN_bn2bin( &pkcInfo->dlpParam_p, dlpKeyInfo->p ); ENSURES( length == bitsToBytes( dlpKeyInfo->pLen ) ); dlpKeyInfo->gLen = BN_num_bits( &pkcInfo->dlpParam_g ); length = BN_bn2bin( &pkcInfo->dlpParam_g, dlpKeyInfo->g ); ENSURES( length == bitsToBytes( dlpKeyInfo->gLen ) ); dlpKeyInfo->qLen = BN_num_bits( &pkcInfo->dlpParam_q ); length = BN_bn2bin( &pkcInfo->dlpParam_q, dlpKeyInfo->q ); ENSURES( length == bitsToBytes( dlpKeyInfo->qLen ) ); dlpKeyInfo->yLen = BN_num_bits( &pkcInfo->dlpParam_y ); length = BN_bn2bin( &pkcInfo->dlpParam_y, dlpKeyInfo->y ); ENSURES( length == bitsToBytes( dlpKeyInfo->yLen ) ); dlpKeyInfo->xLen = BN_num_bits( &pkcInfo->dlpParam_x ); length = BN_bn2bin( &pkcInfo->dlpParam_x, dlpKeyInfo->x ); ENSURES( length == bitsToBytes( dlpKeyInfo->xLen ) ); staticDestroyContext( &staticContextInfo ); return( status ); } #endif /* USE_DH || USE_DSA || USE_ELGAMAL */ int generatePKCcomponents( CONTEXT_INFO *contextInfoPtr, void *keyInfo, const int keySizeBits ) { const CRYPT_ALGO_TYPE cryptAlgo = \ contextInfoPtr->capabilityInfo->cryptAlgo; int status; assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) ); REQUIRES( keyInfo != NULL ); REQUIRES( cryptAlgo == CRYPT_ALGO_DH || \ cryptAlgo == CRYPT_ALGO_RSA || \ cryptAlgo == CRYPT_ALGO_DSA || \ cryptAlgo == CRYPT_ALGO_ELGAMAL ); REQUIRES( keySizeBits >= bytesToBits( MIN_PKCSIZE ) && \ keySizeBits <= bytesToBits( CRYPT_MAX_PKCSIZE ) ); switch( cryptAlgo ) { case CRYPT_ALGO_RSA: status = rsaGenerateComponents( keyInfo, keySizeBits ); break; #if defined( USE_DH ) || defined( USE_DSA ) || defined( USE_ELGAMAL ) case CRYPT_ALGO_DH: case CRYPT_ALGO_DSA: case CRYPT_ALGO_ELGAMAL: status = dlpGenerateComponents( keyInfo, keySizeBits, cryptAlgo ); break; #endif /* USE_DH || USE_DSA || USE_ELGAMAL */ default: return( CRYPT_ERROR_NOTAVAIL ); } if( cryptStatusError( status ) ) return( status ); /* Send the public-key data (needed for certificates and the like) to the context */ return( setPKCinfo( contextInfoPtr, cryptAlgo, keyInfo ) ); } /* Send public-key data to the context for use with certificate objects */ int setPKCinfo( CONTEXT_INFO *contextInfoPtr, const CRYPT_ALGO_TYPE cryptAlgo, const void *keyInfo ) { BYTE keyDataBuffer[ ( CRYPT_MAX_PKCSIZE * 4 ) + 8 ]; MESSAGE_DATA msgData; int keyDataSize, status; assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) ); assert( ( cryptAlgo == CRYPT_ALGO_RSA && \ isReadPtr( keyInfo, sizeof( CRYPT_PKCINFO_RSA ) ) ) || \ ( cryptAlgo != CRYPT_ALGO_RSA && \ isReadPtr( keyInfo, sizeof( CRYPT_PKCINFO_DLP ) ) ) ); REQUIRES( cryptAlgo == CRYPT_ALGO_DH || \ cryptAlgo == CRYPT_ALGO_RSA || \ cryptAlgo == CRYPT_ALGO_DSA || \ cryptAlgo == CRYPT_ALGO_ELGAMAL ); /* Send the public key data to the context. We send the keying information as CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL rather than CRYPT_IATTRIBUTE_KEY_SPKI since the latter transitions the context into the high state. We don't want to do this because we're already in the middle of processing a message that does this on completion, all that we're doing here is sending in encoded public key data for use by objects such as certificates */ switch( cryptAlgo ) { case CRYPT_ALGO_RSA: { const CRYPT_PKCINFO_RSA *rsaKeyInfo = \ ( CRYPT_PKCINFO_RSA * ) keyInfo; if( rsaKeyInfo->isPublicKey ) contextInfoPtr->flags |= CONTEXT_FLAG_ISPUBLICKEY; else contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT; status = writeFlatPublicKey( keyDataBuffer, CRYPT_MAX_PKCSIZE * 4, &keyDataSize, CRYPT_ALGO_RSA, 0, rsaKeyInfo->n, bitsToBytes( rsaKeyInfo->nLen ), rsaKeyInfo->e, bitsToBytes( rsaKeyInfo->eLen ), NULL, 0, NULL, 0 ); break; } case CRYPT_ALGO_DH: case CRYPT_ALGO_DSA: case CRYPT_ALGO_ELGAMAL: { const CRYPT_PKCINFO_DLP *dlpKeyInfo = \ ( CRYPT_PKCINFO_DLP * ) keyInfo; if( dlpKeyInfo->isPublicKey ) contextInfoPtr->flags |= CONTEXT_FLAG_ISPUBLICKEY; else contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT; status = writeFlatPublicKey( keyDataBuffer, CRYPT_MAX_PKCSIZE * 4, &keyDataSize, cryptAlgo, 0, dlpKeyInfo->p, bitsToBytes( dlpKeyInfo->pLen ), dlpKeyInfo->q, bitsToBytes( dlpKeyInfo->qLen ), dlpKeyInfo->g, bitsToBytes( dlpKeyInfo->gLen ), dlpKeyInfo->y, bitsToBytes( dlpKeyInfo->yLen ) ); break; } default: retIntError(); } if( cryptStatusError( status ) ) return( status ); setMessageData( &msgData, keyDataBuffer, keyDataSize ); return( krnlSendMessage( contextInfoPtr->objectHandle, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL ) ); } /* Send encryption/MAC keying metadata to the context */ int setConvInfo( const CRYPT_CONTEXT iCryptContext, const int keySize ) { assert( isHandleRangeValid( iCryptContext ) ); REQUIRES( keySize >= MIN_KEYSIZE && keySize <= CRYPT_MAX_KEYSIZE ); return( krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &keySize, CRYPT_IATTRIBUTE_KEYSIZE ) ); } /* The default cleanup function, which simply frees the context-related data used by the cryptographic hardware if it's an ephemeral key */ int cleanupHardwareContext( const CONTEXT_INFO *contextInfoPtr ) { assert( isReadPtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) ); /* If this is non-ephemeral context data then we leave it intact when the corresponding context is destroyed, the only way to delete it is with an explicit deleteItem() */ if( contextInfoPtr->flags & CONTEXT_FLAG_PERSISTENT ) return( CRYPT_OK ); /* We have to be careful about deleting the context data since it may not have been set up yet, for example if we're called due to a failure in the complete-creation/initialisation step of setting up a context */ if( contextInfoPtr->deviceObject != CRYPT_ERROR ) hwDeleteItem( contextInfoPtr->deviceObject ); return( CRYPT_OK ); } /**************************************************************************** * * * Device Access Routines * * * ****************************************************************************/ /* Mechanisms supported by the hardware. These are actually cryptlib native mechanisms, but not the full set supported by the system device since functions like private key export aren't available. The list is sorted in order of frequency of use in order to make lookups a bit faster */ static const FAR_BSS MECHANISM_FUNCTION_INFO mechanismFunctions[] = { { MESSAGE_DEV_EXPORT, MECHANISM_ENC_PKCS1, ( MECHANISM_FUNCTION ) exportPKCS1 }, { MESSAGE_DEV_IMPORT, MECHANISM_ENC_PKCS1, ( MECHANISM_FUNCTION ) importPKCS1 }, { MESSAGE_DEV_SIGN, MECHANISM_SIG_PKCS1, ( MECHANISM_FUNCTION ) signPKCS1 }, { MESSAGE_DEV_SIGCHECK, MECHANISM_SIG_PKCS1, ( MECHANISM_FUNCTION ) sigcheckPKCS1 }, { MESSAGE_DEV_EXPORT, MECHANISM_ENC_PKCS1_RAW, ( MECHANISM_FUNCTION ) exportPKCS1 }, { MESSAGE_DEV_IMPORT, MECHANISM_ENC_PKCS1_RAW, ( MECHANISM_FUNCTION ) importPKCS1 }, #ifdef USE_PGP { MESSAGE_DEV_EXPORT, MECHANISM_ENC_PKCS1_PGP, ( MECHANISM_FUNCTION ) exportPKCS1PGP }, { MESSAGE_DEV_IMPORT, MECHANISM_ENC_PKCS1_PGP, ( MECHANISM_FUNCTION ) importPKCS1PGP }, #endif /* USE_PGP */ { MESSAGE_DEV_EXPORT, MECHANISM_ENC_CMS, ( MECHANISM_FUNCTION ) exportCMS }, { MESSAGE_DEV_IMPORT, MECHANISM_ENC_CMS, ( MECHANISM_FUNCTION ) importCMS }, { MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_PKCS5, ( MECHANISM_FUNCTION ) derivePKCS5 }, #if defined( USE_PGP ) || defined( USE_PGPKEYS ) { MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_PGP, ( MECHANISM_FUNCTION ) derivePGP }, #endif /* USE_PGP || USE_PGPKEYS */ #ifdef USE_SSL { MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_TLS, ( MECHANISM_FUNCTION ) deriveSSL }, { MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_SSL, ( MECHANISM_FUNCTION ) deriveTLS }, { MESSAGE_DEV_SIGN, MECHANISM_SIG_SSL, ( MECHANISM_FUNCTION ) signSSL }, { MESSAGE_DEV_SIGCHECK, MECHANISM_SIG_SSL, ( MECHANISM_FUNCTION ) sigcheckSSL }, #endif /* USE_SSL */ #ifdef USE_CMP { MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_CMP, ( MECHANISM_FUNCTION ) deriveCMP }, #endif /* USE_CMP */ #ifdef USE_PKCS12 { MESSAGE_DEV_DERIVE, MECHANISM_DERIVE_PKCS12, ( MECHANISM_FUNCTION ) derivePKCS12 }, #endif /* USE_PKCS12 */ { MESSAGE_NONE, MECHANISM_NONE, NULL }, { MESSAGE_NONE, MECHANISM_NONE, NULL } }; /* Set up the function pointers to the device methods */ CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \ int setDeviceHardware( INOUT DEVICE_INFO *deviceInfo ) { assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); deviceInfo->initFunction = initFunction; deviceInfo->shutdownFunction = shutdownFunction; deviceInfo->controlFunction = controlFunction; deviceInfo->getItemFunction = getItemFunction; deviceInfo->setItemFunction = setItemFunction; deviceInfo->deleteItemFunction = deleteItemFunction; deviceInfo->getFirstItemFunction = getFirstItemFunction; deviceInfo->getNextItemFunction = getNextItemFunction; deviceInfo->getRandomFunction = getRandomFunction; deviceInfo->capabilityInfoList = capabilityInfoList; deviceInfo->mechanismFunctions = mechanismFunctions; deviceInfo->mechanismFunctionCount = \ FAILSAFE_ARRAYSIZE( mechanismFunctions, MECHANISM_FUNCTION_INFO ); return( CRYPT_OK ); } #endif /* USE_HARDWARE */