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

📄 chain.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 4 页
字号:
								   const CRYPT_KEYID_TYPE keyIDtype,
								   const void *keyID, const int keyIDlength )
	{
	STREAM stream;
	const BYTE *serialNumber;
	const void *issuerDNptr;
	int issuerDNsize, serialNumberSize;
	int length, i, status;

	assert( certChainSize > 0 && certChainSize < MAX_CHAINLENGTH );
	assert( isReadPtr( chainInfo, sizeof( CHAIN_INFO ) * certChainSize ) );
	assert( keyIDtype == CRYPT_IKEYID_KEYID || \
			keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER );
	assert( keyID != NULL );
	assert( keyIDlength > 16 );

	/* If it's a subjectKeyIdentifier, walk down the chain looking for a
	   match */
	if( keyIDtype == CRYPT_IKEYID_KEYID )
		{
		for( i = 0; i < certChainSize; i++ )
			if( chainInfo[ i ].subjectKeyIDsize > MIN_SKID_SIZE && \
				chainInfo[ i ].subjectKeyIDsize == keyIDlength && \
				!memcmp( chainInfo[ i ].subjectKeyIdentifier, keyID,
						 keyIDlength ) )
			return( i );

		return( CRYPT_ERROR_NOTFOUND );
		}

	/* It's an issuerAndSerialNumber, extract the issuer DN and serial 
	   number */
	sMemConnect( &stream, keyID, keyIDlength );
	readSequence( &stream, NULL );
	issuerDNptr = sMemBufPtr( &stream );
	readSequence( &stream, &length );				/* Issuer DN */
	issuerDNsize = ( int ) sizeofObject( length );
	sSkip( &stream, length );
	readGenericHole( &stream, &serialNumberSize, BER_INTEGER );
	serialNumber = sMemBufPtr( &stream );			/* Serial number */
	status = sSkip( &stream, serialNumberSize );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( CRYPT_ERROR_NOTFOUND );

	/* Walk down the chain looking for the one identified by the 
	   issuerAndSerialNumber */
	for( i = 0; i < certChainSize; i++ )
		if( chainInfo[ i ].issuerDNsize > 0 && \
			chainInfo[ i ].issuerDNsize == issuerDNsize && \
			!memcmp( chainInfo[ i ].issuerDN, issuerDNptr,
					 issuerDNsize ) && \
			!compareSerialNumber( chainInfo[ i ].serialNumber, 
								  chainInfo[ i ].serialNumberSize,
								  serialNumber, serialNumberSize ) )
			return( i );

	return( CRYPT_ERROR_NOTFOUND );
	}

/* Sort the issuer certs in a cert chain, discarding any unnecessary certs.  
   If we're canonicalising an existing chain then the start point in the 
   chain is given by certChainStart and the -1th cert is the end user cert 
   and isn't part of the ordering process.  If we're building a new chain 
   from an arbitrary set of certs then the start point is given by the 
   chaining info for the leaf cert.

   The canonicalisation of the chain can be handled in one of two ways, the 
   logical way and the PKIX way.  The latter allows apparently self-signed
   certs in the middle of a chain due to cert renewals/reparenting, which
   completely breaks the standard cert convention that a self-signed cert is
   a root CA.  This means that without special handling the chain will 
   terminate at a cert that appears to be (but isn't) the CA root cert.  A
   sample chain of this form (in this case involving an oldWithNew cert) is 
   as follows:

	Issuer		Subject		Key/sKID	Sig/aKID
	------		-------		--------	----------
	Root		CA			ca_new		root
	CA			CA			ca_old		ca_new
	CA			EE			ee			ca_old

   In order to handle these chains, we need to match by both DN *and* keyID,
   however since so many CAs get keyIDs wrong, enabling this by default 
   would break many cert chains.  To handle this, we only enable the extra-
   match behaviour if the compliance level is CRYPT_COMPLIANCELEVEL_PKIX_FULL,
   for which people should be expecting all sorts of weird behaviour anyway.
   
   Returns the length of the ordered chain */

static int sortCertChain( CRYPT_CERTIFICATE *iCertChain,
						  CHAIN_INFO *chainInfo,
						  const int certChainSize,
						  const CRYPT_CERTIFICATE certChainStart,
						  CHAINING_INFO *chainingInfo,
						  const BOOLEAN useStrictChaining )
	{
	CRYPT_CERTIFICATE orderedChain[ MAX_CHAINLENGTH ];
	CHAINING_INFO localChainingInfo, *chainingInfoPtr = &localChainingInfo;
	BOOLEAN moreMatches;
	const int maxMatchLevel = useStrictChaining ? 1 : 0;
	int orderedChainIndex = 0, i;

	assert( certChainSize > 0 && certChainSize < MAX_CHAINLENGTH );
	assert( isWritePtr( iCertChain, sizeof( CRYPT_CERTIFICATE ) * certChainSize ) );
	assert( isWritePtr( chainInfo, sizeof( CHAIN_INFO ) * certChainSize ) );
	assert( ( isHandleRangeValid( certChainStart ) && \
			  chainingInfo == NULL ) || \
			( certChainStart == CRYPT_UNUSED && \
			  isWritePtr( chainingInfo, sizeof( CHAINING_INFO ) ) ) );

	/* If we're canonicalising an existing chain, there's a predefined chain
	   start that we copy over and prepare to look for the next cert up the
	   chain */
	if( certChainStart != CRYPT_UNUSED )
		{
		orderedChain[ orderedChainIndex++ ] = certChainStart;
		getIssuerChainingInfo( chainingInfoPtr, &chainInfo[ 0 ] );
		memset( &chainInfo[ 0 ], 0, sizeof( CHAIN_INFO ) );
		}
	else
		/* We're building a new chain, the caller has supplied the chaining
		   info */
		chainingInfoPtr = chainingInfo;

	/* Build an ordered chain of certs from the leaf to the root */
	do
		{
		int matchLevel;

		moreMatches = FALSE;

		/* Find the cert with the current issuer as its subject.  If we're
		   using strict chaining we first try a strict match 
		   (matchLevel = TRUE), if that fails we fall back to a standard 
		   match (matchLevel = FALSE).  This is required to handle the
		   significant number of CAs that don't get chaining by keyID 
		   right */
		for( matchLevel = maxMatchLevel; \
			 !moreMatches && matchLevel >= 0; matchLevel-- )
			{
			for( i = 0; i < certChainSize; i++ )
				if( chainInfo[ i ].subjectDN != NULL && \
					isSubject( chainingInfoPtr, &chainInfo[ i ], 
							   matchLevel ) )
					{
					/* We've found the issuer, move the certs to the ordered
					   chain and prepare to find the issuer of this cert */
					orderedChain[ orderedChainIndex++ ] = iCertChain[ i ];
					getIssuerChainingInfo( chainingInfoPtr, &chainInfo[ i ] );
					memset( &chainInfo[ i ], 0, sizeof( CHAIN_INFO ) );
					moreMatches = TRUE;
					break;
					}
			}
		}
	while( moreMatches );

	/* If there are any certs left, they're not needed for anything so we can
	   free the resources */
	for( i = 0; i < certChainSize; i++ )
		if( chainInfo[ i ].subjectDN != NULL )
			krnlSendNotifier( iCertChain[ i ], IMESSAGE_DECREFCOUNT );

	/* Replace the existing chain with the ordered version */
	memset( iCertChain, 0, sizeof( CRYPT_CERTIFICATE ) * MAX_CHAINLENGTH );
	if( orderedChainIndex > 0 )
		memcpy( iCertChain, orderedChain,
				sizeof( CRYPT_CERTIFICATE ) * orderedChainIndex );

	return( orderedChainIndex );
	}

/* Read a collection of certs in a cert chain into a cert object */

static int buildCertChain( CRYPT_CERTIFICATE *iLeafCert, 
						   CRYPT_CERTIFICATE *iCertChain, int certChainEnd,
						   const CRYPT_KEYID_TYPE keyIDtype,
						   const void *keyID, const int keyIDlength )
	{
	CHAIN_INFO chainInfo[ MAX_CHAINLENGTH ];
	CERT_INFO *certChainPtr;
	CHAINING_INFO chainingInfo;
	int leafNodePos, complianceLevel, status;

	assert( certChainEnd > 0 && certChainEnd < MAX_CHAINLENGTH );
	assert( isWritePtr( chainInfo, sizeof( CHAIN_INFO ) * certChainEnd ) );
	assert( isReadPtr( iCertChain, sizeof( CRYPT_CERTIFICATE ) * certChainEnd ) );

	status = krnlSendMessage( iCertChain[ 0 ], IMESSAGE_GETATTRIBUTE, 
							  &complianceLevel, 
							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusError( status ) )
		return( status );

	/* We've now got a collection of certs in unknown order (although it's 
	   common for the first cert to be the leaf).  Extract the chaining info 
	   and search the chain for the leaf node */
	status = buildChainInfo( chainInfo, iCertChain, certChainEnd );
	if( cryptStatusError( status ) )
		{
		freeCertChain( iCertChain, certChainEnd );
		return( status );
		}
	if( keyID != NULL )
		leafNodePos = findIdentifiedLeafNode( chainInfo, certChainEnd,
											  keyIDtype, keyID, keyIDlength );
	else
		leafNodePos = findLeafNode( chainInfo, certChainEnd );
	if( cryptStatusError( leafNodePos ) )
		{
		freeCertChain( iCertChain, certChainEnd );
		return( leafNodePos );
		}

	/* Now that we have the leaf node, clear its entry in the chain to make
	   sure that it isn't used for further processing, order the remaining 
	   certs up to the root, and discard any unneeded certs */
	*iLeafCert = iCertChain[ leafNodePos ];
	getIssuerChainingInfo( &chainingInfo, &chainInfo[ leafNodePos ] );
	memset( &chainInfo[ leafNodePos ], 0, sizeof( CHAIN_INFO ) );
	status = sortCertChain( iCertChain, chainInfo, certChainEnd,
							CRYPT_UNUSED, &chainingInfo,
							( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_FULL ) ? \
								TRUE : FALSE );
	if( cryptStatusError( status ) )
		{
		/* We've cleared the leaf node entry in the chain so we have to 
		   explicitly clean up the corresponding cert */
		krnlSendNotifier( *iLeafCert, IMESSAGE_DECREFCOUNT );
		freeCertChain( iCertChain, certChainEnd );
		return( status );
		}
	certChainEnd = status;
	if( certChainEnd <= 0 )
		/* There's only one cert in the chain, either due to the chain 
		   containing only a single cert or due to all other certs being 
		   discarded, leave it as a standalone cert rather than turning it 
		   into a chain */
		return( CRYPT_OK );

	/* Walk up the chain re-setting the pseudo-selfsigned flag on any
	   chain-internal path-kludge certs if necessary.  This means that if 
	   the chain contains n certs, we reset the flag on certs 0...n-1.  This 
	   is required when there's a re-issued cert kludged into the middle of 
	   the path to connect a new CA signing key with a cert signed with the 
	   old key.  Note that this can't detect the case where the first cert 
	   in the chain is a path kludge cert with further certs held 
	   externally, e.g. in the trusted cert store, since it appears as a 
	   self-signed CA root cert */
	if( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_FULL )
		{
		int i;

		for( i = 0; i < certChainEnd - 1; i++ )
			{
			CERT_INFO *certInfoPtr;
			int value;

			/* Check whether this is a self-signed cert */
			status = krnlSendMessage( iCertChain[ i ], IMESSAGE_GETATTRIBUTE,
									  &value, CRYPT_CERTINFO_SELFSIGNED );
			if( cryptStatusError( status ) || !value )
				continue;

			/* Convert the self-signed flag into the pseudo self-signed/path
			   kludge flag */
			status = krnlAcquireObject( iCertChain[ i ], OBJECT_TYPE_CERTIFICATE, 
										( void ** ) &certInfoPtr, 
										CRYPT_ERROR_SIGNALLED );
			if( cryptStatusError( status ) )
				continue;
			certInfoPtr->flags &= ~CERT_FLAG_SELFSIGNED;
			certInfoPtr->flags |= CERT_FLAG_PATHKLUDGE;
			krnlReleaseObject( certInfoPtr->objectHandle );
			}
		}

	/* Finally, we've got the leaf cert and a chain up to the root.  Make the
	   leaf a cert-chain type and copy in the chain */
	status = krnlAcquireObject( *iLeafCert, OBJECT_TYPE_CERTIFICATE, 
								( void ** ) &certChainPtr, 
								CRYPT_ERROR_SIGNALLED );
	if( cryptStatusError( status ) )
		{
		/* We've cleared the leaf node entry in the chain so we have to 
		   explicitly clean up the corresponding cert */
		krnlSendNotifier( *iLeafCert, IMESSAGE_DECREFCOUNT );
		freeCertChain( iCertChain, certChainEnd );
		return( status );
		}
	memcpy( certChainPtr->cCertCert->chain, iCertChain,
			certChainEnd * sizeof( CRYPT_CERTIFICATE ) );
	certChainPtr->cCertCert->chainEnd = certChainEnd;
	certChainPtr->type = CRYPT_CERTTYPE_CERTCHAIN;
	krnlReleaseObject( certChainPtr->objectHandle );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Copy a Certificate Chain						*
*																			*
****************************************************************************/

/* Determine whether a cert is present in a cert collection based on its
   fingerprint */

static BOOLEAN certPresent( BYTE certChainHashes[][ CRYPT_MAX_HASHSIZE ],
							const int certChainLen, 
							const CRYPT_CERTIFICATE iCryptCert )
	{
	RESOURCE_DATA msgData;
	int i, status;

	/* Get the fingerprint of the (potential) next cert in the collection.  
	   This leaves it at the end of the existing collection of hashes so 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -