📄 ms_capi.c
字号:
return( mapError( cryptoapiInfo, CRYPT_ERROR_NOTFOUND ) );
if( !pCryptGetUserKey( hProv, dwKeySpec, &hKey ) )
return( mapError( cryptoapiInfo, CRYPT_ERROR_NOTFOUND ) );
*hKeyPtr = hKey;
return( CRYPT_OK );
}
#endif /* 0 */
/* Create a private-key context using a CryptoAPI native key */
static int createPrivkeyContext( DEVICE_INFO *deviceInfo,
CRYPT_CONTEXT *iCryptContext,
CRYPT_ALGO_TYPE *cryptAlgo,
const HCRYPTKEY hKey,
const char *label )
{
ALG_ID algID;
DWORD dwDataLen = sizeof( ALG_ID );
const CAPABILITY_INFO *capabilityInfoPtr = NULL;
MESSAGE_DATA msgData;
int status;
/* Clear return values */
*iCryptContext = CRYPT_ERROR;
*cryptAlgo = CRYPT_ALGO_NONE;
/* Get the algorithm type and look up the corresponding capability
info */
if( !pCryptGetKeyParam( hKey, KP_ALGID, ( BYTE * ) &algID, &dwDataLen,
0 ) || \
( *cryptAlgo = capiToCryptlibID( algID ) ) == CRYPT_ALGO_NONE )
return( CRYPT_ERROR_NOTAVAIL );
capabilityInfoPtr = findCapabilityInfo( deviceInfo->capabilityInfoList,
*cryptAlgo );
if( capabilityInfoPtr == NULL )
return( CRYPT_ERROR_NOTAVAIL );
/* Create a dummy context for the key, remember the device it's
contained in, the handle for the device-internal key, and the
object's label, and mark it as initialised (i.e. with a key loaded) */
status = createContextFromCapability( iCryptContext,
deviceInfo->ownerHandle, capabilityInfoPtr,
CREATEOBJECT_FLAG_DUMMY );
if( cryptStatusError( status ) )
return( status );
krnlSendMessage( *iCryptContext, IMESSAGE_SETDEPENDENT,
&deviceInfo->objectHandle, SETDEP_OPTION_INCREF );
krnlSendMessage( *iCryptContext, IMESSAGE_SETATTRIBUTE,
( void * ) &hKey, CRYPT_IATTRIBUTE_DEVICEOBJECT );
setMessageData( &msgData, ( void * ) label,
min( strlen( label ), CRYPT_MAX_TEXTSIZE ) );
krnlSendMessage( *iCryptContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_LABEL );
#if 0
if( cryptAlgo == CRYPT_ALGO_RSA )
/* Send the keying info to the context. This is only possible for
RSA keys since it's not possible to read y from a DSA private
key object (see the comments in the DSA code for more on this),
however the only time this is necessary is when a certificate is
being generated for a key that was pre-generated in the device by
someone else, which is typically done in Europe where DSA isn't
used so this shouldn't be a problem */
// Use getPubkeyComponents()
cryptStatus = rsaSetPublicComponents( deviceInfo, *iCryptContext,
hObject );
else
cryptStatus = krnlSendMessage( *iCryptContext, IMESSAGE_SETATTRIBUTE,
&keySize, CRYPT_IATTRIBUTE_KEYSIZE );
#endif
if( cryptStatusOK( status ) )
status = krnlSendMessage( *iCryptContext, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_IATTRIBUTE_INITIALISED );
if( cryptStatusError( status ) )
{
krnlSendNotifier( *iCryptContext, IMESSAGE_DECREFCOUNT );
return( status );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Device Init/Shutdown/Device Control Routines *
* *
****************************************************************************/
/* Prototypes for functions to get and free device capability information */
static int getCapabilities( DEVICE_INFO *deviceInfo );
static void freeCapabilities( DEVICE_INFO *deviceInfo );
/* Close a previously-opened session with the device. We have to have this
before the init function since it may be called by it if the init process
fails */
static void shutdownFunction( DEVICE_INFO *deviceInfo )
{
CRYPTOAPI_INFO *cryptoapiInfo = deviceInfo->deviceCryptoAPI;
/* Log out and close the session with the device */
if( deviceInfo->flags & DEVICE_LOGGEDIN )
{
if( cryptoapiInfo->hPrivateKey )
pCryptDestroyKey( cryptoapiInfo->hPrivateKey );
pCryptReleaseContext( cryptoapiInfo->hProv, 0 );
}
if( cryptoapiInfo->hCertStore != NULL )
{
pCertCloseStore( cryptoapiInfo->hCertStore, 0 );
cryptoapiInfo->hCertStore = 0;
}
cryptoapiInfo->hProv = HCRYPTPROV_NONE;
deviceInfo->flags &= ~( DEVICE_ACTIVE | DEVICE_LOGGEDIN );
/* Free the device capability information */
freeCapabilities( deviceInfo );
}
/* Open a session with the device */
static int initFunction( DEVICE_INFO *deviceInfo, const char *name,
const int nameLength )
{
CRYPTOAPI_INFO *cryptoapiInfo = deviceInfo->deviceCryptoAPI;
HCRYPTPROV hProv;
HCERTSTORE hCertStore;
char providerNameBuffer[ CRYPT_MAX_TEXTSIZE + 1 + 8 ];
char keysetNameBuffer[ CRYPT_MAX_TEXTSIZE + 1 + 8 ];
const char *keysetName = NULL;
DWORD value;
int i, driverNameLength = nameLength, status;
/* Check whether a keyset name has been specified */
strlcpy_s( keysetNameBuffer, CRYPT_MAX_TEXTSIZE, "MY" );/* Default keyset */
for( i = 1; i < nameLength - 1; i++ )
{
if( name[ i ] == ':' && name[ i + 1 ] == ':' )
{
const int keysetNameLength = nameLength - ( i + 2 );
if( i > CRYPT_MAX_TEXTSIZE || keysetNameLength <= 0 || \
keysetNameLength > CRYPT_MAX_TEXTSIZE )
return( CRYPT_ARGERROR_STR1 );
/* We've got a keyset name appended to the provider name, break
out the provider and keyset names */
memcpy( providerNameBuffer, name, i );
providerNameBuffer[ i ] = '\0';
memcpy( keysetNameBuffer, name + i + 2, keysetNameLength );
keysetNameBuffer[ keysetNameLength ] = '\0';
name = providerNameBuffer;
keysetName = keysetNameBuffer;
break;
}
}
/* If we're auto-detecting the device, try various choices */
if( driverNameLength == 12 && \
!strnicmp( "[Autodetect]", name, driverNameLength ) )
{
if( CryptAcquireContextA( &hProv, keysetName, MS_ENHANCED_PROV,
PROV_RSA_FULL, 0 ) )
cryptoapiInfo->hProv = hProv;
else
{
if( CryptAcquireContextA( &hProv, keysetName, MS_DEF_PROV,
PROV_RSA_FULL, 0 ) )
cryptoapiInfo->hProv = hProv;
else
return( mapError( cryptoapiInfo, CRYPT_ERROR_NOTFOUND ) );
}
}
else
{
/* Try and find a specific provider */
if( CryptAcquireContextA( &hProv, keysetName, name, PROV_RSA_FULL, 0 ) )
cryptoapiInfo->hProv = hProv;
}
/* Get information on device-specific capabilities */
value = CRYPT_MAX_TEXTSIZE + 1;
if( !CryptGetProvParam( cryptoapiInfo->hProv, PP_NAME,
cryptoapiInfo->label, &value, 0 ) )
return( mapError( cryptoapiInfo, CRYPT_ERROR_NOTFOUND ) );
cryptoapiInfo->labelLen = value;
deviceInfo->label = cryptoapiInfo->label;
deviceInfo->labelLen = cryptoapiInfo->labelLen;
deviceInfo->flags |= DEVICE_ACTIVE;
/* Set up the capability information for this device */
status = getCapabilities( deviceInfo );
if( cryptStatusError( status ) )
{
shutdownFunction( deviceInfo );
return( ( status == CRYPT_ERROR ) ? CRYPT_ERROR_OPEN : status );
}
/* Create the special-purpose key needed to allow symmetric key loads */
status = createExportKey( cryptoapiInfo->hProv,
&cryptoapiInfo->hPrivateKey,
&cryptoapiInfo->privateKeySize );
if( cryptStatusError( status ) )
{
shutdownFunction( deviceInfo );
return( status );
}
/* Open the certificate store used to store/retrieve certificates */
hCertStore = pCertOpenSystemStore( cryptoapiInfo->hProv,
keysetNameBuffer );
if( hCertStore == NULL )
{
shutdownFunction( deviceInfo );
return( CRYPT_ERROR_OPEN );
}
cryptoapiInfo->hCertStore = hCertStore;
return( CRYPT_OK );
}
/* Handle device control functions */
static int controlFunction( DEVICE_INFO *deviceInfo,
const CRYPT_ATTRIBUTE_TYPE type,
const void *data, const int dataLength,
MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
{
retIntError();
}
/****************************************************************************
* *
* Misc.Device Interface Routines *
* *
****************************************************************************/
/* Get random data from the device */
static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
const int length,
MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
{
CRYPTOAPI_INFO *cryptoapiInfo = deviceInfo->deviceCryptoAPI;
if( pCryptGenRandom( cryptoapiInfo->hProv, length, buffer ) )
return( CRYPT_OK );
return( mapError( cryptoapiInfo, CRYPT_ERROR_FAILED ) );
}
/* Instantiate an object in a device. This works like the create context
function but instantiates a cryptlib object using data already contained
in the device (for example a stored private key or certificate). If the
value being read is a public key and there's a certificate attached, the
instantiated object is a native cryptlib object rather than a device
object with a native certificate object attached because there doesn't
appear to be any good reason to create the public-key object in the
device.
CryptoAPI doesn't have any concept of multiple private keys, only a
default encryption + signature key for the provider as a whole, and an
optional additional signature key to complement the encryption (and
signature if necessary) one. In addition the ties between a private key
and its associated certificate(s) are rather tenuous, requiring jumping
through several levels of indirection in order to get from one to the
other. To handle this, we have to use a meet-in-the-middle approach
where we try to go from private key to certificate if the identity of the
private key is obvious (the user has specifically asked for a private
decryption or signature key), or from certificate to private key in all
other cases */
static int getItemFunction( DEVICE_INFO *deviceInfo,
CRYPT_CONTEXT *iCryptContext,
const KEYMGMT_ITEM_TYPE itemType,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
void *auxInfo, int *auxInfoLength,
const int flags )
{
CRYPTOAPI_INFO *cryptoapiInfo = deviceInfo->deviceCryptoAPI;
// CRYPT_CERTIFICATE iCryptCert;
HCRYPTKEY hKey = 0;
PCCERT_CONTEXT pCertContext = NULL;
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
DWORD dwKeySpec = 0;
CRYPT_CERTIFICATE iCryptCert;
CRYPT_ALGO_TYPE cryptAlgo = CRYPT_ALGO_NONE;
const char *label = "Private key";
int status;
assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
itemType == KEYMGMT_ITEM_PRIVATEKEY );
/* If we're searching for the key by label and the user has specified
one of the special-case key descriptions, get the appropriate key */
if( keyIDtype == CRYPT_KEYID_NAME )
{
if( keyIDlength == 13 && \
!memcmp( keyID, "Signature key", 13 ) )
dwKeySpec = AT_SIGNATURE;
else
if( keyIDlength == 14 && \
!memcmp( keyID, "Encryption key", 14 ) )
dwKeySpec = AT_KEYEXCHANGE;
}
/* If we haven't got a key type from the label and we're looking for a
particular usage, get the appropriate key */
if( dwKeySpec == 0 && itemType == KEYMGMT_ITEM_PRIVATEKEY )
{
if( flags & KEYMGMT_FLAG_USAGE_SIGN )
dwKeySpec = AT_SIGNATURE;
else
if( flags & KEYMGMT_FLAG_USAGE_CRYPT )
dwKeySpec = AT_KEYEXCHANGE;
}
/* If we still haven't got a key type, try and get the certificate for
the given ID */
if( dwKeySpec != 0 )
{
/* Get the required key type */
if( !pCryptGetUserKey( cryptoapiInfo->hProv, dwKeySpec, &hKey ) )
return( CRYPT_ERROR_NOTFOUND );
label = ( dwKeySpec == AT_SIGNATURE ) ? \
"Signature key" : "Encryption key";
/* If we're only doing a presence check, we don't need the key and
can exit */
if( flags & KEYMGMT_FLAG_CHECK_ONLY )
{
pCryptDestroyKey( hKey );
return( CRYPT_OK );
}
/* Since CryptoAPI doesn't have any concept of key labels, the best
that we can do is provide a generic description of the intended
key usage as a form of pseudo-label */
if( flags & KEYMGMT_FLAG_LABEL_ONLY )
{
strlcpy_s( auxInfo, *auxInfoLength, label );
*auxInfoLength = strlen( label );
pCryptDestroyKey( hKey );
return( CRYPT_OK );
}
/* We've got the key, try and get the associated certificate */
status = getCertificateFromKey( cryptoapiInfo, hKey,
( flags & KEYMGMT_FLAG_USAGE_SIGN ) ? \
TRUE : FALSE, &pCertContext );
if( cryptStatusError( status ) && \
itemType == KEYMGMT_ITEM_PUBLICKEY )
{
/* We couldn't get a certificate for the key, if we're after a
public key return it as a native context */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -