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

📄 chain.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
	   hashes so that if the certificate 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 < MAX_CHAINLENGTH; i++ )
		{
		if( !memcmp( certChainHashes[ i ], 
					 certChainHashes[ certChainLen ], msgData.length ) )
			return( TRUE );
		}
	return( FALSE );
	}

/* Copy a certificate chain into a certificate object and canonicalise the 
   chain by ordering the certificates from the leaf certificate up to the 
   root.  This function is used when signing a certificate 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 certificate contains the old certificate and its 
   attached certificate chain */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int copyCertChain( INOUT CERT_INFO *certInfoPtr, 
				   IN_HANDLE const CRYPT_HANDLE certChain,
				   const BOOLEAN isCertCollection )
	{
	CRYPT_CERTIFICATE iChainCert;
	CERT_INFO *chainCertInfoPtr;
	CERT_CERT_INFO *certChainInfo = certInfoPtr->cCertCert;
	CHAIN_INFO chainInfo[ MAX_CHAINLENGTH + 8 ];
	BYTE certChainHashes[ MAX_CHAINLENGTH + 1 + 8 ][ CRYPT_MAX_HASHSIZE + 8 ];
	const int oldChainEnd = certChainInfo->chainEnd;
	int i, status;

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

	REQUIRES( isHandleRangeValid( certChain ) );

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

	/* If we're building a certificate collection all that we need to ensure 
	   is non-duplicate certificates rather than a strict chain.  To handle 
	   duplicate-checking we build a list of the fingerprints for each 
	   certificate in the chain */
	if( isCertCollection )
		{
		for( i = 0; i < certChainInfo->chainEnd && i < MAX_CHAINLENGTH; i++ )
			{
			MESSAGE_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 );
			}
		ENSURES( i < MAX_CHAINLENGTH );
		}

	/* Extract the base certificate from the chain and copy it over (the
	   certPresent() check also sets up the hash for the new certificate 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 certificates and deletes unused ones) we copy 
	   individual certificates over rather than copying only the base 
	   certificate and relying on the chain held in that */
	for( i = 0; cryptStatusOK( status ) && \
				i < chainCertInfoPtr->cCertCert->chainEnd && \
				i < MAX_CHAINLENGTH; 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;
			}
		}
	ENSURES( i < MAX_CHAINLENGTH );
	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( DEBUG_WARN );

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

		return( status );
		}

	/* If we're building an unordered certificate collection, mark the 
	   certificate chain object as a certificate collection only and exit.  
	   This is a pure container object for which only the certificate chain 
	   member contains certificates, the base certificate object doesn't 
	   correspond to an actual certificate */
	if( isCertCollection )
		{
		certInfoPtr->flags |= CERT_FLAG_CERTCOLLECTION;
		return( CRYPT_OK );
		}

	/* If the chain being attached consists of a single certificate (which 
	   occurs when we're building a new chain by signing a certificate with 
	   a CA certificate) 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 certificate 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 certificate 
	   we feed in the leaf certificate and omit the chaining information.  
	   Since sortCertChain() deletes unused certificates (and never returns 
	   an error status, all it does is shuffle existing certificates 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 certificates 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 */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readCertChain( INOUT STREAM *stream, 
				   OUT CRYPT_CERTIFICATE *iCryptCert,
				   IN_HANDLE const CRYPT_USER iCryptOwner,
				   IN_ENUM( CRYPT_CERTTYPE ) const CRYPT_CERTTYPE_TYPE type,
				   IN_KEYID_OPT const CRYPT_KEYID_TYPE keyIDtype,
				   IN_BUFFER_OPT( keyIDlength ) const void *keyID, 
				   IN_LENGTH_KEYID_Z const int keyIDlength,
				   const BOOLEAN dataOnlyCert )
	{
	CRYPT_CERTIFICATE iCertChain[ MAX_CHAINLENGTH + 8 ];
	int certSequenceLength, endPos = 0, certChainEnd = 0;
	int iterationCount, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( iCryptCert, sizeof( CRYPT_CERTIFICATE ) ) );
	assert( ( keyIDtype == CRYPT_KEYID_NONE && keyID == NULL && \
			  keyIDlength == 0 ) || \
			( ( keyIDtype == CRYPT_IKEYID_KEYID || \
				keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ) && \
			  isReadPtr( keyID, keyIDlength ) && \
			  keyIDlength >= MIN_SKID_SIZE ) );

	REQUIRES( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
			  isHandleRangeValid( iCryptOwner ) );
	REQUIRES( type == CRYPT_CERTTYPE_CERTCHAIN || \
			  type == CRYPT_ICERTTYPE_CMS_CERTSET || \
			  type == CRYPT_ICERTTYPE_SSL_CERTCHAIN );
	REQUIRES( ( keyIDtype == CRYPT_KEYID_NONE && \
				keyID == NULL && keyIDlength == 0 ) || \
			  ( ( keyIDtype == CRYPT_IKEYID_KEYID || \
				  keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ) && \
				keyID != NULL && \
				keyIDlength >= MIN_SKID_SIZE && \
				keyIDlength < MAX_ATTRIBUTE_SIZE ) );

	switch( type )
		{
		case CRYPT_CERTTYPE_CERTCHAIN:
			{
			BYTE oid[ MAX_OID_SIZE + 8 ];
			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 readEncodedOID() rather 
			   than readUniversal() to make sure that we're at least getting 
			   an OID at this point */
			status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, 
									 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 readEncodedOID()
			   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 
			   certificate chain), if there's data present then we skip it */
			readSequenceI( stream, &length );
			status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, 
									 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( cryptStatusError( status ) )
					return( status );
				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 
				   certificate 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 certificate chain however the length will be equal to the 
			   total remaining stream size */
			certSequenceLength = sMemDataLeft( stream );
			status = CRYPT_OK;
			break;

		default:
			retIntError();
		}
	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 
	   certificates into certificate objects.  We allow for a bit of slop 
	   for software that gets the length encoding wrong by a few bytes.  
	   Note that the limit is given as FAILSAFE_ITERATIONS_MED since we're 
	   using it as a fallback check on the existing MAX_CHAINLENGTH check.  
	   In other words anything over MAX_CHAINLENGTH is handled as a normal 
	   error and it's only if we exceed this that we have an internal 
	   error */
	for( iterationCount = 0;
		 ( certSequenceLength == CRYPT_UNUSED || \
		   stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE ) && \
			iterationCount < FAILSAFE_ITERATIONS_MED; 
		 iterationCount++ )
		{
		CRYPT_CERTIFICATE iNewCert = DUMMY_INIT;
		void *dataPtr;
		int length;

		/* 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 certificate chain then there's a 24-bit length 
		   field between certificates */
		if( type == CRYPT_ICERTTYPE_SSL_CERTCHAIN )
			sSkip( stream, 3 );

		/* Read the next certificate and add it to the chain.  When 
		   importing the chain from an external (untrusted) source we create 
		   standard certificates so that we can check the signatures on each 
		   link in the chain.  When importing from a trusted source we 
		   create data-only certificates, once we've got all of the 
		   certificates and know which certificate is the leaf we can go 
		   back and decode the public key information for it */
		status = sMemGetDataBlockRemaining( stream, &dataPtr, &length );
		if( cryptStatusOK( status ) )
			{
			status = importCert( dataPtr, length, &iNewCert, iCryptOwner, 
								 CRYPT_KEYID_NONE, NULL, 0, 
								 dataOnlyCert ? \

⌨️ 快捷键说明

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