📄 dev_capi.c
字号:
/* Set the two exponents to 1 */
*keyBlobPtr++ = 1;
memset( keyBlobPtr, 0, bitLen16 - 1 );
keyBlobPtr += bitLen16 - 1;
*keyBlobPtr++ = 1;
memset( keyBlobPtr, 0, bitLen16 - 1 );
keyBlobPtr += bitLen16 - 1;
/* Set the private exponent to 1 */
keyBlobPtr += bitLen16; /* Skip coefficient */
*keyBlobPtr++ = 1;
memset( keyBlobPtr, 0, bitLen16 - 1 );
keyBlobPtr += bitLen16 - 1;
/* Finally, import the hacked key and clean up */
status = pCryptImportKey( hProv, keyBlob, keyBlobLen, 0, 0, hPrivateKey );
if( status )
*privateKeySize = pubKeyPtr->bitlen / 8;
else
*hPrivateKey = 0;
zeroise( keyBlob, keyBlobLen );
return( status ? CRYPT_OK : CRYPT_ERROR );
}
/* Import a raw session key using the exponent-one RSA key */
static int importPlainKey( const HCRYPTPROV hProv,
const HCRYPTKEY hPrivateKey,
const privateKeySize, HCRYPTKEY *hSessionKey,
const CRYPT_ALGO_TYPE cryptAlgo, const BYTE *keyData,
const int keyDataSize )
{
BLOBHEADER *blobHeaderPtr;
BYTE keyBlob[ 1024 ], *keyBlobPtr;
struct {
const CRYPT_ALGO_TYPE cryptAlgo;
const ALG_ID algID;
} algoMap[] = {
{ CRYPT_ALGO_DES, CALG_DES },
{ CRYPT_ALGO_3DES, CALG_3DES },
{ CRYPT_ALGO_RC2, CALG_RC2 },
{ CRYPT_ALGO_RC4, CALG_RC4 },
{ CRYPT_ALGO_SKIPJACK, CALG_SKIPJACK },
{ CRYPT_ALGO_NONE, 0 }
};
ALG_ID algID;
DWORD *dwPtr;
const int blobSize = sizeof( BLOBHEADER ) + sizeof( ALG_ID ) + privateKeySize;
int i, status;
for( i = 0; algoMap[ i ].cryptAlgo != CRYPT_ALGO_NONE; i++ )
if( algoMap[ i ].cryptAlgo == cryptAlgo )
break;
if( algoMap[ i ].cryptAlgo == CRYPT_ALGO_NONE )
return( CRYPT_ERROR_NOTAVAIL );
algID = algoMap[ i ].algID;
/* Set up a SIMPLEBLOB:
Ofs Value
0 PUBLICKEYSTRUC publickeystruc {
0 BYTE bType;
1 BYTE bVersion;
2 WORD reserved;
4 ALG_ID aiKeyAlg; }
8 ALG_ID algid;
12 BYTE encryptedkey[ rsapubkey.bitlen/8 ]; */
memset( keyBlob, 0, 1024 );
/* Set up the PUBLICKEYSTRUC part of the blob */
blobHeaderPtr = ( BLOBHEADER * ) keyBlob;
blobHeaderPtr->bType = SIMPLEBLOB;
blobHeaderPtr->bVersion = 2;
blobHeaderPtr->aiKeyAlg = algID;
/* Set up the private-key algorithm ID */
dwPtr = ( DWORD * )( keyBlob + 8 );
*dwPtr = CALG_RSA_KEYX;
/* Store the key as byte-reversed PKCS #1 padded data (or at least close
enough to it to work for the import) */
keyBlobPtr = keyBlob + 12;
for( i = keyDataSize - 1; i >= 0; i-- )
*keyBlobPtr++ = keyData[ i ];
*keyBlobPtr++ = 0;
memset( keyBlobPtr, 2, privateKeySize - ( keyDataSize + 2 ) );
/* Import the key from the faked PKCS #1 wrapped form */
status = pCryptImportKey( hProv, keyBlob, blobSize, hPrivateKey, 0, hSessionKey );
zeroise( keyBlob, blobSize );
return( status ? CRYPT_OK : CRYPT_ERROR_FAILED );
}
/****************************************************************************
* *
* 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 );
/* Prototypes for device-specific functions */
static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
const int length );
/* 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 );
}
cryptoapiInfo->hProv = CRYPT_ERROR;
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;
char providerNameBuffer[ CRYPT_MAX_TEXTSIZE + 1 ];
char keysetNameBuffer[ CRYPT_MAX_TEXTSIZE + 1 ];
const char *keysetName = NULL;
DWORD value;
int i, driverNameLength = nameLength, status;
/* Check whether a keyset name has been specified */
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->labelBuffer, &value, 0 ) )
return( mapError( cryptoapiInfo, CRYPT_ERROR_NOTFOUND ) );
deviceInfo->label = cryptoapiInfo->labelBuffer;
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 );
}
return( CRYPT_OK );
}
/* Handle device control functions */
static int controlFunction( DEVICE_INFO *deviceInfo,
const CRYPT_ATTRIBUTE_TYPE type,
const void *data, const int dataLength )
{
#if 0
/* Handle user authorisation */
if( type == CRYPT_DEVINFO_AUTHENT_USER || \
type == CRYPT_DEVINFO_AUTHENT_SUPERVISOR )
{
/* If the user is already logged in, log them out before we try
logging in with a new authentication value */
if( deviceInfo->flags & DEVICE_LOGGEDIN )
{
C_Logout( cryptoapiInfo->hProv );
deviceInfo->flags &= ~DEVICE_LOGGEDIN;
}
/* Authenticate the user to the device */
status = C_Login( cryptoapiInfo->hProv,
( type == CRYPT_DEVINFO_AUTHENT_USER ) ? \
CKU_USER : CKU_SO, ( CK_CHAR_PTR ) data,
( CK_ULONG ) dataLength );
if( status != CKR_OK && status != CKR_USER_ALREADY_LOGGED_IN )
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
/* The device is now ready for use */
deviceInfo->flags |= DEVICE_LOGGEDIN;
return( CRYPT_OK );
}
/* Handle authorisation value change */
#if 0 /* 24/11/02 Removed to see if it's still used by anyone */
if( type == CRYPT_DEVINFO_SET_AUTHENT_USER || \
type == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR )
{
status = C_SetPIN( cryptoapiInfo->hProv, ( CK_CHAR_PTR ) data2,
( CK_ULONG ) data2Length, ( CK_CHAR_PTR ) data,
( CK_ULONG ) dataLength );
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
}
#endif /* 0 */
/* Handle initialisation and zeroisation */
if( type == CRYPT_DEVINFO_INITIALISE || \
type == CRYPT_DEVINFO_ZEROISE )
{
CK_SESSION_HANDLE hSession;
CK_CHAR label[ 32 ];
/* If there's a session active with the device, log out and terminate
the session, since the token init will reset this */
if( cryptoapiInfo->hProv != CRYPT_ERROR )
{
C_Logout( cryptoapiInfo->hProv );
C_CloseSession( cryptoapiInfo->hProv );
}
cryptoapiInfo->hProv = CRYPT_ERROR;
/* Initialise/clear the device */
memset( label, ' ', 32 );
status = C_InitToken( deviceInfo->slotHandle,
( CK_CHAR_PTR ) data,
( CK_ULONG ) dataLength, label );
if( status != CKR_OK )
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
/* Reopen the session with the device */
status = C_OpenSession( deviceInfo->slotHandle,
CKF_RW_SESSION | CKF_SERIAL_SESSION,
NULL_PTR, NULL_PTR, &hSession );
if( status != CKR_OK )
return( mapError( deviceInfo, status, CRYPT_ERROR_OPEN ) );
cryptoapiInfo->hProv = hSession;
/* If it's a straight zeroise, we're done */
if( type == CRYPT_DEVINFO_ZEROISE )
return( CRYPT_OK );
/* We're initialising it, log in as supervisor and set the initial
user PIN to the same as the SSO PIN. We do this because the init
user PIN functionality is a bit of an oddball function that has
to fill the gap between C_InitToken() (which sets the SSO PIN) and
C_SetPIN() (which can only set the SSO PIN for the SSO or the user
PIN for the user). Setting the user PIN by the SSO, which is
usually required to perform any useful (non-administrative)
function with the token, requires the special-case C_InitPIN().
Since the token will initially be used by the SSO we set it to the
same as the SSO PIN and rely on the SSO to change it before they
hand it over to the user. In most cases the user *is* the SSO, so
this ensures that the device behaves as expected when the user
isn't even aware that there are SSO and user roles. A useful
side-effect of this is that it also eliminates problems with
some devices that can behave somewhat strangely if the SSO PIN is
set but the user PIN isn't */
status = C_Login( cryptoapiInfo->hProv, CKU_SO,
( CK_CHAR_PTR ) data, ( CK_ULONG ) dataLength );
if( status == CKR_OK )
status = C_InitPIN( cryptoapiInfo->hProv,
( CK_CHAR_PTR ) data,
( CK_ULONG ) dataLength );
if( status != CKR_OK )
{
C_Logout( cryptoapiInfo->hProv );
C_CloseSession( cryptoapiInfo->hProv );
cryptoapiInfo->hProv = CRYPT_ERROR;
return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
}
/* We're logged in and ready to go */
deviceInfo->flags |= DEVICE_LOGGEDIN;
return( CRYPT_OK );
}
#endif
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL ); /* Get rid of compiler warning */
}
/****************************************************************************
* *
* Misc.Device Interface Routines *
* *
****************************************************************************/
/* Get random data from the device */
static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -