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 ) ); }
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 ) ); }
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 issueCertFromRequest( INOUT SESSION_INFO *sessionInfoPtr, INOUT SCEP_PROTOCOL_INFO *protocolInfo ) { MESSAGE_KEYMGMT_INFO setkeyInfo; MESSAGE_CERTMGMT_INFO certMgmtInfo; int status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) ); /* Check that the request is permitted and add it to the certificate store */ status = checkPkiUserInfo( sessionInfoPtr, protocolInfo ); if( cryptStatusError( status ) ) return( status ); setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0, NULL, 0, KEYMGMT_FLAG_NONE ); setkeyInfo.cryptHandle = sessionInfoPtr->iCertRequest; status = krnlSendMessage( sessionInfoPtr->cryptKeyset, IMESSAGE_KEY_SETKEY, &setkeyInfo, KEYMGMT_ITEM_REQUEST ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Request couldn't be added to certificate store" ) ); } /* Convert the request into a certificate */ setMessageCertMgmtInfo( &certMgmtInfo, sessionInfoPtr->privateKey, sessionInfoPtr->iCertRequest ); status = krnlSendMessage( sessionInfoPtr->cryptKeyset, IMESSAGE_KEY_CERTMGMT, &certMgmtInfo, CRYPT_CERTACTION_ISSUE_CERT ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't issue certificate for user" ) ); } sessionInfoPtr->iCertResponse = certMgmtInfo.cryptCert; return( CRYPT_OK ); }
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 ) ); }
static int checkPkiUserInfo( INOUT SESSION_INFO *sessionInfoPtr, INOUT SCEP_PROTOCOL_INFO *protocolInfo ) { const ATTRIBUTE_LIST *userNamePtr = \ findSessionInfo( sessionInfoPtr->attributeList, CRYPT_SESSINFO_USERNAME ); MESSAGE_KEYMGMT_INFO getkeyInfo; MESSAGE_DATA msgData; BYTE keyID[ 64 + 8 ]; BYTE requestPassword[ CRYPT_MAX_TEXTSIZE + 8 ]; BYTE userPassword[ CRYPT_MAX_TEXTSIZE + 8 ]; int requestPasswordSize, userPasswordSize = DUMMY_INIT; int keyIDsize, status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) ); REQUIRES( userNamePtr != NULL ); /* Get the password from the PKCS #10 request */ setMessageData( &msgData, requestPassword, CRYPT_MAX_TEXTSIZE ); status = krnlSendMessage( sessionInfoPtr->iCertRequest, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_CHALLENGEPASSWORD ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't get challenge password from PKCS #10 request" ) ); } requestPasswordSize = msgData.length; /* Since it's a cryptlib encoded user ID we need to decode it before we can look up a PKI user with it */ REQUIRES( userNamePtr->flags & ATTR_FLAG_ENCODEDVALUE ); status = decodePKIUserValue( keyID, 64, &keyIDsize, userNamePtr->value, userNamePtr->valueLength ); ENSURES( cryptStatusOK( status ) ); /* Get the user information for the request from the certificate store */ setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_KEYID, keyID, keyIDsize, NULL, 0, KEYMGMT_FLAG_NONE ); status = krnlSendMessage( sessionInfoPtr->cryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, KEYMGMT_ITEM_PKIUSER ); if( cryptStatusError( status ) ) { char userID[ CRYPT_MAX_TEXTSIZE + 8 ]; int userIDlen; zeroise( requestPassword, CRYPT_MAX_TEXTSIZE ); userIDlen = min( userNamePtr->valueLength, CRYPT_MAX_TEXTSIZE ); memcpy( userID, userNamePtr->value, userIDlen ); retExtObj( status, ( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset, "Couldn't find PKI user information for %s", sanitiseString( userID, CRYPT_MAX_TEXTSIZE, userIDlen ) ) ); } /* Get the password from the PKI user object */ setMessageData( &msgData, userPassword, CRYPT_MAX_TEXTSIZE ); status = krnlSendMessage( getkeyInfo.cryptHandle, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD ); if( cryptStatusOK( status ) ) { userPasswordSize = msgData.length; status = updateSessionInfo( &sessionInfoPtr->attributeList, CRYPT_SESSINFO_PASSWORD, userPassword, userPasswordSize, CRYPT_MAX_TEXTSIZE, ATTR_FLAG_ENCODEDVALUE ); } if( cryptStatusError( status ) ) { zeroise( requestPassword, CRYPT_MAX_TEXTSIZE ); zeroise( userPassword, CRYPT_MAX_TEXTSIZE ); krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); retExt( status, ( status, SESSION_ERRINFO, "Couldn't copy read PKI user data from PKI user object " "into session object" ) ); } /* Make sure that the password matches the one in the request */ if( userPasswordSize != requestPasswordSize || \ !compareDataConstTime( userPassword, requestPassword, userPasswordSize ) ) { zeroise( requestPassword, CRYPT_MAX_TEXTSIZE ); zeroise( userPassword, CRYPT_MAX_TEXTSIZE ); krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); retExt( status, ( status, SESSION_ERRINFO, "Password in PKCS #10 request doesn't match PKI user " "password" ) ); } zeroise( userPassword, CRYPT_MAX_TEXTSIZE ); /* If the subject only knows their CN, they may send a CN-only subject DN in the hope that we can fill it in for them. In addition there may be other constraints that the CA wants to apply, these are handled by applying the PKI user information to the request */ status = krnlSendMessage( sessionInfoPtr->iCertRequest, IMESSAGE_SETATTRIBUTE, &getkeyInfo.cryptHandle, CRYPT_IATTRIBUTE_PKIUSERINFO ); krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); if( cryptStatusError( status ) ) { retExt( CRYPT_ERROR_INVALID, ( CRYPT_ERROR_INVALID, SESSION_ERRINFO, "User information in PKCS #10 request can't be " "reconciled with stored information for the user" ) ); } return( CRYPT_OK ); }
static int readCheckClientCerts( INOUT SESSION_INFO *sessionInfoPtr, INOUT SSL_HANDSHAKE_INFO *handshakeInfo, INOUT STREAM *stream ) { #ifndef CONFIG_SUITEB_TESTS MESSAGE_KEYMGMT_INFO getkeyInfo; MESSAGE_DATA msgData; BYTE certID[ KEYID_SIZE + 8 ]; #endif /* !CONFIG_SUITEB_TESTS */ #ifdef CONFIG_SUITEB int length; #endif /* CONFIG_SUITEB */ int status; /* Read the client certificate chain */ status = readSSLCertChain( sessionInfoPtr, handshakeInfo, stream, &sessionInfoPtr->iKeyexAuthContext, TRUE ); if( cryptStatusError( status ) ) return( status ); /* Make sure that the client certificate is present in our certificate store. Since we've already got a copy of the certificate, we only do a presence check rather than actually fetching the certificate */ #ifndef CONFIG_SUITEB_TESTS setMessageData( &msgData, certID, KEYID_SIZE ); status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_FINGERPRINT_SHA1 ); if( cryptStatusOK( status ) ) { setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID, certID, KEYID_SIZE, NULL, 0, KEYMGMT_FLAG_CHECK_ONLY ); status = krnlSendMessage( sessionInfoPtr->cryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, KEYMGMT_ITEM_PUBLICKEY ); } if( cryptStatusError( status ) ) { retExt( CRYPT_ERROR_INVALID, ( CRYPT_ERROR_INVALID, SESSION_ERRINFO, "Client certificate is not trusted for authentication " "purposes" ) ); } #endif /* CONFIG_SUITEB_TESTS */ /* Make sure that the key is of the appropriate size for the Suite B security level. At the 128-bit level both P256 and P384 are allowed, at the 256-bit level only P384 is allowed */ #ifdef CONFIG_SUITEB status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext, IMESSAGE_GETATTRIBUTE, &length, CRYPT_CTXINFO_KEYSIZE ); if( cryptStatusOK( status ) ) { const int suiteBtype = \ sessionInfoPtr->protocolFlags & SSL_PFLAG_SUITEB; if( suiteBtype == SSL_PFLAG_SUITEB_256 ) { if( length != bitsToBytes( 384 ) ) { retExt( CRYPT_ERROR_INVALID, ( CRYPT_ERROR_INVALID, SESSION_ERRINFO, "Client Suite B certificate uses %d-bit key at " "256-bit security level, should use 384-bit key", bytesToBits( length ) ) ); } } else { if( length != bitsToBytes( 256 ) && \ length != bitsToBytes( 384 ) ) { retExt( CRYPT_ERROR_INVALID, ( CRYPT_ERROR_INVALID, SESSION_ERRINFO, "Client Suite B certificate uses %d-bit key at " "128-bit security level, should use 256- or " "384-bit key", bytesToBits( length ) ) ); } } } #endif /* CONFIG_SUITEB */ return( CRYPT_OK ); }
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 ); }
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 ); }