📄 fortezza.c
字号:
setMessageData( &msgData, name, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_HOLDERNAME );
if( cryptStatusError( status ) )
strlcpy_s( name, CRYPT_MAX_TEXTSIZE,
"CA certificate-only entry" );
else
name[ min( msgData.length, 24 ) ] = '\0';
labelPtr = name;
}
/* Write the new certificate and label */
status = updateCertificate( fortezzaInfo, currentCertInfo->index,
iCryptCert, labelPtr, CRYPT_MAX_TEXTSIZE,
currentCertInfo->parentIndex );
if( cryptStatusError( status ) )
return( status );
}
while( krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, &value,
CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK && \
iterationCount++ < FAILSAFE_ITERATIONS_MED );
if( iterationCount >= FAILSAFE_ITERATIONS_MED )
retIntError();
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 */
static int exportKEA( DEVICE_INFO *deviceInfo, MECHANISM_WRAP_INFO *mechanismInfo );
static int importKEA( DEVICE_INFO *deviceInfo, MECHANISM_WRAP_INFO *mechanismInfo );
static const MECHANISM_FUNCTION_INFO mechanismFunctions[] = {
{ MESSAGE_DEV_EXPORT, MECHANISM_ENC_KEA, exportKEA },
{ MESSAGE_DEV_IMPORT, MECHANISM_ENC_KEA, importKEA },
{ MESSAGE_NONE, MECHANISM_NONE, NULL }, { 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 )
{
FORTEZZA_INFO *fortezzaInfo = deviceInfo->deviceFortezza;
/* Clear the personality list if it exists */
if( fortezzaInfo->personalities != NULL )
{
zeroise( fortezzaInfo->personalities,
fortezzaInfo->personalityCount * sizeof( CI_PERSON ) );
clFree( "shutdownFunction", fortezzaInfo->personalities );
fortezzaInfo->personalities = NULL;
fortezzaInfo->personalityCount = 0;
}
if( fortezzaInfo->certHashes != NULL )
{
zeroise( fortezzaInfo->certHashes,
fortezzaInfo->personalityCount * sizeof( CI_HASHVALUE ) );
clFree( "shutdownFunction", fortezzaInfo->certHashes );
fortezzaInfo->certHashes = NULL;
fortezzaInfo->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, fortezzaInfo->socketIndex );
}
/* Open a session with the device */
static int initFunction( DEVICE_INFO *deviceInfo, const char *name,
const int nameLength )
{
FORTEZZA_INFO *fortezzaInfo = deviceInfo->deviceFortezza;
CI_CONFIG deviceConfiguration;
CI_TIME cardTime;
int socket, i, fortezzaStatus = CI_FAIL, iterationCount = 0;
int status = CRYPT_ERROR_OPEN;
UNUSED_ARG( name );
/* The Fortezza open is in theory a bit problematic since with older
drivers 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 that we're not just rhapsodising into the void. This also
catches a bug in the Spyrus driver (see the comment further on) in
which it tries to open a nonexistent device in the USB (pseudo)-slot
before it opens the real Fortezza card in the PCMCIA slot.
For some drivers such as the 1996-vintage (non-PnP) NT Fortezza
driver which uses a custom kernel driver to handle PCMCIA cards this
isn't a problem because the driver won't load unless there's a card
inserted, but newer PnP drivers, multi-slot readers with the card
inserted in a slot other than the first one, 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 some drivers do
start at slot 0 we go from there (typically we just get a
CI_INV_SOCKET_INDEX for slot 0 if the driver happens to start at 1).
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 UFOs if their ones really do
behave as documented) */
for( socket = 0; socket <= noSockets && \
iterationCount++ < FAILSAFE_ITERATIONS_MED;
socket++ )
{
CI_STATE deviceState;
/* Try and open the card in the current socket */
fortezzaStatus = pCI_Open( CI_NULL_FLAG, socket );
if( fortezzaStatus != CI_OK )
continue;
fortezzaInfo->socketIndex = socket;
/* We've opened the card, reset it to get it into a known state
and make sure that 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 */
fortezzaStatus = pCI_Reset();
if( fortezzaStatus == CI_NO_CARD )
{
/* Some versions of the Syprus driver return CI_NO_CARD at this
point if the Spyrus USB (pseudo-)slot is enabled, since they
allow an open of the USB pseudo-slot (even though no device
is present) and then fail to communicate with the nonexistant
device. If we get this error, we continue, since the
Fortezza should be present in a later slot */
continue;
}
else
{
/* If there was some other type of failure, don't try and go any
further */
if( fortezzaStatus != CI_OK )
{
pCI_Close( CI_NULL_FLAG, socket );
continue;
}
}
fortezzaStatus = pCI_GetState( &deviceState );
if( fortezzaStatus != CI_OK || \
( deviceState == CI_POWER_UP || \
deviceState == CI_INTERNAL_FAILURE ) )
{
pCI_Close( CI_NULL_FLAG, socket );
if( fortezzaStatus == CI_OK )
fortezzaStatus = CI_INV_STATE;
continue;
}
deviceInfo->flags = DEVICE_ACTIVE | DEVICE_NEEDSLOGIN;
status = CRYPT_OK;
break;
}
if( iterationCount >= FAILSAFE_ITERATIONS_MED )
retIntError();
if( cryptStatusError( status ) )
{
fortezzaInfo->errorInfo.errorCode = fortezzaStatus;
return( status );
}
/* Since the onboard clock could be arbitrarily inaccurate (and even
nonfunctional by now on older cards, since the design life was only
7 years), we compare it with the system time and only rely on it if
it's within +/- 1 day of the system time */
status = pCI_GetTime( cardTime );
if( status == CI_OK )
{
const time_t theTime = getTokenTime( cardTime );
const time_t currentTime = getTime();
if( theTime >= currentTime - 86400 && \
theTime <= currentTime + 86400 )
deviceInfo->flags |= DEVICE_TIME;
}
/* 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 );
fortezzaInfo->largestBlockSize = deviceConfiguration.LargestBlockSize;
fortezzaInfo->minPinSize = 4;
fortezzaInfo->maxPinSize = CI_PIN_SIZE;
fortezzaInfo->keyRegisterCount = deviceConfiguration.KeyRegisterCount;
fortezzaInfo->keyRegisterFlags = 1; /* Register 0 is reserved */
fortezzaInfo->personalityCount = deviceConfiguration.CertificateCount + 1;
fortezzaInfo->personalities = \
clAlloc( "initFunction", fortezzaInfo->personalityCount * \
sizeof( CI_PERSON ) );
fortezzaInfo->certHashes = \
clAlloc( "initFunction", fortezzaInfo->personalityCount * \
sizeof( CI_HASHVALUE ) );
if( fortezzaInfo->personalities == NULL || \
fortezzaInfo->certHashes == NULL )
{
shutdownFunction( deviceInfo );
return( CRYPT_ERROR_MEMORY );
}
memset( fortezzaInfo->personalities, 0,
fortezzaInfo->personalityCount * sizeof( CI_PERSON ) );
fortezzaInfo->currentPersonality = CRYPT_ERROR;
memset( fortezzaInfo->certHashes, 0,
fortezzaInfo->personalityCount * sizeof( CI_HASHVALUE ) );
fortezzaInfo->certHashesInitialised = FALSE;
memcpy( fortezzaInfo->label, deviceConfiguration.ProductName, CI_NAME_SIZE );
for( i = CI_NAME_SIZE;
i > 0 && ( fortezzaInfo->label[ i - 1 ] == ' ' || \
!fortezzaInfo->label[ i - 1 ] );
i-- );
fortezzaInfo->labelLen = i;
deviceInfo->label = fortezzaInfo->label;
deviceInfo->labelLen = fortezzaInfo->labelLen;
return( CRYPT_OK );
}
/* Handle device control functions */
static int controlFunction( DEVICE_INFO *deviceInfo,
const CRYPT_ATTRIBUTE_TYPE type,
const void *data, const int dataLength,
MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
{
FORTEZZA_INFO *fortezzaInfo = deviceInfo->deviceFortezza;
int status;
/* Handle user authorisation */
if( type == CRYPT_DEVINFO_AUTHENT_USER || \
type == CRYPT_DEVINFO_AUTHENT_SUPERVISOR )
{
CI_PERSON *personalityList = fortezzaInfo->personalities;
CI_PIN pin;
BYTE ivBuffer[ 64 + 8 ]; /* For LEAF handling */
int certIndex;
/* Make sure that the PIN is within range */
if( dataLength < fortezzaInfo->minPinSize || \
dataLength > fortezzaInfo->maxPinSize )
return( CRYPT_ARGERROR_NUM1 );
initPIN( pin, data, dataLength );
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 that 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( fortezzaInfo->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 certificate can be read) to
make sure that it isn't treated as an empty personality
slot */
strlcpy_s( personalityList[ 0 ].CertLabel, CI_NAME_SIZE,
"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 that things really are set up this way */
for( index = 0; index < fortezzaInfo->personalityCount && \
index < FAILSAFE_ITERATIONS_MED; index++ )
{
CI_PERSON *personality = getPersonality( fortezzaInfo,
index );
if( personality->CertificateIndex != 0 && \
personality->CertificateIndex != index )
{
status = CI_BAD_TUPLES;
break;
}
}
if( index >= FAILSAFE_ITERATIONS_MED )
retIntError();
}
if( status == CI_OK )
status = pCI_Lock( CI_NULL_FLAG );
if( status != CI_OK )
{
pCI_Reset(); /* Log off */
fortezzaInfo->errorInfo.errorCode = status;
return( CRYPT_ERROR_FAILED );
}
/* Look for the most likely required personality (other than
personality 0, which is a non-personality used for the CA
root certificate) 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 = findCertificateFromLabel( fortezzaInfo, NULL, 0 );
if( !cryptStatusError( certIndex ) && certIndex > 0 )
{
pCI_SetPersonality( certIndex );
fortezzaInfo->currentPersonality = certIndex;
}
/* Handle LEAF suppression. On LEAF-suppressed cards the LEAF bytes
are replaced by 'THIS IS NOT LEAF', in case there are cards that
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -