Пример #1
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 );
	}
Пример #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 );
	}
Пример #3
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 );
	}
Пример #4
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 ) );
}
Пример #5
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 );
	}
Пример #6
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 ) );
	}
Пример #7
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 ) );
	}
Пример #8
0
CHECK_RETVAL \
static int sizeofCertID( IN_HANDLE const CRYPT_CONTEXT iCryptCert )
{
    const int essCertIDSize = objSize( objSize( objSize( objSize( 20 ) ) ) );
    /* Infinitely-nested SHA-1 hash */

    REQUIRES( isHandleRangeValid( iCryptCert ) );

    return( objSize( sizeofOID( OID_ESS_CERTID ) + \
                     sizeofObject( essCertIDSize ) ) );
}
Пример #9
0
int dynCreate( OUT DYNBUF *dynBuf, 
			   IN_HANDLE const CRYPT_HANDLE cryptHandle,
			   IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeType )
	{
	assert( isWritePtr( dynBuf, sizeof( DYNBUF ) ) );

	REQUIRES( isHandleRangeValid( cryptHandle ) );
	REQUIRES( isAttribute( attributeType ) || \
			  isInternalAttribute( attributeType ) );

	return( getDynData( dynBuf, cryptHandle, IMESSAGE_GETATTRIBUTE_S,
						attributeType ) );
	}
Пример #10
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 );
	}
Пример #11
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 );
	}
Пример #12
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 ) );
	}
Пример #13
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 );
	}
Пример #14
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 );
	}
Пример #15
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 );
	}
Пример #16
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 );
	}
Пример #17
0
	BYTE *bufPtr = ( encryptedKey == NULL ) ? NULL : buffer;
	const int bufSize = ( encryptedKey == NULL ) ? 0 : CRYPT_MAX_KEYSIZE + 16;
	int keySize, ivSize, status;

	assert( ( encryptedKey == NULL && encryptedKeyMaxLength == 0 ) || \
			isWritePtr( encryptedKey, encryptedKeyMaxLength ) );
	assert( isWritePtr( encryptedKeyLength, sizeof( int ) ) );

	REQUIRES( ( encryptedKey == NULL && encryptedKeyMaxLength == 0 ) || \
			  ( encryptedKey != NULL && \
				encryptedKeyMaxLength > MIN_CRYPT_OBJECTSIZE && \
				encryptedKeyMaxLength < MAX_INTLENGTH ) );
	REQUIRES( ( keyexType == KEYEX_PGP && \
				iSessionKeyContext == CRYPT_UNUSED ) || \
			  ( keyexType != KEYEX_PGP && \
				isHandleRangeValid( iSessionKeyContext ) ) );
	REQUIRES( isHandleRangeValid( iExportContext ) );
	REQUIRES( keyexType > KEYEX_NONE && keyexType < KEYEX_LAST );

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

	/* Make sure that the requested key exchange format is available */
	if( writeKeyexFunction == NULL )
		return( CRYPT_ERROR_NOTAVAIL );

#ifdef USE_PGP
	/* PGP doesn't actually wrap up a key but derives the session key
	   directly from the password.  Because of this there isn't any key
	   wrapping to be done so we just write the key derivation parameters
	   and exit */
Пример #18
0
static int updateCertChain( INOUT PKCS11_INFO *pkcs11Info, 
							IN_HANDLE const CRYPT_CERTIFICATE iCryptCert )
	{
	static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
	static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
	CK_ATTRIBUTE certTemplate[] = {
		{ CKA_CLASS, ( CK_VOID_PTR ) &certClass, sizeof( CK_OBJECT_CLASS ) },
		{ CKA_CERTIFICATE_TYPE, ( CK_VOID_PTR ) &certType, sizeof( CK_CERTIFICATE_TYPE ) },
		{ CKA_ISSUER, NULL_PTR, 0 },
		{ CKA_SERIAL_NUMBER, NULL_PTR, 0 },
		};
	BOOLEAN isLeafCert = TRUE, seenNonDuplicate = FALSE;
	int value, iterationCount, cryptStatus;

	assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );

	REQUIRES( isHandleRangeValid( iCryptCert ) );

	/* If we've been passed a standalone certificate, check whether it's 
	   implicitly trusted, which allows it to be added without requiring the 
	   presence of a corresponding public/private key in the device */
	cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE, &value, 
								   CRYPT_CERTINFO_CERTTYPE );
	if( cryptStatusError( cryptStatus ) )
		{
		return( ( cryptStatus == CRYPT_ARGERROR_OBJECT ) ? \
				CRYPT_ARGERROR_NUM1 : cryptStatus );
		}
	if( value == CRYPT_CERTTYPE_CERTIFICATE )
		{
		cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE,
									   &value, 
									   CRYPT_CERTINFO_TRUSTED_IMPLICIT );
		if( cryptStatusError( cryptStatus ) )
			return( CRYPT_ARGERROR_NUM1 );

		/* If the certificate is implicitly trusted we indicate that it's 
		   (effectively) a non-leaf certificate so that it can be added even 
		   if there's no corresponding key already in the device */
		if( value )
			isLeafCert = FALSE;
		}

	/* Add each certificate in the chain to the device */
	for( iterationCount = 0; iterationCount < FAILSAFE_ITERATIONS_MED; 
		 iterationCount++ )
		{
		CK_OBJECT_HANDLE hObject;
		DYNBUF iAndSDB;

		/* If the certificate is already present, don't do anything */
		cryptStatus = dynCreate( &iAndSDB, iCryptCert, 
								 CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
		if( cryptStatusError( cryptStatus ) )
			return( cryptStatus );
		cryptStatus = addIAndSToTemplate( &certTemplate[ 2 ], 
										  dynData( iAndSDB ), 
										  dynLength( iAndSDB ) );
		if( cryptStatusError( cryptStatus ) )
			{
			/* In theory we could simply skip any certificates for which we 
			   can't decode the iAndS, but in practice it's probably better 
			   to fail and warn the user than to continue with only some 
			   certificates added */
			dynDestroy( &iAndSDB );
			return( cryptStatus );
			}
		cryptStatus = findObject( pkcs11Info, &hObject, certTemplate, 4 );
		dynDestroy( &iAndSDB );
		if( cryptStatusError( cryptStatus ) )
			{
			/* The certificate isn't already present, write it */
			cryptStatus = updateCertificate( pkcs11Info, iCryptCert, 
											 isLeafCert );
			if( cryptStatusError( cryptStatus ) )
				return( cryptStatus );
			isLeafCert = FALSE;
			seenNonDuplicate = TRUE;
			}

		/* Try and move to the next certificate */
		cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, 
									   MESSAGE_VALUE_CURSORNEXT,
									   CRYPT_CERTINFO_CURRENT_CERTIFICATE );
		if( cryptStatusError( cryptStatus ) )
			break;
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
	
	return( seenNonDuplicate ? CRYPT_OK : CRYPT_ERROR_DUPLICATE );
	}
Пример #19
0
static int updateCertificate( INOUT PKCS11_INFO *pkcs11Info, 
							  IN_HANDLE const CRYPT_HANDLE iCryptHandle,
							  const BOOLEAN isLeafCert )
	{
	static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
	static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
	static const CK_BBOOL bTrue = TRUE;
	CK_DATE startDate, endDate;
	CK_ATTRIBUTE certTemplate[] = {
		{ CKA_CLASS, ( CK_VOID_PTR ) &certClass, sizeof( CK_OBJECT_CLASS ) },
		{ CKA_CERTIFICATE_TYPE, ( CK_VOID_PTR ) &certType, sizeof( CK_CERTIFICATE_TYPE ) },
		{ CKA_TOKEN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
		{ CKA_ID, NULL_PTR, 0 },
		{ CKA_SUBJECT, NULL_PTR, 0 },
		{ CKA_ISSUER, NULL_PTR, 0 },
		{ CKA_SERIAL_NUMBER, NULL_PTR, 0 },
		{ CKA_VALUE, NULL_PTR, 0 },
		/* Optional fields, filled in if required and the driver supports this */
		{ CKA_NONE, NULL_PTR, 0 },	/*  8 */
		{ CKA_NONE, NULL_PTR, 0 },	/*  9 */
		{ CKA_NONE, NULL_PTR, 0 },	/* 10 */
		{ CKA_NONE, NULL_PTR, 0 },	/* 11 */
		};
	CK_OBJECT_HANDLE hObject;
	CK_RV status;
	MESSAGE_DATA msgData;
	DYNBUF subjectDB, iAndSDB, certDB;
	BYTE keyID[ CRYPT_MAX_HASHSIZE + 8 ];
	BOOLEAN hasURL = FALSE;
	time_t theTime;
	char label[ CRYPT_MAX_TEXTSIZE + 8 ], uri[ MAX_URL_SIZE + 8 ];
	int templateCount = 8, cryptStatus;

	assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );

	REQUIRES( isHandleRangeValid( iCryptHandle ) );

	/* Get the keyID from the certificate */
	setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								   &msgData, CRYPT_IATTRIBUTE_KEYID );
	if( cryptStatusError( cryptStatus ) )
		return( CRYPT_ARGERROR_NUM1 );
	certTemplate[ 3 ].pValue = msgData.data;
	certTemplate[ 3 ].ulValueLen = msgData.length;

	/* If it's a leaf certificate, use the keyID to locate the corresponding 
	   public or private key object.  This is used as a check to ensure that 
	   the certificate corresponds to a key in the device.  In theory this 
	   would allow us to read the label from the key so that we can reuse it 
	   for the certificate, but there doesn't seem to be any good reason for 
	   this and it could lead to problems with multiple certificates with the 
	   same labels so we don't do it */
	if( isLeafCert )
		{
		static const CK_OBJECT_CLASS privkeyClass = CKO_PRIVATE_KEY;
		static const CK_OBJECT_CLASS pubkeyClass = CKO_PUBLIC_KEY;
		CK_ATTRIBUTE keyTemplate[] = {
			{ CKA_CLASS, ( CK_VOID_PTR ) &privkeyClass, sizeof( CK_OBJECT_CLASS ) },
			{ CKA_ID, NULL_PTR, 0 }
			};

		keyTemplate[ 1 ].pValue = certTemplate[ 3 ].pValue;
		keyTemplate[ 1 ].ulValueLen = certTemplate[ 3 ].ulValueLen;
		cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
		if( cryptStatusError( cryptStatus ) )
			{
			/* Couldn't find a private key with this ID, try for a public key */
			keyTemplate[ 0 ].pValue = ( CK_VOID_PTR ) &pubkeyClass;
			cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
			}
		if( cryptStatusError( cryptStatus ) )
			return( CRYPT_ARGERROR_NUM1 );
		}

	/* Get the validFrom and validTo dates.  These aren't currently used for
	   anything, but could be used in the future to handle superceded 
	   certificates in the same way that it's done for PKCS #15 keysets */
	setMessageData( &msgData, &theTime, sizeof( time_t ) );
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								   &msgData, CRYPT_CERTINFO_VALIDFROM );
	if( cryptStatusOK( cryptStatus ) )
		{
		convertDate( &startDate, theTime );
		setMessageData( &msgData, &theTime, sizeof( time_t ) );
		cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
									   &msgData, CRYPT_CERTINFO_VALIDTO );
		}
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );
	convertDate( &endDate, theTime );

	/* Get the subjectName and issuerAndSerialNumber from the certificate */
	cryptStatus = dynCreate( &subjectDB, iCryptHandle, 
							 CRYPT_IATTRIBUTE_SUBJECT );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );
	cryptStatus = dynCreate( &iAndSDB, iCryptHandle, 
							 CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
	if( cryptStatusError( cryptStatus ) )
		{
		dynDestroy( &subjectDB );
		return( cryptStatus );
		}
	certTemplate[ 4 ].pValue = dynData( subjectDB );
	certTemplate[ 4 ].ulValueLen = dynLength( subjectDB );
	cryptStatus = addIAndSToTemplate( &certTemplate[ 5 ], dynData( iAndSDB ), 
									  dynLength( iAndSDB ) );
	if( cryptStatusError( cryptStatus ) )
		{
		dynDestroy( &subjectDB );
		dynDestroy( &iAndSDB );
		return( cryptStatus );
		}

	/* Get the certificate data */
	cryptStatus = dynCreateCert( &certDB, iCryptHandle, 
								 CRYPT_CERTFORMAT_CERTIFICATE );
	if( cryptStatusError( cryptStatus ) )
		{
		dynDestroy( &subjectDB );
		dynDestroy( &iAndSDB );
		return( cryptStatus );
		}
	certTemplate[ 7 ].pValue = dynData( certDB );
	certTemplate[ 7 ].ulValueLen = dynLength( certDB );

	/* Get the certificate holder name (label) from the certificate if 
	  available */
	setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE  );
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								   &msgData, CRYPT_IATTRIBUTE_HOLDERNAME );
	if( cryptStatusOK( cryptStatus ) )
		{
		/* We've found a holder name, use it as the certificate object 
		   label */
		addTemplateValue( certTemplate[ templateCount ], 
						  CKA_LABEL, msgData.data, msgData.length );
		templateCount++;
		}

	/* Add the certificate dates.  These have to be located between the 
	   label and the URI so that we can selectively back out the attributes 
	   that don't work for this driver, see the comments further down for 
	   more details */
	addTemplateValue( certTemplate[ templateCount ], 
					  CKA_START_DATE, ( CK_VOID_PTR ) &startDate, sizeof( CK_DATE ) );
	templateCount++;
	addTemplateValue( certTemplate[ templateCount ], 
					  CKA_END_DATE, ( CK_VOID_PTR ) &endDate, sizeof( CK_DATE ) );
	templateCount++;

	/* Get the URI from the certificate if available */
	setMessageData( &msgData, uri, MAX_URL_SIZE );
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								   &msgData, CRYPT_IATTRIBUTE_HOLDERURI );
	if( cryptStatusOK( cryptStatus ) )
		{
		/* We've found a holder URI, use it as the certificate object URL */
		addTemplateValue( certTemplate[ templateCount ], 
						  CKA_URL, msgData.data, msgData.length );
		templateCount++;
		hasURL = TRUE;
		}

	/* Reset the status value, which may contain error values due to not 
	   finding various object attributes above */
	cryptStatus = CRYPT_OK;

	/* We've finally got everything available, try and update the device with
	   the certificate data.  In theory we should also set CKA_PRIVATE = FALSE
	   but the Dallas iButton driver doesn't allow this so we have to rely on
	   drivers doing the right thing with the default setting */
	status = C_CreateObject( pkcs11Info->hSession,
							 ( CK_ATTRIBUTE_PTR ) certTemplate, templateCount, 
							 &hObject );
	if( hasURL && ( status == CKR_TEMPLATE_INCONSISTENT || \
					status == CKR_ATTRIBUTE_TYPE_INVALID ) )
		{
		/* Support for the PKCS #11 v2.20 attribute CKA_URL is pretty hit-
		   and-miss, some drivers from ca.2000 support it but others from 
		   ca.2007 still don't so if we get a CKR_ATTRIBUTE_TYPE_INVALID 
		   return code we try again without the CKA_URL */
		templateCount--;
		status = C_CreateObject( pkcs11Info->hSession,
								 ( CK_ATTRIBUTE_PTR ) certTemplate, 
								 templateCount, &hObject );
		}
	if( status == CKR_TEMPLATE_INCONSISTENT || \
		status == CKR_ATTRIBUTE_TYPE_INVALID )
		{
		/* Even support for dates is hit-and-miss so if we're still getting
		   CKR_ATTRIBUTE_TYPE_INVALID we try again without the 
		   CKA_START_DATE/CKA_END_DATE */
		templateCount -= 2;
		status = C_CreateObject( pkcs11Info->hSession,
								 ( CK_ATTRIBUTE_PTR ) certTemplate, 
								 templateCount, &hObject );
		}
	if( status != CKR_OK )
		cryptStatus = pkcs11MapError( status, CRYPT_ERROR_FAILED );

	/* Clean up */
	dynDestroy( &subjectDB );
	dynDestroy( &iAndSDB );
	dynDestroy( &certDB );
	return( cryptStatus );
	}
Пример #20
0
	int status;

	assert( isReadPtr( inData, inDataLength ) );
	assert( isWritePtr( outData, outDataMaxLength ) );
	assert( isWritePtr( outDataLength, sizeof( int ) ) );

	REQUIRES( inDataLength > 16 && inDataLength < MAX_INTLENGTH );
	REQUIRES( outDataMaxLength > 16 && \
			  outDataMaxLength >= inDataLength + 512 && \
			  outDataMaxLength < MAX_INTLENGTH );
	REQUIRES( formatType == CRYPT_FORMAT_CRYPTLIB || \
			  formatType == CRYPT_FORMAT_CMS );
	REQUIRES( contentType >= CRYPT_CONTENT_NONE && \
			  contentType < CRYPT_CONTENT_LAST );
	REQUIRES( ( iPublicKey == CRYPT_UNUSED ) || \
			  isHandleRangeValid( iPublicKey ) );

	/* Clear return values.  Note that we can't clear the output buffer 
	   at this point since this function is frequently used for in-place 
	   processing, so we clear it after we've pushed the input data */
	*outDataLength = 0;

	/* Create an envelope to wrap the data, add the encryption key if
	   necessary, and pop the wrapped result */
	setMessageCreateObjectInfo( &createInfo, formatType );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
							  OBJECT_TYPE_ENVELOPE );
	if( cryptStatusError( status ) )
		{
		memset( outData, 0, min( 16, outDataMaxLength ) );
Пример #21
0
static int checkAddInfo( const PKCS15_INFO *pkcs15infoPtr,
						 IN_HANDLE const CRYPT_HANDLE iCryptHandle,
						 const BOOLEAN isCertChain, 
						 const BOOLEAN privkeyPresent,
						 const BOOLEAN certPresent,
						 const BOOLEAN pkcs15keyPresent,
						 const BOOLEAN pkcs15certPresent,
						 OUT BOOLEAN *isCertUpdate, 
						 INOUT ERROR_INFO *errorInfo )
	{
	MESSAGE_DATA msgData;
	BOOLEAN unneededCert, unneededKey;
	int status;

	assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
	assert( isWritePtr( isCertUpdate, sizeof( BOOLEAN ) ) );
	
	REQUIRES( isHandleRangeValid( iCryptHandle ) );
	REQUIRES( errorInfo != NULL );

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

	/* Check what we can update (if anything) */
	unneededKey = privkeyPresent & pkcs15keyPresent;
	unneededCert = certPresent & pkcs15certPresent;
	if( ( ( unneededCert && !privkeyPresent ) || \
		  ( unneededKey && unneededCert ) ) && \
		pkcs15infoPtr->validTo > MIN_TIME_VALUE )
		{
		time_t validTo;

		/* The certificate would be a duplicate, see if it's more recent 
		   than the existing one.  We only perform this check if there's a 
		   validTo time stored for the certificate since without this 
		   restriction any certificate without a stored time could be 
		   overwritten */
		setMessageData( &msgData, &validTo, sizeof( time_t ) );
		status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_CERTINFO_VALIDTO );
		if( cryptStatusOK( status ) && validTo > pkcs15infoPtr->validTo )
			{
			time_t validFrom;

			/* It's a newer certificate, don't treat it as a duplicate.  
			   This check is effectively impossible to perform automatically 
			   since there are an infinite number of variations that have to 
			   be taken into account, for example a certificate for the same 
			   key issued by a different CA, same CA but it's changed the 
			   bits it sets in the keyUsage (digitalSignature vs.
			   nonRepudiation), slightly different issuer DN (Thawte 
			   certificates with a date encoded in the DN), and so on and so 
			   on.  Because this really requires manual processing by a 
			   human we don't even try and sort it all out but just allow a 
			   certificate for a given key (checked by the ID match) to be 
			   replaced by a newer certificate for the same key.  This is 
			   restrictive enough to prevent most obviously-wrong 
			   replacements while being permissive enough to allow most 
			   probably-OK replacements */
			unneededCert = FALSE;
			*isCertUpdate = TRUE;

			/* There's one special-case situation in which odd things can 
			   happen when updating certificates and that's when adding a 
			   future-dated certificate, which would result in the 
			   certificate being replaced with one that can't be used yet.  
			   There's no clean way to handle this because in order to know 
			   what to do we'd have to be able to guess the intent of the 
			   user, however for anything but signature certificates it's 
			   likely that the hit-and-miss certificate checking performed 
			   by most software won't even notice a future-dated 
			   certificate, and for signature certificates the semantics of 
			   signing data now using a certificate that isn't valid yet are 
			   somewhat uncertain.  Since in most cases no-one will even 
			   notice the problem, we throw an exception in the debug build 
			   but don't do anything in release builds.  This is probably 
			   less annoying to users than having the code reject an 
			   otherwise-valid future-dated certificate.  If anyone ever
			   complains about this then we can ask the users at that time
			   what sort of behaviour they're prefer */
			setMessageData( &msgData, &validFrom, sizeof( time_t ) );
			status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
									  &msgData, CRYPT_CERTINFO_VALIDFROM );
			if( cryptStatusOK( status ) && \
				validFrom > getApproxTime() + 86400L )
				{
				assert( !"Attempt to replace certificate with future-dated certificate" );
				}
			}
		}

	/* Make sure that we can update at least one of the objects in the PKCS 
	   #15 personality */
	if( ( unneededKey && !certPresent ) ||		/* Key only, duplicate */
		( unneededCert && !privkeyPresent ) ||	/* Certificate only, duplicate */
		( unneededKey && unneededCert ) )		/* Key+certificate, duplicate */
		{
		/* If it's anything other than a certificate chain, we can't add 
		   anything */
		if( !isCertChain )
			{
			retExt( CRYPT_ERROR_DUPLICATE, 
					( CRYPT_ERROR_DUPLICATE, errorInfo, 
					  "No new data to add" ) );
			}

		/* Tell the caller that it's an opportunistic certificate-chain 
		   update */
		return( OK_SPECIAL );
		}

	return( CRYPT_OK );
	}
Пример #22
0
int checkServerCertValid( const CRYPT_CERTIFICATE iServerKey,
						  INOUT ERROR_INFO *errorInfo )
	{
	CRYPT_CERTIFICATE iServerCert;
	CRYPT_ERRTYPE_TYPE errorType DUMMY_INIT;
	CRYPT_ATTRIBUTE_TYPE errorLocus DUMMY_INIT;
	static const int complianceLevelStandard = CRYPT_COMPLIANCELEVEL_STANDARD;
	int complianceLevel, status;

	assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );

	REQUIRES( isHandleRangeValid( iServerKey ) );

	status = krnlSendMessage( iServerKey, IMESSAGE_GETATTRIBUTE, 
							  &complianceLevel, 
							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusError( status ) )
		{
		/* We can't do much more if we can't even get the initial compliance 
		   level */
		return( CRYPT_ERROR_INVALID );
		}

	/* Check whether the certificate is valid at a standard level of 
	   compliance, which catches expired certificates and other obvious
	   problems */
	krnlSendMessage( iServerKey, IMESSAGE_SETATTRIBUTE, 
					 ( MESSAGE_CAST ) &complianceLevelStandard, 
					 CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	status = krnlSendMessage( iServerKey, IMESSAGE_CHECK, NULL, 
							  MESSAGE_CHECK_CERT );
	krnlSendMessage( iServerKey, IMESSAGE_SETATTRIBUTE, 
					 ( MESSAGE_CAST ) &complianceLevel, 
					 CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusOK( status ) )
		return( CRYPT_OK );

	/* The certificate associated with the key isn't valid, get the 
	   certificate (since otherwise we'd be querying the key rather than the
	   certificate) and fetch the extended error information */
	status = krnlSendMessage( iServerKey, IMESSAGE_GETDEPENDENT, 
							  &iServerCert, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusOK( status ) )
		{
		int value;

		status = krnlSendMessage( iServerCert, IMESSAGE_GETATTRIBUTE, 
								  &value, CRYPT_ATTRIBUTE_ERRORLOCUS );
		if( cryptStatusOK( status ) )
			{
			errorLocus = value;	/* int to enum */
			status = krnlSendMessage( iServerCert, IMESSAGE_GETATTRIBUTE, 
									  &value, CRYPT_ATTRIBUTE_ERRORTYPE );
			}
		if( cryptStatusOK( status ) )
			errorType = value;	/* int to enum */
		}
	if( cryptStatusError( status ) )
		{
		/* If we can't get extended error information then there's not much 
		   more that we can do */
		retExt( CRYPT_ERROR_INVALID,
				( CRYPT_ERROR_INVALID, errorInfo,
				  "Server certificate is invalid" ) );
		}

	/* Try and get more	information on common errors and report them to the
	   caller */
	if( errorType == CRYPT_ERRTYPE_CONSTRAINT )
		{
		switch( errorLocus )
			{
			case CRYPT_CERTINFO_VALIDFROM:
				retExt( CRYPT_ERROR_INVALID,
						( CRYPT_ERROR_INVALID, errorInfo,
						  "Server certificate is not valid yet" ) );

			case CRYPT_CERTINFO_VALIDTO:
				retExt( CRYPT_ERROR_INVALID,
						( CRYPT_ERROR_INVALID, errorInfo,
						  "Server certificate has expired" ) );

			case CRYPT_CERTINFO_KEYUSAGE:
				retExt( CRYPT_ERROR_INVALID,
						( CRYPT_ERROR_INVALID, errorInfo,
						  "Server certificate's keyUsage doesn't allow it "
						  "to be used" ) );
			}
		}

	retExt( CRYPT_ERROR_INVALID,
			( CRYPT_ERROR_INVALID, errorInfo,
			  "Server certificate is invalid, error type %d, error "
			  "locus %d", errorType, errorLocus ) );
	}
Пример #23
0
CHECK_RETVAL \
int loadDHcontext( IN_HANDLE const CRYPT_CONTEXT iDHContext, 
				   IN_LENGTH_SHORT_OPT const int requestedKeySize )
	{
	MESSAGE_DATA msgData;
	const void *keyData;
	const int actualKeySize = \
				( requestedKeySize < 128 + 8 ) ? bitsToBytes( 1024 ) : \
				( requestedKeySize < 192 + 8 ) ? bitsToBytes( 1536 ) : \
				( requestedKeySize < 256 + 8 ) ? bitsToBytes( 2048 ) : \
				( requestedKeySize < 384 + 8 ) ? bitsToBytes( 3072 ) : \
				0;
	int keyDataLength, keyDataChecksum;

	REQUIRES( isHandleRangeValid( iDHContext ) );
	REQUIRES( requestedKeySize >= MIN_PKCSIZE && \
			  requestedKeySize <= CRYPT_MAX_PKCSIZE );

	/* Load the built-in DH key value that corresponds best to the client's 
	   requested key size.  We allow for a bit of slop to avoid having 
	   something like a 1025-bit requested key size lead to the use of a 
	   1536-bit key value.

	   In theory we should probably generate a new DH key each time:

		status = krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE,
								  ( MESSAGE_CAST ) &requestedKeySize,
								  CRYPT_CTXINFO_KEYSIZE );
		if( cryptStatusOK( status ) )
			status = krnlSendMessage( iDHContext, IMESSAGE_CTX_GENKEY, 
									  NULL, FALSE );

	   however because the handshake is set up so that the client (rather 
	   than the server) chooses the key size we can't actually perform the 
	   generation until we're in the middle of the handshake.  This means 
	   that the server will grind to a halt during each handshake as it 
	   generates a new key of whatever size takes the client's fancy (it 
	   also leads to a nice potential DoS attack on the server).  To avoid 
	   this problem we use fixed keys of various common sizes.
	   
	   As late as 2014 Java still can't handle DH keys over 1024 bits (it 
	   only allows keys ranging from 512-1024 bits):

		java.security.InvalidAlgorithmParameterException: Prime size must be 
		multiple of 64, and can only range from 512 to 1024 (inclusive)

	   so if you need to talk to a system built in Java you need to hardcode
	   the key size below to 1024 bits, the largest size that Java will 
	   allow */
	switch( actualKeySize )
		{
		case bitsToBytes( 1024 ):
			keyData = dh1024SSL;
			keyDataLength = sizeof( dh1024SSL );
			keyDataChecksum = dh1024checksum;
			break;

		case bitsToBytes( 1536 ):
			keyData = dh1536SSL;
			keyDataLength = sizeof( dh1536SSL );
			keyDataChecksum = dh1536checksum;
			break;

		case bitsToBytes( 2048 ):
			keyData = dh2048SSL;
			keyDataLength = sizeof( dh2048SSL );
			keyDataChecksum = dh2048checksum;
			break;

		case bitsToBytes( 3072 ):
		default:			/* Hier ist der mast zu ende */
			keyData = dh3072SSL;
			keyDataLength = sizeof( dh3072SSL );
			keyDataChecksum = dh3072checksum;
			break;
		}

	/* Make sure that the key data hasn't been corrupted */
	if( keyDataChecksum != checksumData( keyData, keyDataLength ) )
		{
		DEBUG_DIAG(( "Fixed DH value for %d-bit key has been corrupted",
					 bytesToBits( actualKeySize ) ));
		retIntError();
		}

	/* Load the fixed DH key into the context */
	setMessageData( &msgData, ( MESSAGE_CAST ) keyData, keyDataLength );
	return( krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE_S, &msgData, 
							 CRYPT_IATTRIBUTE_KEY_SSL ) );
	}