📄 devices.c
字号:
for encryption */
status = createKey( cryptDevice, cryptAlgo, "user",
( deviceType == CRYPT_DEVICE_PKCS11 ) ? \
"dp_usrcert" : "df_usrcert", sigKeyContext );
#ifdef USE_KEA
if( status && deviceType == CRYPT_DEVICE_FORTEZZA )
status = createKey( cryptDevice, CRYPT_ALGO_KEA, "KEA",
"df_keacert", sigKeyContext );
#endif /* USE_KEA */
cryptDestroyContext( sigKeyContext );
if( !status )
return( FALSE );
}
else
puts( "Skipping key generation test, this assumes that the device "
"contains pre-\n existing keys." );
/* See whether there are any existing keys or certs. Some tokens have
these built in and don't allow anything new to be created, after this
point the handling is somewhat special-case but we can at least report
their presence. Although generally we can re-use a private key
context for both public and private operations, some devices or drivers
(and by logical extension thereof the cryptlib kernel) don't allow
public-key ops with private keys so we have to eplicitly handle public
and private keys. This gets somewhat messy because some devices don't
have public keys but allow public-key ops with their private keys,
while others separate public and private keys and don't allow the
private key to do public-key ops */
status = cryptGetPublicKey( cryptDevice, &pubKeyContext,
CRYPT_KEYID_NAME, keyLabel );
if( cryptStatusOK( status ) )
{
int value;
puts( "Found a public key in the device, details follow..." );
printCertChainInfo( pubKeyContext );
if( cryptStatusOK( \
cryptGetAttribute( pubKeyContext,
CRYPT_CERTINFO_SELFSIGNED, &value ) ) && \
value )
{
/* It's a self-signed cert/cert chain, make sure that it's
valid. Because it's probably not trusted, we make it
temporarily implicitly trusted in order for the sig.check to
succeed */
status = cryptGetAttribute( pubKeyContext,
CRYPT_CERTINFO_TRUSTED_IMPLICIT, &value );
if( cryptStatusOK( status ) )
status = cryptSetAttribute( pubKeyContext,
CRYPT_CERTINFO_TRUSTED_IMPLICIT, 1 );
if( cryptStatusOK( status ) )
status = cryptCheckCert( pubKeyContext, CRYPT_UNUSED );
if( cryptStatusError( status ) )
{
printf( "Signature on public key certificate is invalid, "
"line %d.\n", __LINE__ );
return( FALSE );
}
cryptSetAttribute( pubKeyContext,
CRYPT_CERTINFO_TRUSTED_IMPLICIT, value );
}
}
else
{
puts( "Error: Couldn't locate public key in device." );
pubKeyContext = CRYPT_UNUSED;
}
status = cryptGetPrivateKey( cryptDevice, &privKeyContext,
CRYPT_KEYID_NAME, keyLabel, NULL );
if( cryptStatusOK( status ) )
{
puts( "Found a private key in the device, details follow..." );
printCertChainInfo( privKeyContext );
if( pubKeyContext == CRYPT_UNUSED )
{
/* No explicit public key found, try using the private key for
both key types */
puts( "No public key found, attempting to continue using the "
"private key as both a\n public and a private key." );
pubKeyContext = privKeyContext;
}
}
else
{
puts( "Error: Couldn't locate private key in device." );
privKeyContext = CRYPT_UNUSED;
}
sigKeyContext = privKeyContext;
if( deviceType == CRYPT_DEVICE_FORTEZZA )
{
cryptDestroyContext( pubKeyContext ); /* pubK is sig.only */
status = cryptGetPrivateKey( cryptDevice, &privKeyContext,
CRYPT_KEYID_NAME, "Test KEA key", NULL );
if( cryptStatusOK( status ) )
{
puts( "Found a key agreement key in the device, details follow..." );
printCertChainInfo( privKeyContext );
pubKeyContext = privKeyContext; /* Fortezza allows both uses */
}
else
{
pubKeyContext = CRYPT_UNUSED;
privKeyContext = CRYPT_UNUSED;
}
}
/* If we got something, try some simple operations with it */
if( pubKeyContext != CRYPT_UNUSED )
{
if( !testCMSEnvelopePKCCryptEx( pubKeyContext, cryptDevice, password ) )
return( FALSE );
}
else
puts( "Public-key enveloping tests skipped because no key was "
"available.\n" );
if( sigKeyContext != CRYPT_UNUSED )
{
if( !testCMSEnvelopeSignEx( sigKeyContext ) )
return( FALSE );
}
else
puts( "Signed enveloping tests skipped because no key was "
"available." );
/* Clean up */
if( pubKeyContext == CRYPT_UNUSED && sigKeyContext == CRYPT_UNUSED )
return( FALSE );
if( privKeyContext != CRYPT_UNUSED )
cryptDestroyContext( privKeyContext );
if( sigKeyContext != CRYPT_UNUSED && privKeyContext != sigKeyContext )
cryptDestroyContext( sigKeyContext );
if( pubKeyContext != CRYPT_UNUSED && pubKeyContext != privKeyContext )
cryptDestroyContext( pubKeyContext );
return( TRUE );
}
/* General device test routine */
static int testCryptoDevice( const CRYPT_DEVICE_TYPE deviceType,
const char *deviceName,
const DEVICE_CONFIG_INFO *deviceInfo )
{
CRYPT_DEVICE cryptDevice;
BOOLEAN isWriteProtected = FALSE, isAutoDetect = FALSE;
BOOLEAN initDevice = FALSE, testResult = FALSE, partialSuccess = FALSE;
int status;
/* Open a connection to the device */
if( deviceType == CRYPT_DEVICE_PKCS11 || \
deviceType == CRYPT_DEVICE_CRYPTOAPI )
{
if( !memcmp( deviceInfo->name, "[A", 2 ) )
{
printf( "\nTesting %s with autodetection...\n", deviceName );
isAutoDetect = TRUE;
}
else
printf( "\nTesting %s %s...\n", deviceInfo->name, deviceName );
status = cryptDeviceOpen( &cryptDevice, CRYPT_UNUSED, deviceType,
deviceInfo->name );
}
else
{
printf( "\nTesting %s...\n", deviceName );
status = cryptDeviceOpen( &cryptDevice, CRYPT_UNUSED, deviceType,
deviceName );
}
if( status == CRYPT_ERROR_PARAM2 )
{
puts( "Support for this device type isn't enabled in this build of "
"cryptlib." );
return( CRYPT_ERROR_NOTAVAIL ); /* Device access not available */
}
if( cryptStatusError( status ) )
{
if( status == CRYPT_ERROR_PARAM3 || status == CRYPT_ERROR_NOTFOUND )
puts( "Crypto device not detected, skipping test." );
else
printf( "cryptDeviceOpen() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
/* If it's one of the smarter classes of device, authenticate ourselves to
the device, which is usually required in order to allow it to be used
fully */
if( deviceType == CRYPT_DEVICE_PKCS11 || deviceType == CRYPT_DEVICE_FORTEZZA )
{
deviceInfo = checkLogonDevice( cryptDevice, deviceType, deviceInfo,
isAutoDetect, TEST_INITIALISE_CARD );
if( deviceInfo == NULL )
{
cryptDeviceClose( cryptDevice );
return( FALSE );
}
}
/* Write-protected devices won't allow contexts to be created in them,
before we try the general device capabilities test we make sure that
we can actually perform the operation */
if( deviceType == CRYPT_DEVICE_PKCS11 )
{
CRYPT_CONTEXT cryptContext;
/* Try and create a DES object. The following check for read-only
devices always works because the device object ACL is applied at
a much higher level than any device capability checking, the
device will never even see the create object message if it's
write-protected so all we have to do is make sure that whatever
we create is ephemeral */
status = cryptDeviceCreateContext( cryptDevice, &cryptContext,
CRYPT_ALGO_DES );
if( cryptStatusOK( status ) )
cryptDestroyContext( cryptContext );
if( status == CRYPT_ERROR_PERMISSION )
isWriteProtected = TRUE;
}
/* To force the code not to try to create keys and certs in a writeable
device, uncomment the following line of code. This requires that keys/
certs of the required type are already present in the device */
/* KLUDGE_WARN( "write-protect status" );
isWriteProtected = TRUE; */
if( !isWriteProtected && TEST_KEYGEN )
{
/* If it's a device that we can initialise, go through a full
initialisation */
if( deviceType != CRYPT_DEVICE_CRYPTOAPI && TEST_INITIALISE_CARD )
{
status = initialiseDevice( cryptDevice, deviceType,
deviceInfo );
if( status == FALSE )
{
cryptDeviceClose( cryptDevice );
return( FALSE );
}
}
else
{
/* There may be test keys lying around from an earlier run, in
which case we try to delete them to make sure they won't
interfere with the current one */
deleteTestKey( cryptDevice, "Test CA key", "CA" );
deleteTestKey( cryptDevice, deviceInfo->keyLabel, "user" );
if( deviceType == CRYPT_DEVICE_PKCS11 )
{
deleteTestKey( cryptDevice, RSA_PUBKEY_LABEL, "RSA public" );
deleteTestKey( cryptDevice, RSA_PRIVKEY_LABEL, "RSA private" );
deleteTestKey( cryptDevice, DSA_PUBKEY_LABEL, "DSA public" );
deleteTestKey( cryptDevice, DSA_PRIVKEY_LABEL, "DSA private" );
}
if( deviceType == CRYPT_DEVICE_FORTEZZA )
deleteTestKey( cryptDevice, "Test KEA key", "KEA" );
if( deviceType == CRYPT_DEVICE_CRYPTOAPI )
{
deleteTestKey( cryptDevice, "Encryption key", "RSA private" );
deleteTestKey( cryptDevice, "Signature key", "secondary RSA private" );
}
}
}
#ifdef TEST_DH
return( testLowlevel( cryptDevice, CRYPT_ALGO_DH, FALSE ) );
#endif /* TEST_DH */
/* Report what the device can do. This is intended mostly for simple
crypto accelerators and may fail with for devices that work only
with the higher-level functions centered around certificates,
signatures,and key wrapping, so we skip the tests for devices that
allow only high-level access */
#if TEST_ALGORITHMS
if( deviceType != CRYPT_DEVICE_FORTEZZA )
testResult = testDeviceCapabilities( cryptDevice, deviceName,
isWriteProtected );
#else
puts( "Skipping device algorithm tests." );
#endif /* TEST_ALGORITHMS */
/* If it's a smart device, try various device-specific operations */
if( deviceType == CRYPT_DEVICE_FORTEZZA || \
deviceType == CRYPT_DEVICE_PKCS11 || \
deviceType == CRYPT_DEVICE_CRYPTOAPI )
partialSuccess = testDeviceHighlevel( cryptDevice, deviceType,
deviceInfo->keyLabel, deviceInfo->password,
isWriteProtected );
/* Clean up */
status = cryptDeviceClose( cryptDevice );
if( cryptStatusError( status ) )
{
printf( "cryptDeviceClose() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
if( !testResult && !partialSuccess )
return( FALSE );
if( testResult && partialSuccess )
printf( "%s tests succeeded.\n\n", deviceName );
else
printf( "Some %s tests succeeded.\n\n", deviceName );
return( TRUE );
}
int testDevices( void )
{
int i, status;
/* Test Fortezza devices */
#if 0
status = testCryptoDevice( CRYPT_DEVICE_FORTEZZA, "Fortezza card",
&fortezzaDeviceInfo );
if( cryptStatusError( status ) && status != CRYPT_ERROR_NOTAVAIL )
return( status );
#endif /* 0 */
/* Test PKCS #11 devices */
#if 1
for( i = 0; pkcs11DeviceInfo[ i ].name != NULL; i++ )
{
status = testCryptoDevice( CRYPT_DEVICE_PKCS11, "PKCS #11 crypto token",
&pkcs11DeviceInfo[ i ] );
if( cryptStatusError( status ) && \
!( status == CRYPT_ERROR_NOTAVAIL || \
( i == 0 && status == CRYPT_ERROR_WRONGKEY ) ) )
return( status );
}
#endif /* 0 */
#if 0 /* For test purposes only to check CAPI data, don't use the CAPI code */
#ifdef __WINDOWS__
for( i = 0; capiDeviceInfo[ i ].name != NULL; i++ )
{
status = testCryptoDevice( CRYPT_DEVICE_CRYPTOAPI, "Microsoft CryptoAPI",
&capiDeviceInfo[ i ] );
if( cryptStatusError( status ) && \
!( status == CRYPT_ERROR_NOTAVAIL || \
( i == 0 && status == CRYPT_ERROR_WRONGKEY ) ) )
return( status );
}
#endif /* __WINDOWS__ */
#endif /* 0 */
putchar( '\n' );
return( TRUE );
}
/****************************************************************************
* *
* Full Device Initialisation Test *
* *
****************************************************************************/
/* The following code takes two unitialised devices and turns one into a
fully initialised CA device, which then runs a PnP PKI session that turns
the other into a fully initialised user device.
The following configuration options can be used to change the beaviour of
the self-test, for example to run it on the local machine in loopback mode
vs. running on two distinct machines. Defining an IP address (or host
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -