📄 devices.c
字号:
/* Make it a persistent object and load a key */
status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_LABEL,
SYMMETRIC_KEY_LABEL,
strlen( SYMMETRIC_KEY_LABEL ) );
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptContext, CRYPT_CTXINFO_PERSISTENT,
TRUE );
if( cryptStatusError( status ) )
{
printf( "\nCouldn't make device context persistent, status = %d, "
"line %d.\n", status, __LINE__ );
return( FALSE );
}
status = cryptGenerateKey( cryptContext );
if( cryptStatusError( status ) )
{
printf( "\nCouldn't load key into persistent context, status = %d, "
"line %d.\n", status, __LINE__ );
return( FALSE );
}
puts( " succeeded." );
/* Destroy the context. Since it's persistent, it'll still be present
in the device */
cryptDestroyContext( cryptContext );
/* Recreate the object from the device */
printf( "Reading back symmetric key..." );
status = cryptGetKey( cryptDevice, &cryptContext, CRYPT_KEYID_NAME,
SYMMETRIC_KEY_LABEL, NULL );
if( cryptStatusError( status ) )
{
printf( "\nRead of symmetric key failed, status = %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
puts( " succeeded." );
/* Re-destroy it and make sure that it's still there afterwards. This
tests the persistence of read-back objects vs. created objects */
cryptDestroyContext( cryptContext );
printf( "Re-reading back symmetric key..." );
status = cryptGetKey( cryptDevice, &cryptContext, CRYPT_KEYID_NAME,
SYMMETRIC_KEY_LABEL, NULL );
if( cryptStatusError( status ) )
{
printf( "\nRe-read of symmetric key failed, status = %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
puts( " succeeded." );
/* Perform an encrypt/decrypt test with the recreated object */
printf( "Performing encryption test with recovered key..." );
status = testCrypt( cryptContext, cryptContext, NULL, TRUE, FALSE );
if( cryptStatusError( status ) )
return( FALSE );
puts( " succeeded." );
/* Clean up. Unlike the public/private keys which are reused for
various tests, this object isn't really useful for anything else so
we always clean it up once we're done */
cryptDestroyContext( cryptContext );
deleteTestKey( cryptDevice, SYMMETRIC_KEY_LABEL, NULL );
return( TRUE );
}
static BOOLEAN testDeviceHighlevel( const CRYPT_DEVICE cryptDevice,
const CRYPT_DEVICE_TYPE deviceType,
const char *keyLabel,
const char *password,
const BOOLEAN isWriteProtected )
{
CRYPT_CONTEXT pubKeyContext, privKeyContext, sigKeyContext;
int status;
if( !isWriteProtected && TEST_KEYGEN )
{
const CRYPT_ALGO_TYPE cryptAlgo = \
( deviceType == CRYPT_DEVICE_FORTEZZA ) ? \
CRYPT_ALGO_DSA : CRYPT_ALGO_RSA;
if( deviceType != CRYPT_DEVICE_CRYPTOAPI )
{
/* Create a CA key in the device */
if( !createKey( cryptDevice, cryptAlgo, "CA",
( deviceType == CRYPT_DEVICE_PKCS11 ) ? \
"dp_cacert" : "df_cacert", CRYPT_UNUSED ) )
return( FALSE );
/* Read back the CA key for use in generating end entity certs */
status = cryptGetPrivateKey( cryptDevice, &sigKeyContext,
CRYPT_KEYID_NAME,
TEXT( "Test CA key" ), NULL );
}
else
{
/* CryptoAPI can only store one private key per provider so we
can't have both a CA key and user key in the same "device".
Because of this we have to use the fixed CA key to issue the
cert */
status = getPrivateKey( &sigKeyContext, CA_PRIVKEY_FILE,
CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
}
if( cryptStatusError( status ) )
{
printf( "\nRead of CA key failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
/* Create end-entity certificate(s) for keys using the previously-
generated CA key. If it's a Fortezza card and we're using KEA we
have to generate two sets of keys/certs, one for signing and one
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 certificate is invalid, status %d, "
"line %d.\n", status, __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 )
{
char emailAddress[ CRYPT_MAX_TEXTSIZE + 1 ];
int length;
if( !testEnvelopePKCCryptEx( pubKeyContext, cryptDevice ) )
return( FALSE );
if( !testCMSEnvelopePKCCryptEx( pubKeyContext, cryptDevice,
password, NULL ) )
return( FALSE );
cryptSetAttribute( pubKeyContext, CRYPT_ATTRIBUTE_CURRENT,
CRYPT_CERTINFO_SUBJECTALTNAME );
status = cryptGetAttributeString( pubKeyContext, CRYPT_CERTINFO_EMAIL,
emailAddress, &length );
if( cryptStatusError( status ) )
{
printf( "Couldn't read recipient address from certificate, "
"status %d, line %d.\n", status, __LINE__ );
return( FALSE );
}
emailAddress[ length ] = '\0';
if( !testCMSEnvelopePKCCryptEx( CRYPT_UNUSED, cryptDevice,
password, emailAddress ) )
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." );
/* Test persistent (non-public-key) object creation */
if( !isWriteProtected && TEST_KEYGEN )
{
if( !testPersistentObject( cryptDevice ) )
return( FALSE );
}
/* 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 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, 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 ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -