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

📄 certchn.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
							  CRYPT_CERTINFO_SELFSIGNED );
	if( cryptStatusOK( status ) && selfSigned )
		certChainPtr->flags |= CERT_FLAG_SELFSIGNED;
	krnlReleaseObject( certChainPtr->objectHandle );

	return( CRYPT_OK );
	}

/* 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 = CRYPT_OK;

	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 ) && \
			  keyID != NULL && keyIDlength > 16 ) );

	/* If it's a PKCS #7 chain, skip the contentType OID, read the content 
	   encapsulation and header if necessary, and burrow down into the PKCS 
	   #7 content */
	if( type == CRYPT_CERTTYPE_CERTCHAIN )
		{
		long integer;
		int length, oidLength;

		/* Read the wrapper */
		readUniversal( stream );
		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 and the inner content 
		   encapsulation.  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, NULL, &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 */
			status = checkEOC( stream );
		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 );
		}
	if( type == CRYPT_CERTTYPE_CERTCHAIN || \
		type == CRYPT_ICERTTYPE_CMS_CERTSET )
		status = readConstructedI( stream, &certSequenceLength, 0 );
	else
		/* 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 );
	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 - 1 )
			{
			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 we can check the signatures on each link in the chain.  When
		   importing from a trusted source we create data-only certs, once
		   we've got all the certs and know which cert is the leaf, we can 
		   go back and decode the public key information for it */
		status = importCert( sMemBufPtr( stream ), sMemDataLeft( stream ),
							 &iNewCert, cryptOwner, CRYPT_KEYID_NONE,
							 NULL, 0, dataOnlyCert ? \
								CERTFORMAT_DATAONLY : \
								CRYPT_CERTTYPE_CERTIFICATE );
		if( cryptStatusOK( status ) )
			{
			RESOURCE_DATA msgData;

			/* Add the newly-read cert to the chain and skip over its
			   encoded data.  Unfortunately due to the mixing of stream and 
			   non-stream functions we have to do this in a somewhat 
			   roundabout manner by getting the length of the data in the 
			   newly-created cert object and then skipping that far ahead in
			   the input stream */
			iCertChain[ certChainEnd++ ] = iNewCert;
			setMessageData( &msgData, NULL, 0 );
			status = krnlSendMessage( iNewCert, IMESSAGE_CRT_EXPORT, 
									  &msgData, CRYPT_CERTFORMAT_CERTIFICATE );
			if( cryptStatusOK( status ) )
				status = sSkip( stream, msgData.length );
			}
		if( cryptStatusError( status ) )
			{
			if( certChainEnd > 0 )
				freeCertChain( iCertChain, certChainEnd );
			return( status );
			}

		/* If it's encoded using the indefinite form and we find the EOC
		   octets, exit */
		if( certSequenceLength == CRYPT_UNUSED )
			{
			status = checkEOC( stream );
			if( cryptStatusError( status ) )
				return( status );
			if( status == TRUE )
				/* We've seen EOC octets, we're done */
				break;
			}
		}

	/* We must have read at least one cert in order to create a chain */
	if( certChainEnd <= 0 )
		return( CRYPT_ERROR_BADDATA );

	/* Build the complete chain from the individual certs */
	return( buildCertChain( iCryptCert, iCertChain, certChainEnd, 
							keyIDtype, keyID, keyIDlength ) );
	}

/* Fetch a sequence of certs from an object to create a cert chain */

int assembleCertChain( CRYPT_CERTIFICATE *iCertificate,
					   const CRYPT_HANDLE iCertSource, 
					   const CRYPT_KEYID_TYPE keyIDtype,
					   const void *keyID, const int keyIDlength,
					   const int options )
	{
	CRYPT_CERTIFICATE iCertChain[ MAX_CHAINLENGTH ], lastCert;
	MESSAGE_KEYMGMT_INFO getnextcertInfo;
	const int chainOptions = options & KEYMGMT_FLAG_DATAONLY_CERT;
	int stateInfo = CRYPT_ERROR, certChainEnd = 1, status;

	/* Get the initial cert based on the key ID */
	setMessageKeymgmtInfo( &getnextcertInfo, keyIDtype, keyID, keyIDlength, 
						   &stateInfo, sizeof( int ), 
						   options & KEYMGMT_MASK_CERTOPTIONS );
	status = krnlSendMessage( iCertSource, IMESSAGE_KEY_GETFIRSTCERT,
							  &getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY );
	if( cryptStatusError( status ) )
		return( status );
	iCertChain[ 0 ] = lastCert = getnextcertInfo.cryptHandle;

	/* Fetch subsequent certs that make up the chain based on the state
	   information.  Since the basic options apply only to the leaf cert,
	   we only allow the data-only-cert flag at this point */
	setMessageKeymgmtInfo( &getnextcertInfo, CRYPT_KEYID_NONE, NULL, 0, 
						   &stateInfo, sizeof( int ), chainOptions );
	do
		{
		int selfSigned;

		/* If we've reached a self-signed cert, stop */
		krnlSendMessage( lastCert, IMESSAGE_GETATTRIBUTE, &selfSigned, 
						 CRYPT_CERTINFO_SELFSIGNED );
		if( selfSigned )
			break;

		/* Get the next cert in the chain from the source, import it, and 
		   add it to the collection */
		getnextcertInfo.cryptHandle = CRYPT_ERROR;	/* Reset result handle */
		status = krnlSendMessage( iCertSource, IMESSAGE_KEY_GETNEXTCERT,
								  &getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY );
		if( cryptStatusOK( status ) )
			{
			if( certChainEnd >= MAX_CHAINLENGTH - 1 )
				status = CRYPT_ERROR_OVERFLOW;
			else
				iCertChain[ certChainEnd++ ] = \
							lastCert = getnextcertInfo.cryptHandle;
			}
		if( status == CRYPT_ERROR_NOTFOUND )
			{
			status = CRYPT_OK;
			break;	/* End of chain reached */
			}
		}
	while( cryptStatusOK( status ) );
	if( cryptStatusError( status ) )
		{
		freeCertChain( iCertChain, certChainEnd );
		return( status );
		}

	/* Build the complete chain from the individual certs */
	return( buildCertChain( iCertificate, iCertChain, certChainEnd, 
							CRYPT_KEYID_NONE, NULL, 0 ) );
	}

/****************************************************************************
*																			*
*						Write Certificate-bagging Records					*
*																			*
****************************************************************************/

/* Determine the size of and write a certificate path from a base cert up to 
   the root.  If it's a cert collection, it's just a container for random
   certs but not a cert in its own right, so we skip the leaf cert */

static int sizeofCertPath( const CERT_INFO *certInfoPtr )
	{
	int length = 0, i;

	/* Evaluate the size of the current certificate and the issuer 
	   certificates in the chain */
	if( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) )
		length = certInfoPtr->certificateSize;
	for( i = 0; i < certInfoPtr->certChainEnd; i++ )
		{
		RESOURCE_DATA msgData;
		int status;

		setMessageData( &msgData, NULL, 0 );
		status = krnlSendMessage( certInfoPtr->certChain[ i ], 
								  IMESSAGE_CRT_EXPORT, &msgData, 
								  CRYPT_CERTFORMAT_CERTIFICATE );
		if( cryptStatusError( status ) )
			return( status );
		length += msgData.length;
		}

	return( length );
	}

static int writeCertPath( STREAM *stream, const CERT_INFO *certInfoPtr )
	{
	int i, status = CRYPT_OK;

	/* Write the current certificate and the associated cert chain up to the
	   root */
	if( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) )
		status = swrite( stream, certInfoPtr->certificate, 
						 certInfoPtr->certificateSize );
	for( i = 0; cryptStatusOK( status ) && \
				i < certInfoPtr->certChainEnd; i++ )
		{
		CERT_INFO *certChainPtr;

		status = krnlGetObject( certInfoPtr->certChain[ i ], 
								OBJECT_TYPE_CERTIFICATE, 
								( void ** ) &certChainPtr, 
								CRYPT_ERROR_SIGNALLED );
		if( cryptStatusOK( status ) )
			{
			status = swrite( stream, certChainPtr->certificate,
							 certChainPtr->certificateSize );
			krnlReleaseObject( certChainPtr->objectHandle );
			}
		}

	return( status );
	}

/* Write certificate chain/sequence information:

	CertChain ::= SEQUENCE {
		contentType				OBJECT IDENTIFIER,	-- signedData
		content			  [ 0 ]	EXPLICIT SEQUENCE {
			version				INTEGER (1),
			digestAlgorithms	SET OF AlgorithmIdentifier,	-- SIZE(0)
			contentInfo			SEQUENCE {
				signedData		OBJECT IDENTIFIER	-- data
				}
			certificates  [ 0 ]	IMPLICIT SET OF {
									Certificate
				}
			}
		signerInfos				SET OF SignerInfo			-- SIZE(0)
		} */

int sizeofCertSet( const CERT_INFO *certInfoPtr )
	{
	return( ( int ) sizeofObject( sizeofCertPath( certInfoPtr ) ) );
	}

int writeCertSet( STREAM *stream, const CERT_INFO *certInfoPtr )
	{
	writeConstructed( stream, sizeofCertPath( certInfoPtr ), 0 );
	return( writeCertPath( stream, certInfoPtr ) );
	}

int writeCertSequence( STREAM *stream, const CERT_INFO *certInfoPtr )
	{
	writeSequence( stream, sizeofCertPath( certInfoPtr ) );
	return( writeCertPath( stream, certInfoPtr ) );
	}

int writeCertChain( STREAM *stream, const CERT_INFO *certInfoPtr )
	{
	int innerLength;

	/* Determine how big the encoded cert chain/sequence will be */
	innerLength = sizeofShortInteger( 1 ) + ( int ) sizeofObject( 0 ) + \
					  ( int ) sizeofObject( sizeofOID( OID_CMS_DATA ) ) + \
					  ( int ) sizeofObject( sizeofCertPath( certInfoPtr ) ) + \
					  ( int ) sizeofObject( 0 );

	/* Write the outer SEQUENCE wrapper and contentType and content wrapper */
	writeSequence( stream, 
				   sizeofOID( OID_CMS_SIGNEDDATA ) + \
					( int ) sizeofObject( sizeofObject( innerLength ) ) );
	swrite( stream, OID_CMS_SIGNEDDATA, sizeofOID( OID_CMS_SIGNEDDATA ) );
	writeConstructed( stream, sizeofObject( innerLength ), 0 );
	writeSequence( stream, innerLength );

	/* Write the inner content */
	writeShortInteger( stream, 1, DEFAULT_TAG );
	writeSet( stream, 0 );
	writeSequence( stream, sizeofOID( OID_CMS_DATA ) );
	swrite( stream, OID_CMS_DATA, sizeofOID( OID_CMS_DATA ) );
	writeCertSet( stream, certInfoPtr );
	return( writeSet( stream, 0 ) );
	}

⌨️ 快捷键说明

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