📄 fortezza.c
字号:
pCI_Reset == NULL || pCI_SetKey == NULL || pCI_SetMode == NULL ||
pCI_SetPersonality == NULL || pCI_Sign == NULL ||
pCI_Terminate == NULL || pCI_Unlock == NULL ||
pCI_UnwrapKey == NULL || pCI_VerifySignature == NULL ||
pCI_WrapKey == NULL || pCI_Zeroize == NULL )
{
/* Free the library reference and reset the handle */
FreeLibrary( hFortezza );
hFortezza = NULL_HINSTANCE;
return( CRYPT_ERROR );
}
/* Initialise the Fortezza library */
if( pCI_Initialize( &noSockets ) != CI_OK )
{
/* Free the library reference and reset the handle */
FreeLibrary( hFortezza );
hFortezza = NULL_HINSTANCE;
return( CRYPT_ERROR );
}
return( CRYPT_OK );
}
void deviceEndFortezza( void )
{
if( hFortezza != NULL_HINSTANCE )
{
pCI_Terminate();
FreeLibrary( hFortezza );
}
hFortezza = NULL_HINSTANCE;
}
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Map a Fortezza-specific error to a cryptlib error */
static int mapError( const int errorCode, const int defaultError )
{
switch( errorCode )
{
case CI_OK:
return( CRYPT_OK );
case CI_NO_CARD:
case CI_BAD_CARD:
return( CRYPT_ERROR_SIGNALLED );
case CI_INV_STATE:
return( CRYPT_ERROR_PERMISSION );
case CI_NO_IV:
case CI_NO_KEY:
return( CRYPT_ERROR_NOTINITED );
case CI_EXEC_FAIL:
return( CRYPT_ERROR_FAILED );
}
return( defaultError );
}
/* Set up a PIN in the format required by the Fortezza driver */
static void initPIN( CI_PIN pinBuffer, const void *pin, const int pinLength )
{
memset( pinBuffer, 0, sizeof( CI_PIN ) );
if( pinLength > 0 )
memcpy( pinBuffer, pin, pinLength );
pinBuffer[ pinLength ] = '\0'; /* Ensure that PIN is null-terminated */
}
/* Extract the time from a time string */
static time_t getTokenTime( CI_TIME cardTime )
{
STREAM stream;
BYTE buffer[ 32 + 8 ];
time_t theTime = MIN_TIME_VALUE + 1;
int length, status;
/* Convert the token time to an ASN.1 time string that we can read using
the standard ASN.1 routines by writing a dummy time value and inserting
the token's time string in its place */
sMemOpen( &stream, buffer, 32 );
writeGeneralizedTime( &stream, theTime, DEFAULT_TAG );
length = stell( &stream );
sMemDisconnect( &stream );
memcpy( buffer + 2, cardTime, 14 );
sMemConnect( &stream, buffer, length );
status = readGeneralizedTime( &stream, &theTime );
sMemDisconnect( &stream );
return( ( cryptStatusOK( status ) ) ? theTime : 0 );
}
/* Find a free key register */
static int findFreeKeyRegister( const FORTEZZA_INFO *fortezzaInfo )
{
int mask = 2, i;
/* Search the register-in-use flags for a free register */
for( i = 1; i < fortezzaInfo->keyRegisterCount && \
i < FAILSAFE_ITERATIONS_MED; i++ )
{
if( !( fortezzaInfo->keyRegisterFlags & mask ) )
break;
mask <<= 1;
}
if( i >= FAILSAFE_ITERATIONS_MED )
retIntError();
return( ( i >= fortezzaInfo->keyRegisterCount ) ? \
CRYPT_ERROR_OVERFLOW : i );
}
/* Find a free key/certificate slot */
static int findFreeCertificate( const FORTEZZA_INFO *fortezzaInfo )
{
CI_PERSON *personalityList = fortezzaInfo->personalities;
int certIndex;
for( certIndex = 0; certIndex < fortezzaInfo->personalityCount && \
certIndex < FAILSAFE_ITERATIONS_MED;
certIndex++ )
{
if( personalityList[ certIndex ].CertLabel[ 0 ] == '\0' )
return( certIndex );
}
if( certIndex >= FAILSAFE_ITERATIONS_MED )
retIntError();
return( CRYPT_ERROR );
}
/* Set a certificate/personality label using the labelling system defined
in SDN.605. This is somewhat ad hoc since non-DOD Fortezza usage won't
follow the somewhat peculiar certification heirarchy designed for DOD/
government use, so we just mark a certificate as CA/individual rather
than CA/PCA/PAA. In addition we select between organisational and
individual certificates based on whether an organizationName or
organizationalUnitName is present */
static void getCertificateLabel( const int certIndex, const int parentIndex,
const CRYPT_CERTIFICATE iCryptCert,
const BOOLEAN newEntry, char *label,
const int labelMaxLen )
{
MESSAGE_DATA msgData;
int value, status;
memset( label, 0, sizeof( CI_CERT_STR ) );
/* If this is certificate slot 0, it's a PAA certificate being installed
by the SSO */
if( certIndex <= 0 )
{
memcpy( label, "PAA1FFFF", 8 );
return;
}
/* Check to see whether it's a CA certificate. If it is, label it as a
generic CA key (which encompasses all of CA/PCA/PAA) */
status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_CA );
if( cryptStatusOK( status ) && value > 0 )
{
sprintf_s( label, labelMaxLen, "CAX1FF%02X",
( parentIndex != CRYPT_UNUSED ) ? parentIndex : 0xFF );
return;
}
/* If there's a key agreement key usage, it must be KEA */
status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_KEYUSAGE );
if( cryptStatusOK( status ) && \
( value & ( CRYPT_KEYUSAGE_KEYAGREEMENT | \
CRYPT_KEYUSAGE_ENCIPHERONLY | \
CRYPT_KEYUSAGE_DECIPHERONLY ) ) )
{
sprintf_s( label, labelMaxLen, "KEAKFF%02X",
( parentIndex != CRYPT_UNUSED ) ? parentIndex : 0xFF );
return;
}
/* Select the SubjectName as the current DN and check whether there's
organisation-related components present. Given the dog's breakfast
of DN components present in most certificates this will probably mis-
identify individual keys as organisational ones some of the time,
but it's unlikely that anything distinguishes between I and O keys
anyway */
value = CRYPT_UNUSED;
krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, &value,
CRYPT_CERTINFO_SUBJECTNAME );
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_ORGANIZATIONNAME );
if( status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
&msgData,
CRYPT_CERTINFO_ORGANIZATIONALUNITNAME );
}
if( cryptStatusError( status ) )
sprintf_s( label, labelMaxLen, "DSAIFF%02X",
( parentIndex != CRYPT_UNUSED ) ? parentIndex : 0xFF );
else
sprintf_s( label, labelMaxLen, "DSAOFF%02X",
( parentIndex != CRYPT_UNUSED ) ? parentIndex : 0xFF );
/* If it's a completely new entry (i.e. one that doesn't correspond to a
private key), mark it as a certificate-only key */
if( newEntry > 0 )
label[ 3 ] = 'X';
}
/* Find a certificate/personality using the labelling system defined in
SDN.605 */
static int findCertificateFromLabel( const FORTEZZA_INFO *fortezzaInfo,
const char *label,
const int labelLength )
{
static const char *names[] = {
"DSAI", "DSAO", "DSAX", /* DSA individual, org, certificate-only */
"KEAK", "KEAX", /* KEA, certificate-only */
"CAX1", "PCA1", "PAA1", /* DSA CA, PCA, PAA */
"INKS", "ONKS", /* Legacy DSA+KEA individual, org */
"INKX", "ONKX", /* Legacy KEA individual, org */
NULL, NULL };
CI_PERSON *personalityList = fortezzaInfo->personalities;
int labelIndex, certIndex;
/* If a label is specified, look for the certificate for the personality
with the given label */
if( label != NULL )
{
for( certIndex = 0; certIndex < fortezzaInfo->personalityCount && \
certIndex < FAILSAFE_ITERATIONS_MED; \
certIndex++ )
{
if( !memcmp( personalityList[ certIndex ].CertLabel + 8, label,
labelLength ) )
return( certIndex );
}
if( certIndex >= FAILSAFE_ITERATIONS_MED )
retIntError();
return( CRYPT_ERROR );
}
/* No label given, look for the certificate in order of likeliness.
First we look for a personal certificate with a signing key, if that
fails we look for an organisational certificate with a signing key */
for( labelIndex = 0; names[ labelIndex ] != NULL && \
labelIndex < FAILSAFE_ARRAYSIZE( names, char * );
labelIndex++ )
{
for( certIndex = 0; certIndex < fortezzaInfo->personalityCount && \
certIndex < FAILSAFE_ITERATIONS_MED; \
certIndex++ )
{
if( !strncmp( personalityList[ certIndex ].CertLabel, \
names[ labelIndex ], 4 ) )
return( certIndex );
}
if( certIndex >= FAILSAFE_ITERATIONS_MED )
retIntError();
}
if( labelIndex >= FAILSAFE_ARRAYSIZE( names, char * ) )
retIntError();
return( CRYPT_ERROR );
}
/* Build a list of hashes of all certificates on the card */
static void getCertificateInfo( FORTEZZA_INFO *fortezzaInfo )
{
CI_PERSON *personalityList = fortezzaInfo->personalities;
CI_HASHVALUE *hashList = fortezzaInfo->certHashes;
CI_CERTIFICATE certificate;
HASHFUNCTION_ATOMIC hashFunctionAtomic;
int certIndex, certSize;
getHashAtomicParameters( CRYPT_ALGO_SHA1, &hashFunctionAtomic, NULL );
memset( hashList, 0, fortezzaInfo->personalityCount * sizeof( CI_HASHVALUE ) );
for( certIndex = 0; certIndex < fortezzaInfo->personalityCount && \
certIndex < FAILSAFE_ITERATIONS_MED; certIndex++ )
{
STREAM stream;
int status;
/* If there's no certificate present at this location, continue */
if( personalityList[ certIndex ].CertLabel[ 0 ] == '\0' || \
pCI_GetCertificate( certIndex, certificate ) != CI_OK )
continue;
/* Get the hash of the certificate data. Sometimes the card can
contain existing certificate entries with garbage values so we
don't hash the certificate data if it doesn't look right */
sMemConnect( &stream, certificate, sizeof( CI_CERTIFICATE ) );
status = readSequence( &stream, &certSize );
sMemDisconnect( &stream );
if( cryptStatusError( status ) || \
certSize < 256 || certSize > CI_CERT_SIZE - 4 )
continue;
hashFunctionAtomic( hashList[ certIndex ], sizeof( CI_HASHVALUE ),
certificate, ( int ) sizeofObject( certSize ) );
}
if( certIndex >= FAILSAFE_ITERATIONS_MED )
retIntError_Void();
fortezzaInfo->certHashesInitialised = TRUE;
}
/* Find a certificate based on its hash value */
static int findCertFromHash( const FORTEZZA_INFO *fortezzaInfo,
const void *certHash )
{
CI_HASHVALUE *hashList = fortezzaInfo->certHashes;
int certIndex;
for( certIndex = 0; certIndex < fortezzaInfo->personalityCount && \
certIndex < FAILSAFE_ITERATIONS_MED; \
certIndex++ )
{
if( !memcmp( hashList[ certIndex ], certHash,
sizeof( CI_HASHVALUE ) ) )
return( certIndex );
}
if( certIndex >= FAILSAFE_ITERATIONS_MED )
retIntError();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -