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

📄 chain.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 4 页
字号:
	   that if the cert is then added to the chain, its hash will also be 
	   present */
	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 );
	}

/* Copy a cert chain into a certificate object and canonicalise the chain by
   ordering the certs 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;
	CERT_CERT_INFO *certChainInfo = certInfoPtr->cCertCert;
	CHAIN_INFO chainInfo[ MAX_CHAINLENGTH ];
	BYTE certChainHashes[ MAX_CHAINLENGTH + 1 ][ CRYPT_MAX_HASHSIZE ];
	const int oldChainEnd = certChainInfo->chainEnd;
	int i, status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isHandleRangeValid( certChain ) );

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

	/* If we're building a cert collection, all that 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 < certChainInfo->chainEnd; i++ )
			{
			RESOURCE_DATA msgData;

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

	/* Extract the base certificate from the chain and copy it over (the
	   certPresent() check also sets up the hash for the new cert in the
	   certChainHashes array) */
	status = krnlAcquireObject( iChainCert, OBJECT_TYPE_CERTIFICATE, 
								( void ** ) &chainCertInfoPtr, 
								CRYPT_ERROR_SIGNALLED );
	if( cryptStatusError( status ) )
		return( status );
	if( !isCertCollection || \
		!certPresent( certChainHashes, certChainInfo->chainEnd, iChainCert ) )
		{
		if( certChainInfo->chainEnd >= MAX_CHAINLENGTH )
			status = CRYPT_ERROR_OVERFLOW;
		else
			{
			krnlSendNotifier( iChainCert, IMESSAGE_INCREFCOUNT );
			certChainInfo->chain[ certChainInfo->chainEnd++ ] = iChainCert;
			}
		}

	/* Copy the rest of the chain.  Because we're about to canonicalise it
	   (which re-orders 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; cryptStatusOK( status ) && \
				i < chainCertInfoPtr->cCertCert->chainEnd; i++ )
		if( !isCertCollection || \
			!certPresent( certChainHashes, certChainInfo->chainEnd,
						  chainCertInfoPtr->cCertCert->chain[ i ] ) )
			{
			const CRYPT_CERTIFICATE iCopyCert = \
								chainCertInfoPtr->cCertCert->chain[ i ];

			if( certChainInfo->chainEnd >= MAX_CHAINLENGTH )
				{
				status = CRYPT_ERROR_OVERFLOW;
				break;
				}
			krnlSendNotifier( iCopyCert, IMESSAGE_INCREFCOUNT );
			certChainInfo->chain[ certChainInfo->chainEnd++ ] = iCopyCert;
			}
	krnlReleaseObject( chainCertInfoPtr->objectHandle );
	if( cryptStatusError( status ) )
		{
		/* An error at this point indicates that the upper limit on chain
		   length isn't sufficient, so we throw a (debug) exception if we 
		   get here */
		assert( NOTREACHED );

		/* Clean up the newly-copied certs if necessary */
		if( certChainInfo->chainEnd > oldChainEnd )
			freeCertChain( &certChainInfo->chain[ oldChainEnd ],
						   certChainInfo->chainEnd - oldChainEnd );

		return( status );
		}

	/* If we're building an unordered cert collection, mark the cert chain
	   object as a cert collection only and exit.  This is a pure container
	   object for which only the cert chain member contains certs, the base
	   cert object doesn't correspond to an actual cert */
	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->cCertCert->chainEnd <= 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.  Since sortCertChain() deletes unused 
	   certs (and never returns an error status, all it does is shuffle
	   existing certs around) we only perform a cleanup if the chain-build
	   fails */
	status = buildChainInfo( chainInfo, certChainInfo->chain,
							 certChainInfo->chainEnd );
	if( cryptStatusError( status ) )
		{
		/* Clean up the newly-copied certs if necessary */
		if( certChainInfo->chainEnd > oldChainEnd )
			freeCertChain( &certChainInfo->chain[ oldChainEnd ],
						   certChainInfo->chainEnd - oldChainEnd );

		return( status );
		}
	certChainInfo->chainEnd = sortCertChain( certChainInfo->chain, chainInfo,
											 certChainInfo->chainEnd, 
											 iChainCert, NULL, FALSE );
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						Read Certificate-bagging Records					*
*																			*
****************************************************************************/

/* Read certificate chain/sequence information */

int readCertChain( STREAM *stream, CRYPT_CERTIFICATE *iCryptCert,
				   const CRYPT_USER cryptOwner,
				   const CRYPT_CERTTYPE_TYPE type,
				   const CRYPT_KEYID_TYPE keyIDtype,
				   const void *keyID, const int keyIDlength,
				   const BOOLEAN dataOnlyCert )
	{
	CRYPT_CERTIFICATE iCertChain[ MAX_CHAINLENGTH ];
	int certSequenceLength, endPos, certChainEnd = 0, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( iCryptCert, sizeof( CRYPT_CERTIFICATE ) ) );
	assert( isHandleRangeValid( cryptOwner ) || \
			cryptOwner == DEFAULTUSER_OBJECT_HANDLE );
	assert( type == CRYPT_CERTTYPE_CERTCHAIN || \
			type == CRYPT_ICERTTYPE_CMS_CERTSET || \
			type == CRYPT_ICERTTYPE_SSL_CERTCHAIN );
	assert( ( keyIDtype == CRYPT_KEYID_NONE && keyID == NULL && \
			  keyIDlength == 0 ) || \
			( ( keyIDtype == CRYPT_IKEYID_KEYID || \
				keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ) && \
			  isReadPtr( keyID, keyIDlength ) && keyIDlength > 16 ) );

	switch( type )
		{
		case CRYPT_CERTTYPE_CERTCHAIN:
			{
			BYTE oid[ MAX_OID_SIZE ];
			long integer;
			int length, oidLength;

			/* Skip the contentType OID, read the content encapsulation and 
			   header if necessary, and burrow down into the PKCS #7 content.  
			   First we read the wrapper.  We use readRawObject() rather 
			   than readUniversal() to make sure that we're at least getting 
			   an OID at this point */
			status = readRawObject( stream, oid, &oidLength, MAX_OID_SIZE, 
									BER_OBJECT_IDENTIFIER );
			if( cryptStatusError( status ) )
				return( status );
			readConstructed( stream, NULL, 0 );
			readSequence( stream, NULL );

			/* Read the version number (1 = PKCS #7 v1.5, 2 = PKCS #7 v1.6,
			   3 = S/MIME with attribute certificate(s)), and (should be 
			   empty) SET OF DigestAlgorithmIdentifier */
			readShortInteger( stream, &integer );
			status = readSet( stream, &length );
			if( cryptStatusOK( status ) && ( integer < 1 || integer > 3 ) )
				status = CRYPT_ERROR_BADDATA;
			if( cryptStatusError( status ) )
				return( status );
			if( length > 0 )
				sSkip( stream, length );

			/* Read the ContentInfo header, contentType OID (ignored) and 
			   the inner content encapsulation.  We use readRawObject()
			   rather than readUniversal() to make sure that we're at least
			   getting an OID at this point.

			   Sometimes we may (incorrectly) get passed actual signed data 
			   (rather than degenerate zero-length data signifying a pure 
			   cert chain), if there's data present we skip it */
			readSequenceI( stream, &length );
			status = readRawObject( stream, oid, &oidLength, MAX_OID_SIZE, 
									BER_OBJECT_IDENTIFIER );
			if( cryptStatusError( status ) )
				return( status );
			if( length == CRYPT_UNUSED )
				{
				/* It's an indefinite-length ContentInfo, check for the 
				   EOC.  If there's no EOC present that means there's 
				   indefinite-length inner data present and we have to dig 
				   down further */
				status = checkEOC( stream );
				if( status == FALSE )
					{
					int innerLength;

					/* Try and get the length from the ContentInfo.  We're
					   really reaching the point of diminishing return here,
					   if we can't get a length at this point we bail out
					   since we're not even supposed to be getting down to
					   this level */
					status = readConstructedI( stream, &innerLength, 0 );
					if( cryptStatusError( status ) )
						return( status );
					if( innerLength == CRYPT_UNUSED )
						return( CRYPT_ERROR_BADDATA );
					status = sSkip( stream, innerLength );
					}
				}
			else
				/* If we've been fed signed data (i.e. the ContentInfo has 
				   the content field present), skip the content to get to 
				   the cert chain */
				if( length > sizeofObject( oidLength ) )
					status = readUniversal( stream );
			status = readConstructedI( stream, &certSequenceLength, 0 );
			break;
			}

		case CRYPT_ICERTTYPE_CMS_CERTSET:
			status = readConstructedI( stream, &certSequenceLength, 0 );
			break;

		case CRYPT_ICERTTYPE_SSL_CERTCHAIN:
			/* There's no outer wrapper to give us length information for an 
			   SSL cert chain, however the length will be equal to the total 
			   stream size */
			certSequenceLength = sMemBufSize( stream );
			status = CRYPT_OK;
			break;

		default:
			assert( NOTREACHED );
			return( CRYPT_ERROR_BADDATA );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* If it's a definite-length chain, determine where it ends */
	if( certSequenceLength != CRYPT_UNUSED )
		endPos = stell( stream ) + certSequenceLength;

	/* We've finally reached the certificate(s), read the collection of certs
	   into cert objects.  We allow for a bit of slop for software that gets 
	   the length encoding wrong by a few bytes */
	while( certSequenceLength == CRYPT_UNUSED || \
		   stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
		{
		CRYPT_CERTIFICATE iNewCert;

		/* Make sure that we don't overflow the chain */
		if( certChainEnd >= MAX_CHAINLENGTH )
			{
			freeCertChain( iCertChain, certChainEnd );
			return( CRYPT_ERROR_OVERFLOW );
			}

		/* If it's an SSL cert chain, there's a 24-bit length field between
		   certs */
		if( type == CRYPT_ICERTTYPE_SSL_CERTCHAIN )
			sSkip( stream, 3 );

		/* Read the next cert and add it to the chain.  When importing the
		   chain from an external (untrusted) source we create standard certs
		   so that we can check the signatures on each link in the chain.  
		   When importing from a trusted source we create data-only certs, 

⌨️ 快捷键说明

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