Example #1
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 );
	}
Example #2
0
BOOLEAN sanityCheckCapability( const CAPABILITY_INFO *capabilityInfoPtr )
	{
	CRYPT_ALGO_TYPE cryptAlgo = capabilityInfoPtr->cryptAlgo;

	assert( isReadPtr( capabilityInfoPtr, sizeof( CAPABILITY_INFO ) ) );

	/* Check the algorithm and mode parameters.  We check for an algorithm
	   name one shorter than the maximum because as returned to an external
	   caller it's an ASCIZ string so we need to allow room for the
	   terminator */
	if( cryptAlgo <= CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST )
		return( FALSE );
	if( capabilityInfoPtr->algoName == NULL || \
		capabilityInfoPtr->algoNameLen < 3 || \
		capabilityInfoPtr->algoNameLen > CRYPT_MAX_TEXTSIZE - 1 )
		return( FALSE );

	/* Make sure that the minimum functions are present.  We don't check for
	   the presence of the keygen function since the symmetric capabilities
	   use the generic keygen and the hash capabilities don't do keygen at 
	   all */
	if( capabilityInfoPtr->selfTestFunction == NULL || \
		capabilityInfoPtr->getInfoFunction == NULL )
		return( FALSE );
	if( !sanityCheckFunctionality( capabilityInfoPtr, cryptAlgo ) )
		return( FALSE );

	/* Make sure that the algorithm/mode-specific parameters are
	   consistent */
	if( capabilityInfoPtr->minKeySize > capabilityInfoPtr->keySize || \
		capabilityInfoPtr->maxKeySize < capabilityInfoPtr->keySize )
		return( FALSE );
	if( isConvAlgo( cryptAlgo ) )
		{
		if( ( capabilityInfoPtr->blockSize < bitsToBytes( 8 ) || \
        	  capabilityInfoPtr->blockSize > CRYPT_MAX_IVSIZE ) || \
			( capabilityInfoPtr->minKeySize < MIN_KEYSIZE || \
			  capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE ) )
			return( FALSE );
		if( capabilityInfoPtr->keySize > MAX_WORKING_KEYSIZE )
			return( FALSE );	/* Requirement for key wrap */
		if( capabilityInfoPtr->initParamsFunction == NULL || \
			capabilityInfoPtr->initKeyFunction == NULL )
			return( FALSE );
		if( !isStreamCipher( cryptAlgo ) && \
			 capabilityInfoPtr->blockSize < bitsToBytes( 64 ) )
			return( FALSE );

		return( TRUE );
		}

	/* Check any remaining algorithm types */
	if( isPkcAlgo( cryptAlgo ) )
		{
		const int minKeySize = isEccAlgo( cryptAlgo ) ? \
							   MIN_PKCSIZE_ECC : MIN_PKCSIZE;

		if( capabilityInfoPtr->blockSize != 0 || \
			( capabilityInfoPtr->minKeySize < minKeySize || \
			  capabilityInfoPtr->maxKeySize > CRYPT_MAX_PKCSIZE ) )
			return( FALSE );
		if( capabilityInfoPtr->initKeyFunction == NULL || \
			capabilityInfoPtr->generateKeyFunction == NULL )
			return( FALSE );

		return( TRUE );
		}
	if( isHashAlgo( cryptAlgo ) )
		{
		if( ( capabilityInfoPtr->blockSize < bitsToBytes( 128 ) || \
			  capabilityInfoPtr->blockSize > CRYPT_MAX_HASHSIZE ) || \
			( capabilityInfoPtr->minKeySize != 0 || \
			  capabilityInfoPtr->keySize != 0 || \
			  capabilityInfoPtr->maxKeySize != 0 ) )
			return( FALSE );

		return( TRUE );
		}
	if( isMacAlgo( cryptAlgo ) )
		{
		if( ( capabilityInfoPtr->blockSize < bitsToBytes( 128 ) || \
			  capabilityInfoPtr->blockSize > CRYPT_MAX_HASHSIZE ) || \
			( capabilityInfoPtr->minKeySize < MIN_KEYSIZE || \
			  capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE ) )
			return( FALSE );
		if( capabilityInfoPtr->keySize > MAX_WORKING_KEYSIZE )
			return( FALSE );	/* Requirement for key wrap */
		if( capabilityInfoPtr->initKeyFunction == NULL )
			return( FALSE );

		return( TRUE );
		}
	if( isSpecialAlgo( cryptAlgo ) )
		{
		if( capabilityInfoPtr->blockSize != 0 || \
			capabilityInfoPtr->minKeySize < bitsToBytes( 128 ) || \
			capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE )
			return( FALSE );
		if( capabilityInfoPtr->initKeyFunction == NULL )
			return( FALSE );

		return( TRUE );
		}

	retIntError_Boolean();
	}
Example #3
0
static BOOLEAN sanityCheckFunctionality( const CAPABILITY_INFO *capabilityInfoPtr,
										 IN_ALGO CRYPT_ALGO_TYPE cryptAlgo )
	{
	const BOOLEAN isCrypt = \
		( capabilityInfoPtr->encryptCBCFunction != NULL || \
		  capabilityInfoPtr->decryptCBCFunction != NULL || \
		  capabilityInfoPtr->encryptCFBFunction != NULL || \
		  capabilityInfoPtr->decryptCFBFunction != NULL || \
		  capabilityInfoPtr->encryptGCMFunction != NULL || \
		  capabilityInfoPtr->decryptGCMFunction != NULL ) ? TRUE : FALSE;
	const BOOLEAN isSig = \
		( capabilityInfoPtr->signFunction != NULL || \
		  capabilityInfoPtr->sigCheckFunction != NULL ) ? TRUE : FALSE;

	assert( isReadPtr( capabilityInfoPtr, sizeof( CAPABILITY_INFO ) ) );

	REQUIRES( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );

	/* Generic-secret algorithms are non-capabilities used to to store
	   keying data, but that can't perform any operations themselves */
	if( isSpecialAlgo( cryptAlgo ) )
		{
		if( capabilityInfoPtr->encryptFunction != NULL || \
			capabilityInfoPtr->decryptFunction != NULL || \
			isCrypt || isSig )
			return( FALSE );

		return( TRUE );
		}

	/* We need at least one mechanism pair to be able to do anything useful 
	   with the capability */
	if( ( capabilityInfoPtr->encryptFunction == NULL || \
		  capabilityInfoPtr->decryptFunction == NULL ) && \
		( capabilityInfoPtr->encryptCBCFunction == NULL || \
		  capabilityInfoPtr->decryptCBCFunction == NULL ) && \
		( capabilityInfoPtr->encryptCFBFunction == NULL || \
		  capabilityInfoPtr->decryptCFBFunction == NULL ) && \
		( capabilityInfoPtr->encryptGCMFunction == NULL || \
		  capabilityInfoPtr->decryptGCMFunction == NULL ) && \
		( capabilityInfoPtr->signFunction == NULL || \
		  capabilityInfoPtr->sigCheckFunction == NULL ) )
		return( FALSE );

	/* Perform algorithm class-specific checks */
	if( isConvAlgo( cryptAlgo ) )
		{
		if( isSig )
			return( FALSE );
		if( isStreamCipher( cryptAlgo ) )
			{
			if( capabilityInfoPtr->encryptCFBFunction == NULL || \
				capabilityInfoPtr->decryptCFBFunction == NULL )
				return( FALSE );
			if( capabilityInfoPtr->encryptFunction != NULL || \
				capabilityInfoPtr->decryptFunction != NULL || \
				capabilityInfoPtr->encryptCBCFunction != NULL || \
				capabilityInfoPtr->decryptCBCFunction != NULL || \
				capabilityInfoPtr->encryptCFBFunction != NULL || \
				capabilityInfoPtr->decryptCFBFunction != NULL || \
				capabilityInfoPtr->encryptGCMFunction != NULL || \
				capabilityInfoPtr->decryptGCMFunction != NULL )
				return( FALSE );
			}
		else
			{
			if( capabilityInfoPtr->encryptFunction == NULL && \
				capabilityInfoPtr->decryptFunction == NULL && \
				!isCrypt )
				return( FALSE );
			}
		if( ( capabilityInfoPtr->encryptCBCFunction != NULL && \
			  capabilityInfoPtr->decryptCBCFunction == NULL ) || \
			( capabilityInfoPtr->encryptCBCFunction == NULL && \
			  capabilityInfoPtr->decryptCBCFunction != NULL ) )
			return( FALSE );
		if( ( capabilityInfoPtr->encryptCFBFunction != NULL && \
			  capabilityInfoPtr->decryptCFBFunction == NULL ) || \
			( capabilityInfoPtr->encryptCFBFunction == NULL && \
			  capabilityInfoPtr->decryptCFBFunction != NULL ) )
			return( FALSE );
		if( ( capabilityInfoPtr->encryptGCMFunction != NULL && \
			  capabilityInfoPtr->decryptGCMFunction == NULL ) || \
			( capabilityInfoPtr->encryptGCMFunction == NULL && \
			  capabilityInfoPtr->decryptGCMFunction != NULL ) )
			return( FALSE );
		
		return( TRUE );
		}
	if( isPkcAlgo( cryptAlgo ) )
		{
		if( capabilityInfoPtr->encryptFunction == NULL && \
			capabilityInfoPtr->decryptFunction == NULL && \
			capabilityInfoPtr->signFunction == NULL && \
			capabilityInfoPtr->sigCheckFunction == NULL )
			return( FALSE );
		if( isCrypt )
			return( FALSE );

		return( TRUE );
		}
	if( isHashAlgo( cryptAlgo ) || isMacAlgo( cryptAlgo ) )
		{
		if( capabilityInfoPtr->encryptFunction == NULL || \
			capabilityInfoPtr->decryptFunction == NULL )
			return( FALSE );
		if( isCrypt || isSig )
			return( FALSE );

		return( TRUE );
		}

	retIntError_Boolean();
	}
Example #4
0
BOOLEAN sanityCheckCapability( const CAPABILITY_INFO *capabilityInfoPtr,
							   const BOOLEAN asymmetricOK )
	{
	CRYPT_ALGO_TYPE cryptAlgo = capabilityInfoPtr->cryptAlgo;

	assert( isReadPtr( capabilityInfoPtr, sizeof( CAPABILITY_INFO ) ) );

	/* Check the algorithm and mode parameters.  We check for an algorithm
	   name one shorter than the maximum because as returned to an external
	   caller it's an ASCIZ string so we need to allow room for the
	   terminator */
	if( cryptAlgo <= CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST || \
		capabilityInfoPtr->algoName == NULL || \
		capabilityInfoPtr->algoNameLen < 3 || \
		capabilityInfoPtr->algoNameLen > CRYPT_MAX_TEXTSIZE - 1 )
		return( FALSE );

	/* Make sure that the minimum functions are present.  We don't check for
	   the presence of the keygen function since the symmetric capabilities
	   use the generic keygen and the hash capabilities don't do keygen at 
	   all */
	if( capabilityInfoPtr->selfTestFunction == NULL || \
		capabilityInfoPtr->getInfoFunction == NULL )
		return( FALSE );
	if( isStreamCipher( cryptAlgo ) )
		{
		if( capabilityInfoPtr->encryptOFBFunction == NULL || \
			capabilityInfoPtr->decryptOFBFunction == NULL )
			return( FALSE );
		}
	else
		{
		if( asymmetricOK )
			{
			/* If asymmetric capabilities (e.g. decrypt but not encrypt,
			   present in some tinkertoy tokens) are permitted then we only 
			   check that there's at least one useful capability available */
			if( capabilityInfoPtr->decryptFunction == NULL && \
				capabilityInfoPtr->signFunction == NULL )
				return( FALSE );
			}
		else
			{
			if( !isSpecialAlgo( cryptAlgo ) )
				{
				/* We need at least one mechanism pair to be able to do 
				   anything useful with the capability */
				if( ( capabilityInfoPtr->encryptFunction == NULL || \
					  capabilityInfoPtr->decryptFunction == NULL ) && \
					( capabilityInfoPtr->encryptCBCFunction == NULL || \
					  capabilityInfoPtr->decryptCBCFunction == NULL ) && \
					( capabilityInfoPtr->encryptCFBFunction == NULL || \
					  capabilityInfoPtr->decryptCFBFunction == NULL ) && \
					( capabilityInfoPtr->encryptOFBFunction == NULL || \
					  capabilityInfoPtr->decryptOFBFunction == NULL ) && \
					( capabilityInfoPtr->encryptGCMFunction == NULL || \
					  capabilityInfoPtr->decryptGCMFunction == NULL ) && \
					( capabilityInfoPtr->signFunction == NULL || \
					  capabilityInfoPtr->sigCheckFunction == NULL ) )
					return( FALSE );
				}
			}
		}

	/* Make sure that the algorithm/mode-specific parameters are
	   consistent */
	if( capabilityInfoPtr->minKeySize > capabilityInfoPtr->keySize || \
		capabilityInfoPtr->maxKeySize < capabilityInfoPtr->keySize )
		return( FALSE );
	if( isConvAlgo( cryptAlgo ) )
		{
		if( ( capabilityInfoPtr->blockSize < bitsToBytes( 8 ) || \
        	  capabilityInfoPtr->blockSize > CRYPT_MAX_IVSIZE ) || \
			( capabilityInfoPtr->minKeySize < MIN_KEYSIZE || \
			  capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE ) )
			return( FALSE );
		if( capabilityInfoPtr->keySize > MAX_WORKING_KEYSIZE )
			return( FALSE );	/* Requirement for key wrap */
		if( capabilityInfoPtr->initParamsFunction == NULL || \
			capabilityInfoPtr->initKeyFunction == NULL )
			return( FALSE );
		if( !isStreamCipher( cryptAlgo ) && \
			 capabilityInfoPtr->blockSize < bitsToBytes( 64 ) )
			return( FALSE );
		if( ( capabilityInfoPtr->encryptCBCFunction != NULL && \
			  capabilityInfoPtr->decryptCBCFunction == NULL ) || \
			( capabilityInfoPtr->encryptCBCFunction == NULL && \
			  capabilityInfoPtr->decryptCBCFunction != NULL ) )
			return( FALSE );
		if( ( capabilityInfoPtr->encryptCFBFunction != NULL && \
			  capabilityInfoPtr->decryptCFBFunction == NULL ) || \
			( capabilityInfoPtr->encryptCFBFunction == NULL && \
			  capabilityInfoPtr->decryptCFBFunction != NULL ) )
			return( FALSE );
		if( ( capabilityInfoPtr->encryptOFBFunction != NULL && \
			  capabilityInfoPtr->decryptOFBFunction == NULL ) || \
			( capabilityInfoPtr->encryptOFBFunction == NULL && \
			  capabilityInfoPtr->decryptOFBFunction != NULL ) )
			return( FALSE );
		if( ( capabilityInfoPtr->encryptGCMFunction != NULL && \
			  capabilityInfoPtr->decryptGCMFunction == NULL ) || \
			( capabilityInfoPtr->encryptGCMFunction == NULL && \
			  capabilityInfoPtr->decryptGCMFunction != NULL ) )
			return( FALSE );

		return( TRUE );
		}

	/* We've checked the conventional algorithms, beyond this point there
	   shouldn't be any conventional encryption modes present */
	if( capabilityInfoPtr->encryptCBCFunction != NULL || \
		capabilityInfoPtr->decryptCBCFunction != NULL || \
		capabilityInfoPtr->encryptCFBFunction != NULL || \
		capabilityInfoPtr->decryptCFBFunction != NULL || \
		capabilityInfoPtr->encryptOFBFunction != NULL || \
		capabilityInfoPtr->decryptOFBFunction != NULL || \
		capabilityInfoPtr->encryptGCMFunction != NULL || \
		capabilityInfoPtr->decryptGCMFunction != NULL )
		return( FALSE );

	/* Check any remaining algorithm types */
	if( isPkcAlgo( cryptAlgo ) )
		{
		const int minKeySize = isEccAlgo( cryptAlgo ) ? \
							   MIN_PKCSIZE_ECC : MIN_PKCSIZE;

		if( capabilityInfoPtr->blockSize != 0 || \
			( capabilityInfoPtr->minKeySize < minKeySize || \
			  capabilityInfoPtr->maxKeySize > CRYPT_MAX_PKCSIZE ) )
			return( FALSE );
		if( capabilityInfoPtr->initKeyFunction == NULL || \
			capabilityInfoPtr->generateKeyFunction == NULL )
			return( FALSE );

		return( TRUE );
		}
	if( isHashAlgo( cryptAlgo ) )
		{
		if( ( capabilityInfoPtr->blockSize < bitsToBytes( 128 ) || \
			  capabilityInfoPtr->blockSize > CRYPT_MAX_HASHSIZE ) || \
			( capabilityInfoPtr->minKeySize != 0 || \
			  capabilityInfoPtr->keySize != 0 || \
			  capabilityInfoPtr->maxKeySize != 0 ) )
			return( FALSE );

		return( TRUE );
		}
	if( isMacAlgo( cryptAlgo ) )
		{
		if( ( capabilityInfoPtr->blockSize < bitsToBytes( 128 ) || \
			  capabilityInfoPtr->blockSize > CRYPT_MAX_HASHSIZE ) || \
			( capabilityInfoPtr->minKeySize < MIN_KEYSIZE || \
			  capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE ) )
			return( FALSE );
		if( capabilityInfoPtr->keySize > MAX_WORKING_KEYSIZE )
			return( FALSE );	/* Requirement for key wrap */
		if( capabilityInfoPtr->initKeyFunction == NULL )
			return( FALSE );

		return( TRUE );
		}
	if( isSpecialAlgo( cryptAlgo ) )
		{
		if( capabilityInfoPtr->blockSize != 0 || \
			capabilityInfoPtr->minKeySize < bitsToBytes( 128 ) || \
			capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE )
			return( FALSE );
		if( capabilityInfoPtr->encryptFunction != NULL || \
			capabilityInfoPtr->decryptFunction != NULL )
			return( FALSE );
		if( capabilityInfoPtr->initKeyFunction == NULL )
			return( FALSE );

		return( TRUE );
		}

	retIntError_Boolean();
	}