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

📄 certchn.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
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, status;

	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 > MIN_SKID_SIZE && \
				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 );				/* 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( certChainInfo[ i ].issuerDNsize > 0 && \
			certChainInfo[ i ].issuerDNsize == issuerDNsize && \
			!memcmp( certChainInfo[ i ].issuerDN, issuerDNptr,
					 issuerDNsize ) && \
			!compareSerialNumber( certChainInfo[ i ].serialNumber, 
								  certChainInfo[ i ].serialNumberSize,
								  serialNumber, serialNumberSize ) )
			return( i );

	return( CRYPT_ERROR_NOTFOUND );
	}

/* 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 */
	setMessageData( &msgData, certChainHashes[ certChainLen ], 
					CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_CERTINFO_FINGERPRINT );
	if( cryptStatusError( status ) )
		return( status );

	/* Make sure that it isn't already present in the collection */
	for( i = 0; i < certChainLen; i++ )
		if( !memcmp( certChainHashes[ i ], 
					 certChainHashes[ certChainLen ], msgData.length ) )
			return( TRUE );
	return( FALSE );
	}

/* 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 ];
	CHAINING_INFO localChainingInfo, *chainingInfoPtr = &localChainingInfo;
	int orderedChainIndex = 0, i;

	assert( certChainSize > 0 && certChainSize < MAX_CHAINLENGTH );
	assert( isWritePtrEx( iCertChain, CRYPT_CERTIFICATE, certChainSize ) );
	assert( isWritePtrEx( certChainInfo, CERTCHAIN_INFO, certChainSize ) );
	assert( ( checkHandleRange( certChainStart ) && \
			  chainingInfo == NULL ) || \
			( certChainStart == CRYPT_UNUSED && \
			  isWritePtr( chainingInfo, 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, &certChainInfo[ 0 ] );
		memset( &certChainInfo[ 0 ], 0, sizeof( CERTCHAIN_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
		{
		/* Find the cert with the current issuer as its subject */
		for( i = 0; i < certChainSize; i++ )
			if( isSubject( chainingInfoPtr, &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( chainingInfoPtr, &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 ], 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 );
	}

/* 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[ ... ] ], i.e.the chain for the new cert
   contains the old cert and its attached cert chain */

int copyCertChain( CERT_INFO *certInfoPtr, const CRYPT_HANDLE certChain,
				   const BOOLEAN isCertCollection )
	{
	CRYPT_CERTIFICATE iChainCert;
	CERT_INFO *chainCertInfoPtr;
	CERTCHAIN_INFO certChainInfo[ MAX_CHAINLENGTH ];
	BYTE certChainHashes[ MAX_CHAINLENGTH + 1 ][ CRYPT_MAX_HASHSIZE ];
	int i, status;

	assert( isWritePtr( certInfoPtr, CERT_INFO ) );

	status = krnlSendMessage( certChain, IMESSAGE_GETDEPENDENT, &iChainCert, 
							  OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		return( status );

	/* If we're building a cert collection, all we need to ensure is non-
	   duplicate certs rather than a strict chain.  To handle duplicate-
	   checking, we build a list of the fingerprints for each cert in the
	   chain */
	if( isCertCollection )
		{
		for( i = 0; i < certInfoPtr->certChainEnd; i++ )
			{
			RESOURCE_DATA msgData;

			setMessageData( &msgData, certChainHashes[ i ], 
							CRYPT_MAX_HASHSIZE );
			status = krnlSendMessage( certInfoPtr->certChain[ i ], 
									  IMESSAGE_GETATTRIBUTE_S, &msgData, 
									  CRYPT_CERTINFO_FINGERPRINT );
			if( cryptStatusError( status ) )
				return( status );
			}
		}

	/* Extract the base certificate from the chain and copy it over */
	status = krnlGetObject( iChainCert, OBJECT_TYPE_CERTIFICATE, 
							( void ** ) &chainCertInfoPtr, 
							CRYPT_ERROR_SIGNALLED );
	if( cryptStatusError( status ) )
		return( status );
	if( !isCertCollection || \
		!certPresent( certChainHashes, certInfoPtr->certChainEnd,
					  iChainCert ) )
		{
		krnlSendNotifier( iChainCert, 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++ )
		if( !isCertCollection || \
			!certPresent( certChainHashes, certInfoPtr->certChainEnd,
						  chainCertInfoPtr->certChain[ i ] ) )
			{
			certInfoPtr->certChain[ certInfoPtr->certChainEnd++ ] = \
										chainCertInfoPtr->certChain[ i ];
			krnlSendNotifier( chainCertInfoPtr->certChain[ i ],
							  IMESSAGE_INCREFCOUNT );
			}
	krnlReleaseObject( chainCertInfoPtr->objectHandle );

	/* If we're building an unordered cert collection, mark the cert chain
	   object as a cert collection only and exit */
	if( isCertCollection )
		{
		certInfoPtr->flags |= CERT_FLAG_CERTCOLLECTION;
		return( CRYPT_OK );
		}

	/* 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 <= 0 )
		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( cryptStatusOK( 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 )
		return( krnlGetObject( certInfoPtr->certChain[ certChainIndex ], 
							   OBJECT_TYPE_CERTIFICATE, 
							   ( void ** ) certChainPtr, 
							   CRYPT_ERROR_SIGNALLED ) );
	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, checked if complianceLevel >=
   CRYPT_COMPLIANCELEVEL_PKIX_FULL.  There are three types of constraints 
   that can cover multiple certs: path constraints, name constraints, and 
   policy constraints.

   Path constraints are easiest to check, just make sure that 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 no-one actually knows how to apply them, and even if people could
   agree, with the de facto use of the policy extension as the kitchenSink
   extension it's uncertain how to apply the constraints to typical
   kitchenSink constructs.  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 )
	{
	const ATTRIBUTE_LIST *nameAttributeListPtr, *policyAttributeListPtr;
	const ATTRIBUTE_LIST *attributeListPtr;
	BOOLEAN hasExcludedSubtrees, hasPermittedSubtrees, hasPolicy;
	BOOLEAN requireExplicitPolicyPresent = FALSE;
	int requireExplicitPolicyLevel = CRYPT_ERROR;
	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 
	   length */
	attributeListPtr = findAttributeField( issuerCertInfoPtr->attributes,
										   CRYPT_CERTINFO_PATHLENCONSTRAINT, 
										   CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr != NULL && \
		!( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) && \
		attributeListPtr->intValue <= certIndex )
		{
		setErrorInfo( certInfoPtr, CRYPT_CERTINFO_PATHLENCONSTRAINT,
					  CRYPT_ERRTYPE_ISSUERCONSTRAINT );
		return( CRYPT_ERROR_INVALID );

⌨️ 快捷键说明

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