⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pkcs11_pkc.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:

		krnlReleaseObject( iCryptDevice );
		return( cryptStatus );
		}

	/* Send the keying info to the context and set up the key ID info */
	cryptStatus = dsaSetKeyInfo( pkcs11Info, contextInfoPtr->objectHandle, 
								 hDsaKey, CK_OBJECT_NONE,
								 dsaKey->p, bitsToBytes( dsaKey->pLen ), 
								 dsaKey->q, bitsToBytes( dsaKey->qLen ),
								 dsaKey->g, bitsToBytes( dsaKey->gLen ),
								 yValue, yValueLength, FALSE );
	if( cryptStatusError( cryptStatus ) )
		C_DestroyObject( pkcs11Info->hSession, hDsaKey );
	else
		/* Remember that this object is backed by a crypto device */
		contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT;

	krnlReleaseObject( iCryptDevice );
	return( cryptStatus );
	}

static int dsaGenerateKey( CONTEXT_INFO *contextInfoPtr, const int keysizeBits )
	{
	static const CK_MECHANISM mechanism = { CKM_DSA_KEY_PAIR_GEN, NULL_PTR, 0 };
	static const CK_BBOOL bTrue = TRUE;
	CK_ATTRIBUTE privateKeyTemplate[] = {
		{ CKA_TOKEN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
		{ CKA_PRIVATE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
		{ CKA_SENSITIVE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
		{ CKA_LABEL, contextInfoPtr->label, contextInfoPtr->labelSize },
		{ CKA_SIGN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
		};
	CK_ATTRIBUTE publicKeyTemplate[] = {
		{ CKA_TOKEN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
		{ CKA_LABEL, contextInfoPtr->label, contextInfoPtr->labelSize },
		{ CKA_VERIFY, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
		{ CKA_PRIME, NULL, 0 },
		{ CKA_SUBPRIME, NULL, 0 },
		{ CKA_BASE, NULL, 0 },
		};
	CK_ATTRIBUTE yValueTemplate = { CKA_VALUE, NULL, CRYPT_MAX_PKCSIZE * 2 };
	CK_OBJECT_HANDLE hPublicKey, hPrivateKey;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	MESSAGE_DATA msgData;
	CRYPT_DEVICE iCryptDevice;
	PKCS11_INFO *pkcs11Info;
	BYTE pubkeyBuffer[ ( CRYPT_MAX_PKCSIZE * 3 ) + 8 ], label[ 8 + 8 ];
	CK_RV status;
	STREAM stream;
	void *dataPtr = DUMMY_INIT_PTR;
	long length;
	int cryptStatus;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( keysizeBits >= bytesToBits( MIN_PKCSIZE ) && \
			keysizeBits <= bytesToBits( CRYPT_MAX_PKCSIZE ) );

	/* CKM_DSA_KEY_PAIR_GEN is really a Clayton's key generation mechanism 
	   since it doesn't actually generate the p, q, or g values (presumably 
	   it dates back to the original FIPS 186 shared domain parameters idea).
	   Because of this we'd have to generate half the key ourselves in a 
	   native context, then copy portions from the native context over in 
	   flat form and complete the keygen via the device.  The easiest way to
	   do this is to create a native DSA context, generate a key, grab the
	   public portions, and destroy the context again (i.e. generate a full
	   key on a superscalar 2GHz RISC CPU, then throw half of it away, and 
	   regenerate it on a 5MHz 8-bit tinkertoy).  Since the keygen can take 
	   awhile and doesn't require the device, we do it before we grab the 
	   device */
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_DSA );
	cryptStatus = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
								   IMESSAGE_DEV_CREATEOBJECT, &createInfo, 
								   OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );
	setMessageData( &msgData, label, 8 );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, 
					 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
	krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE_S,
					 &msgData, CRYPT_CTXINFO_LABEL );
	cryptStatus = krnlSendNotifier( createInfo.cryptHandle, 
									IMESSAGE_CTX_GENKEY );
	if( cryptStatusOK( cryptStatus ) )
		{
		setMessageData( &msgData, pubkeyBuffer, CRYPT_MAX_PKCSIZE * 3 );
		cryptStatus = krnlSendMessage( createInfo.cryptHandle, 
									   IMESSAGE_GETATTRIBUTE_S, &msgData, 
									   CRYPT_IATTRIBUTE_KEY_SPKI );
		}
	krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );

	/* Set up the public key info by extracting the flat values from the
	   SubjectPublicKeyInfo.  Note that the data used is represented in
	   DER-canonical form, there may be PKCS #11 implementations that
	   can't handle this (for example they may require q to be zero-padded
	   to make it exactly 20 bytes rather than (say) 19 bytes if the high
	   byte is zero) */
	sMemConnect( &stream, pubkeyBuffer, msgData.length );
	readSequence( &stream, NULL );				/* SEQUENCE */
	readSequence( &stream, NULL );					/* SEQUENCE */
	readUniversal( &stream );							/* OID */
	readSequence( &stream, NULL );						/* SEQUENCE */
	status = readGenericHole( &stream, &length, 16, BER_INTEGER  );	/* p */
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( &stream, &dataPtr, length );
	if( cryptStatusError( status ) )
		retIntError();
	publicKeyTemplate[ 3 ].pValue = dataPtr;
	publicKeyTemplate[ 3 ].ulValueLen = length;
	sSkip( &stream, length );
	status = readGenericHole( &stream, &length, 16, BER_INTEGER  );	/* q */
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( &stream, &dataPtr, length );
	if( cryptStatusError( status ) )
		retIntError();
	publicKeyTemplate[ 4 ].pValue = dataPtr;
	publicKeyTemplate[ 4 ].ulValueLen = length;
	sSkip( &stream, length );
	status = readGenericHole( &stream, &length, 16, BER_INTEGER  );	/* g */
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( &stream, &dataPtr, length );
	if( cryptStatusError( status ) )
		retIntError();
	publicKeyTemplate[ 5 ].pValue = dataPtr;
	publicKeyTemplate[ 5 ].ulValueLen = length;
	sMemDisconnect( &stream );

	/* Get the info for the device associated with this context */
	cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle, 
										&iCryptDevice, &pkcs11Info );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );

	/* Generate the keys */
	status = C_GenerateKeyPair( pkcs11Info->hSession,
								( CK_MECHANISM_PTR ) &mechanism,
								( CK_ATTRIBUTE_PTR ) publicKeyTemplate, 6,
								( CK_ATTRIBUTE_PTR ) privateKeyTemplate, 5,
								&hPublicKey, &hPrivateKey );
	cryptStatus = pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED );
	if( cryptStatusError( cryptStatus ) )
		{
		krnlReleaseObject( iCryptDevice );
		return( cryptStatus );
		}

	/* Read back the generated y value, send the public key info to the 
	   context, and set up the key ID info.  The odd two-phase y value read 
	   is necessary for buggy implementations that fail if the given size 
	   isn't exactly the same as the data size */
	status = C_GetAttributeValue( pkcs11Info->hSession, hPublicKey,
								  &yValueTemplate, 1 );
	if( status == CKR_OK )
		{
		yValueTemplate.pValue = pubkeyBuffer;
		status = C_GetAttributeValue( pkcs11Info->hSession, hPublicKey, 
									  &yValueTemplate, 1 );
		}
	cryptStatus = pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED );
	if( cryptStatusOK( cryptStatus ) )
		cryptStatus = dsaSetKeyInfo( pkcs11Info, contextInfoPtr->objectHandle, 
			hPrivateKey, hPublicKey,
			publicKeyTemplate[ 3 ].pValue, publicKeyTemplate[ 3 ].ulValueLen, 
			publicKeyTemplate[ 4 ].pValue, publicKeyTemplate[ 4 ].ulValueLen, 
			publicKeyTemplate[ 5 ].pValue, publicKeyTemplate[ 5 ].ulValueLen,
			yValueTemplate.pValue, yValueTemplate.ulValueLen, FALSE );
	if( cryptStatusError( cryptStatus ) )
		{
		C_DestroyObject( pkcs11Info->hSession, hPublicKey );
		C_DestroyObject( pkcs11Info->hSession, hPrivateKey );
		}
	else
		/* Remember that this object is backed by a crypto device */
		contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT;

	krnlReleaseObject( iCryptDevice );
	return( cryptStatus );
	}

static int dsaSign( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int length )
	{
	static const CK_MECHANISM mechanism = { CKM_DSA, NULL_PTR, 0 };
	CRYPT_DEVICE iCryptDevice;
	PKCS11_INFO *pkcs11Info;
	DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
	PKC_INFO *dsaKey = contextInfoPtr->ctxPKC;
	BIGNUM *r, *s;
	BYTE signature[ 40 + 8 ];
	int cryptStatus;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( isWritePtr( buffer, length ) );
	assert( length == sizeof( DLP_PARAMS ) );
	assert( dlpParams->inParam1 != NULL && \
			dlpParams->inLen1 == 20 );
	assert( dlpParams->inParam2 == NULL && dlpParams->inLen2 == 0 );
	assert( dlpParams->outParam != NULL && \
			dlpParams->outLen >= ( 2 + 20 ) * 2 );

	/* Get the info for the device associated with this context */
	cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle, 
										&iCryptDevice, &pkcs11Info );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );
	cryptStatus = genericSign( pkcs11Info, contextInfoPtr, &mechanism, 
							   dlpParams->inParam1, dlpParams->inLen1, 
							   signature, 40 );
	krnlReleaseObject( iCryptDevice );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );

	/* Encode the result as a DL data block.  We have to do this via bignums, 
	   but this isn't a big deal since DSA signing via tokens is almost never 
	   used */
	r = BN_new();
	if( r == NULL )
		return( CRYPT_ERROR_MEMORY );
	s = BN_new();
	if( s == NULL )
		{
		BN_free( r );
		return( CRYPT_ERROR_MEMORY );
		}
	cryptStatus = extractBignum( r, signature, 20, 
								 bitsToBytes( 160 - 32 ), 20, NULL, FALSE );
	if( cryptStatusOK( cryptStatus ) )
		cryptStatus = extractBignum( r, signature + 20, 20,
									 bitsToBytes( 160 - 32 ), 20, NULL, FALSE );
	if( cryptStatusOK( cryptStatus ) )
		{
		cryptStatus = \
			dsaKey->encodeDLValuesFunction( dlpParams->outParam, 
											dlpParams->outLen, &dlpParams->outLen,
											r, s, dlpParams->formatType );
		}
	BN_clear_free( s );
	BN_clear_free( r );
	return( cryptStatus );
	}

static int dsaVerify( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int length )
	{
	static const CK_MECHANISM mechanism = { CKM_DSA, NULL_PTR, 0 };
/*	CRYPT_DEVICE iCryptDevice; */
	DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
	PKC_INFO *dsaKey = contextInfoPtr->ctxPKC;
	BIGNUM r, s;
/*	BYTE signature[ 40 + 8 ]; */
	int cryptStatus;

	/* This function is present but isn't used as part of any normal 
	   operation because cryptlib does the same thing much faster in 
	   software and because some tokens don't support public-key 
	   operations */

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( isWritePtr( buffer, length ) );
	assert( length == sizeof( DLP_PARAMS ) );
	assert( dlpParams->inParam1 != NULL && dlpParams->inLen1 == 20 );
	assert( dlpParams->inParam2 != NULL && \
			( ( dlpParams->formatType == CRYPT_FORMAT_CRYPTLIB && \
				dlpParams->inLen2 >= 46 ) || \
			  ( dlpParams->formatType == CRYPT_FORMAT_PGP && \
				dlpParams->inLen2 == 44 ) || \
				( dlpParams->formatType == CRYPT_IFORMAT_SSH && \
				dlpParams->inLen2 == 40 ) ) );
	assert( dlpParams->outParam == NULL && dlpParams->outLen == 0 );

	/* Decode the values from a DL data block and make sure r and s are
	   valid */
	BN_init( &r );
	BN_init( &s );
	cryptStatus = \
		dsaKey->decodeDLValuesFunction( dlpParams->inParam2, dlpParams->inLen2, 
										&r, &s, NULL, dlpParams->formatType );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );

	/* This code can never be called since DSA public-key contexts are 
	   always native contexts */
	retIntError();

#if 0
	/* Get the info for the device associated with this context */
	cryptStatus = getContextDeviceInfo( contextInfoPtr->objectHandle, 
										&iCryptDevice, &pkcs11Info );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );
	cryptStatus = genericVerify( pkcs11Info, contextInfoPtr, &mechanism, 
								 buffer, 20, signature, 40 );
	krnlReleaseObject( iCryptDevice );
	return( cryptStatus );
#endif /* 0 */
	}

/****************************************************************************
*																			*
*						 	Device Capability Routines						*
*																			*
****************************************************************************/

/* PKC mechanism info */

static const PKCS11_MECHANISM_INFO mechanismInfoPKC[] = {
	/* The handling of the RSA mechanism is a bit odd.  Almost everyone 
	   supports CKM_RSA_X_509 even though what's reported as being supported 
	   is CKM_RSA_PKCS, however the PKCS mechanism is often implemented in a 
	   buggy manner with all sorts of problems with handling the padding.  
	   The safest option would be to use the raw RSA one and do the padding 
	   ourselves, which means that it'll always be done right.  Since some 
	   implementations report raw RSA as being unavailable even though it's 
	   present, we detect it by checking for the PKCS mechanism but using 
	   raw RSA.  However, some implementations genuinely don't do raw RSA, so
	   the code fakes it by removing/adding dummy PKCS padding as required 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -