📄 pkcs11_pkc.c
字号:
/****************************************************************************
* *
* cryptlib PKCS #11 PKC Routines *
* Copyright Peter Gutmann 1998-2006 *
* *
****************************************************************************/
#define PKC_CONTEXT /* Tell context.h that we're working with PKC ctxs */
#if defined( INC_ALL )
#include "crypt.h"
#include "context.h"
#include "device.h"
#include "pkcs11_api.h"
#include "asn1.h"
#else
#include "crypt.h"
#include "context/context.h"
#include "device/device.h"
#include "device/pkcs11_api.h"
#include "misc/asn1.h"
#endif /* Compiler-specific includes */
#ifdef USE_PKCS11
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Read an attribute value, used to read public-key components. The odd
two-phase read is necessary for buggy implementations that fail if the
given size isn't exactly the same as the data size */
static int readAttributeValue( PKCS11_INFO *pkcs11Info,
const CK_OBJECT_HANDLE hObject,
const CK_ATTRIBUTE_TYPE attrType,
void *buffer, const int bufMaxLen,
int *length )
{
CK_ATTRIBUTE attrTemplate = { attrType, NULL_PTR, bufMaxLen };
CK_RV status;
int cryptStatus;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isWritePtr( buffer, bufMaxLen ) );
assert( isWritePtr( length, sizeof( int ) ) );
/* Clear return value */
memset( buffer, 0, min( 16, bufMaxLen ) );
*length = CRYPT_ERROR;
status = C_GetAttributeValue( pkcs11Info->hSession, hObject,
&attrTemplate, 1 );
if( status == CKR_OK )
{
attrTemplate.pValue = buffer;
status = C_GetAttributeValue( pkcs11Info->hSession, hObject,
&attrTemplate, 1 );
}
cryptStatus = pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED );
if( cryptStatusOK( status ) )
*length = attrTemplate.ulValueLen;
return( cryptStatus );
}
/****************************************************************************
* *
* Capability Interface Routines *
* *
****************************************************************************/
/* Sign data, check a signature. We use Sign and Verify rather than the
xxxRecover variants because there's no need to use Recover, and because
many implementations don't do Recover */
static int genericSign( PKCS11_INFO *pkcs11Info,
CONTEXT_INFO *contextInfoPtr,
const CK_MECHANISM *pMechanism,
const void *inBuffer, const int inLength,
void *outBuffer, const int outLength )
{
CK_ULONG resultLen = outLength;
CK_RV status;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isReadPtr( inBuffer, inLength ) );
assert( isWritePtr( outBuffer, outLength ) );
/* If we're currently in the middle of a multi-stage sign operation we
can't start a new one. We have to perform this tracking explicitly
since PKCS #11 only allows one multi-stage operation per session */
if( pkcs11Info->hActiveSignObject != CK_OBJECT_NONE )
return( CRYPT_ERROR_INCOMPLETE );
status = C_SignInit( pkcs11Info->hSession,
( CK_MECHANISM_PTR ) pMechanism,
contextInfoPtr->deviceObject );
if( status == CKR_OK )
status = C_Sign( pkcs11Info->hSession, ( CK_BYTE_PTR ) inBuffer,
inLength, outBuffer, &resultLen );
if( status != CKR_OK )
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
return( CRYPT_OK );
}
static int genericVerify( PKCS11_INFO *pkcs11Info,
CONTEXT_INFO *contextInfoPtr,
const CK_MECHANISM *pMechanism,
const void *inBuffer, const int inLength,
void *outBuffer, const int outLength )
{
CK_RV status;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isReadPtr( pMechanism, sizeof( CK_MECHANISM ) ) );
assert( isReadPtr( inBuffer, inLength ) );
assert( isWritePtr( outBuffer, outLength ) );
/* If we're currently in the middle of a multi-stage sign operation we
can't start a new one. We have to perform this tracking explicitly
since PKCS #11 only allows one multi-stage operation per session */
if( pkcs11Info->hActiveSignObject != CK_OBJECT_NONE )
return( CRYPT_ERROR_INCOMPLETE );
status = C_VerifyInit( pkcs11Info->hSession,
( CK_MECHANISM_PTR ) pMechanism,
contextInfoPtr->deviceObject );
if( status == CKR_OK )
status = C_Verify( pkcs11Info->hSession, ( CK_BYTE_PTR ) inBuffer,
inLength, outBuffer, outLength );
if( status != CKR_OK )
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
return( CRYPT_OK );
}
/* Encrypt, decrypt */
static int genericEncrypt( PKCS11_INFO *pkcs11Info,
CONTEXT_INFO *contextInfoPtr,
const CK_MECHANISM *pMechanism, void *buffer,
const int length, const int outLength )
{
CK_ULONG resultLen = outLength;
CK_RV status;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isReadPtr( pMechanism, sizeof( CK_MECHANISM ) ) );
assert( isWritePtr( buffer, length ) );
assert( isWritePtr( buffer, outLength ) );
status = C_EncryptInit( pkcs11Info->hSession,
( CK_MECHANISM_PTR ) pMechanism,
contextInfoPtr->deviceObject );
if( status == CKR_OK )
status = C_Encrypt( pkcs11Info->hSession, buffer, length,
buffer, &resultLen );
if( status != CKR_OK )
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
/* When performing RSA operations some buggy implementations perform
leading-zero trunction, so we restore leading zeroes if necessary */
if( ( pMechanism->mechanism == CKM_RSA_X_509 || \
pMechanism->mechanism == CKM_RSA_PKCS ) && \
( int ) resultLen < length )
{
const int delta = length - resultLen;
memmove( ( BYTE * ) buffer + delta, buffer, resultLen );
memset( buffer, 0, delta );
}
return( CRYPT_OK );
}
static int genericDecrypt( PKCS11_INFO *pkcs11Info,
CONTEXT_INFO *contextInfoPtr,
const CK_MECHANISM *pMechanism, void *buffer,
const int length, int *resultLength )
{
CK_ULONG resultLen = length;
CK_RV status;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( isReadPtr( pMechanism, sizeof( CK_MECHANISM ) ) );
assert( isWritePtr( buffer, length ) );
assert( isWritePtr( resultLength, sizeof( int ) ) );
status = C_DecryptInit( pkcs11Info->hSession,
( CK_MECHANISM_PTR ) pMechanism,
contextInfoPtr->deviceObject );
if( status == CKR_OK )
status = C_Decrypt( pkcs11Info->hSession, buffer, length,
buffer, &resultLen );
if( status == CKR_KEY_FUNCTION_NOT_PERMITTED )
{
static const CK_OBJECT_CLASS secretKeyClass = CKO_SECRET_KEY;
static const CK_KEY_TYPE secretKeyType = CKK_GENERIC_SECRET;
static const CK_BBOOL bTrue = TRUE;
CK_ATTRIBUTE symTemplate[] = {
{ CKA_CLASS, ( CK_VOID_PTR ) &secretKeyClass, sizeof( CK_OBJECT_CLASS ) },
{ CKA_KEY_TYPE, ( CK_VOID_PTR ) &secretKeyType, sizeof( CK_KEY_TYPE ) },
{ CKA_EXTRACTABLE, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_VALUE_LEN, &resultLen, sizeof( CK_ULONG ) }
};
CK_OBJECT_HANDLE hSymKey;
/* If a straight decrypt isn't allowed, try an unwrap instead and
then export the key. This works because we're using the same
mechanism as for decrypt and converting the entire "unwrapped key"
into a generic secret key that we then extract, which is the
same as doing a straight decrypt of the data (this sort of thing
should require a note from your mother before you're allowed to do
it). The reason why it's done in this roundabout manner is that
this is what Netscape tries first, so people doing a minimal
implementation do this first and don't bother with anything else.
Note that doing it this way is rather slower than a straight
decrypt, which is why we try for decrypt first */
status = C_UnwrapKey( pkcs11Info->hSession,
( CK_MECHANISM_PTR ) pMechanism,
contextInfoPtr->deviceObject, buffer, length,
symTemplate, 4, &hSymKey );
if( status == CKR_OK )
{
CK_ATTRIBUTE valueTemplate[] = { CKA_VALUE, buffer, length };
status = C_GetAttributeValue( pkcs11Info->hSession,
hSymKey, valueTemplate, 1 );
if( status == CKR_OK )
resultLen = valueTemplate[ 0 ].ulValueLen;
C_DestroyObject( pkcs11Info->hSession, hSymKey );
}
}
if( status != CKR_OK )
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
/* When performing raw RSA operations some buggy implementations perform
leading-zero trunction, so we restore leading zeroes if necessary. We
can't do the restore with the PKCS mechanism since it always returns a
result length shorter than the input length */
if( pMechanism->mechanism == CKM_RSA_X_509 && \
( int ) resultLen < length )
{
const int delta = length - resultLen;
memmove( ( BYTE * ) buffer + delta, buffer, resultLen );
memset( buffer, 0, delta );
resultLen = length;
}
/* Some mechanisms change the data length, in which case we need to tell
the caller how much was actually returned */
if( resultLength != NULL )
*resultLength = ( int ) resultLen;
return( CRYPT_OK );
}
/****************************************************************************
* *
* DH Mapping Functions *
* *
****************************************************************************/
/* DH algorithm-specific mapping functions. These work somewhat differently
from the other PKC functions because DH objects are ephemeral, the only
fixed values being p and g. In addition there's no real concept of
public and private keys, only an object where the CKA_VALUE attribute
contains y (nominally the public key) and one where it contains x
(nominally the private key). The use of DH objects then is as follows:
load/genkey: genkey with supplied p and g to produce x and y values;
save "public key" (y) as altObjectHandle;
DH phase 1: return public key CKA_VALUE (= y);
DH phase 2: derive using private key, y' = mechanism parameters */
int dhSetPublicComponents( PKCS11_INFO *pkcs11Info,
const CRYPT_CONTEXT iCryptContext,
const CK_OBJECT_HANDLE hDhKey,
const void *q, const int qLen )
{
BYTE p[ CRYPT_MAX_PKCSIZE + 8 ], g[ CRYPT_MAX_PKCSIZE + 8 ];
BYTE y[ CRYPT_MAX_PKCSIZE + 8 ];
BYTE keyDataBuffer[ ( CRYPT_MAX_PKCSIZE * 3 ) + 8 ];
MESSAGE_DATA msgData;
int pLen, gLen = DUMMY_INIT, yLen = DUMMY_INIT, keyDataSize, cryptStatus;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isHandleRangeValid( iCryptContext ) );
assert( isReadPtr( q, qLen ) );
/* Get the public key components from the device */
cryptStatus = readAttributeValue( pkcs11Info, hDhKey, CKA_PRIME,
p, CRYPT_MAX_PKCSIZE, &pLen );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = readAttributeValue( pkcs11Info, hDhKey, CKA_BASE,
g, CRYPT_MAX_PKCSIZE, &gLen );
if( cryptStatusOK( cryptStatus ) )
cryptStatus = readAttributeValue( pkcs11Info, hDhKey, CKA_VALUE,
y, CRYPT_MAX_PKCSIZE, &yLen );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
/* Send the public key data to the context. We send the keying info as
CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL rather than CRYPT_IATTRIBUTE_KEY_SPKI
since the latter transitions the context into the high state. We
don't want to do this because we're already in the middle of processing
a message that does this on completion, all we're doing here is
sending in encoded public key data for use by objects such as
certificates */
cryptStatus = writeFlatPublicKey( keyDataBuffer, CRYPT_MAX_PKCSIZE * 3,
&keyDataSize, CRYPT_ALGO_DH,
p, pLen, g, gLen, q, qLen, y, yLen );
if( cryptStatusOK( cryptStatus ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -