📄 dev_fort.c
字号:
/* Handle device control functions */
static int controlFunction( DEVICE_INFO *deviceInfo,
const CRYPT_ATTRIBUTE_TYPE type,
const void *data1, const int data1Length,
const void *data2, const int data2Length )
{
STATIC_FN int findCertificate( DEVICE_INFO *deviceInfo, const char *label,
const int labelLength );
int status;
/* Handle user authorisation */
if( type == CRYPT_DEVINFO_AUTHENT_USER || \
type == CRYPT_DEVINFO_AUTHENT_SUPERVISOR )
{
CI_PERSON *personalityList = deviceInfo->personalities;
CI_PIN pin;
BYTE ivBuffer[ 64 ]; /* For LEAF handling */
int certIndex;
initPIN( pin, data1, data1Length );
status = pCI_CheckPIN( ( type == CRYPT_DEVINFO_AUTHENT_USER ) ? \
CI_USER_PIN : CI_SSO_PIN, pin );
if( status != CI_OK )
return( ( status == CI_FAIL ) ? CRYPT_ERROR_WRONGKEY : \
mapError( status, CRYPT_ERROR_WRONGKEY ) );
/* Get the list of device personalities (skipping the zero-th
personality which can't be selected) and lock the device for our
exclusive use. We should really do this as soon as we open the
device to make sure the user isn't presented with any nasty
surprises due to state changes caused by other active sessions
with the device, but the driver won't let us do it until we've
authenticated ourselves to the device */
status = pCI_GetPersonalityList( deviceInfo->personalityCount - 1,
&personalityList[ 1 ] );
if( status == CI_OK )
{
int index;
/* Set a label for the zero-th personality (which can't be
explicitly accessed but whose cert can be read) to make sure
it isn't treated as an empty personality slot */
strcpy( personalityList[ 0 ].CertLabel,
"PAA1FFFFPersonality 0 dummy label" );
/* Perform a sanity check for certificate indices. The
documentation implies that the certificate index always
matches the personality index (skipping the zero-th
personality), but doesn't seem to mandate this anywhere so
we make sure things really are set up this way */
for( index = 0; index < deviceInfo->personalityCount; index++ )
{
CI_PERSON *personality = getPersonality( deviceInfo, index );
if( personality->CertificateIndex != 0 && \
personality->CertificateIndex != index )
{
status = CI_BAD_TUPLES;
break;
}
}
}
if( status == CI_OK )
status = pCI_Lock( CI_NULL_FLAG );
if( status != CI_OK )
{
pCI_Reset(); /* Log off */
deviceInfo->errorCode = status;
return( CRYPT_ERROR_FAILED );
}
deviceInfo->flags |= DEVICE_LOGGEDIN;
/* Look for the most likely required personality (other than
personality 0, which is a non-personality used for the CA
root cert) and set it as the currently active one. If this
fails we stay with the default personality for lack of any
better way to handle it */
certIndex = findCertificate( deviceInfo, NULL, 0 );
if( !cryptStatusError( certIndex ) && certIndex )
{
pCI_SetPersonality( certIndex );
deviceInfo->currentPersonality = certIndex;
}
/* Handle LEAF suppression. On LEAF-suppressed cards the LEAF bytes
are replaced by 'THIS IS NOT LEAF', in case there are cards which
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( deviceInfo->leafString, ( status == CI_OK ) ? \
ivBuffer : "THIS IS NOT LEAF", 16 );
pCI_DeleteKey( 1 );
return( CRYPT_OK );
}
/* Handle authorisation value change */
if( type == CRYPT_DEVINFO_SET_AUTHENT_USER || \
type == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR )
{
CI_PIN oldPIN, newPIN;
initPIN( oldPIN, data1, data1Length );
initPIN( newPIN, data2, data2Length );
status = pCI_ChangePIN( ( type == CRYPT_DEVINFO_SET_AUTHENT_USER ) ? \
CI_USER_PIN : CI_SSO_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 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, data1, data1Length );
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 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 );
return( CRYPT_OK );
}
/* Handle zeroisation */
if( type == CRYPT_DEVINFO_ZEROISE )
{
CI_STATE deviceState;
CI_PIN pin;
/* Zeroise the card */
status = pCI_Zeroize();
if( status == CI_OK )
status = pCI_GetState( &deviceState );
if( status != CI_OK )
return( mapError( status, CRYPT_ERROR_FAILED ) );
if( deviceState != CI_ZEROIZED )
return( CRYPT_ERROR_FAILED );
/* Log on with the zeroise PIN to move it into the uninitialised
state */
initPIN( pin, data1, data1Length );
status = pCI_CheckPIN( CI_SSO_PIN, pin );
return( mapError( status, CRYPT_ERROR_WRONGKEY ) );
}
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,
const int length )
{
CI_RANDOM randomBuffer;
BYTE *bufPtr = buffer;
int count, status;
/* 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 )
{
static const int keySize = 128;
const CAPABILITY_INFO *capabilityInfoPtr;
CRYPT_CERTIFICATE iCryptCert;
CRYPT_ALGO cryptAlgo;
CI_PERSON *personality;
CI_CERTIFICATE certificate;
RESOURCE_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 = findCertificate( deviceInfo, 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( deviceInfo, 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 cert 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->capabilityInfo,
cryptAlgo );
if( capabilityInfoPtr == NULL )
return( CRYPT_ERROR_NOTAVAIL );
/* If we're after a private key, make sure 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 which matches the key. The process
is as follows:
if public key
if cert
create native cert chain (+key) object
else
create device pubkey object, mark as "key loaded"
else
create device privkey object, mark as "key loaded"
if cert
create native data-only cert chain object
attach cert chain object to key
The reason for doing things this way is given in the comment at the
top of this section */
if( certPresent )
{
status = iCryptImportCertIndirect( &iCryptCert,
deviceInfo->objectHandle, keyIDtype, keyID,
keyIDlength, ( itemType == KEYMGMT_ITEM_PRIVATEKEY ) ? \
KEYMGMT_FLAG_DATAONLY_CERT : 0 );
if( cryptStatusError( status ) )
return( status );
/* We got the cert, if we're being asked for a public key then we've
created a native object to contain it so we return that */
if( itemType == KEYMGMT_ITEM_PUBLICKEY )
{
/* Set up the keying info in the context based on the data from
the cert if necessary */
if( cryptAlgo == CRYPT_ALGO_KEA )
{
BYTE keyDataBuffer[ 1024 ];
setResourceData( &msgData, keyDataBuffer, 1024 );
status = krnlSendMessage( iCryptCert,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -