Exemple #1
0
CHECK_RETVAL_BOOL \
static BOOLEAN checkPrivateKey( IN_HANDLE const CRYPT_CONTEXT iCryptContext,
								const BOOLEAN isCertKey )
	{
	int value, status;

	REQUIRES( isHandleRangeValid( iCryptContext ) );

	/* If the private key requires an associated certificate, make sure that 
	   it's present and of the correct form */
	if( isCertKey )
		{
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, 
								  &value, CRYPT_CERTINFO_IMMUTABLE );
		if( cryptStatusError( status ) || !value )
			return( FALSE );
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, 
								  &value, CRYPT_CERTINFO_CERTTYPE );
		if( cryptStatusError( status ) || \
			( value != CRYPT_CERTTYPE_CERTIFICATE && \
			  value != CRYPT_CERTTYPE_CERTCHAIN ) )
			return( FALSE );
		
		return( TRUE );
		}

	/* The private key can't have an associated certificate, make sure 
	   there's none present */
	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, 
							  &value, CRYPT_CERTINFO_CERTTYPE );
	return( cryptStatusOK( status ) ? FALSE : TRUE );
	}
Exemple #2
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 );
	}
Exemple #3
0
static int getDynData( OUT DYNBUF *dynBuf, 
					   IN_HANDLE const CRYPT_HANDLE cryptHandle,
					   IN_MESSAGE const MESSAGE_TYPE message, 
					   IN_INT const int messageParam )
	{
	MESSAGE_DATA msgData;
	void *dataPtr = NULL;
	int status;

	assert( isWritePtr( dynBuf, sizeof( DYNBUF ) ) );

	REQUIRES( isHandleRangeValid( cryptHandle ) );
	REQUIRES( ( message == IMESSAGE_GETATTRIBUTE_S && \
				( isAttribute( messageParam ) || \
				  isInternalAttribute( messageParam ) ) ) || \
			  ( message == IMESSAGE_CRT_EXPORT && \
		 		messageParam == CRYPT_CERTFORMAT_CERTIFICATE ) );

	/* Clear return values.  Note that we don't use the usual memset() to 
	   clear the value since the structure contains the storage for the 
	   fixed-size portion of the buffer appended to it, and using memset() 
	   to clear that is just unnecessary overhead */
	dynBuf->data = dynBuf->dataBuffer;
	dynBuf->length = 0;

	/* Get the data from the object */
	setMessageData( &msgData, NULL, 0 );
	status = krnlSendMessage( cryptHandle, message, &msgData, messageParam );
	if( cryptStatusError( status ) )
		return( status );
	if( msgData.length > DYNBUF_SIZE )
		{
		/* The data is larger than the built-in buffer size, dynamically
		   allocate a larger buffer */
		if( ( dataPtr = clDynAlloc( "dynCreate", msgData.length ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		msgData.data = dataPtr;
		status = krnlSendMessage( cryptHandle, message, &msgData,
								  messageParam );
		if( cryptStatusError( status ) )
			{
			clFree( "dynCreate", dataPtr );
			return( status );
			}
		dynBuf->data = dataPtr;
		}
	else
		{
		/* The data will fit into the built-in buffer, read it directly into
		   the buffer */
		msgData.data = dynBuf->data;
		status = krnlSendMessage( cryptHandle, message, &msgData,
								  messageParam );
		if( cryptStatusError( status ) )
			return( status );
		}
	dynBuf->length = msgData.length;

	return( CRYPT_OK );
	}
Exemple #4
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 ) );
	}
Exemple #5
0
void slowPoll( void )
	{
	MESSAGE_DATA msgData;
	BYTE buffer[ RANDOM_BUFSIZE ];
	int quality = 95, status;

	status = readRandom( RANDOM_BUFSIZE, buffer );
	assert( status == 0 );
	setMessageData( &msgData, buffer, RANDOM_BUFSIZE );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData,
					 CRYPT_IATTRIBUTE_ENTROPY );
	zeroise( buffer, sizeof( buffer ) );
	if( status == 0 )
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
						 &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
	}
Exemple #6
0
static int writeCertID( INOUT STREAM *stream,
                        IN_HANDLE const CRYPT_CONTEXT iCryptCert )
{
    MESSAGE_DATA msgData;
    BYTE certHash[ CRYPT_MAX_HASHSIZE + 8 ];
    int essCertIDSize, payloadSize, status;

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

    REQUIRES( isHandleRangeValid( iCryptCert ) );

    /* Find out how big the payload will be */
    setMessageData( &msgData, certHash, CRYPT_MAX_HASHSIZE );
    status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
                              &msgData, CRYPT_CERTINFO_FINGERPRINT_SHA1 );
    if( cryptStatusError( status ) )
        return( status );
    essCertIDSize = ( int ) sizeofObject( msgData.length );
    payloadSize = objSize( objSize( objSize( essCertIDSize ) ) );

    /* Write the signing certificate ID information */
    writeSequence( stream, sizeofOID( OID_ESS_CERTID ) + \
                   ( int ) sizeofObject( payloadSize ) );
    writeOID( stream, OID_ESS_CERTID );
    writeSet( stream, payloadSize );
    writeSequence( stream, objSize( objSize( essCertIDSize ) ) );
    writeSequence( stream, objSize( essCertIDSize ) );
    writeSequence( stream, essCertIDSize );
    return( writeOctetString( stream, certHash, msgData.length,
                              DEFAULT_TAG ) );
}
static int writeRequestBody( INOUT STREAM *stream,
							 const SESSION_INFO *sessionInfoPtr,
							 const CMP_PROTOCOL_INFO *protocolInfo )
	{
	const CRYPT_CERTFORMAT_TYPE certType = \
				( protocolInfo->operation == CTAG_PB_RR ) ? \
				CRYPT_ICERTFORMAT_DATA : CRYPT_CERTFORMAT_CERTIFICATE;
	MESSAGE_DATA msgData;
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );

	/* Find out how big the payload will be.  Since revocation requests are
	   unsigned entities we have to vary the attribute type that we're 
	   reading (via the certType specifier) based on whether we're 
	   submitting a signed or unsigned object in the request */
	setMessageData( &msgData, NULL, 0 );
	status = krnlSendMessage( sessionInfoPtr->iCertRequest,
							  IMESSAGE_CRT_EXPORT, &msgData, certType );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the request body */
	writeConstructed( stream, objSize( msgData.length ),
					  protocolInfo->operation );
	writeSequence( stream, msgData.length );
	return( exportCertToStream( stream, sessionInfoPtr->iCertRequest, 
								certType ) );
	}
Exemple #8
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 ) );
	}
Exemple #9
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 ) );
	}
Exemple #10
0
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 );
	}
Exemple #11
0
void slowPoll( void )
	{
	MESSAGE_DATA msgData;
	BYTE buffer[ SCC_RANDOM_SIZE * SCC_NO_CALLS ];
	int quality = 100, i;

	for( i = 0; i < SCC_NO_CALLS; i++ )
		sccGetRandomNumber( buffer + ( i * SCC_RANDOM_SIZE ), RANDOM_RANDOM );

	/* Add the data to the randomness pool */
	setResourceData( &msgData, buffer, SCC_RANDOM_SIZE * SCC_NO_CALLS );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S,
					 &msgData, CRYPT_IATTRIBUTE_ENTROPY );
	zeroise( buffer, SCC_RANDOM_SIZE * SCC_NO_CALLS );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
					 &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
	}
static BOOLEAN checkEmptyDnOK( INOUT CERT_INFO *subjectCertInfoPtr )
	{
	ATTRIBUTE_PTR *attributePtr;
	int value, complianceLevel, status;

	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );

	/* PKIX allows empty subject DNs if a subject altName is present, 
	   however creating certificates like this breaks every certificate-
	   using protocol supported by cryptlib so we only allow it at the 
	   highest compliance level */
	if( cryptStatusError( \
			krnlSendMessage( subjectCertInfoPtr->ownerHandle,
							 IMESSAGE_GETATTRIBUTE, &complianceLevel,
							 CRYPT_OPTION_CERT_COMPLIANCELEVEL ) ) || \
		complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_FULL )
		{
		/* We only allow this behaviour at the highest compliance level */
		return( FALSE );
		}
	   
	/* We also have to be very careful to ensure that the empty subject 
	   DN can't end up becoming an empty issuer DN, which can occur if it's 
	   a self-signed certificate */
	if( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED )
		{
		/* We can't have an empty issuer (== subject) DN */
		return( FALSE );
		}

	/* In addition if it's a CA certificate then the subject DN can't be 
	   empty, for obvious reasons */
	status = getAttributeFieldValue( subjectCertInfoPtr->attributes,
									 CRYPT_CERTINFO_CA, CRYPT_ATTRIBUTE_NONE,
									 &value );
	if( cryptStatusOK( status ) && value > 0 )
		{
		/* It's a CA certificate, the subject DN can't be empty */
		return( FALSE );
		}

	/* Finally, if there's no subject DN present then there has to be an 
	   altName present to take its place */
	attributePtr = findAttributeField( subjectCertInfoPtr->attributes,
									   CRYPT_CERTINFO_SUBJECTALTNAME,
									   CRYPT_ATTRIBUTE_NONE );
	if( attributePtr == NULL )
		{
		/* Either a subject DN or subject altName must be present */
		return( FALSE );
		}

	/* There's a subject altName present but no subject DN, mark the altName 
	   as critical */
	setAttributeProperty( attributePtr, ATTRIBUTE_PROPERTY_CRITICAL, 0 );

	return( TRUE );
	}
Exemple #13
0
static int writeKeyDerivationInfo( INOUT STREAM *stream,
								   IN_HANDLE const CRYPT_CONTEXT iCryptContext )
	{
	MESSAGE_DATA msgData;
	BYTE salt[ CRYPT_MAX_HASHSIZE + 8 ];
	int saltLength, keySetupIterations, prfAlgo = DUMMY_INIT;
	int derivationInfoSize, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES( isHandleRangeValid( iCryptContext ) );

	/* Get the key derivation information */
	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
							  &keySetupIterations,
							  CRYPT_CTXINFO_KEYING_ITERATIONS );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
								  &prfAlgo, CRYPT_CTXINFO_KEYING_ALGO );
	if( cryptStatusError( status ) )
		return( status );
	setMessageData( &msgData, salt, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_CTXINFO_KEYING_SALT );
	if( cryptStatusError( status ) )
		return( status );
	saltLength = msgData.length;
	derivationInfoSize = ( int ) sizeofObject( saltLength ) + \
						 sizeofShortInteger( keySetupIterations );
	if( prfAlgo != CRYPT_ALGO_HMAC_SHA1 )
		derivationInfoSize += sizeofAlgoID( prfAlgo );

	/* Write the PBKDF2 information */
	writeConstructed( stream, sizeofOID( OID_PBKDF2 ) +
					  ( int ) sizeofObject( derivationInfoSize ), CTAG_KK_DA );
	writeOID( stream, OID_PBKDF2 );
	writeSequence( stream, derivationInfoSize );
	writeOctetString( stream, salt, saltLength, DEFAULT_TAG );
	status = writeShortInteger( stream, keySetupIterations, DEFAULT_TAG );
	if( prfAlgo != CRYPT_ALGO_HMAC_SHA1 )
		status = writeAlgoID( stream, prfAlgo );
	zeroise( salt, CRYPT_MAX_HASHSIZE );
	return( status );
	}
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 );
	}
Exemple #15
0
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 ) );
	}
Exemple #16
0
void fastPoll( void )
	{
	MESSAGE_DATA msgData;
	BYTE buffer[ SCC_RANDOM_SIZE ];

	sccGetRandomNumber( buffer, RANDOM_RANDOM );
	setResourceData( &msgData, buffer, SCC_RANDOM_SIZE );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S,
					 &msgData, CRYPT_IATTRIBUTE_ENTROPY );
	zeroise( buffer, SCC_RANDOM_SIZE );
	}
Exemple #17
0
static int setItemFunction( INOUT DEVICE_INFO *deviceInfo, 
							IN_HANDLE const CRYPT_HANDLE iCryptHandle )
	{
	CRYPT_CERTIFICATE iCryptCert;
	PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;
	int value, cryptStatus;

	assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );

	REQUIRES( isHandleRangeValid( iCryptHandle ) );

	/* If the certificate isn't signed then we can't store it in this 
	   state */
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE,
								   &value, CRYPT_CERTINFO_IMMUTABLE );
	if( cryptStatusError( cryptStatus ) || !value )
		return( CRYPT_ERROR_NOTINITED );

	/* Lock the certificate for our exclusive use (in case it's a 
	   certificate chain we also select the first certificate in the 
	   chain), update the device with the certificate, and unlock it to 
	   allow others access */
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETDEPENDENT, 
								   &iCryptCert, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusOK( cryptStatus ) )
		cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
									   MESSAGE_VALUE_TRUE, 
									   CRYPT_IATTRIBUTE_LOCKED );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );
	cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, 
								   MESSAGE_VALUE_CURSORFIRST, 
								   CRYPT_CERTINFO_CURRENT_CERTIFICATE );
	if( cryptStatusOK( cryptStatus ) )
		cryptStatus = updateCertChain( pkcs11Info, iCryptCert );
	( void ) krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, 
							  MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );

	return( cryptStatus );
	}
Exemple #18
0
void fastPoll( void )
	{
	MESSAGE_DATA msgData;
	hreport_t heapReport;
	const clock_t timeStamp = clock();
	int quality = 5;

	/* There really isn't much available under MVS, it would be nice if we
	   could get output from DISPLAY but this requires a level of plumbing
	   that isn't easily managed from C */
	setMessageData( &msgData, &timeStamp, sizeof( clock_t ) );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S,
					 &msgData, CRYPT_IATTRIBUTE_ENTROPY );
	if( __heaprpt( &heapReport ) != -1 )
		{
		setMessageData( &msgData, &heapReport, sizeof( hreport_t ) );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S,
						 &msgData, CRYPT_IATTRIBUTE_ENTROPY );
		}
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
					 &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
	}
Exemple #19
0
int getKeyTypeTag( IN_HANDLE_OPT const CRYPT_CONTEXT cryptContext,
				   IN_ALGO_OPT const CRYPT_ALGO_TYPE cryptAlgo,
				   OUT int *tag )
	{
	static const MAP_TABLE tagMapTbl[] = {
		{ CRYPT_ALGO_RSA, 100 },
		{ CRYPT_ALGO_DH, CTAG_PK_DH },
		{ CRYPT_ALGO_ELGAMAL, CTAG_PK_DH },
		{ CRYPT_ALGO_DSA, CTAG_PK_DSA },
		{ CRYPT_ALGO_ECDSA, CTAG_PK_ECC },
		{ CRYPT_ERROR, CRYPT_ERROR }, { CRYPT_ERROR, CRYPT_ERROR }
		};
	int keyCryptAlgo, value, status;

	REQUIRES( ( isHandleRangeValid( cryptContext ) && \
				cryptAlgo == CRYPT_ALGO_NONE ) || \
			  ( cryptContext == CRYPT_UNUSED && \
				isPkcAlgo( cryptAlgo ) ) );

	/* Clear return value */
	*tag = 0;

	/* If the caller hasn't already supplied the algorithm details, get them
	   from the context */
	if( cryptAlgo != CRYPT_ALGO_NONE )
		keyCryptAlgo = cryptAlgo;
	else
		{
		status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
								  &keyCryptAlgo, CRYPT_CTXINFO_ALGO );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Map the algorithm to the corresponding tag.  We have to be a bit 
	   careful with the tags because the out-of-band special-case value 
	   DEFAULT_TAG looks like an error value, so we supply a dummy value
	   of '100' for this tag and map it back to DEFAULT_TAG when we return
	   it to the caller */
	status = mapValue( keyCryptAlgo, &value, tagMapTbl, 
					   FAILSAFE_ARRAYSIZE( tagMapTbl, MAP_TABLE ) );
	ENSURES( cryptStatusOK( status ) );
	*tag = ( value == 100 ) ? DEFAULT_TAG : value;

	return( CRYPT_OK );
	}
Exemple #20
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 ) );
	}
Exemple #21
0
static int pgpReadDecryptMPI( INOUT STREAM *stream,
							  IN_HANDLE const CRYPT_CONTEXT iCryptContext,
							  IN_LENGTH_PKC const int minLength, 
							  IN_LENGTH_PKC const int maxLength )
	{
	void *mpiDataPtr = DUMMY_INIT_PTR;
	const long mpiDataStartPos = stell( stream ) + UINT16_SIZE;
	int mpiLength, dummy, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES( isHandleRangeValid( iCryptContext ) );
	REQUIRES( minLength >= bitsToBytes( 155 ) && \
			  minLength <= maxLength && \
			  maxLength <= CRYPT_MAX_PKCSIZE );

	/* Get the MPI length and decrypt the payload data.  We have to be 
	   careful how we handle this because readInteger16Ubits() returns the 
	   canonicalised form of the values (with leading zeroes truncated) so 
	   the returned length value doesn't necessarily represent the amount
	   of data that we need to decrypt:

		startPos	dataStart		 stell()
			|			|				|
			v			v <-- length -->v
		+---+-----------+---------------+
		|	|			|///////////////| Stream
		+---+-----------+---------------+ */
	status = readInteger16Ubits( stream, NULL, &dummy, minLength, 
								 maxLength );
	if( cryptStatusError( status ) )
		return( status );
	mpiLength = stell( stream ) - mpiDataStartPos;
	status = sMemGetDataBlockAbs( stream, mpiDataStartPos, &mpiDataPtr, 
								  mpiLength );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_DECRYPT,
								  mpiDataPtr, mpiLength );
	return( status );
	}
Exemple #22
0
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 );
	}
Exemple #23
0
BOOLEAN checkRequest( IN_HANDLE const CRYPT_CERTIFICATE iCertRequest,
					  IN_ENUM( CRYPT_CERTACTION ) \
						const CRYPT_CERTACTION_TYPE action )
	{
	MESSAGE_DATA msgData;
	int certType, value, status;

	REQUIRES_B( isHandleRangeValid( iCertRequest ) );
	REQUIRES_B( action == CRYPT_CERTACTION_CERT_CREATION || \
				action == CRYPT_CERTACTION_ISSUE_CERT || \
				action == CRYPT_CERTACTION_REVOKE_CERT || \
				action == CRYPT_CERTACTION_NONE );

	/* Make sure that the request type is consistent with the operation
	   being performed */
	status = krnlSendMessage( iCertRequest, IMESSAGE_GETATTRIBUTE,
							  &certType, CRYPT_CERTINFO_CERTTYPE );
	if( cryptStatusError( status ) )
		return( FALSE );
	switch( action )
		{
		case CRYPT_CERTACTION_CERT_CREATION:
		case CRYPT_CERTACTION_ISSUE_CERT:
			if( certType != CRYPT_CERTTYPE_CERTREQUEST && \
				certType != CRYPT_CERTTYPE_REQUEST_CERT )
				return( FALSE );
			break;

		case CRYPT_CERTACTION_REVOKE_CERT:
			if( certType != CRYPT_CERTTYPE_REQUEST_REVOCATION )
				return( FALSE );
			break;
Exemple #24
0
#endif /* CONFIG_SUITEB_TESTS */

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( preferredCurveIdPtr, \
						sizeof( CRYPT_ECCCURVE_TYPE ) ) );

	REQUIRES( extLength >= 0 && extLength < MAX_INTLENGTH_SHORT );

	/* Clear return values */
	*preferredCurveIdPtr = CRYPT_ECCCURVE_NONE;
	*extErrorInfoSet = FALSE;

	/* Get the size of the server's signing key to bound the curve size */
	status = krnlSendMessage( sessionInfoPtr->privateKey,
							  IMESSAGE_GETATTRIBUTE, &keySize,
							  CRYPT_CTXINFO_KEYSIZE );
	if( cryptStatusError( status ) )
		return( status );

	/* Read and check the ECC curve list header */
	status = listLen = readUint16( stream );
	if( cryptStatusError( status ) )
		return( status );
	if( listLen != extLength - UINT16_SIZE || \
		listLen < UINT16_SIZE || listLen > 256 || \
		( listLen % UINT16_SIZE ) != 0 )
		return( CRYPT_ERROR_BADDATA );

	/* Read the list of curve IDs, recording the most preferred one */
	for( i = 0; i < listLen / UINT16_SIZE; i++ )
Exemple #25
0
static CAPABILITY_INFO *getCapability( const DEVICE_INFO *deviceInfo,
									   const PKCS11_MECHANISM_INFO *mechanismInfoPtr,
									   const int maxMechanisms )
	{
	VARIABLE_CAPABILITY_INFO *capabilityInfo;
	CK_MECHANISM_INFO pMechanism;
	CK_RV status;
	const CRYPT_ALGO_TYPE cryptAlgo = mechanismInfoPtr->cryptAlgo;
	const BOOLEAN isPKC = isPkcAlgo( cryptAlgo ) ? TRUE : FALSE;
	const CK_FLAGS keyGenFlag = isPKC ? CKF_GENERATE_KEY_PAIR : CKF_GENERATE;
	PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;
	int hardwareOnly, i, iterationCount;

	assert( isReadPtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
	assert( isReadPtr( mechanismInfoPtr, \
					   maxMechanisms * sizeof( PKCS11_MECHANISM_INFO ) ) );

	/* Set up canary values for the mechanism information in case the driver
	   blindly reports success for every mechanism that we ask for */
	memset( &pMechanism, 0, sizeof( CK_MECHANISM_INFO ) );
	pMechanism.ulMinKeySize = 0xA5A5;
	pMechanism.ulMaxKeySize = 0x5A5A;

	/* Get the information for this mechanism.  Since many PKCS #11 drivers
	   implement some of their capabilities using God knows what sort of 
	   software implementation, we provide the option to skip emulated 
	   mechanisms if required */
	status = C_GetMechanismInfo( pkcs11Info->slotID, 
								 mechanismInfoPtr->mechanism,
								 &pMechanism );
	if( status != CKR_OK )
		return( NULL );
	if( pMechanism.ulMinKeySize == 0xA5A5 && \
		pMechanism.ulMaxKeySize == 0x5A5A )
		{
		/* The driver reported that this mechanism is available but didn't
		   update the mechanism information, it's lying */
		DEBUG_DIAG(( "Driver reports that mechanism %X is available even "
					 "though it isn't", mechanismInfoPtr->mechanism ));
		assert( DEBUG_WARN );
		return( NULL );
		}
	status = krnlSendMessage( deviceInfo->ownerHandle, IMESSAGE_GETATTRIBUTE, 
							  &hardwareOnly, 
							  CRYPT_OPTION_DEVICE_PKCS11_HARDWAREONLY );
	if( cryptStatusOK( status ) && hardwareOnly && \
		!( pMechanism.flags & CKF_HW ) )
		{
		DEBUG_DIAG(( "Skipping mechanism %X, which is only available in "
					 "software emulation", mechanismInfoPtr->mechanism ));
		return( NULL );
		}
	if( mechanismInfoPtr->requiredFlags != CKF_NONE )
		{
		/* Make sure that the driver flags indicate support for the specific 
		   functionality that we require */
		if( ( mechanismInfoPtr->requiredFlags & \
			  pMechanism.flags ) != mechanismInfoPtr->requiredFlags )
			{
			DEBUG_DIAG(( "Driver reports that mechanism %X only has "
						 "capabilities %lX when we require %lX", 
						 mechanismInfoPtr->mechanism, 
						 mechanismInfoPtr->requiredFlags & pMechanism.flags,
						 mechanismInfoPtr->requiredFlags ));
//////////////////////////////////
// Kludge to allow it to be used
//////////////////////////////////
//			assert( DEBUG_WARN );
//			return( NULL );
			}
		}

	/* Copy across the template for this capability */
	if( ( capabilityInfo = clAlloc( "getCapability", \
									sizeof( CAPABILITY_INFO ) ) ) == NULL )
		return( NULL );
	for( i = 0; capabilityTemplates[ i ].cryptAlgo != cryptAlgo && \
				capabilityTemplates[ i ].cryptAlgo != CRYPT_ERROR && \
				i < FAILSAFE_ARRAYSIZE( capabilityTemplates, CAPABILITY_INFO ); 
		 i++ );
	ENSURES_N( i < FAILSAFE_ARRAYSIZE( capabilityTemplates, CAPABILITY_INFO ) );
	ENSURES_N( capabilityTemplates[ i ].cryptAlgo != CRYPT_ERROR );
	memcpy( capabilityInfo, &capabilityTemplates[ i ],
			sizeof( CAPABILITY_INFO ) );

	/* Set up the keysize information if there's anything useful available */
	if( keysizeValid( cryptAlgo ) )
		{
		int minKeySize = ( int ) pMechanism.ulMinKeySize;
		int maxKeySize = ( int ) pMechanism.ulMaxKeySize;

		/* Adjust the key size to bytes and make sure that all values are 
		   consistent.  Some implementations report silly bounds (e.g. 1-bit 
		   RSA, "You naughty minKey" or alternatively 4Gbit RSA) so we 
		   adjust them to a sane value if necessary.  We also limit the 
		   maximum key size to match the cryptlib native maximum key size, 
		   both for consistency and because cryptlib performs buffer 
		   allocation based on the maximum native buffer size */
		if( pMechanism.ulMinKeySize < 0 || \
			pMechanism.ulMinKeySize >= 10000L )
			{
			DEBUG_DIAG(( "Driver reports invalid minimum key size %lu for "
						 "%s algorithm", pMechanism.ulMinKeySize,
						 capabilityInfo->algoName ));
			assert( DEBUG_WARN );
			minKeySize = 0;
			}
		if( pMechanism.ulMaxKeySize < 0 || \
			pMechanism.ulMaxKeySize >= 100000L )
			{
			DEBUG_DIAG(( "Driver reports invalid maximum key size %lu for "
						 "%s algorithm", pMechanism.ulMaxKeySize,
						 capabilityInfo->algoName ));
			assert( DEBUG_WARN );
			maxKeySize = 0;
			}
		if( !keysizeInBytes( cryptAlgo ) )
			{
			minKeySize = bitsToBytes( minKeySize );
			maxKeySize = bitsToBytes( maxKeySize );
			}
		if( minKeySize > capabilityInfo->minKeySize )
			capabilityInfo->minKeySize = minKeySize;
		if( capabilityInfo->keySize < capabilityInfo->minKeySize )
			capabilityInfo->keySize = capabilityInfo->minKeySize;
		capabilityInfo->maxKeySize = min( maxKeySize, 
										  capabilityInfo->maxKeySize );
		if( capabilityInfo->maxKeySize < capabilityInfo->minKeySize )
			{
			/* Serious braindamage in the driver, we'll just have to make
			   a sensible guess */
			DEBUG_DIAG(( "Driver reports maximum key size %d < minimum key "
						 "size %d for %s algorithm", 
						 capabilityInfo->maxKeySize, 
						 capabilityInfo->minKeySize, 
						 capabilityInfo->algoName ));
			assert( DEBUG_WARN );
			if( isPKC )
				{
				capabilityInfo->maxKeySize = \
					max( capabilityInfo->minKeySize, bitsToBytes( 2048 ) );
				}
			else
				capabilityInfo->maxKeySize = 16;
			}
		if( capabilityInfo->keySize > capabilityInfo->maxKeySize )
			capabilityInfo->keySize = capabilityInfo->maxKeySize;
		capabilityInfo->endFunction = genericEndFunction;
		}

	/* Set up the device-specific handlers */
	capabilityInfo->selfTestFunction = selfTestFunction;
	capabilityInfo->getInfoFunction = getDefaultInfo;
	if( !isPKC )
		capabilityInfo->initParamsFunction = initGenericParams;
	capabilityInfo->endFunction = mechanismInfoPtr->endFunction;
	capabilityInfo->initKeyFunction = mechanismInfoPtr->initKeyFunction;
	if( pMechanism.flags & keyGenFlag )
		capabilityInfo->generateKeyFunction = \
									mechanismInfoPtr->generateKeyFunction;
	if( pMechanism.flags & CKF_SIGN )
		{
		/* cryptlib treats hashing as an encrypt/decrypt operation while 
		   PKCS #11 treats it as a sign/verify operation, so we have to
		   juggle the function pointers based on the underlying algorithm
		   type */
		if( isPKC )
			capabilityInfo->signFunction = mechanismInfoPtr->signFunction;
		else
			capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction;
		}
	if( pMechanism.flags & CKF_VERIFY )
		{
		/* See comment above */
		if( isPKC )
			capabilityInfo->sigCheckFunction = mechanismInfoPtr->sigCheckFunction;
		else
			capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction;
		}
	if( pMechanism.flags & CKF_ENCRYPT )
		{
		/* Not all devices implement all modes, so we have to be careful to 
		   set up the pointer for the exact mode that's supported */
		switch( mechanismInfoPtr->cryptMode )
			{
			case CRYPT_MODE_CBC:
				capabilityInfo->encryptCBCFunction = mechanismInfoPtr->encryptFunction;
				break;

			case CRYPT_MODE_CFB:
				capabilityInfo->encryptCFBFunction = mechanismInfoPtr->encryptFunction;
				break;

			case CRYPT_MODE_GCM:
				capabilityInfo->encryptGCMFunction = mechanismInfoPtr->encryptFunction;
				break;

			default:	/* ECB or a PKC */
				capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction;
				break;
			}
		}
	if( pMechanism.flags & CKF_DECRYPT )
		{
		/* Not all devices implement all modes, so we have to be careful to 
		   set up the pointer for the exact mode that's supported */
		switch( mechanismInfoPtr->cryptMode )
			{
			case CRYPT_MODE_CBC:
				capabilityInfo->decryptCBCFunction = mechanismInfoPtr->decryptFunction;
				break;

			case CRYPT_MODE_CFB:
				capabilityInfo->decryptCFBFunction = mechanismInfoPtr->decryptFunction;
				break;

			case CRYPT_MODE_GCM:
				capabilityInfo->decryptGCMFunction = mechanismInfoPtr->decryptFunction;
				break;

			default:	/* ECB or a PKC */
				capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction;
				break;
			}
		}
	if( cryptAlgo == CRYPT_ALGO_DH && pMechanism.flags & CKF_DERIVE )
		{
		/* DH is a special-case that doesn't really have an encrypt function 
		   and where "decryption" is actually a derivation */
		capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction;
		capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction;
		}

	/* Keygen capabilities are generally present as separate mechanisms,
	   sometimes CKF_GENERATE/CKF_GENERATE_KEY_PAIR is set for the main 
	   mechanism and sometimes it's set for the separate one so if it isn't 
	   present in the main one we check the alternative one */
	if( !( pMechanism.flags & keyGenFlag ) && \
		( mechanismInfoPtr->keygenMechanism != CKM_NONE ) )
		{
		status = C_GetMechanismInfo( pkcs11Info->slotID, 
									 mechanismInfoPtr->keygenMechanism,
									 &pMechanism );
		if( status == CKR_OK && ( pMechanism.flags & keyGenFlag ) && \
			( !hardwareOnly || ( pMechanism.flags & CKF_HW ) ) )
			{
			/* Some tinkertoy tokens don't implement key generation in 
			   hardware but instead do it on the host PC (!!!) and load the
			   key into the token afterwards, so we have to perform another 
			   check here to make sure that they're doing things right */
			capabilityInfo->generateKeyFunction = \
									mechanismInfoPtr->generateKeyFunction;
			}
		}

	/* Record mechanism-specific parameters if required */
	if( isConvAlgo( cryptAlgo ) || isMacAlgo( cryptAlgo ) )
		{
		capabilityInfo->paramKeyType = mechanismInfoPtr->keyType;
		capabilityInfo->paramKeyGen = mechanismInfoPtr->keygenMechanism;
		capabilityInfo->paramDefaultMech = mechanismInfoPtr->defaultMechanism;
		}

	/* Some drivers report bizarre combinations of capabilities like (for 
	   RSA) sign, verify, and decrypt but not encrypt, which will fail later 
	   sanity checks.  If we run into one of these we force the capabilities 
	   to be consistent by disabling any for which only partial capabilities
	   are supported */
	if( isPkcAlgo( cryptAlgo ) )
		{
		if( capabilityInfo->decryptFunction != NULL && \
			capabilityInfo->encryptFunction == NULL )
			{
			DEBUG_DIAG(( "Driver reports decryption but not encryption "
						 "capability for %s algorithm, disabling "
						 "encryption", capabilityInfo->algoName ));
			capabilityInfo->decryptFunction = NULL;
			}
		if( capabilityInfo->signFunction != NULL && \
			capabilityInfo->sigCheckFunction == NULL )
			{
			DEBUG_DIAG(( "Driver reports signature-generation but not "
						 "signature-verification capability for %s "
						 "algorithm, disabling signing", 
						 capabilityInfo->algoName ));
//////////////////////////////////
// Kludge to allow it to be used
//////////////////////////////////
if( cryptAlgo == CRYPT_ALGO_ECDSA )
capabilityInfo->sigCheckFunction = capabilityInfo->signFunction;
else
			capabilityInfo->signFunction = NULL;
			}

		/* If we've now disabled all capabilities, we can't use this 
		   algorithm */
		if( capabilityInfo->decryptFunction == NULL && \
			capabilityInfo->signFunction == NULL )
			{
			DEBUG_DIAG(( "Use of algorithm %s disabled since no consistent "
						 "set of capabilities is available", 
						 capabilityInfo->algoName ));
			clFree( "getCapability", capabilityInfo );
			assert( DEBUG_WARN );
			return( NULL );
			}
		}

	/* If it's not a conventional encryption algo, we're done */
	if( !isConvAlgo( cryptAlgo ) )
		return( ( CAPABILITY_INFO * ) capabilityInfo );

	/* PKCS #11 handles encryption modes by defining a separate mechanism for
	   each one.  In order to enumerate all the modes available for a 
	   particular algorithm we check for each mechanism in turn and set up 
	   the appropriate function pointers if it's available */
	for( mechanismInfoPtr++, iterationCount = 0; 
		 mechanismInfoPtr->cryptAlgo == cryptAlgo && \
			iterationCount < maxMechanisms; 
		 mechanismInfoPtr++, iterationCount++ )
		{
		/* There's a different form of the existing mechanism available,
		   check whether the driver implements it */
		status = C_GetMechanismInfo( pkcs11Info->slotID, 
									 mechanismInfoPtr->mechanism,
									 &pMechanism );
		if( status != CKR_OK )
			continue;

		/* Set up the pointer for the appropriate encryption mode */
		switch( mechanismInfoPtr->cryptMode )
			{
			case CRYPT_MODE_CBC:
				if( pMechanism.flags & CKF_ENCRYPT )
					capabilityInfo->encryptCBCFunction = \
										mechanismInfoPtr->encryptFunction;
				if( pMechanism.flags & CKF_DECRYPT )
					capabilityInfo->decryptCBCFunction = \
										mechanismInfoPtr->decryptFunction;
				break;
			case CRYPT_MODE_CFB:
				if( pMechanism.flags & CKF_ENCRYPT )
					capabilityInfo->encryptCFBFunction = \
										mechanismInfoPtr->encryptFunction;
				if( pMechanism.flags & CKF_DECRYPT )
					capabilityInfo->decryptCFBFunction = \
										mechanismInfoPtr->decryptFunction;
				break;
			case CRYPT_MODE_GCM:
				if( pMechanism.flags & CKF_ENCRYPT )
					capabilityInfo->encryptGCMFunction = \
										mechanismInfoPtr->encryptFunction;
				if( pMechanism.flags & CKF_DECRYPT )
					capabilityInfo->decryptGCMFunction = \
										mechanismInfoPtr->decryptFunction;
				break;

			default:
				retIntError_Null();
			}
		}
	ENSURES_N( iterationCount < maxMechanisms );

	return( ( CAPABILITY_INFO * ) capabilityInfo );
	}
Exemple #26
0
CHECK_RETVAL \
int deviceInitPKCS11( void )
	{
	int tblIndex = 0, optionIndex, status;

	/* If we've previously tried to initialise the drivers, don't try it 
	   again */
	if( pkcs11Initialised )
		return( CRYPT_OK );
	memset( pkcs11InfoTbl, 0, sizeof( pkcs11InfoTbl ) );

	/* Try and link in each driver specified in the config options.  Since
	   this is a general systemwide config option, we always query the built-
	   in default user object */
	for( optionIndex = 0; optionIndex < MAX_PKCS11_DRIVERS; optionIndex++ )
		{
		MESSAGE_DATA msgData;
		char deviceDriverName[ MAX_PATH_LENGTH + 1 + 8 ];

		setMessageData( &msgData, deviceDriverName, MAX_PATH_LENGTH );
		status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, 
						IMESSAGE_GETATTRIBUTE_S, &msgData, 
						optionIndex + CRYPT_OPTION_DEVICE_PKCS11_DVR01 );
		if( cryptStatusError( status ) )
			continue;
		deviceDriverName[ msgData.length ] = '\0';
		status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ], 
								   deviceDriverName );
		if( cryptStatusOK( status ) )
			{
			tblIndex++;
			pkcs11Initialised = TRUE;
			}
		}

	/* If it's a Unix system and there were no drivers explicitly specified,
	   try with the default driver name "libpkcs11.so".  Unlike Windows,
	   where there are large numbers of PKCS #11 vendors and we have to use
	   vendor-specific names, under Unix there are very few vendors and 
	   there's usually only one device/driver in use which inevitably 
	   co-opts /usr/lib for its own use, so we can always try for a standard
	   name and location.  As a backup measure we also try for the nCipher 
	   PKCS #11 driver, which is by far the most commonly used one on Unix 
	   systems (this may sometimes be found as /usr/lib/libcknfast.so).

	   An unfortunate side-effect of this handling is that if there's more
	   than one PKCS #11 driver present and the user forgets to explicitly
	   specify it then this may load the wrong one, however the chances of
	   there being multiple drivers present on a Unix system is close to 
	   zero so it's probably better to take the more user-friendly option
	   of trying to load a default driver */
#ifdef __UNIX__
	if( !pkcs11Initialised )
		{
		status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ], 
								   "libpkcs11.so" );
		if( cryptStatusOK( status ) )
			pkcs11Initialised = TRUE;
		}
	if( !pkcs11Initialised )
		{
		status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ], 
								   "/opt/nfast/toolkits/pkcs11/libcknfast.so" );
		if( cryptStatusOK( status ) )
			pkcs11Initialised = TRUE;
		}
#endif /* __UNIX__ */
	
	return( pkcs11Initialised ? CRYPT_OK : CRYPT_ERROR );
	}
Exemple #27
0
int deleteCertComponent( INOUT CERT_INFO *certInfoPtr,
						 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType )
	{
	int status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );

	REQUIRES( isAttribute( certInfoType ) || \
			  isInternalAttribute( certInfoType ) );

	/* If it's a GeneralName or DN component, delete it.  These are 
	   special-case attribute values so they have to come before the 
	   general attribute-handling code */
	if( isGeneralNameSelectionComponent( certInfoType ) )
		{
		/* Check whether this GeneralName is present */
		status = selectGeneralName( certInfoPtr, certInfoType,
									MUST_BE_PRESENT );
		if( cryptStatusError( status ) )
			return( status );

		/* Delete each field in the GeneralName */
		if( deleteCompositeAttributeField( &certInfoPtr->attributes,
					&certInfoPtr->attributeCursor, certInfoPtr->attributeCursor,
					certInfoPtr->currentSelection.dnPtr ) == OK_SPECIAL )
			{
			/* We've deleted the attribute containing the currently selected 
			   DN, deselect it */
			certInfoPtr->currentSelection.dnPtr = NULL;
			}

		return( CRYPT_OK );
		}
	if( isGeneralNameComponent( certInfoType ) )
		{
		SELECTION_STATE selectionState;
		ATTRIBUTE_PTR *attributePtr = DUMMY_INIT_PTR;

		/* Find the requested GeneralName component.  Since 
		   selectGeneralNameComponent() changes the current selection within 
		   the GeneralName, we save the selection state around the call */
		saveSelectionState( selectionState, certInfoPtr );
		status = selectGeneralNameComponent( certInfoPtr, certInfoType );
		if( cryptStatusOK( status ) )
			attributePtr = certInfoPtr->attributeCursor;
		restoreSelectionState( selectionState, certInfoPtr );
		if( cryptStatusError( status ))
			return( status );
		ENSURES( attributePtr != NULL );

		/* Delete the field within the GeneralName */
		if( deleteAttributeField( &certInfoPtr->attributes,
						&certInfoPtr->attributeCursor, attributePtr,
						certInfoPtr->currentSelection.dnPtr ) == OK_SPECIAL )
			{
			/* We've deleted the attribute containing the currently selected
			   DN, deselect it */
			certInfoPtr->currentSelection.dnPtr = NULL;
			}
		return( CRYPT_OK );
		}
	if( isDNComponent( certInfoType ) )
		{
		status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
						   MUST_BE_PRESENT );
		if( cryptStatusOK( status ) )
			status = deleteDNComponent( certInfoPtr->currentSelection.dnPtr,
										certInfoType, NULL, 0 );
		return( status );
		}

	/* If it's standard certificate or CMS attribute, delete it */
	if( ( certInfoType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
		  certInfoType <= CRYPT_CERTINFO_LAST_EXTENSION ) || \
		( certInfoType >= CRYPT_CERTINFO_FIRST_CMS && \
		  certInfoType <= CRYPT_CERTINFO_LAST_CMS ) )
		return( deleteCertAttribute( certInfoPtr, certInfoType ) );

	/* If it's anything else, handle it specially */
	switch( certInfoType )
		{
		case CRYPT_CERTINFO_SELFSIGNED:
			if( !( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->flags &= ~CERT_FLAG_SELFSIGNED;
			return( CRYPT_OK );

		case CRYPT_CERTINFO_CURRENT_CERTIFICATE:
		case CRYPT_ATTRIBUTE_CURRENT_GROUP:
		case CRYPT_ATTRIBUTE_CURRENT:
		case CRYPT_ATTRIBUTE_CURRENT_INSTANCE:
			if( certInfoPtr->attributeCursor == NULL )
				return( CRYPT_ERROR_NOTFOUND );
			if( certInfoType == CRYPT_ATTRIBUTE_CURRENT_GROUP )
				{
				status = deleteAttribute( &certInfoPtr->attributes,
									&certInfoPtr->attributeCursor,
									certInfoPtr->attributeCursor,
									certInfoPtr->currentSelection.dnPtr );
				}
			else
				{
				/* The current component and field are essentially the
				   same thing since a component is one of a set of
				   entries in a multivalued field, thus they're handled
				   identically */
				status = deleteAttributeField( &certInfoPtr->attributes,
									&certInfoPtr->attributeCursor,
									certInfoPtr->attributeCursor,
									certInfoPtr->currentSelection.dnPtr );
				}
			if( status == OK_SPECIAL )
				{
				/* We've deleted the attribute containing the currently 
				   selected DN, deselect it */
				certInfoPtr->currentSelection.dnPtr = NULL;
				}
			return( CRYPT_OK );

		case CRYPT_CERTINFO_TRUSTED_USAGE:
			if( certInfoPtr->cCertCert->trustedUsage == CRYPT_ERROR )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->cCertCert->trustedUsage = CRYPT_ERROR;
			return( CRYPT_OK );

		case CRYPT_CERTINFO_TRUSTED_IMPLICIT:
			return( krnlSendMessage( certInfoPtr->ownerHandle,
									 IMESSAGE_USER_TRUSTMGMT,
									 &certInfoPtr->objectHandle,
									 MESSAGE_TRUSTMGMT_DELETE ) );

		case CRYPT_CERTINFO_VALIDFROM:
		case CRYPT_CERTINFO_THISUPDATE:
			if( certInfoPtr->startTime <= 0 )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->startTime = 0;
			return( CRYPT_OK );

		case CRYPT_CERTINFO_VALIDTO:
		case CRYPT_CERTINFO_NEXTUPDATE:
			if( certInfoPtr->endTime <= 0 )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->endTime = 0;
			return( CRYPT_OK );

		case CRYPT_CERTINFO_SUBJECTNAME:
			if( certInfoPtr->currentSelection.dnPtr == &certInfoPtr->subjectName )
				{
				/* This is the currently selected DN, deselect it before 
				   deleting it */
				certInfoPtr->currentSelection.dnPtr = NULL;
				}
			deleteDN( &certInfoPtr->subjectName );
			return( CRYPT_OK );

#ifdef USE_CERTREV
		case CRYPT_CERTINFO_REVOCATIONDATE:
			{
			time_t *revocationTimePtr = ( time_t * ) \
							getRevocationTimePtr( certInfoPtr );

			if( revocationTimePtr == NULL )
				return( CRYPT_ERROR_NOTFOUND );
			*revocationTimePtr = 0;
			return( CRYPT_OK );
			}
#endif /* USE_CERTREV */

#ifdef USE_PKIUSER
		case CRYPT_CERTINFO_PKIUSER_RA:
			if( !certInfoPtr->cCertUser->isRA )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->cCertUser->isRA = FALSE;
			return( CRYPT_OK );
#endif /* USE_PKIUSER */
		}

	retIntError();
	}
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 processAdditionalScepRequest( INOUT SESSION_INFO *sessionInfoPtr,
										 const HTTP_URI_INFO *httpReqInfo )
	{
	HTTP_URI_INFO rewrittenHttpReqInfo;
	MESSAGE_DATA msgData;
	int operationType, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( httpReqInfo, sizeof( HTTP_URI_INFO ) ) );

	/* If the client has fed us an HTTP GET request, find out what they  
	   want.  SCEP's handling of HTTP requests is a bit different from the 
	   "attribute '=' value" lookup that's normally used for HTTP data 
	   retrieval.  Instead, it uses the format 
	   "'operation =' value '&' extraData", with the search key buried in 
	   the 'extraData' value.  In addition the content of the 'extraData' 
	   value isn't defined outside of "any string which is understood by the 
	   CA".  However since 'value' defines what we want, we can determine 
	   what to return based on this and ignore the 'extraData' portion.

	   In order to fix up the query information into a format that works 
	   with standard HTTP queries, we rewrite the query data from the 
	   "'operation =' value '&' extraData" form into "attribute '=' value" 
	   before we process the query */
	memset( &rewrittenHttpReqInfo, 0, sizeof( HTTP_URI_INFO ) );
	memcpy( rewrittenHttpReqInfo.attribute, httpReqInfo->value, 
			httpReqInfo->valueLen );
	rewrittenHttpReqInfo.attributeLen = httpReqInfo->valueLen;
	if( httpReqInfo->extraDataLen > 0 )
		{
		memcpy( rewrittenHttpReqInfo.value, httpReqInfo->extraData, 
				httpReqInfo->extraDataLen );
		rewrittenHttpReqInfo.valueLen = httpReqInfo->extraDataLen;
		}
	status = processCertQuery( sessionInfoPtr, &rewrittenHttpReqInfo,
							   certstoreReadInfo, 
							   FAILSAFE_ARRAYSIZE( certstoreReadInfo, \
												   CERTSTORE_READ_INFO ),
							   &operationType, NULL, 0, NULL );
	if( cryptStatusError( status ) )
		{
		sendCertErrorResponse( sessionInfoPtr, status );
		return( status );
		}
	ENSURES( operationType == SCEP_OPERATION_GETCACAPS || \
			 operationType == SCEP_OPERATION_GETCACERT || \
			 operationType == SCEP_OPERATION_GETCACERTCHAIN );

	/* If it's a CA capabilities query, return the information as raw text
	   over HTTP */
	if( operationType == SCEP_OPERATION_GETCACAPS )
		{
		STREAM stream;

		sMemOpen( &stream, sessionInfoPtr->receiveBuffer, 1024 );
		status = swrite( &stream, "POSTPKIOperation\n", 17 );
		if( algoAvailable( CRYPT_ALGO_SHA1 ) )
			status = swrite( &stream, "SHA-1\n", 6 );
		if( algoAvailable( CRYPT_ALGO_SHA2 ) )
			status = swrite( &stream, "SHA-256\n", 8 );
		if( algoAvailable( CRYPT_ALGO_SHAng ) )
			status = swrite( &stream, "SHAng\n", 6 );
		if( algoAvailable( CRYPT_ALGO_3DES ) )
			status = swrite( &stream, "DES3\n", 5 );
		if( algoAvailable( CRYPT_ALGO_AES ) )
			status = swrite( &stream, "AES\n", 4 );
		if( cryptStatusOK( status ) )
			sessionInfoPtr->receiveBufEnd = stell( &stream );
		sMemDisconnect( &stream );
		ENSURES( cryptStatusOK( status ) );
		return( writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE,
								  SCEP_CONTENT_TYPE_LEN ) );
		}

	/* Export the CA certificate and send it to the client */
	setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
					sessionInfoPtr->receiveBufSize );
	status = krnlSendMessage( sessionInfoPtr->privateKey,
							  IMESSAGE_CRT_EXPORT, &msgData,
							  ( operationType == SCEP_OPERATION_GETCACERT ) ? \
								CRYPT_CERTFORMAT_CERTIFICATE : \
								CRYPT_CERTFORMAT_CERTCHAIN );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't export CA certificate%s for '%s' request", 
				  ( operationType == SCEP_OPERATION_GETCACERT ) ? \
					"" : " chain",
				  ( operationType == SCEP_OPERATION_GETCACERT ) ? \
					"GetCACert" : "GetCACertChain" ) );
		}
	sessionInfoPtr->receiveBufEnd = msgData.length;
	if( operationType == SCEP_OPERATION_GETCACERT )
		{
		return( writePkiDatagram( sessionInfoPtr, 
								  SCEP_CONTENT_TYPE_GETCACERT,
								  SCEP_CONTENT_TYPE_GETCACERT_LEN ) );
		}
	return( writePkiDatagram( sessionInfoPtr, 
							  SCEP_CONTENT_TYPE_GETCACERTCHAIN,
							  SCEP_CONTENT_TYPE_GETCACERTCHAIN_LEN ) );
	}