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

📄 certchn.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 4 页
字号:
	certUsed[ 0 ] = TRUE;
	lastCertPos = 0;

	/* Walk down the chain from the currently selected cert checking for
	   certs issued by it, until we can't go any further */
	do
		{
		/* Try and find a cert issued by the current cert */
		for( i = 0; i < certChainSize; i++ )
			if( !certUsed[ i ] && \
				isIssuer( &chainingInfo, &certChainInfo[ i ] ) )
				{
				/* There's another cert below the current one in the chain, 
				   mark the current one as used and move on to the next
				   one */
				getSubjectChainingInfo( &chainingInfo, &certChainInfo[ i ] );
				certUsed[ i ] = TRUE;
				lastCertPos = i;
				break;
				}
		}
	while( i != certChainSize );

	return( lastCertPos );
	}

/* Find a leaf node as identified by issuerAndSerialNumber.  Returns the 
   position of the leaf node in the chain */

static int findIdentifiedLeafNode( const CERTCHAIN_INFO *certChainInfo,
								   const int certChainSize,
								   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;

	assert( certChainSize > 0 && certChainSize < MAX_CHAINLENGTH );
	assert( isReadPtrEx( certChainInfo, CERTCHAIN_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( certChainInfo[ i ].subjectKeyIDsize == keyIDlength && \
				!memcmp( certChainInfo[ 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 );
	issuerDNsize = ( int ) sizeofObject( length );
	sSkip( &stream, length );
	readTag( &stream );
	serialNumberSize = readShortLength( &stream );
	serialNumber = sMemBufPtr( &stream );
	assert( sStatusOK( &stream ) );
	sMemDisconnect( &stream );
	while( !serialNumber[ 0 ] && serialNumberSize > 1 )
		{
		/* Strip any leading zeroes on non-zero serial numbers.  This is
		   necessary because the cert-handling code canonicalises the
		   serial number value while the raw issuerAndSerialNumber can
		   contain any random encoding. so we need to canonicalise it as
		   well for a binary comparison to work */
		serialNumber++;
		serialNumberSize--;
		}

	/* Walk down the chain looking for the one identified by the 
	   issuerAndSerialNumber */
	for( i = 0; i < certChainSize; i++ )
		if( certChainInfo[ i ].issuerDNsize == issuerDNsize && \
			certChainInfo[ i ].serialNumberSize == serialNumberSize && \
			!memcmp( certChainInfo[ i ].issuerDN, issuerDNptr,
					 issuerDNsize ) && \
			!memcmp( certChainInfo[ i ].serialNumber, 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.  Returns the length of the ordered 
   chain */

static int sortCertChain( CRYPT_CERTIFICATE *iCertChain,
						  CERTCHAIN_INFO *certChainInfo,
						  const int certChainSize,
						  const CRYPT_CERTIFICATE certChainStart,
						  CHAINING_INFO *chainingInfo )
	{
	CRYPT_CERTIFICATE orderedChain[ MAX_CHAINLENGTH ];
	int orderedChainIndex = 0, i;

	assert( certChainSize > 0 && certChainSize < MAX_CHAINLENGTH );
	assert( isWritePtrEx( iCertChain, CRYPT_CERTIFICATE, certChainSize ) );
	assert( isWritePtrEx( certChainInfo, CERTCHAIN_INFO, certChainSize ) );
	assert( isWritePtr( chainingInfo, CHAINING_INFO ) );

	/* If we're canonicalising an existing chain, there's a predefined chain
	   start which we copy over and prepare to look for the next cert up the
	   chain */
	if( certChainStart != CRYPT_UNUSED )
		{
		orderedChain[ orderedChainIndex++ ] = certChainStart;
		getIssuerChainingInfo( chainingInfo, &certChainInfo[ 0 ] );
		memset( &certChainInfo[ 0 ], 0, sizeof( CERTCHAIN_INFO ) );
		}

	/* Build an ordered chain of certs from the leaf to the root */
	do
		{
		/* Find the cert with the current issuer as its subject */
		for( i = 0; i < certChainSize; i++ )
			if( isSubject( chainingInfo, &certChainInfo[ i ] ) )
				{
				/* 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( chainingInfo, &certChainInfo[ i ] );
				memset( &certChainInfo[ i ], 0, sizeof( CERTCHAIN_INFO ) );
				break;
				}
		}
	while( i != certChainSize );

	/* 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( certChainInfo[ i ].subjectDN != NULL )
			krnlSendNotifier( iCertChain[ i ], RESOURCE_IMESSAGE_DECREFCOUNT );

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

	return( orderedChainIndex );
	}

/* Copy a cert chain into a certificate object and canonicalise the chain by
   ordering the certs in a cert chain from the leaf cert up to the root.  
   This function is used when signing a cert with a cert chain, and takes as
   input ( oldCert, oldCert.chain[ ... ] ) and produces as output ( newCert, 
   chain[ oldCert, oldCert.chain[ ... ] ], ie the chain for the new cert
   contains the old cert and its attached cert chain */

int copyCertChain( CERT_INFO *certInfoPtr, const CRYPT_HANDLE certChain )
	{
	CRYPT_CERTIFICATE iChainCert;
	CERT_INFO *chainCertInfoPtr;
	CERTCHAIN_INFO certChainInfo[ MAX_CHAINLENGTH ];
	int i, status;

	assert( isWritePtr( certInfoPtr, CERT_INFO ) );

	/* Extract the base certificate from the chain and copy it over.  Note
	   that we pass in the cert chain handle for the copy since the internal
	   cert won't be visible */
	status = krnlSendMessage( certChain, RESOURCE_MESSAGE_GETDEPENDENT,
							  &iChainCert, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		return( status );
	getCheckInternalResource( iChainCert, chainCertInfoPtr,
							  OBJECT_TYPE_CERTIFICATE );
	krnlSendNotifier( iChainCert, RESOURCE_IMESSAGE_INCREFCOUNT );
	certInfoPtr->certChain[ certInfoPtr->certChainEnd++ ] = iChainCert;

	/* Copy the rest of the chain.  Because we're about to canonicalise it
	   (which reorders the certs and deletes unused ones) we copy individual
	   certs over rather than copying only the base cert and relying on the
	   chain held in that */
	for( i = 0; i < chainCertInfoPtr->certChainEnd; i++ )
		{
		certInfoPtr->certChain[ certInfoPtr->certChainEnd++ ] = \
										chainCertInfoPtr->certChain[ i ];
		krnlSendNotifier( chainCertInfoPtr->certChain[ i ],
						  RESOURCE_IMESSAGE_INCREFCOUNT );
		}
	unlockResource( chainCertInfoPtr );

	/* If the chain being attached consists of a single cert (which occurs
	   when we're building a new chain by signing a cert with a CA cert), we 
	   don't have to bother doing anything else */
	if( !chainCertInfoPtr->certChainEnd )
		return( CRYPT_OK );

	/* Extract the chaining info from each certificate and use it to sort the
	   chain.  Since we know what the leaf cert is and since chaining info 
	   such as the encoded DN data in the certinfo structure may not have been
	   set up yet if it contains an unsigned cert, we feed in the leaf cert 
	   and omit the chaining info */
	status = buildCertChainInfo( certChainInfo, certInfoPtr->certChain,
								 certInfoPtr->certChainEnd );
	if( cryptStatusError( status ) )
		return( status );
	status = sortCertChain( certInfoPtr->certChain, certChainInfo,
							certInfoPtr->certChainEnd, iChainCert, NULL );
	if( cryptStatusError( status ) )
		return( status );

	certInfoPtr->certChainEnd = status;
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Verify a Certificate Chain						*
*																			*
****************************************************************************/

/* Get the next certificate down the chain.  Returns OK_SPECIAL if there are
   no more certs present */

static int getNextCert( const CERT_INFO *certInfoPtr,
						CERT_INFO **certChainPtr, const int certChainIndex )
	{
	assert( isReadPtr( certInfoPtr, CERT_INFO ) );

	if( certChainIndex >= 0 )
		{
		getCheckInternalResource( certInfoPtr->certChain[ certChainIndex ],
								  *certChainPtr, OBJECT_TYPE_CERTIFICATE );
		return( CRYPT_OK );
		}
	if( certChainIndex == -1 )
		{
		/* The -1th cert is the leaf itself */
		*certChainPtr = ( CERT_INFO * ) certInfoPtr;
		return( CRYPT_OK );
		}

	/* We've reached the end of the chain, return a special status value to
	   indicate this */
	*certChainPtr = NULL;
	return( OK_SPECIAL );
	}

/* Check constraints along a cert chain.  There are three types of
   constraints which can cover multiple certs: path constraints, name
   constraints, and policy constraints.

   Path constraints are easiest to check, just make sure the number of certs
   from the issuer to the leaf is less than the constraint length.

   Name constraints are a bit more difficult, the abstract description
   requires building and maintaining a (potentially enormous) name constraint
   tree which is applied to each cert in turn as it is processed, however
   since name constraints are practically nonexistant and chains are short
   it's more efficient to walk down the cert chain when a constraint is
   encountered and check each cert in turn, which avoids having to maintain
   massive amounts of state information and is no less efficient than a
   single monolithic state comparison.

   Policy constraints are hardest of all because, with the complex mishmash
   of policies, policy constraints, qualifiers, and mappings it turns out
   that noone actually knows how to apply them.  The ambiguity of name
   constraints when applied to altNames is bad enough, with a 50/50 split in
   PKIX about whether it should be an AND or OR operation, and whether a DN
   constraint applies to a subjectName or altName or both (the latter was
   fixed in the final version of RFC 2459, although how many implementations 
   follow exactly this version rather than the dozen earlier drafts or any 
   other profile is unknown).  With policy constraints it's even worse and 
   no-one seems to be able to agree on what to do with them.  For this reason 
   we should leave this particular rathole for someone else to fall into, but 
   to claim buzzword-compliance to PKIX we need to implement this checking 
   (although we don't handle the weirder constraints on policies, which have 
   never been seen in the wild, yet).  Massa make big magic, gunga din */

static int checkConstraints( CERT_INFO *certInfoPtr,
							 const CERT_INFO *issuerCertInfoPtr,
							 int *subjectCertIndex )
	{
	ATTRIBUTE_LIST *attributeListPtr, *nameAttributeListPtr;
	ATTRIBUTE_LIST *policyAttributeListPtr;
	int certIndex = *subjectCertIndex, status = CRYPT_OK;

	assert( isWritePtr( certInfoPtr, CERT_INFO ) );
	assert( isReadPtr( issuerCertInfoPtr, CERT_INFO ) );

	/* If there's a path length constraint present, check that it's
	   satisfied: The number of certs from the issuer (at subjectCertIndex 
	   + 1) to the end entity (at -1) must be less than the length 
	   constraint, i.e. the subjectCertIndex must be greater than the 

⌨️ 快捷键说明

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