Пример #1
0
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 ) );
	}
Пример #2
0
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 ) );
	}
Пример #3
0
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 ) );
	}
Пример #4
0
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 );
	}
Пример #5
0
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 ) );
	}
Пример #6
0
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 );
	}
Пример #7
0
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 );
	}
Пример #8
0
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 );
	}
Пример #9
0
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 );
	}