📄 fortezza.c
字号:
use a different string we remember it with the device info so we
can load LEAF-less IV's */
status = pCI_DeleteKey( 1 );
if( status == CI_OK )
status = pCI_GenerateMEK( 1, 0 );
if( status == CI_OK )
status = pCI_SetKey( 1 );
if( status == CI_OK )
status = pCI_GenerateIV( ivBuffer );
memcpy( fortezzaInfo->leafString, ( status == CI_OK ) ? \
ivBuffer : "THIS IS NOT LEAF", 16 );
pCI_DeleteKey( 1 );
/* The device is now ready for use */
deviceInfo->flags |= DEVICE_LOGGEDIN;
krnlSendMessage( deviceInfo->objectHandle, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED, CRYPT_IATTRIBUTE_INITIALISED );
return( CRYPT_OK );
}
/* Handle authorisation value change. Fortezza uses a multi-stage
bootstrap FSM and requires that all of the various intialisation
functions be used one after the other, with no intervening operations
apart from setting the PAA (CA root) certificate in the SSO
initialised state. Interrupting the process (for example by logging
off/closing the device) requires that it be restarted from scratch:
uninitialised
v
CI_Zeroize (enter zeroise PIN)
v
zeroised
v
CI_CheckPIN (enter init PIN)
v
initialised
v
CI_ChangePIN (set SSO PIN)
v
SSO initialised
v
CI_ChangePIN (set user PIN)
v
user initialised
The single-sequence requirement means that the initialised -> SSO
initialised step re-uses the PIN set at initialisation, and the SSO
initialised -> user initialised uses the same PIN as the old and new
PIN, since there's no user PIN set at that point. Once we've set the
initial user PIN, the card is automagically moved into the user
initialised state */
if( type == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR )
{
CI_PIN oldPIN, newPIN;
/* Make sure that the PIN is within range */
if( dataLength < fortezzaInfo->minPinSize || \
dataLength > fortezzaInfo->maxPinSize )
return( CRYPT_ARGERROR_NUM1 );
/* Make sure that there's an SSO PIN present from a previous device
initialisation */
if( fortezzaInfo->initPinLen <= 0 )
{
setErrorInfo( deviceInfo, CRYPT_DEVINFO_INITIALISE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* This assumes that we're in the initialised state and are setting
the initial SSO PIN to move us into the SSO initialised state,
for which oldPIN == initialisation PIN. Once we've done this we
clear the initialisation PIN, since it's no longer valid in the
new state */
initPIN( oldPIN, fortezzaInfo->initPin, fortezzaInfo->initPinLen );
initPIN( newPIN, data, dataLength );
status = pCI_ChangePIN( CI_SSO_PIN, oldPIN, newPIN );
zeroise( fortezzaInfo->initPin, CRYPT_MAX_TEXTSIZE );
return( ( status == CI_FAIL ) ? CRYPT_ERROR_WRONGKEY : \
mapError( status, CRYPT_ERROR_WRONGKEY ) );
}
if( type == CRYPT_DEVINFO_SET_AUTHENT_USER )
{
CI_PIN oldPIN, newPIN;
/* Make sure that the PIN is within range */
if( dataLength < fortezzaInfo->minPinSize || \
dataLength > fortezzaInfo->maxPinSize )
return( CRYPT_ARGERROR_NUM1 );
/* This assumes that we're in the SSO initialised state and are
setting the initial user PIN to move us into the user initialised
state, for which oldPIN == newPIN */
initPIN( oldPIN, data, dataLength );
initPIN( newPIN, data, dataLength );
status = pCI_ChangePIN( CI_USER_PIN, oldPIN, newPIN );
return( ( status == CI_FAIL ) ? CRYPT_ERROR_WRONGKEY : \
mapError( status, CRYPT_ERROR_WRONGKEY ) );
}
/* Handle initialisation */
if( type == CRYPT_DEVINFO_INITIALISE )
{
CI_RANDOM randomBuffer;
CI_STATE deviceState;
CI_PIN pin;
/* Make sure that the PIN is within range */
if( dataLength < fortezzaInfo->minPinSize || \
dataLength > fortezzaInfo->maxPinSize )
return( CRYPT_ARGERROR_NUM1 );
/* Make sure that the device is in the uninitialised state */
status = pCI_GetState( &deviceState );
if( status != CI_OK || deviceState != CI_UNINITIALIZED )
return( CRYPT_ERROR_INITED );
/* Log on with the SSO PIN */
initPIN( pin, data, dataLength );
status = pCI_CheckPIN( CI_SSO_PIN, pin );
if( status != CI_OK )
return( mapError( status, CRYPT_ERROR_FAILED ) );
/* Load the random number seed and storage key from the device's
RNG output and make sure that the card has now in the
initialised state */
status = pCI_GenerateRandom( randomBuffer );
if( status == CI_OK )
status = pCI_LoadInitValues( randomBuffer,
randomBuffer + sizeof( CI_RANDSEED ) );
zeroise( randomBuffer, sizeof( CI_RANDOM ) );
if( status == CI_OK )
status = pCI_GetState( &deviceState );
if( status != CI_OK )
return( mapError( status, CRYPT_ERROR_FAILED ) );
if( deviceState != CI_INITIALIZED )
return( CRYPT_ERROR_FAILED );
/* Remember the initialisation PIN for a future CI_ChangePIN() */
memcpy( fortezzaInfo->initPin, data, dataLength );
fortezzaInfo->initPinLen = dataLength;
return( CRYPT_OK );
}
/* Handle zeroisation */
if( type == CRYPT_DEVINFO_ZEROISE )
{
CI_STATE deviceState;
CI_PIN pin;
/* Make sure that the PIN is within range */
if( dataLength < fortezzaInfo->minPinSize || \
dataLength > fortezzaInfo->maxPinSize )
return( CRYPT_ARGERROR_NUM1 );
/* Zeroise the card */
status = pCI_Zeroize();
if( status != CI_OK )
return( mapError( status, CRYPT_ERROR_FAILED ) );
status = pCI_GetState( &deviceState );
if( status != CI_OK )
return( mapError( status, CRYPT_ERROR_FAILED ) );
if( deviceState != CI_ZEROIZED )
return( CRYPT_ERROR_FAILED );
/* Clear any in-memory state information that we were holding about
the card */
memset( fortezzaInfo->personalities, 0,
fortezzaInfo->personalityCount * sizeof( CI_PERSON ) );
memset( fortezzaInfo->certHashes, 0,
fortezzaInfo->personalityCount * sizeof( CI_HASHVALUE ) );
fortezzaInfo->certHashesInitialised = FALSE;
fortezzaInfo->currentPersonality = CRYPT_ERROR;
/* Log on with the zeroise PIN to move it into the uninitialised
state */
initPIN( pin, data, dataLength );
status = pCI_CheckPIN( CI_SSO_PIN, pin );
return( mapError( status, CRYPT_ERROR_WRONGKEY ) );
}
/* Handle high-reliability time */
if( type == CRYPT_IATTRIBUTE_TIME )
{
CI_TIME cardTime;
time_t *timePtr = ( time_t * ) data, theTime;
status = pCI_GetTime( cardTime );
if( status != CI_OK )
return( mapError( status, CRYPT_ERROR_FAILED ) );
if( ( theTime = getTokenTime( cardTime ) ) <= MIN_TIME_VALUE )
return( CRYPT_ERROR_NOTAVAIL );
*timePtr = getTime();
return( CRYPT_OK );
}
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 )
{
CI_RANDOM randomBuffer;
BYTE *bufPtr = buffer;
int count, status = CRYPT_ERROR_RANDOM;
/* Get as many 20-byte blocks as required to fill the request */
for( count = 0; count < length; count += 20 )
{
const int noBytes = min( 20, length - count );
status = pCI_GenerateRandom( randomBuffer );
if( status != CI_OK )
break;
memcpy( bufPtr, randomBuffer, noBytes );
bufPtr += noBytes;
}
zeroise( randomBuffer, 20 );
return( mapError( status, 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,
and the cryptlib native object will probably be faster anyway */
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 )
{
CRYPT_CERTIFICATE iCryptCert = DUMMY_INIT;
CRYPT_ALGO_TYPE cryptAlgo = CRYPT_ALGO_NONE;
static const int keySize = 128;
const CAPABILITY_INFO *capabilityInfoPtr;
FORTEZZA_INFO *fortezzaInfo = deviceInfo->deviceFortezza;
CI_PERSON *personality;
CI_CERTIFICATE certificate;
MESSAGE_DATA msgData;
BOOLEAN certPresent = TRUE;
int certIndex, status;
assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
itemType == KEYMGMT_ITEM_PRIVATEKEY );
assert( keyIDtype == CRYPT_KEYID_NAME );
/* Find the referenced personality on the device and determine the
algorithm type for the key */
certIndex = findCertificateFromLabel( fortezzaInfo, keyID, keyIDlength );
if( certIndex == CRYPT_ERROR )
return( CRYPT_ERROR_NOTFOUND );
if( flags & KEYMGMT_FLAG_CHECK_ONLY )
/* If we're just checking whether an object exists, return now */
return( CRYPT_OK );
personality = getPersonality( fortezzaInfo, certIndex );
if( flags & KEYMGMT_FLAG_LABEL_ONLY )
{
/* All we want is the key label, copy it back to the caller and
exit */
*auxInfoLength = strlen( personality->CertLabel + 8 );
if( auxInfo != NULL )
memcpy( auxInfo, personality->CertLabel + 8, *auxInfoLength );
return( CRYPT_OK );
}
status = pCI_GetCertificate( certIndex, certificate );
if( status != CI_OK )
return( mapError( status, CRYPT_ERROR_READ ) );
if( !memcmp( personality->CertLabel, "TEMP", 4 ) )
{
STREAM stream;
/* It's a work in progress, read the algorithm from the start of the
public key data */
sMemConnect( &stream, certificate, 128 );
status = readSequence( &stream, NULL );
if( !cryptStatusError( status ) )
status = readAlgoID( &stream, &cryptAlgo );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
/* Remember that there's no certificate available for this key */
certPresent = FALSE;
}
else
{
/* It's a certificate, determine the algorithm type from the label */
if( !memcmp( personality->CertLabel, "DSA", 3 ) || \
!memcmp( personality->CertLabel, "CAX", 3 ) || \
!memcmp( personality->CertLabel, "PCA", 3 ) || \
!memcmp( personality->CertLabel, "PAA", 3 ) )
cryptAlgo = CRYPT_ALGO_DSA;
else
{
if( !memcmp( personality->CertLabel, "KEA", 3 ) )
cryptAlgo = CRYPT_ALGO_KEA;
else
return( CRYPT_ERROR_BADDATA );
}
}
capabilityInfoPtr = findCapabilityInfo( deviceInfo->capabilityInfoList,
cryptAlgo );
if( capabilityInfoPtr == NULL )
return( CRYPT_ERROR_NOTAVAIL );
/* If we're after a private key, make sure that it really is a private
key. This check isn't completely effective since the CA labels
don't identify the presence of a private key */
if( personality->CertLabel[ 4 ] == 'X' && \
itemType == KEYMGMT_ITEM_PRIVATEKEY )
return( CRYPT_ERROR_NOTFOUND );
/* Try and create a certificate chain that matches the key. The process
is as follows:
if public key
if certificate
create native certificate chain (+key) object
else
create device pubkey object,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -