📄 devices.c
字号:
debugDump( dumpName, certBuffer, certificateLength );
}
/* Update the key with the cert */
printf( "Updating device with certificate..." );
status = cryptAddPublicKey( cryptDevice, cryptCert );
cryptDestroyCert( cryptCert );
if( cryptStatusError( status ) )
{
printf( "\ncryptAddPublicKey() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
puts( " succeeded." );
return( TRUE );
}
/****************************************************************************
* *
* Device Logon/Initialisation *
* *
****************************************************************************/
/* Print information about a device and log in if necessary */
static const DEVICE_CONFIG_INFO *checkLogonDevice( const CRYPT_DEVICE cryptDevice,
const CRYPT_DEVICE_TYPE deviceType,
const DEVICE_CONFIG_INFO *deviceInfo,
const BOOLEAN isAutoDetect,
const BOOLEAN willInitialise )
{
char tokenLabel[ CRYPT_MAX_TEXTSIZE + 1 ];
int loggedOn, tokenLabelSize, status;
/* Tell the user what we're talking to */
status = cryptGetAttributeString( cryptDevice, CRYPT_DEVINFO_LABEL,
tokenLabel, &tokenLabelSize );
if( cryptStatusError( status ) )
puts( "(Device doesn't appear to have a label)." );
else
{
tokenLabel[ tokenLabelSize ] = '\0';
printf( "Device label is '%s'.\n", tokenLabel );
}
/* Check whether the device corresponds to a known device. We do this
because some devices require specific test passwords and whatnot in
order to work */
if( isAutoDetect )
{
int i;
for( i = 1; pkcs11DeviceInfo[ i ].name != NULL; i++ )
if( tokenLabelSize == \
( int ) strlen( pkcs11DeviceInfo[ i ].name ) && \
!memcmp( pkcs11DeviceInfo[ i ].name, tokenLabel,
tokenLabelSize ) )
{
printf( "Found a match for pre-defined device '%s',\n"
" using pre-set parameters.\n",
pkcs11DeviceInfo[ i ].description );
deviceInfo = &pkcs11DeviceInfo[ i ];
break;
}
}
/* See if we need to authenticate ourselves */
status = cryptGetAttribute( cryptDevice, CRYPT_DEVINFO_LOGGEDIN,
&loggedOn );
if( cryptStatusError( status ) )
{
puts( "Couldn't obtain device login status." );
return( NULL );
}
if( loggedOn )
{
/* Device may not require a login, or has already been logged in
via a keypad or similar mechanism */
puts( "Device is already logged in, skipping login." );
return( deviceInfo );
}
/* Try and log in */
printf( "Logging on to the device..." );
status = cryptSetAttributeString( cryptDevice,
CRYPT_DEVINFO_AUTHENT_USER, deviceInfo->password,
strlen( deviceInfo->password ) );
if( status == CRYPT_ERROR_INITED )
{
/* Some devices may not require any login, in which case we're
done */
puts( " device is already logged in." );
return( deviceInfo );
}
if( status == CRYPT_ERROR_NOTINITED )
{
/* It's an uninitialised device, tell the user and exit */
puts( " device needs to be initialised." );
if( willInitialise )
return( deviceInfo );
printf( "cryptlib will not automatically initialise the device "
"during the self-test\n in case it contains data that "
"needs to be preserved or requires special\n steps to be "
"taken before the initialisation is performed. If you want "
"to\n initialise it, set TEST_INITIALISE_CARD at the top "
"of\n " __FILE__ " to a nonzero value.\n" );
return( NULL );
}
if( cryptStatusError( status ) )
{
printf( "\nDevice %s failed with error code %d, line %d.\n",
( status == CRYPT_ERROR_WRONGKEY ) ? \
"login" : "initialisation/setup", status, __LINE__ );
if( status == CRYPT_ERROR_WRONGKEY && willInitialise )
{
/* If we're going to initialise the card, being in the wrong (or
even totally uninitialised) state isn't an error */
puts( "This may be because the device isn't in the user-"
"initialised state, in which\n case the standard user "
"PIN can't be used to log on to it." );
return( deviceInfo );
}
if( isAutoDetect )
puts( "This may be because the auto-detection test uses a fixed "
"login value rather\n than one specific to the device "
"type." );
return( NULL );
}
puts( " succeeded." );
return( deviceInfo );
}
/* Initialise a device. Note that when doing this with a Fortezza card,
these operations have to be done in a more or less continuous sequence
(i.e. without an intervening device open call) because it's not possible
to escape from some of the states if the card is closed and reopened in
between. In addition the PKCS #11 interface maps some of the
initialisation steps differently than the CI interface, so we have to
special-case this below */
static BOOLEAN initialiseDevice( const CRYPT_DEVICE cryptDevice,
const CRYPT_DEVICE_TYPE deviceType,
const DEVICE_CONFIG_INFO *deviceInfo )
{
const char *defaultSSOPIN = ( deviceType == CRYPT_DEVICE_FORTEZZA ) ? \
FORTEZZA_SSO_DEFAULT_PIN : \
deviceInfo->password;
const char *ssoPIN = ( deviceType == CRYPT_DEVICE_FORTEZZA ) ? \
FORTEZZA_SSO_PIN : deviceInfo->password;
const char *userPIN = deviceInfo->password;
int status;
/* PKCS #11 doesn't distinguish between zeroisation and initialisation,
so we only perform the zeroise test if it's a Fortezza card */
if( deviceType == CRYPT_DEVICE_FORTEZZA )
{
printf( "Zeroising device..." );
status = cryptSetAttributeString( cryptDevice,
CRYPT_DEVINFO_ZEROISE, FORTEZZA_ZEROISE_PIN,
strlen( FORTEZZA_ZEROISE_PIN ) );
if( cryptStatusError( status ) )
{
printf( "\nZeroise failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
puts( " succeeded." );
}
/* Initialise the device and set the SO PIN. */
printf( "Initialising device..." );
status = cryptSetAttributeString( cryptDevice, CRYPT_DEVINFO_INITIALISE,
defaultSSOPIN, strlen( defaultSSOPIN ) );
if( cryptStatusError( status ) )
{
printf( "\nCouldn't initialise device, status = %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
puts( " succeeded." );
printf( "Setting SO PIN to '%s'...", ssoPIN );
status = cryptSetAttributeString( cryptDevice,
CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR,
ssoPIN, strlen( ssoPIN ) );
if( cryptStatusError( status ) )
{
printf( "\nCouldn't set SO PIN, status = %d, line %d.\n", status,
__LINE__ );
return( FALSE );
}
puts( " succeeded." );
/* If it's a Fortezza card, create a CA root key and install its cert.
We have to do it at this point because the operation is only allowed
in the SSO initialised state. In addition we can't use the card for
this operation because cert slot 0 is a data-only slot (that is, it
can't correspond to a key held on the card), so we create a dummy
external cert and use that */
if( deviceType == CRYPT_DEVICE_FORTEZZA )
{
CRYPT_CERTIFICATE cryptCert;
CRYPT_CONTEXT signContext;
printf( "Loading PAA certificate..." );
if( !loadDSAContexts( CRYPT_UNUSED, &signContext, NULL ) )
return( FALSE );
cryptCreateCert( &cryptCert, CRYPT_UNUSED,
CRYPT_CERTTYPE_CERTIFICATE );
status = cryptSetAttribute( cryptCert,
CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, signContext );
if( cryptStatusOK( status ) && \
!addCertFields( cryptCert, paaCertData ) )
return( FALSE );
if( cryptStatusOK( status ) )
status = cryptSignCert( cryptCert, signContext );
cryptDestroyContext( signContext );
if( cryptStatusError( status ) )
{
cryptDestroyCert( cryptCert );
printf( "\nCreation of certificate failed with error code %d, "
"line %d.\n", status, __LINE__ );
return( FALSE );
}
status = cryptAddPublicKey( cryptDevice, cryptCert );
cryptDestroyCert( cryptCert );
if( cryptStatusError( status ) )
{
printf( "\ncryptAddPublicKey() failed with error code %d, line "
"%d.\n", status, __LINE__ );
return( FALSE );
}
puts( " succeeded." );
}
/* Set the user PIN and log on as the user */
printf( "Setting user PIN to '%s'...", userPIN );
status = cryptSetAttributeString( cryptDevice,
CRYPT_DEVINFO_SET_AUTHENT_USER,
userPIN, strlen( userPIN ) );
if( cryptStatusOK( status ) )
{
int loggedOn;
/* Some devices automatically log the user in when they set the user
password, so we check to see if it's necessary to log in before we
actually do it */
status = cryptGetAttribute( cryptDevice, CRYPT_DEVINFO_LOGGEDIN,
&loggedOn );
if( cryptStatusError( status ) )
{
puts( "Couldn't obtain device login status." );
return( FALSE );
}
if( !loggedOn )
status = cryptSetAttributeString( cryptDevice,
CRYPT_DEVINFO_AUTHENT_USER,
userPIN, strlen( userPIN ) );
}
if( cryptStatusError( status ) )
{
printf( "\nCouldn't set user PIN/log on as user, status = %d, line "
"%d.\n", status, __LINE__ );
return( FALSE );
}
puts( " succeeded." );
return( TRUE );
}
/****************************************************************************
* *
* Device Tests *
* *
****************************************************************************/
/* Test the general capabilities of a device */
static BOOLEAN testDeviceCapabilities( const CRYPT_DEVICE cryptDevice,
const char *deviceName,
const BOOLEAN isWriteProtected )
{
CRYPT_ALGO_TYPE cryptAlgo;
int testCount = 0, failCount = 0;
printf( "Checking %s capabilities...\n", deviceName );
for( cryptAlgo = CRYPT_ALGO_FIRST_CONVENTIONAL;
cryptAlgo <= CRYPT_ALGO_LAST; cryptAlgo++ )
if( cryptStatusOK( cryptDeviceQueryCapability( cryptDevice,
cryptAlgo, NULL ) ) )
{
testCount++;
if( !testLowlevel( cryptDevice, cryptAlgo, isWriteProtected ) )
/* The test failed, we don't exit at this point but only
remember that there was a problem since we want to test
every possible algorithm */
failCount++;
}
if( isWriteProtected )
puts( "No tests were performed since the device is write-protected." );
else
if( failCount )
printf( "%d of %d test%s failed.\n", failCount, testCount,
( testCount > 1 ) ? "s" : "" );
else
puts( "Device capabilities test succeeded." );
return( ( failCount == testCount ) ? FALSE : TRUE );
}
/* Test the high-level functionality provided by a device */
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -