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

📄 certsign.c

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

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

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

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int recoverCertData( INOUT CERT_INFO *certInfoPtr,
							IN_ENUM( CRYPT_CERTTYPE ) \
								const CRYPT_CERTTYPE_TYPE certType, 
							IN_BUFFER( encodedCertDataLength ) \
								const void *encodedCertData,
							IN_LENGTH_SHORT_MIN( 16 ) \
								const int encodedCertDataLength )
	{
	STREAM stream;
	int length, status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isReadPtr( encodedCertData, encodedCertDataLength ) );

	REQUIRES( certType > CRYPT_CERTTYPE_NONE && \
			  certType < CRYPT_CERTTYPE_LAST );
	REQUIRES( encodedCertDataLength >= 16 && \
			  encodedCertDataLength < MAX_INTLENGTH_SHORT );

	/* If there's public-key data stored with the certificate free it since 
	   we now have a copy as part of the encoded certificate */
	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 certificate 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( cryptStatusOK( status ) && \
			peekTag( &stream ) == MAKE_CTAG( 4 ) )
			status = readUniversal( &stream );	/* Validity */
		if( cryptStatusOK( status ) && \
			peekTag( &stream ) == MAKE_CTAG( 5 ) )
			{
			status = readConstructed( &stream, &length, 5 );
			if( cryptStatusOK( status ) )		/* Subj.name wrapper */
				status = sMemGetDataBlock( &stream, &certInfoPtr->subjectDNptr, 
										   certInfoPtr->subjectDNsize );
			ENSURES( cryptStatusOK( status ) );
			status = readUniversal( &stream );	/* Subject name */
			}
		if( cryptStatusOK( status ) && \
			peekTag( &stream ) != MAKE_CTAG( 6 ) )	/* Public key */
			status = CRYPT_ERROR_BADDATA;
		if( cryptStatusOK( status ) )
			status = sMemGetDataBlock( &stream, &certInfoPtr->publicKeyInfo, 
									   certInfoPtr->publicKeyInfoSize );
		ENSURES( cryptStatusOK( status ) && \
				 cryptStatusOK( getStreamObjectLength( &stream, &length ) ) && \
				 length == certInfoPtr->publicKeyInfoSize );
		sMemDisconnect( &stream );

		return( CRYPT_OK );
		}

	/* 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, &length );
		if( cryptStatusOK( status ) )
			status = sMemGetDataBlock( &stream, &certInfoPtr->subjectDNptr, 
									   certInfoPtr->subjectDNsize );
		sMemDisconnect( &stream );
		ENSURES( cryptStatusOK( status ) );

		return( CRYPT_OK );
		}

	ENSURES( 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 certificate data is written but the position of the other 
	   elements in the certificate can't be determined until the certificate 
	   has been signed) */
	sMemConnect( &stream, encodedCertData, encodedCertDataLength );
	readSequence( &stream, NULL );			/* Outer wrapper */
	status = readSequence( &stream, NULL );	/* Inner wrapper */
	if( cryptStatusOK( status ) && \
		peekTag( &stream ) == MAKE_CTAG( 0 ) )
		readUniversal( &stream );			/* Version */
	readUniversal( &stream );				/* Serial number */
	status = readUniversal( &stream );		/* Signature algo */
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( &stream, &certInfoPtr->issuerDNptr, 
								   certInfoPtr->issuerDNsize );
	ENSURES( cryptStatusOK( status ) );
	readUniversal( &stream );				/* Issuer DN */
	status = readUniversal( &stream );		/* Validity */
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( &stream, &certInfoPtr->subjectDNptr, 
								   certInfoPtr->subjectDNsize );
	ENSURES( cryptStatusOK( status ) );
	status = readUniversal( &stream );		/* Subject DN */
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( &stream, &certInfoPtr->publicKeyInfo, 
								   certInfoPtr->publicKeyInfoSize );
	ENSURES( cryptStatusOK( status ) && \
			 cryptStatusOK( getStreamObjectLength( &stream, &length ) ) && \
			 length == certInfoPtr->publicKeyInfoSize );
	sMemDisconnect( &stream );

	/* Since the certificate 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 );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );
	status = krnlSendMessage( certInfoPtr->objectHandle,
							  IMESSAGE_SETDEPENDENT,
							  &certInfoPtr->iPubkeyContext,
							  SETDEP_OPTION_NOINCREF );
	if( cryptStatusOK( status ) )
		certInfoPtr->flags &= ~CERT_FLAG_DATAONLY;
	return( status );
	}


/* Check the key being used to sign a certificate object */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int checkSigningKey( INOUT CERT_INFO *certInfoPtr,
							const CERT_INFO *issuerCertInfoPtr,
							const BOOLEAN isCertificate,
							IN_RANGE( CRYPT_COMPLIANCELEVEL_OBLIVIOUS, \
									  CRYPT_COMPLIANCELEVEL_LAST - 1 ) \
								const int complianceLevel )
	{
	int status;

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

	REQUIRES( complianceLevel >= CRYPT_COMPLIANCELEVEL_OBLIVIOUS && \
			  complianceLevel < CRYPT_COMPLIANCELEVEL_LAST );

	/* Make sure that the signing key is associated with a complete issuer 
	   certificate which is valid for certificate/CRL signing (if it's a 
	   self-signed certificate then we don't have to have a completed 
	   certificate present because the self-sign operation hasn't created it 
	   yet) */
	if( ( !( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) && \
		  issuerCertInfoPtr->certificate == NULL ) || \
		( issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
		  issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN ) )
		return( CRYPT_ARGERROR_VALUE );

	/* If it's an OCSP request or response then the signing certificate has 
	   to be valid for signing */
	if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
		certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
		{
		return( checkKeyUsage( issuerCertInfoPtr, CHECKKEY_FLAG_NONE,
							   CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
							   CRYPT_KEYUSAGE_NONREPUDIATION,
							   complianceLevel, &certInfoPtr->errorLocus,
							   &certInfoPtr->errorType ) );
		}

	/* If it's a non-self-signed object then it must be signed by a CA 
	   certificate */
	if( !( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
		{
		status = checkKeyUsage( issuerCertInfoPtr, CHECKKEY_FLAG_CA,
								isCertificate ? CRYPT_KEYUSAGE_KEYCERTSIGN : \
												CRYPT_KEYUSAGE_CRLSIGN,
								complianceLevel, &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 certificate rather than the certificate being signed 
			   so we have to change the error type accordingly.  What's 
			   reported isn't strictly accurate since the locus is in the 
			   issuer rather than subject certificate but it's the best that 
			   we can do */
			certInfoPtr->errorType = CRYPT_ERRTYPE_ISSUERCONSTRAINT;
			}

		return( status );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Signing Setup Functions							*
*																			*
****************************************************************************/

/* Copy a signing certificate chain into the certificate being signed */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int copySigningCertChain( INOUT CERT_INFO *certInfoPtr,
								 IN_HANDLE const CRYPT_CONTEXT iSignContext )
	{
	CERT_CERT_INFO *certInfo = certInfoPtr->cCertCert;

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

	REQUIRES( isHandleRangeValid( iSignContext ) );

	/* If there's a chain of certificates present (for example from a 
	   previous signing attempt that wasn't completed due to an error), free 
	   them */
	if( certInfo->chainEnd > 0 )
		{
		int i;
			
		for( i = 0; i < certInfo->chainEnd && i < MAX_CHAINLENGTH; i++ )
			krnlSendNotifier( certInfo->chain[ i ], IMESSAGE_DECREFCOUNT );
		certInfo->chainEnd = 0;
		}

	/* If it's a self-signed certificate it must be the only one in the 
	   chain (creating a chain like this doesn't make much sense but we 
	   handle it anyway) */
	if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
		{
		if( certInfo->chainEnd > 0 )
			{
			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
						  CRYPT_ERRTYPE_ATTR_PRESENT );
			return( CRYPT_ERROR_INVALID );
			}
		
		return( CRYPT_OK );
		}

	/* Copy the certificate chain into the certificate to be signed */
	return( copyCertChain( certInfoPtr, iSignContext, FALSE ) );
	}

/* Set up any required timestamp data for a certificate object */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int setCertTimeinfo( INOUT CERT_INFO *certInfoPtr,
							IN_HANDLE_OPT const CRYPT_CONTEXT iSignContext,
							const BOOLEAN isCertificate )
	{
	const time_t currentTime = ( iSignContext == CRYPT_UNUSED ) ? \
							   getTime() : getReliableTime( iSignContext );
	int status;

⌨️ 快捷键说明

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