📄 pkcs11_rw.c
字号:
/****************************************************************************
* *
* cryptlib PKCS #11 Item Read/Write Routines *
* Copyright Peter Gutmann 1998-2007 *
* *
****************************************************************************/
#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 *
* *
****************************************************************************/
/* Convert a time_t to a PKCS #11 CK_DATE */
static void convertDate( CK_DATE *date, const time_t theTime )
{
STREAM stream;
BYTE dateBuffer[ 32 + 8 ];
assert( isWritePtr( date, sizeof( CK_DATE ) ) );
/* Clear return value */
memset( date, 0, sizeof( CK_DATE ) );
/* Convert the time_t value to an ASN.1 time string that we can use to
populate the CK_DATE fields, which are stored as ASCII text strings */
sMemOpen( &stream, dateBuffer, 32 );
writeGeneralizedTime( &stream, theTime, DEFAULT_TAG );
sMemDisconnect( &stream );
memcpy( &date->year, dateBuffer + 2, 4 );
memcpy( &date->month, dateBuffer + 6, 2 );
memcpy( &date->day, dateBuffer + 8, 2 );
}
/* Get the label for an object. We can't use a dynBuf for this because it's
a PKCS #11 attribute rather than a cryptlib attribute */
static int getObjectLabel( PKCS11_INFO *pkcs11Info,
const CK_OBJECT_HANDLE hObject,
char *label, const int maxLabelSize,
int *labelLength )
{
CK_ATTRIBUTE keyLabelTemplate = \
{ CKA_LABEL, NULL_PTR, 0 };
CK_RV status;
char labelBuffer[ CRYPT_MAX_TEXTSIZE + 8 ], *labelPtr = labelBuffer;
assert( isReadPtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isWritePtr( label, maxLabelSize ) );
assert( isWritePtr( labelLength, sizeof( int ) ) );
status = C_GetAttributeValue( pkcs11Info->hSession, hObject,
&keyLabelTemplate, 1 );
if( status == CKR_OK )
{
if( keyLabelTemplate.ulValueLen > CRYPT_MAX_TEXTSIZE && \
( labelPtr = clAlloc( "getObjectLabel", \
( size_t ) ( keyLabelTemplate.ulValueLen ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
keyLabelTemplate.pValue = labelPtr;
status = C_GetAttributeValue( pkcs11Info->hSession, hObject,
&keyLabelTemplate, 1 );
}
if( status != CKR_OK )
{
*labelLength = 0;
if( label != NULL )
label[ 0 ] = '\0';
}
else
{
*labelLength = min( keyLabelTemplate.ulValueLen, maxLabelSize );
if( label != NULL )
memcpy( label, labelPtr, *labelLength );
}
if( labelPtr != labelBuffer )
clFree( "getObjectLabel", labelPtr );
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
}
/* Read a flag for an object. An absent value is treated as FALSE */
static BOOLEAN readFlag( const PKCS11_INFO *pkcs11Info,
const CK_OBJECT_HANDLE hObject,
const CK_ATTRIBUTE_TYPE flagType )
{
CK_BBOOL bFlag = FALSE;
CK_ATTRIBUTE flagTemplate = { flagType, &bFlag, sizeof( CK_BBOOL ) };
assert( isReadPtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
/* Some buggy implementations return CKR_OK but forget to set the
data value in the template (!!!) so we have to initialise bFlag
to a default of FALSE to handle this */
return( ( C_GetAttributeValue( pkcs11Info->hSession, hObject,
&flagTemplate, 1 ) == CKR_OK && bFlag ) ? \
TRUE : FALSE );
}
/* Get the permitted-action flags for an object */
static int getActionFlags( PKCS11_INFO *pkcs11Info,
const CK_OBJECT_HANDLE hObject,
const KEYMGMT_ITEM_TYPE itemType,
const CRYPT_ALGO_TYPE cryptAlgo )
{
const BOOLEAN checkSign = ( isSigAlgo( cryptAlgo ) || \
( cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
cryptAlgo <= CRYPT_ALGO_LAST_MAC ) ) ? \
TRUE : FALSE;
const BOOLEAN checkCrypt = ( isCryptAlgo( cryptAlgo ) || \
( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
cryptAlgo < CRYPT_ALGO_LAST_CONVENTIONAL ) ) ? \
TRUE : FALSE;
const BOOLEAN checkWrap = isCryptAlgo( cryptAlgo );
BOOLEAN cryptAllowed = FALSE, sigAllowed = FALSE;
int actionFlags = 0;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
itemType == KEYMGMT_ITEM_PRIVATEKEY || \
itemType == KEYMGMT_ITEM_SECRETKEY );
assert( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
cryptAlgo <= CRYPT_ALGO_LAST_MAC );
/* Get the permitted actions for the object. Some devices report bogus
capabilities (for example encrypt for a MAC object) so we restrict
the actions that we check for to try and weed out false positives.
The kernel won't allow the setting of an invalid action anyway, but
it's better to be safe here.
We also have to provide special translation for the sign and sig-
check action flags, PKCS #11 treats the MAC operation as a member
of the signature family while cryptlib treats it as a member of the
hash family so if we get a sign/sigcheck permitted action for a MAC
object we map it to a hash permitted action */
if( ( checkCrypt && readFlag( pkcs11Info, hObject, CKA_ENCRYPT ) ) || \
( checkWrap && readFlag( pkcs11Info, hObject, CKA_WRAP ) ) )
{
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_ALL );
cryptAllowed = TRUE;
}
if( ( checkCrypt && itemType != KEYMGMT_ITEM_PUBLICKEY && \
readFlag( pkcs11Info, hObject, CKA_DECRYPT ) ) || \
( checkWrap && itemType == KEYMGMT_ITEM_PRIVATEKEY && \
readFlag( pkcs11Info, hObject, CKA_UNWRAP ) ) )
{
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_ALL );
cryptAllowed = TRUE;
}
if( checkSign && itemType != KEYMGMT_ITEM_PUBLICKEY && \
readFlag( pkcs11Info, hObject, CKA_SIGN ) )
{
if( cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
cryptAlgo <= CRYPT_ALGO_LAST_MAC )
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_HASH, ACTION_PERM_ALL );
else
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_SIGN, ACTION_PERM_ALL );
sigAllowed = TRUE;
}
if( checkSign && readFlag( pkcs11Info, hObject, CKA_VERIFY ) )
{
if( cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
cryptAlgo <= CRYPT_ALGO_LAST_MAC )
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_HASH, ACTION_PERM_ALL );
else
actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_ALL );
sigAllowed = TRUE;
}
if( cryptAlgo == CRYPT_ALGO_RSA )
{
/* If there are any restrictions on the key usage, we have to make it
internal-only because of RSA's signature/encryption duality */
if( !( cryptAllowed && sigAllowed ) )
actionFlags = MK_ACTION_PERM_NONE_EXTERNAL( actionFlags );
}
else
if( isDlpAlgo( cryptAlgo ) )
{
/* Because of the special-case data formatting requirements for
DLP algorithms, we make the usage internal-only */
actionFlags = MK_ACTION_PERM_NONE_EXTERNAL( actionFlags );
}
return( actionFlags );
}
/* Get cryptlib algorithm and capability info for a PKCS #11 object */
static int getMechanismInfo( const PKCS11_INFO *pkcs11Info,
const CK_OBJECT_HANDLE hObject,
const void *capabilityInfoList,
const BOOLEAN isPKC,
const CAPABILITY_INFO **capabilityInfoPtrPtr,
CRYPT_ALGO_TYPE *cryptAlgo )
{
CK_KEY_TYPE keyType;
CK_ATTRIBUTE keyTypeTemplate = \
{ CKA_KEY_TYPE, ( CK_VOID_PTR ) &keyType, sizeof( CK_KEY_TYPE ) };
CK_RV status;
const CAPABILITY_INFO *capabilityInfoPtr;
const PKCS11_MECHANISM_INFO *mechanismInfoPtr;
int mechanismInfoSize, i;
assert( isReadPtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( capabilityInfoList != NULL );
assert( isReadPtr( capabilityInfoPtrPtr, sizeof( CAPABILITY_INFO ) ) );
assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
/* Clear return values */
*capabilityInfoPtrPtr = NULL;
*cryptAlgo = CRYPT_ALGO_NONE;
/* Get the key type (equivalent to the cryptlib algoID) for this
object */
status = C_GetAttributeValue( pkcs11Info->hSession, hObject,
&keyTypeTemplate, 1 );
if( status != CKR_OK )
{
assert( DEBUG_WARN );
return( CRYPT_ERROR_FAILED );
}
/* Hack for PKCS #11's broken HMAC "support", PKCS #11 has no HMAC
object types so if we find a generic secret key object we assume that
it's an HMAC-SHA1 object, the most common type */
if( keyType == CKK_GENERIC_SECRET )
{
*cryptAlgo = CRYPT_ALGO_HMAC_SHA1;
capabilityInfoPtr = findCapabilityInfo( capabilityInfoList,
*cryptAlgo );
if( capabilityInfoPtr == NULL )
return( CRYPT_ERROR_NOTAVAIL );
*capabilityInfoPtrPtr = capabilityInfoPtr;
return( CRYPT_OK );
}
/* Get the equivalent cryptlib algorithm type and use that to get the
capability info for the algorithm */
if( isPKC )
mechanismInfoPtr = getMechanismInfoPKC( &mechanismInfoSize );
else
mechanismInfoPtr = getMechanismInfoConv( &mechanismInfoSize );
for( i = 0; mechanismInfoPtr[ i ].keyType != keyType && \
i < mechanismInfoSize; i++ );
if( i >= mechanismInfoSize )
retIntError();
mechanismInfoPtr = &mechanismInfoPtr[ i ];
*cryptAlgo = mechanismInfoPtr->cryptAlgo;
capabilityInfoPtr = findCapabilityInfo( capabilityInfoList, *cryptAlgo );
if( capabilityInfoPtr == NULL )
return( CRYPT_ERROR_NOTAVAIL );
*capabilityInfoPtrPtr = capabilityInfoPtr;
return( CRYPT_OK );
}
/* Add the components of an issuerAndSerialnumber to a certificate
template */
static int addIAndSToTemplate( CK_ATTRIBUTE *certTemplate,
const void *iAndSPtr, const int iAndSLength,
DYNBUF *iAndSDB,
const CRYPT_HANDLE iCryptHandle )
{
STREAM stream;
void *dataPtr = DUMMY_INIT_PTR;
int length, cryptStatus;
assert( isWritePtr( certTemplate, sizeof( CK_ATTRIBUTE ) * 2 ) );
assert( ( iAndSPtr == NULL && iAndSLength == 0 && \
isWritePtr( iAndSDB, sizeof( DYNBUF ) ) && \
isHandleRangeValid( iCryptHandle ) ) || \
( isReadPtr( iAndSPtr, iAndSLength ) && \
iAndSDB == NULL && iCryptHandle == CRYPT_UNUSED ) );
/* Get the issuerAndSerialNumber from the certificate if necessary */
if( iAndSDB != NULL )
{
cryptStatus = dynCreate( iAndSDB, iCryptHandle,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
}
/* Parse the data and add it to the template */
if( iAndSDB != NULL )
sMemConnect( &stream, dynData( *iAndSDB ), dynLength( *iAndSDB ) );
else
sMemConnect( &stream, iAndSPtr, iAndSLength );
readSequence( &stream, NULL );
cryptStatus = getStreamObjectLength( &stream, &length );
if( cryptStatusOK( cryptStatus ) ) /* Issuer DN */
{
certTemplate->ulValueLen = length;
cryptStatus = sMemGetDataBlock( &stream, &dataPtr, length );
}
if( cryptStatusOK( cryptStatus ) )
{
certTemplate->pValue = dataPtr;
cryptStatus = sSkip( &stream, length );
}
if( cryptStatusOK( cryptStatus ) )
{
certTemplate; /* Move on to next entry */
cryptStatus = getStreamObjectLength( &stream, &length );
}
if( cryptStatusOK( cryptStatus ) ) /* Serial number */
{
certTemplate->ulValueLen = length;
cryptStatus = sMemGetDataBlock( &stream, &dataPtr, length );
}
if( cryptStatusOK( cryptStatus ) )
{
certTemplate->pValue = dataPtr;
cryptStatus = sSkip( &stream, length );
}
sMemDisconnect( &stream );
if( cryptStatusError( cryptStatus ) )
{
assert( DEBUG_WARN );
if( iAndSDB != NULL )
dynDestroy( iAndSDB );
return( cryptStatus );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -