Beispiel #1
0
static void cleanupReqResp( INOUT SESSION_INFO *sessionInfoPtr,
							const BOOLEAN preTransaction )
	{
	const BOOLEAN isServer = isServer( sessionInfoPtr );

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );

	/* Clean up server requests left over from a previous transaction or 
	   that have been created by the just-completed transaction */
	if( isServer && sessionInfoPtr->iCertRequest != CRYPT_ERROR )
		{
		krnlSendNotifier( sessionInfoPtr->iCertRequest,
						  IMESSAGE_DECREFCOUNT );
		sessionInfoPtr->iCertRequest = CRYPT_ERROR;
		}

	/* Clean up client/server responses left over from a previous
	   transaction */
	if( preTransaction && sessionInfoPtr->iCertResponse != CRYPT_ERROR )
		{
		krnlSendNotifier( sessionInfoPtr->iCertResponse,
						  IMESSAGE_DECREFCOUNT );
		sessionInfoPtr->iCertResponse = CRYPT_ERROR;
		}
	}
Beispiel #2
0
static void sendErrorResponse( INOUT SESSION_INFO *sessionInfoPtr,
							   INOUT SCEP_PROTOCOL_INFO *protocolInfo,
							   IN_ERROR const int scepStatus )
	{
	CRYPT_CERTIFICATE iCmsAttributes;
	int status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) );
	
	REQUIRES_V( cryptStatusError( scepStatus ) );

	/* Sign the error response using the CA key and SCEP attributes */
	status = createScepAttributes( sessionInfoPtr, protocolInfo,  
								   &iCmsAttributes, MESSAGETYPE_CERTREP, 
								   scepStatus );
	if( cryptStatusOK( status ) )
		{
		ERROR_INFO errorInfo;

		/* Since this message is being sent in response to an existing 
		   error, we don't care about the possible error information 
		   returned from the function that sends the error response,
		   so the errorInfo result is ignored */
		status = envelopeSign( NULL, 0, sessionInfoPtr->receiveBuffer, 
							   sessionInfoPtr->receiveBufSize, 
							   &sessionInfoPtr->receiveBufEnd, 
							   CRYPT_CONTENT_NONE, sessionInfoPtr->privateKey, 
							   iCmsAttributes, &errorInfo );
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		}
	if( cryptStatusError( status ) )
		{
		HTTP_DATA_INFO httpDataInfo;

		/* If we encounter an error processing the initial request then 
		   there won't be enough information available to create an error 
		   response.  Similarly if we run into problems generating the
		   response then there won't be anything available to send.  At this 
		   point the best that we can do is send an error at the HTTP 
		   level */
		initHttpDataInfo( &httpDataInfo, sessionInfoPtr->receiveBuffer,
						  sessionInfoPtr->receiveBufSize );
		httpDataInfo.reqStatus = scepStatus;
		swrite( &sessionInfoPtr->stream, &httpDataInfo, 
				sizeof( HTTP_DATA_INFO ) );
		return;
		}
	DEBUG_DUMP_FILE( "scep_srespx", sessionInfoPtr->receiveBuffer, 
					 sessionInfoPtr->receiveBufEnd );

	/* Return the response to the client, discarding any error indication 
	   from the write.  Since we're already in an error state there's not 
	   much that we can do in terms of alerting the user if a further error 
	   occurs when writing the error response, so we ignore any potential 
	   write errors that occur at this point */
	sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_LASTMESSAGE, TRUE );
	( void ) writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE, 
							   SCEP_CONTENT_TYPE_LEN );
	}
Beispiel #3
0
static int cloneActionContext( OUT_HANDLE_OPT CRYPT_CONTEXT *iClonedContext,
							   IN_HANDLE const CRYPT_CONTEXT cryptContext,
							   IN_ALGO const CRYPT_ALGO_TYPE algorithm )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	int status;

	assert( isWritePtr( iClonedContext, sizeof( CRYPT_CONTEXT ) ) );

	REQUIRES( isHandleRangeValid( cryptContext ) );
	REQUIRES( algorithm > CRYPT_ALGO_NONE && algorithm < CRYPT_ALGO_LAST );

	setMessageCreateObjectInfo( &createInfo, algorithm );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
							  OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	status = krnlSendMessage( cryptContext, IMESSAGE_CLONE, NULL,
							  createInfo.cryptHandle );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		return( status );
		}
	*iClonedContext = createInfo.cryptHandle;

	return( CRYPT_OK );
	}
Beispiel #4
0
void destroySCEPprotocolInfo( INOUT SCEP_PROTOCOL_INFO *protocolInfo )
	{
	assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) );

	if( protocolInfo->iScepCert != CRYPT_ERROR )
		krnlSendNotifier( protocolInfo->iScepCert, IMESSAGE_DECREFCOUNT );

	zeroise( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) );
	}
Beispiel #5
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 ) );
	}
Beispiel #6
0
static int readUserID( INOUT STREAM *stream, 
					   INOUT CMP_PROTOCOL_INFO *protocolInfo )
	{
	BYTE userID[ CRYPT_MAX_HASHSIZE + 8 ];
	int userIDsize, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );

	/* Read the PKI user ID that we'll need to handle the integrity 
	   protection on the message */
	readConstructed( stream, NULL, CTAG_PH_SENDERKID );
	status = readOctetString( stream, userID, &userIDsize, 8, 
							  CRYPT_MAX_HASHSIZE );
	if( cryptStatusError( status ) )
		return( status );
	ANALYSER_HINT( userIDsize >= 8 && userIDsize <= CRYPT_MAX_HASHSIZE );

	/* If there's already been a previous transaction (which means that we 
	   have PKI user information present) and the current transaction 
	   matches what was used in the previous one, we don't have to update 
	   the user information */
	if( protocolInfo->userIDsize == userIDsize && \
		!memcmp( protocolInfo->userID, userID, userIDsize ) )
		{
		DEBUG_PRINT(( "%s: Skipped repeated userID.\n",
					  protocolInfo->isServer ? "SVR" : "CLI" ));
		DEBUG_DUMP_HEX( protocolInfo->isServer ? "SVR" : "CLI", 
						protocolInfo->userID, protocolInfo->userIDsize );
		return( CRYPT_OK );
		}

	/* Record the new or changed the PKI user information and delete the 
	   MAC context associated with the previous user if necessary */
	memcpy( protocolInfo->userID, userID, userIDsize );
	protocolInfo->userIDsize = userIDsize;
	protocolInfo->userIDchanged = TRUE;
	if( protocolInfo->iMacContext != CRYPT_ERROR )
		{
		krnlSendNotifier( protocolInfo->iMacContext,
						  IMESSAGE_DECREFCOUNT );
		protocolInfo->iMacContext = CRYPT_ERROR;
		}
	DEBUG_PRINT(( "%s: Read new userID.\n",
				  protocolInfo->isServer ? "SVR" : "CLI" ));
	DEBUG_DUMP_HEX( protocolInfo->isServer ? "SVR" : "CLI", 
					protocolInfo->userID, protocolInfo->userIDsize );

	return( CRYPT_OK );
	}
Beispiel #7
0
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 );
	}
static int createScepResponse( INOUT SESSION_INFO *sessionInfoPtr,
							   INOUT SCEP_PROTOCOL_INFO *protocolInfo )
	{
	CRYPT_CERTIFICATE iCmsAttributes;
	MESSAGE_DATA msgData;
	int dataLength, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) );

	/* Extract the response data into the session buffer */
	setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
					sessionInfoPtr->receiveBufSize );
	status = krnlSendMessage( sessionInfoPtr->iCertResponse,
							  IMESSAGE_CRT_EXPORT, &msgData,
							  CRYPT_CERTFORMAT_CERTCHAIN );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't get PKCS #7 certificate chain from SCEP "
				  "response object" ) );
		}
	DEBUG_DUMP_FILE( "scep_sresp0", sessionInfoPtr->receiveBuffer, 
					 msgData.length );

	/* Phase 1: Encrypt the data using the client's key */
	status = envelopeWrap( sessionInfoPtr->receiveBuffer, msgData.length,
						   sessionInfoPtr->receiveBuffer, 
						   sessionInfoPtr->receiveBufSize, &dataLength, 
						   CRYPT_FORMAT_CMS, CRYPT_CONTENT_NONE, 
						   protocolInfo->iScepCert );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't encrypt response data with client key" ) );
		}
	DEBUG_DUMP_FILE( "scep_sresp1", sessionInfoPtr->receiveBuffer, 
					 dataLength );

	/* Create the SCEP signing attributes */
	status = createScepAttributes( sessionInfoPtr, protocolInfo,  
								   &iCmsAttributes, FALSE, CRYPT_OK );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't create SCEP response signing attributes" ) );
		}

	/* Phase 2: Sign the data using the CA key and SCEP attributes */
	status = envelopeSign( sessionInfoPtr->receiveBuffer, dataLength,
						   sessionInfoPtr->receiveBuffer, 
						   sessionInfoPtr->receiveBufSize, 
						   &sessionInfoPtr->receiveBufEnd, 
						   CRYPT_CONTENT_NONE, sessionInfoPtr->privateKey, 
						   iCmsAttributes );
	krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't sign response data with CA key" ) );
		}
	DEBUG_DUMP_FILE( "scep_sresp2", sessionInfoPtr->receiveBuffer, 
					 sessionInfoPtr->receiveBufEnd );

	return( CRYPT_OK );
	}
