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

📄 comp_set.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*							Set Certificate Components						*
*						Copyright Peter Gutmann 1997-2007					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "cert.h"
  #include "certattr.h"
  #include "asn1.h"
  #include "asn1_ext.h"
#else
  #include "cert/cert.h"
  #include "cert/certattr.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*								Utility Routines							*
*																			*
****************************************************************************/

/* Copy the encoded issuer DN */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyIssuerDnData( INOUT CERT_INFO *destCertInfoPtr,
							 const CERT_INFO *srcCertInfoPtr )
	{
	void *dnDataPtr;

	assert( isWritePtr( destCertInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isReadPtr( srcCertInfoPtr, sizeof( CERT_INFO ) ) );
	assert( srcCertInfoPtr->issuerDNptr != NULL );

	if( ( dnDataPtr = clAlloc( "copyIssuerDnData",
							   srcCertInfoPtr->issuerDNsize ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	memcpy( dnDataPtr, srcCertInfoPtr->issuerDNptr,
			srcCertInfoPtr->issuerDNsize );
	destCertInfoPtr->issuerDNptr = destCertInfoPtr->issuerDNdata = dnDataPtr;
	destCertInfoPtr->issuerDNsize = srcCertInfoPtr->issuerDNsize;

	return( CRYPT_OK );
	}

/* Copy revocation information into a CRL or revocation request */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyRevocationInfo( INOUT CERT_INFO *certInfoPtr,
							   const CERT_INFO *revInfoPtr )
	{
	int status = CRYPT_OK;

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

	REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
			  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );
	REQUIRES( revInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
			  revInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
			  revInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN || \
			  revInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION );

	/* If there's an issuer name recorded make sure that it matches the one
	   in the certificate that's being added */
	if( certInfoPtr->issuerDNptr != NULL )
		{
		if( certInfoPtr->issuerDNsize != revInfoPtr->issuerDNsize || \
			memcmp( certInfoPtr->issuerDNptr, revInfoPtr->issuerDNptr,
					certInfoPtr->issuerDNsize ) )
			{
			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
						  CRYPT_ERRTYPE_ATTR_VALUE );
			status = CRYPT_ERROR_INVALID;
			}
		}
	else
		{
		/* There's no issuer name present yet, set the CRL issuer name to
		   the certificate's issuer to make sure that we can't add 
		   certificates or sign the CRL with a different issuer.  We do this 
		   here rather than after setting the revocation list entry because 
		   of the difficulty of undoing the revocation entry addition */
		status = copyIssuerDnData( certInfoPtr, revInfoPtr );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Add the certificate information to the revocation list and make it 
	   the currently selected entry.  The ID type isn't quite an
	   issueAndSerialNumber but the checking code eventually converts it 
	   into this form using the supplied issuer certificate DN */
	if( revInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
		{
		status = addRevocationEntry( &certInfoPtr->cCertRev->revocations,
									 &certInfoPtr->cCertRev->currentRevocation,
									 CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
									 revInfoPtr->cCertReq->serialNumber,
									 revInfoPtr->cCertReq->serialNumberLength,
									 FALSE );
		}
	else
		{
		status = addRevocationEntry( &certInfoPtr->cCertRev->revocations,
									 &certInfoPtr->cCertRev->currentRevocation,
									 CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
									 revInfoPtr->cCertCert->serialNumber,
									 revInfoPtr->cCertCert->serialNumberLength,
									 FALSE );
		}
	if( status == CRYPT_ERROR_DUPLICATE )
		{
		/* If this certificate is already present in the list set the 
		   extended error code for it */
		setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
					  CRYPT_ERRTYPE_ATTR_PRESENT );
		}
	return( status );
	}

/* Copy public key data into a certificate object */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int copyPublicKeyInfo( INOUT CERT_INFO *certInfoPtr,
							  IN_HANDLE_OPT const CRYPT_HANDLE cryptHandle,
							  IN_OPT const CERT_INFO *srcCertInfoPtr )
	{
	void *publicKeyInfoPtr;
	int length = DUMMY_INIT, status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( ( isHandleRangeValid( cryptHandle ) && \
			  srcCertInfoPtr == NULL ) || \
			( cryptHandle == CRYPT_UNUSED && \
			  isReadPtr( srcCertInfoPtr, sizeof( CERT_INFO ) ) ) );

	REQUIRES( ( isHandleRangeValid( cryptHandle ) && \
				srcCertInfoPtr == NULL ) || \
			  ( cryptHandle == CRYPT_UNUSED && \
			    srcCertInfoPtr != NULL ) );

	/* Make sure that we haven't already got a public key present */
	if( certInfoPtr->iPubkeyContext != CRYPT_ERROR || \
		certInfoPtr->publicKeyInfo != NULL )
		{
		setErrorInfo( certInfoPtr, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
					  CRYPT_ERRTYPE_ATTR_PRESENT );
		return( CRYPT_ERROR_INITED );
		}

	/* If we've been given a data-only certificate copy over the public key 
	   data */
	if( srcCertInfoPtr != NULL )
		{
		REQUIRES( memcmp( srcCertInfoPtr->publicKeyID,
						  "\x00\x00\x00\x00\x00\x00\x00\x00", 8 ) );
		REQUIRES( ( ( BYTE * ) srcCertInfoPtr->publicKeyInfo )[ 0 ] == 0x30 );

		length = srcCertInfoPtr->publicKeyInfoSize;
		if( ( publicKeyInfoPtr = clAlloc( "copyPublicKeyInfo", length ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		memcpy( publicKeyInfoPtr, srcCertInfoPtr->publicKeyInfo, length );
		certInfoPtr->publicKeyAlgo = srcCertInfoPtr->publicKeyAlgo;
		certInfoPtr->publicKeyFeatures = srcCertInfoPtr->publicKeyFeatures;
		memcpy( certInfoPtr->publicKeyID, srcCertInfoPtr->publicKeyID,
				KEYID_SIZE );
		}
	else
		{
		CRYPT_CONTEXT iCryptContext;
		MESSAGE_DATA msgData;

		/* Get the context handle.  All other checking has already been
		   performed by the kernel */
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETDEPENDENT,
								  &iCryptContext, OBJECT_TYPE_CONTEXT );
		if( cryptStatusError( status ) )
			{
			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
						  CRYPT_ERRTYPE_ATTR_VALUE );
			return( status );
			}
		ENSURES( cryptStatusOK( \
					krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
									 MESSAGE_CHECK_PKC ) ) );

		/* Get the key information */
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
								  &certInfoPtr->publicKeyAlgo,
								  CRYPT_CTXINFO_ALGO );
		if( cryptStatusOK( status ) )
			status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
									  &certInfoPtr->publicKeyFeatures,
									  CRYPT_IATTRIBUTE_KEYFEATURES );
		if( cryptStatusOK( status ) )
			{
			setMessageData( &msgData, certInfoPtr->publicKeyID, KEYID_SIZE );
			status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
									  &msgData, CRYPT_IATTRIBUTE_KEYID );
			}
		if( cryptStatusError( status ) )
			return( status );

		/* Copy over the public-key data.  We copy the data rather than
		   keeping a reference to the context for two reasons.  Firstly,
		   when the certificate is transitioned into the high state it will
		   constrain the attached context so a context shared between two
		   certificates could be constrained in unexpected ways.  Secondly, 
		   the context could be a private-key context and attaching that to 
		   a certificate would be rather inappropriate.  Furthermore, the 
		   constraint issue is even more problematic in that a context 
		   constrained by an encryption-only request could then no longer be 
		   used to sign the request or a PKI protocol message containing the 
		   request */
		setMessageData( &msgData, NULL, 0 );
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_IATTRIBUTE_KEY_SPKI );
		if( cryptStatusError( status ) )
			return( status );
		length = msgData.length;
		if( ( publicKeyInfoPtr = clAlloc( "copyPublicKeyInfo", length ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		msgData.data = publicKeyInfoPtr;
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_IATTRIBUTE_KEY_SPKI );
		if( cryptStatusError( status ) )
			return( status );
		}
	certInfoPtr->publicKeyData = certInfoPtr->publicKeyInfo = \
		publicKeyInfoPtr;
	certInfoPtr->publicKeyInfoSize = length;
	certInfoPtr->flags |= CERT_FLAG_DATAONLY;

	return( CRYPT_OK );
	}

/* Convert a DN in string form into a certificate DN */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int getEncodedDn( INOUT CERT_INFO *certInfoPtr, 
						 IN_BUFFER( dnStringLength ) const void *dnString,
						 IN_LENGTH_ATTRIBUTE const int dnStringLength )
	{
	SELECTION_STATE savedState;
	int status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isReadPtr( dnString, dnStringLength ) );

	REQUIRES( dnStringLength > 0 && dnStringLength < MAX_INTLENGTH_SHORT );

	/* If there's already a DN set we can't do anything else */
	saveSelectionState( savedState, certInfoPtr );
	status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE, MUST_BE_PRESENT );
	if( cryptStatusOK( status ) && \
		*certInfoPtr->currentSelection.dnPtr == NULL )
		{
		/* There's a DN selected but it's empty, we're OK */
		status = CRYPT_ERROR;
		}
	restoreSelectionState( savedState, certInfoPtr );
	if( cryptStatusOK( status ) )
		return( CRYPT_ERROR_INITED );
	status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE, CREATE_IF_ABSENT );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the entire DN from its string form into the selected DN */
	status = readDNstring( certInfoPtr->currentSelection.dnPtr,
						   dnString, dnStringLength );
	if( cryptStatusOK( status ) && \
		certInfoPtr->currentSelection.updateCursor )
		{
		/* If we couldn't update the cursor earlier on because the attribute
		   field in question hadn't been created yet do it now.  Since this 
		   is merely a side-effect of this operation we ignore the return 
		   status and return the main result status */
		( void ) selectGeneralName( certInfoPtr,
									certInfoPtr->currentSelection.generalName,
									MAY_BE_ABSENT );
		}
	return( status );
	}

/* The OCSPv1 ID doesn't contain any usable fields so we pre-encode it when
   the certificate is added to the OCSP request and treat it as a blob 
   thereafter */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int writeOCSPv1ID( INOUT STREAM *stream, 
						  const CERT_INFO *certInfoPtr,
						  IN_BUFFER( issuerKeyHashLength ) \
								const void *issuerKeyHash,
						  IN_LENGTH_FIXED( KEYID_SIZE ) \
								const int issuerKeyHashLength )
	{
	HASHFUNCTION_ATOMIC hashFunctionAtomic;
	BYTE hashBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
	int hashSize;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );

	REQUIRES( issuerKeyHashLength == KEYID_SIZE );
	REQUIRES( certInfoPtr->issuerDNptr != NULL );
	REQUIRES( certInfoPtr->cCertCert->serialNumber != NULL );

	/* Get the issuerName hash */
	getHashAtomicParameters( CRYPT_ALGO_SHA1, &hashFunctionAtomic, &hashSize );
	hashFunctionAtomic( hashBuffer, CRYPT_MAX_HASHSIZE,
						certInfoPtr->issuerDNptr,
						certInfoPtr->issuerDNsize );

	/* Write the request data */
	writeSequence( stream,
			sizeofAlgoID( CRYPT_ALGO_SHA1 ) + \
			sizeofObject( hashSize ) + sizeofObject( hashSize ) + \
			sizeofInteger( certInfoPtr->cCertCert->serialNumber,
						   certInfoPtr->cCertCert->serialNumberLength ) );
	writeAlgoID( stream, CRYPT_ALGO_SHA1 );
	writeOctetString( stream, hashBuffer, hashSize, DEFAULT_TAG );
	writeOctetString( stream, issuerKeyHash, issuerKeyHashLength, 
					  DEFAULT_TAG );
	return( writeInteger( stream, certInfoPtr->cCertCert->serialNumber,
						  certInfoPtr->cCertCert->serialNumberLength,
						  DEFAULT_TAG ) );
	}

/* Sanitise certificate attributes based on a user-supplied template.  This 
   is used to prevent a user from supplying potentially dangerous attributes 
   in a certificate request, for example to request a CA certificate by 
   setting the basicConstraints/keyUsage = CA extensions in the request in a 
   manner that would result in the creation of a CA certificate when the 
   request is processed.  We use an allow-all default rather than deny-all 
   since deny-all would require the caller to specify a vast range of 
   (mostly never-used) attributes to permit when usually all they want to 
   block is the CA flag and equivalent mechanisms */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int sanitiseCertAttributes( INOUT CERT_INFO *certInfoPtr,
								   IN_OPT const ATTRIBUTE_LIST *templateListPtr )
	{
	const ATTRIBUTE_LIST *attributeListCursor;
	int iterationCount;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( templateListPtr == NULL || \
			( isReadPtr( templateListPtr, sizeof( ATTRIBUTE_LIST ) ) ) );

⌨️ 快捷键说明

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