⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fortezza.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
			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 + -