static int checkScepRequest( INOUT SESSION_INFO *sessionInfoPtr,
							 INOUT SCEP_PROTOCOL_INFO *protocolInfo, 
							 OUT BOOLEAN *requestDataAvailable )
	{
	CRYPT_CERTIFICATE iCmsAttributes;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	MESSAGE_DATA msgData;
	int dataLength, sigResult, value, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) );
	assert( isWritePtr( requestDataAvailable, sizeof( BOOLEAN ) ) );

	/* Clear return value */
	*requestDataAvailable = FALSE;

	/* Phase 1: Sig-check the self-signed data */
	DEBUG_DUMP_FILE( "scep_sreq2", sessionInfoPtr->receiveBuffer, 
					 sessionInfoPtr->receiveBufEnd );
	status = envelopeSigCheck( sessionInfoPtr->receiveBuffer, 
							   sessionInfoPtr->receiveBufEnd,
							   sessionInfoPtr->receiveBuffer, 
							   sessionInfoPtr->receiveBufSize, &dataLength, 
							   CRYPT_UNUSED, &sigResult, 
							   &protocolInfo->iScepCert, &iCmsAttributes );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Invalid CMS signed data in client request" ) );
		}
	DEBUG_DUMP_FILE( "scep_sreq1", sessionInfoPtr->receiveBuffer, 
					 dataLength );
	if( cryptStatusError( sigResult ) )
		{
		/* The signed data was valid but the signature on it wasn't, this is
		   a different style of error than the previous one */
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		retExt( sigResult, 
				( sigResult, SESSION_ERRINFO, 
				  "Bad signature on client request data" ) );
		}

	/* Make sure that the client certificate is valid for signing and 
	   decryption.  In effect the signing capability has already been 
	   checked by the fact that the certificate signed the request but we do 
	   an explicit check here just to be thorough */
	status = krnlSendMessage( protocolInfo->iScepCert, IMESSAGE_CHECK, 
							  NULL, MESSAGE_CHECK_PKC_SIGCHECK );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( protocolInfo->iScepCert, IMESSAGE_CHECK, 
								  NULL, MESSAGE_CHECK_PKC_ENCRYPT );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		retExt( CRYPT_ERROR_INVALID, 
				( CRYPT_ERROR_INVALID, SESSION_ERRINFO, 
				  "Ephemeral SCEP client certificate isn't valid for "
				  "signing/encryption" ) );
		}

	/* Get the nonce and transaction ID and save it for the reply */
	setMessageData( &msgData, protocolInfo->nonce, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_CERTINFO_SCEP_SENDERNONCE );
	if( cryptStatusOK( status ) )
		{
		protocolInfo->nonceSize = msgData.length;
		setMessageData( &msgData, protocolInfo->transID, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
								  &msgData,
								  CRYPT_CERTINFO_SCEP_TRANSACTIONID );
		}
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Request is missing a nonce/transaction ID" ) );
		}
	protocolInfo->transIDsize = msgData.length;

	/* We've now got enough request data available to construct a SCEP-level 
	   response to an error instead of an HTTP-level one, let the caller 
	   know.  Note that this lets an attacker know that they've made it this
	   far in the checking, but it's not obvious that this is a security
	   problem, especially since they can get a good idea of how far they 
	   got from the different error conditions that will be returned */
	*requestDataAvailable = TRUE;

	/* Since the request is for a cryptlib server it'll have a transaction 
	   ID that's a cryptlib-encoded PKI user ID.  If we don't get this then 
	   we reject the request */
	if( protocolInfo->transIDsize != 17 || \
		!isPKIUserValue( protocolInfo->transID, protocolInfo->transIDsize ) )
		{
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
				  "Request has an invalid transaction ID '%s'",
				  sanitiseString( protocolInfo->transID, 
								  protocolInfo->transIDsize,
				  				  protocolInfo->transIDsize ) ) );
		}
	status = updateSessionInfo( &sessionInfoPtr->attributeList,
								CRYPT_SESSINFO_USERNAME, 
								protocolInfo->transID, 
								protocolInfo->transIDsize, 
								CRYPT_MAX_TEXTSIZE, ATTR_FLAG_ENCODEDVALUE );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		return( status );
		}

	/* Check that we've been sent the correct type of message */
	status = getScepStatusValue( iCmsAttributes,
								 CRYPT_CERTINFO_SCEP_MESSAGETYPE, &value );
	if( cryptStatusOK( status ) && value != MESSAGETYPE_PKCSREQ_VALUE )
		status = CRYPT_ERROR_BADDATA;
	krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Incorrect SCEP message type %d", value ) );
		}

	/* Phase 2: Decrypt the data using our CA key */
	status = envelopeUnwrap( sessionInfoPtr->receiveBuffer, dataLength,
							 sessionInfoPtr->receiveBuffer, 
							 sessionInfoPtr->receiveBufSize, &dataLength, 
							 sessionInfoPtr->privateKey );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Couldn't decrypt CMS enveloped data in client request" ) );
		}

	/* Finally, import the request as a PKCS #10 request */
	setMessageCreateObjectIndirectInfo( &createInfo,
								sessionInfoPtr->receiveBuffer, dataLength,
								CRYPT_CERTTYPE_CERTREQUEST );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
							  &createInfo, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Invalid PKCS #10 request in client request" ) );
		}
	sessionInfoPtr->iCertRequest = createInfo.cryptHandle;

	return( CRYPT_OK );
	}
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 );
	}
Beispiel #11
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 );
	}
Beispiel #12
0
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 );
	}