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

📄 certsig.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*					  Certificate Signing/Checking Routines					*
*						Copyright Peter Gutmann 1997-2003					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) ||  defined( INC_CHILD )
  #include "cert.h"
  #include "../misc/asn1_rw.h"
#else
  #include "cert/cert.h"
  #include "misc/asn1_rw.h"
#endif /* Compiler-specific includes */

/* Prototypes for functions in sign.c */

int createX509signature( void *signedObject, int *signedObjectLength,
						 const int sigMaxLength, const void *object, 
						 const int objectLength, 
						 const CRYPT_CONTEXT signContext,
						 const CRYPT_ALGO_TYPE hashAlgo,
						 const int formatInfo, const int extraDataLength );
int checkX509signature( const void *signedObject, const int signedObjectLength,
						void **object, int *objectLength, 
						const CRYPT_CONTEXT sigCheckContext,
						const int formatInfo );

/****************************************************************************
*																			*
*							Certificate Signing Functions					*
*																			*
****************************************************************************/

/* Recover information normally set up on cert import.  After signing, the 
   cert data is present without the cert having been explicitly imported, so 
   we have to explicitly perform the actions normally performed on cert 
   import here */

static int recoverCertData( CERT_INFO *certInfoPtr, 
							const void *encodedCertData, 
							const int encodedCertDataLength,
							const CRYPT_CERTTYPE_TYPE certType )
	{
	STREAM stream;
	int status;

	/* If there's public-key data stored with the cert, free it since we now 
	   have a copy as part of the encoded cert */
	if( certInfoPtr->publicKeyData != NULL )
		{
		zeroise( certInfoPtr->publicKeyData, certInfoPtr->publicKeyInfoSize );
		clFree( "recoverCertData", certInfoPtr->publicKeyData );
		certInfoPtr->publicKeyData = NULL;
		}

	/* If it's a CRMF request, parse the signed form to locate the start of 
	   the encoded DN if there is one (the issuer DN is already set up when 
	   the issuer cert is added) and the public key.  The public key is 
	   actually something of a special case in that in the CRMF/CMP tradition
	   it has a weird nonstandard tag, which means that a straight memcpy() 
	   won't move the data across correctly */
	if( certType == CRYPT_CERTTYPE_REQUEST_CERT )
		{
		sMemConnect( &stream, encodedCertData, encodedCertDataLength );
		readSequence( &stream, NULL );			/* Outer wrapper */
		readSequence( &stream, NULL );
		readUniversal( &stream );				/* Request ID */
		status = readSequence( &stream, NULL );	/* Inner wrapper */
		if( peekTag( &stream ) == MAKE_CTAG( 4 ) )
			status = readUniversal( &stream );	/* Validity */
		if( peekTag( &stream ) == MAKE_CTAG( 5 ) )
			{
			readConstructed( &stream, NULL, 5 );/* Subj.name wrapper */
			certInfoPtr->subjectDNptr = sMemBufPtr( &stream );
			status = readUniversal( &stream );
			}
		assert( peekTag( &stream ) == MAKE_CTAG( 6 ) );/* Public key */
		certInfoPtr->publicKeyInfo = sMemBufPtr( &stream );
		assert( certInfoPtr->publicKeyInfoSize == \
				getStreamObjectLength( &stream ) );
		sMemDisconnect( &stream );

		assert( cryptStatusOK( status ) );
		return( status );
		}

	/* If it's PKI user data, parse the encoded form to locate the start of 
	   the user DN */
	if( certInfoPtr->type == CRYPT_CERTTYPE_PKIUSER )
		{
		sMemConnect( &stream, encodedCertData, encodedCertDataLength );
		readSequence( &stream, NULL );		/* Outer wrapper */
		status = readSequence( &stream, &certInfoPtr->subjectDNsize );
		certInfoPtr->subjectDNptr = sMemBufPtr( &stream );
		sMemDisconnect( &stream );

		assert( cryptStatusOK( status ) );
		return( status );
		}

	assert( certType == CRYPT_CERTTYPE_CERTIFICATE || \
			certType == CRYPT_CERTTYPE_CERTCHAIN );

	/* It's a certificate, parse the signed form to locate the start of the 
	   encoded issuer and subject DN and public key (the length is recorded 
	   when the cert data is written, but the position of the other elements 
	   in the cert can't be determined until the cert has been signed) */
	sMemConnect( &stream, encodedCertData, encodedCertDataLength );
	readSequence( &stream, NULL );			/* Outer wrapper */
	readSequence( &stream, NULL );			/* Inner wrapper */
	if( peekTag( &stream ) == MAKE_CTAG( 0 ) )
		readUniversal( &stream );			/* Version */
	readUniversal( &stream );				/* Serial number */
	readUniversal( &stream );				/* Sig.algo */
	certInfoPtr->issuerDNptr = sMemBufPtr( &stream );
	readUniversal( &stream );				/* Issuer DN */
	readUniversal( &stream );				/* Validity */
	certInfoPtr->subjectDNptr = sMemBufPtr( &stream );
	status = readUniversal( &stream );		/* Subject DN */
	certInfoPtr->publicKeyInfo = sMemBufPtr( &stream );
	assert( certInfoPtr->publicKeyInfoSize == \
			getStreamObjectLength( &stream ) );
	sMemDisconnect( &stream );
	assert( cryptStatusOK( status ) );
	if( cryptStatusError( status ) )
		return( status );

	/* Since the cert may be used for public-key operations as soon as it's 
	   signed, we have to reconstruct the public-key context and apply to
	   it the constraints that would be applied on import */
	sMemConnect( &stream, certInfoPtr->publicKeyInfo, 
				 certInfoPtr->publicKeyInfoSize );
	status = iCryptReadSubjectPublicKey( &stream, 
										 &certInfoPtr->iPubkeyContext,
										 FALSE );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( certInfoPtr->objectHandle, 
								  IMESSAGE_SETDEPENDENT,
								  &certInfoPtr->iPubkeyContext, 
								  SETDEP_OPTION_NOINCREF );
	if( cryptStatusOK( status ) )
		certInfoPtr->flags &= ~CERT_FLAG_DATAONLY;
	return( status );
	}

/* Pseudo-sign certificate information by writing the outer wrapper and 
   moving the object into the initialised state */

static int pseudoSignCertificate( CERT_INFO *certInfoPtr, 
								  void *signedCertObject, 
								  const void *certObject, 
								  const int certObjectLength )
	{
	STREAM stream;
	int signedCertObjectLength;

	switch( certInfoPtr->type )
		{
		case CRYPT_CERTTYPE_OCSP_REQUEST:
		case CRYPT_CERTTYPE_PKIUSER:
			/* It's an unsigned OCSP request or PKI user info, write the 
			   outer wrapper */
			signedCertObjectLength = sizeofObject( certObjectLength );
			sMemOpen( &stream, signedCertObject, signedCertObjectLength );
			writeSequence( &stream, certObjectLength );
			swrite( &stream, certObject, certObjectLength );
			assert( sStatusOK( &stream ) );
			sMemDisconnect( &stream );
			if( certInfoPtr->type == CRYPT_CERTTYPE_PKIUSER )
				recoverCertData( certInfoPtr, signedCertObject, 
								 signedCertObjectLength, 
								 CRYPT_CERTTYPE_PKIUSER );
			break;

		case CRYPT_CERTTYPE_RTCS_REQUEST:
		case CRYPT_CERTTYPE_RTCS_RESPONSE:
		case CRYPT_CERTTYPE_OCSP_RESPONSE:
			/* It's an RTCS request/response or OCSP response, it's already 
			   in the form required */
			signedCertObjectLength = certObjectLength;
			memcpy( signedCertObject, certObject, certObjectLength );
			break;

		case CRYPT_CERTTYPE_REQUEST_CERT:
			{
			const int dataSize = certObjectLength + \
								 sizeofObject( sizeofShortInteger( 0 ) );

			assert( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );

			/* It's an encryption-only key, wrap up the cert data with an 
			   indication that private key POP will be performed via out-of-
			   band means and remember where the encoded data starts */
			signedCertObjectLength = sizeofObject( dataSize );
			sMemOpen( &stream, signedCertObject, signedCertObjectLength );
			writeSequence( &stream, dataSize );
			swrite( &stream, certObject, certObjectLength );
			writeConstructed( &stream, sizeofShortInteger( 0 ), 2 );
			writeShortInteger( &stream, 0, 1 );
			assert( sStatusOK( &stream ) );
			sMemDisconnect( &stream );
			recoverCertData( certInfoPtr, signedCertObject, 
							 signedCertObjectLength, 
							 CRYPT_CERTTYPE_REQUEST_CERT );

			/* The pseudo-signature has been checked (since we just created
			   it), this also avoids nasty semantic problems with not-really-
			   signed CRMF requests with encryption-only keys */
			certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
			break;
			}

		case CRYPT_CERTTYPE_REQUEST_REVOCATION:
			/* Revocation requests can't be signed so the (pseudo-)signed
			   data is just the object data */
			memcpy( signedCertObject, certObject, certObjectLength );
			signedCertObjectLength = certObjectLength;

			/* Since revocation requests can't be signed we mark them as 
			   pseudo-signed to avoid any problems that might arise from 
			   this */
			certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
			break;

		default:
			assert( NOTREACHED );
			return( CRYPT_ERROR_NOTAVAIL );
		}
	certInfoPtr->certificate = signedCertObject;
	certInfoPtr->certificateSize = signedCertObjectLength;

	/* The object is now (pseudo-)signed and initialised */
	certInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
	if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
		/* If it's a CRMF request with POP done via out-of-band means, we 
		   got here via a standard signing action (except that the key was
		   an encryption-only key), don't change the object state since the
		   kernel will do this as the post-signing step */
		return( CRYPT_OK );
	return( krnlSendMessage( certInfoPtr->objectHandle, 
							 IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED, 
							 CRYPT_IATTRIBUTE_INITIALISED ) );
	}

/* Sign a certificate object */

int signCert( CERT_INFO *certInfoPtr, const CRYPT_CONTEXT signContext )
	{
	CERT_INFO *issuerCertInfoPtr = NULL;
	STREAM stream;
	const BOOLEAN isCertificate = \
			( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
			  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
			  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN ) ? TRUE : FALSE;
	BOOLEAN issuerCertPresent = FALSE, nonSigningKey = FALSE;
	BYTE certObjectBuffer[ 1024 ], *certObjectPtr = certObjectBuffer;
	int ( *writeCertObjectFunction )( STREAM *stream, CERT_INFO *subjectCertInfoPtr,
									  const CERT_INFO *issuerCertInfoPtr,
									  const CRYPT_CONTEXT iIssuerCryptContext );
	void *signedCertObject;
	const time_t currentTime = ( signContext == CRYPT_UNUSED ) ? \
							   getTime() : getReliableTime( signContext );
	int certObjectLength, signedCertObjectLength, signedCertAllocSize;
	int extraDataLength = 0, i, status = CRYPT_OK;

	assert( certInfoPtr->certificate == NULL );

	/* If it's a non-signing key we have to create a special format of cert
	   request that isn't signed but contains an indication that the private
	   key POP will be performed by out-of-band means.  We also have to check 
	   for the signContext being absent to handle OCSP requests for which the
	   signature is optional so there may be no signing key present */
	if( signContext == CRYPT_UNUSED || \
		cryptStatusError( krnlSendMessage( signContext, IMESSAGE_CHECK, 
						  NULL, MESSAGE_CHECK_PKC_SIGN ) ) )
		nonSigningKey = TRUE;

	/* Obtain the issuer certificate from the private key if necessary */
	if( isCertificate || certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
		( ( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
			certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE ) && \
		  !nonSigningKey ) )
		{
		/* If it's a self-signed cert, the issuer is also the subject */
		if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
			issuerCertInfoPtr = certInfoPtr;
		else
			{
			CRYPT_CERTIFICATE dataOnlyCert;

			/* Get the data-only certificate from the context */
			status = krnlSendMessage( signContext, IMESSAGE_GETDEPENDENT, 
									  &dataOnlyCert, OBJECT_TYPE_CERTIFICATE );
			if( cryptStatusError( status ) )
				return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
						CRYPT_ARGERROR_VALUE : status );
			status = krnlGetObject( dataOnlyCert, OBJECT_TYPE_CERTIFICATE, 
									( void ** ) &issuerCertInfoPtr, 
									CRYPT_ARGERROR_VALUE );
			if( cryptStatusError( status ) )
				return( status );
			issuerCertPresent = TRUE;
			}

		/* Make sure that the signing key is associated with a complete 
		   issuer cert which is valid for cert/CRL signing */
		if( ( issuerCertPresent && issuerCertInfoPtr->certificate == NULL ) || \
			( issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
			  issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN ) )
			{
			if( issuerCertPresent )
				krnlReleaseObject( issuerCertInfoPtr->objectHandle );
			return( CRYPT_ARGERROR_VALUE );
			}

		/* If it's an OCSP request or response, the signing cert has to be 
		   valid for signing */
		if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
			certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
			status = checkCertUsage( issuerCertInfoPtr, 
							CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_NONREPUDIATION,
							MESSAGE_CHECK_PKC_SIGN, &certInfoPtr->errorLocus, 
							&certInfoPtr->errorType );
		else
			/* If it's a non-self-signed object, it must be signed by a CA 
			   cert */
			if( issuerCertPresent )
				{
				status = checkCertUsage( issuerCertInfoPtr, isCertificate ? \
							CRYPT_KEYUSAGE_KEYCERTSIGN : CRYPT_KEYUSAGE_CRLSIGN,
							MESSAGE_CHECK_CA, &certInfoPtr->errorLocus, 
							&certInfoPtr->errorType );
				if( cryptStatusError( status ) && \
					certInfoPtr->errorType == CRYPT_ERRTYPE_CONSTRAINT )
					/* If there was a constraint problem, it's something in 
					   the issuer's cert rather than the cert being signed 
					   so we have to change the error type accordingly.  

⌨️ 快捷键说明

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