📄 dev_fort.c
字号:
const int leafCertIndex )
{
CI_PERSON *personalityList = deviceInfo->personalities;
BOOLEAN presentList[ 16 ];
int certList[ 16 ], parentList[ 16 ];
int chainIndex = 0, freeCertIndex = 1, oldCertIndex, value, i;
/* Initialise the certificate index information and hashes for the certs
on the card if necessary. certList[] contains the mapping of certs in
the chain to positions in the card, parentList[] contains the mapping
of certs in the chain to the position of their parents in the card */
for( i = 0; i < 16; i++ )
{
presentList[ i ] = FALSE;
certList[ i ] = parentList[ i ] = CRYPT_UNUSED;
}
if( !deviceInfo->certHashesInitialised )
getCertificateInfo( deviceInfo );
/* Start at the top-level cert and work our way down, which ensures that
the CA certs appear first, and that if an update fails, the parent
cert pointers point to valid fields (since higher-level certs are
added first) */
krnlSendMessage( iCryptCert, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORLAST, CRYPT_CERTINFO_CURRENT_CERTIFICATE );
/* Pass 1: Build an index of cert and parent cert positions in the card.
Once this loop has completed, certList[] contains a mapping from cert
chain position to position in the card, and parentList[] contains a
mapping from cert chain position to parent cert position in the card */
do
{
CI_HASHVALUE *hashList = deviceInfo->certHashes;
RESOURCE_DATA msgData;
CI_HASHVALUE hash;
BOOLEAN isPresent = FALSE;
int certIndex;
/* Get the hash for this cert and check whether it's already present */
setResourceData( &msgData, &hash, sizeof( CI_HASHVALUE ) );
if( cryptStatusError( \
krnlSendMessage( iCryptCert, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_FINGERPRINT_SHA ) ) )
return( CRYPT_ARGERROR_NUM1 );
for( certIndex = 0; certIndex < deviceInfo->personalityCount; certIndex++ )
if( !memcmp( hashList[ certIndex ], hash, sizeof( CI_HASHVALUE ) ) )
{
isPresent = TRUE;
break;
}
/* Set the mapping from cert to parent cert position in the card.
The cert at position 0 is the root cert */
if( chainIndex != 0 )
parentList[ chainIndex ] = oldCertIndex;
/* Set the mapping from cert to position in the card */
if( isPresent )
{
certList[ chainIndex ] = certIndex;
presentList[ chainIndex ] = TRUE;
}
else
{
/* Make sure there's room for more certificates in the card */
if( freeCertIndex >= deviceInfo->personalityCount )
return( CRYPT_ERROR_OVERFLOW ); /* No more room in card */
/* Allocate this cert to the next free position in the card */
while( freeCertIndex < deviceInfo->personalityCount && \
personalityList[ freeCertIndex ].CertLabel[ 0 ] != '\0' )
freeCertIndex++;
certList[ chainIndex ] = freeCertIndex;
}
/* Remember the just-assigned position in the card and move on to the
next cert in the chain */
oldCertIndex = certList[ chainIndex ];
chainIndex++;
}
while( krnlSendMessage( iCryptCert, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORPREVIOUS,
CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK );
/* The last cert in the chain will either already be present, or be
present in raw-key form. If it's present in raw-key form the previous
code will add it as a pseudo-new cert, so we go back and set its index
to the actual position without marking it as present */
if( certList[ chainIndex - 1 ] == freeCertIndex )
certList[ chainIndex - 1 ] = leafCertIndex;
/* Pass 2: Update either the label or cert+label as required */
value = CRYPT_CURSOR_LAST;
krnlSendMessage( iCryptCert, RESOURCE_IMESSAGE_SETATTRIBUTE, &value,
CRYPT_CERTINFO_CURRENT_CERTIFICATE );
value = CRYPT_CURSOR_PREVIOUS;
chainIndex = 0;
do
{
const int parentIndex = parentList[ chainIndex ];
const int certIndex = certList[ chainIndex ];
const BOOLEAN isPresent = presentList[ chainIndex++ ];
char name[ CRYPT_MAX_TEXTSIZE + 1 ], *labelPtr = NULL;
int status;
/* If the cert is already present, make sure the parent index info
is correct */
if( isPresent )
{
CI_CERTIFICATE certificate;
char buffer[ 8 ];
int index;
/* If the cert is present and the parent cert index is correct,
continue */
if( ( sscanf( personalityList[ certIndex ].CertLabel + 6, "%02X",
&index ) == 1 ) && \
( parentIndex == index || parentIndex == CRYPT_UNUSED ) )
continue;
/* Update the parent cert index in the label, read the cert, and
write it back out with the new label */
sprintf( buffer, "%02X", parentIndex );
memcpy( personalityList[ certIndex ].CertLabel + 6, buffer, 2 );
status = pCI_GetCertificate( certIndex, certificate );
#ifndef NO_UPDATE
if( status == CI_OK )
status = pCI_LoadCertificate( certIndex,
personalityList[ certIndex ].CertLabel,
certificate, 0 );
#endif /* NO_UPDATE */
if( status != CI_OK )
return( mapError( status, CRYPT_ERROR_WRITE ) );
continue;
}
/* If we're adding a new cert for a non-present personality, get
SubjectName information from the cert to use as the label and make
sure it's within the maximum allowed length. Some certs don't
have CN components, so we try for the OU instead. If that also
fails, we try for the O, and if that fails we just use a dummy
label */
if( certIndex != leafCertIndex || !certIndex )
{
RESOURCE_DATA msgData;
value = CRYPT_UNUSED;
krnlSendMessage( iCryptCert, RESOURCE_IMESSAGE_SETATTRIBUTE,
&value, CRYPT_CERTINFO_SUBJECTNAME );
setResourceData( &msgData, name, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptCert,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_COMMONNAME );
if( status == CRYPT_ERROR_NOTFOUND )
status = krnlSendMessage( iCryptCert,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_ORGANIZATIONALUNITNAME );
if( status == CRYPT_ERROR_NOTFOUND )
status = krnlSendMessage( iCryptCert,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_ORGANIZATIONALUNITNAME );
if( status == CRYPT_ERROR_NOTFOUND )
strcpy( name, "CA certificate-only entry" );
else
name[ min( msgData.length, 24 ) ] = '\0';
labelPtr = name;
}
/* Write the new cert and label */
status = updateCertificate( deviceInfo, certIndex, iCryptCert,
NULL, 0, labelPtr, parentIndex );
if( cryptStatusError( status ) )
return( status );
}
while( krnlSendMessage( iCryptCert, RESOURCE_IMESSAGE_SETATTRIBUTE, &value,
CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Device Init/Shutdown/Device Control Routines *
* *
****************************************************************************/
/* Table of mechanisms supported by this device. These are sorted in order
of frequency of use in order to make lookups a bit faster */
int exportKEA( DEVICE_INFO *deviceInfo, MECHANISM_WRAP_INFO *mechanismInfo );
int importKEA( DEVICE_INFO *deviceInfo, MECHANISM_WRAP_INFO *mechanismInfo );
static const MECHANISM_FUNCTION_INFO objectMechanisms[] = {
{ RESOURCE_MESSAGE_DEV_EXPORT, MECHANISM_KEA, exportKEA },
{ RESOURCE_MESSAGE_DEV_IMPORT, MECHANISM_KEA, importKEA },
{ RESOURCE_MESSAGE_NONE, MECHANISM_NONE, NULL }
};
/* Close a previously-opened session with the device. We have to have this
before the init function since it may be called by it if the init process
fails */
static void shutdownFunction( DEVICE_INFO *deviceInfo )
{
/* Clear the personality list if it exists */
if( deviceInfo->personalities != NULL )
{
zeroise( deviceInfo->personalities,
deviceInfo->personalityCount * sizeof( CI_PERSON ) );
free( deviceInfo->personalities );
deviceInfo->personalities = NULL;
deviceInfo->personalityCount = 0;
}
if( deviceInfo->certHashes != NULL )
{
zeroise( deviceInfo->certHashes,
deviceInfo->personalityCount * sizeof( CI_HASHVALUE ) );
free( deviceInfo->certHashes );
deviceInfo->certHashes = NULL;
deviceInfo->certHashesInitialised = FALSE;
}
/* Unlock the socket and close the session with the device */
if( deviceInfo->flags & DEVICE_LOGGEDIN )
{
pCI_Unlock();
deviceInfo->flags &= ~DEVICE_LOGGEDIN;
}
pCI_Close( CI_NULL_FLAG, deviceInfo->slotHandle );
}
/* Open a session with the device */
static int initFunction( DEVICE_INFO *deviceInfo, const char *name,
const int nameLength )
{
CI_CONFIG deviceConfiguration;
int socket, i, status;
UNUSED( name );
/* The Fortezza open is in theory a bit problematic since the open will
succeed even if there's no device in the socket, so after we perform
the open we reset the card and check its state to make sure we're not
just rhapsodising into the void. In practice the currently available
(1996-vintage non PnP) NT Fortezza driver won't load unless there's a
card inserted so this isn't usually a problem, but multi-slot readers
with the card inserted in a slot other than the first one, possible
future drivers, and the Unix driver (which has a dedicated daemon to
handle the card) may not exhibit this behaviour so we check for things
working in the manner specified in the docs.
The choice of socket for the card can be a bit confusing. According
to some docs the socket can start from 0 (in violation of the spec),
whereas others say they should start from 1, since it doesn't hurt to
start from 0 we go from there (typically we just get a
CI_INV_SOCKET_INDEX for slot 0). Once we've done that, we reset the
card to get it into a known state (although judging by the equivalent
time delay of CI_Open() and CI_Reset(), the open does this anyway) and
check that a card is actually present (see the comments above - the
NSA must be using their own drivers recovered from crashed UFO's if
their ones really do behave as documented) */
for( socket = 0; socket <= noSockets; socket++ )
{
CI_STATE deviceState;
/* Try and open the card in the current socket */
status = pCI_Open( CI_NULL_FLAG, socket );
if( status != CI_OK )
continue;
deviceInfo->slotHandle = socket;
/* We've opened the card, reset it to get it into a known state
and make sure the state is valid. Unfortunately the exact
definition of a valid state is a bit tricky, for example we
shouldn't allow the initialised or SSO initialised states here
since there doesn't appear to be any way to get from them to
CAW initialised at this point (that is, you need to go
uninitialised -> initialised -> SSO initialised -> CAW
initialised in a straight sequence), however we need to get
past this point in order to perform the only valid operation on
the card (zeroise) so we have to let these pass even though
there's not much we can do in them */
status = pCI_Reset();
if( status == CI_OK )
status = pCI_GetState( &deviceState );
if( status != CI_OK || \
( deviceState == CI_POWER_UP || \
deviceState == CI_INTERNAL_FAILURE ) )
{
pCI_Close( CI_NULL_FLAG, socket );
if( status == CI_OK )
status = CI_INV_STATE;
continue;
}
deviceInfo->flags = DEVICE_ACTIVE | DEVICE_NEEDSLOGIN;
break;
}
if( status != CI_OK )
{
deviceInfo->errorCode = status;
return( CRYPT_ERROR_OPEN );
}
/* Set up device-specific information. We can't read the personality
list until the user logs on, so all we can do at this point is
allocate memory for it. Note that personality 0 can never be selected
and so it isn't returned when the personality info is read, this leads
to confusing fencepost errors so when we allocate/read the personality
info we leave space for a zero-th personality which is never used */
pCI_GetConfiguration( &deviceConfiguration );
deviceInfo->largestBlockSize = deviceConfiguration.LargestBlockSize;
deviceInfo->minPinSize = 4;
deviceInfo->maxPinSize = CI_PIN_SIZE;
deviceInfo->keyRegisterCount = deviceConfiguration.KeyRegisterCount;
deviceInfo->keyRegisterFlags = 1; /* Register 0 is reserved */
deviceInfo->personalityCount = deviceConfiguration.CertificateCount + 1;
deviceInfo->personalities = malloc( deviceInfo->personalityCount * \
sizeof( CI_PERSON ) );
deviceInfo->certHashes = malloc( deviceInfo->personalityCount * \
sizeof( CI_HASHVALUE ) );
deviceInfo->certHashesInitialised = FALSE;
deviceInfo->currentPersonality = CRYPT_ERROR;
if( deviceInfo->personalities == NULL || deviceInfo->certHashes == NULL )
{
shutdownFunction( deviceInfo );
return( CRYPT_ERROR_MEMORY );
}
memset( deviceInfo->personalities, 0,
deviceInfo->personalityCount * sizeof( CI_PERSON ) );
memset( deviceInfo->certHashes, 0,
deviceInfo->personalityCount * sizeof( CI_HASHVALUE ) );
memcpy( deviceInfo->label, deviceConfiguration.ProductName,
CI_NAME_SIZE );
for( i = CI_NAME_SIZE;
i && ( deviceInfo->label[ i - 1 ] == ' ' || \
!deviceInfo->label[ i - 1 ] ); i-- );
deviceInfo->label[ i ] = '\0';
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -