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

📄 certsig.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
	sMemDisconnect( &stream );
	if( issuerCertPresent )
		unlockResource( issuerCertInfoPtr );
	if( cryptStatusError( status ) )
		{
		zeroise( certObjectPtr, certObjectLength );
		if( certObjectPtr != certObjectBuffer )
			free( certObjectPtr );
		free( signedCertObject );
		return( status );
		}

	/* If there's no signing key present, pseudo-sign the certificate 
	   information by writing the outer wrapper and moving the object into
	   the initialised state */
	if( nonSigningKey )
		{
		if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
			certInfoPtr->type == 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, certObjectPtr, certObjectLength );
			sMemDisconnect( &stream );
			}
		else
			{
			const int dataSize = certObjectLength + \
								 sizeofObject( sizeofShortInteger( 0 ) );
			long dataStart;

			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 subject name 
			   starts */
			signedCertObjectLength = sizeofObject( dataSize );
			sMemOpen( &stream, signedCertObject, signedCertObjectLength );
			writeSequence( &stream, dataSize );
			dataStart = stell( &stream );
			swrite( &stream, certObjectPtr, certObjectLength );
			writeConstructed( &stream, sizeofShortInteger( 0 ), 2 );
			writeShortInteger( &stream, 0, 1 );
			sseek( &stream, dataStart );
			readSequence( &stream, NULL );	/* Wrapper */
			readUniversal( &stream );		/* Request ID */
			readSequence( &stream, NULL );	/* Inner wrapper */
			if( peekTag( &stream ) == MAKE_CTAG( 4 ) )
				readUniversal( &stream );	/* Validity */
			readConstructed( &stream, NULL, 5 );	/* Subj.name wrapper */
			certInfoPtr->subjectDNptr = sMemBufPtr( &stream );
			assert( sGetStatus( &stream ) == CRYPT_OK );
			sMemDisconnect( &stream );

			/* 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;
			}
		certInfoPtr->certificate = signedCertObject;
		certInfoPtr->certificateSize = signedCertObjectLength;

		/* The object is now (pseudo-)signed and initialised */
		certInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
		krnlSendMessage( certInfoPtr->objectHandle, 
						 RESOURCE_IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED, 
						 CRYPT_IATTRIBUTE_INITIALISED );

		/* Clean up */
		zeroise( certObjectPtr, certObjectLength );
		if( certObjectPtr != certObjectBuffer )
			free( certObjectPtr );
		return( CRYPT_OK );
		}

	/* Sign the certificate information */
	status = createX509signature( signedCertObject, &signedCertObjectLength,
								  certObjectPtr, certObjectLength, signContext,
								  CRYPT_ALGO_SHA );
	if( cryptStatusError( status ) )
		{
		zeroise( certObjectPtr, certObjectLength );
		if( certObjectPtr != certObjectBuffer )
			free( certObjectPtr );
		return( status );
		}
	certInfoPtr->certificate = signedCertObject;
	certInfoPtr->certificateSize = signedCertObjectLength;

	/* CRMF and OCSP use a signature format which is almost, but not quite, 
	   right, so if it's a signed CRMF or OCSP request we have to rewrite the 
	   signature slightly to use the nonstandard format.  Rewriting it here is 
	   easier than trying to pass different "use nonstandard signature format" 
	   flags down 20 levels of function calls to have it done by the 
	   signature-generation code */
	if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT || \
		certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST )
		{
		BYTE *dataStart;
		int totalSize, sigSize, newSigSize, delta;

		/* Rewrite the outer wrapper to account for the overhead of the 
		   extra tag(s), copy down the payload, and re-wrap the signature in 
		   an extra [1] or [0] SEQUENCE wrapper.  This rewrites:
			
			SEQ {
				...,
				AlgoID,
				BIT STRING
				}
		   to:

			SEQ' {		-- CRMF		SEQ' {		-- OCSP
				...						...
				[1] {					[0] {
					AlgoID,					SEQUENCE {
					BIT STRING					AlgoID,
					}							BIT STRING
				}								}
											}
										}
   
		   First we read the data and get location and size information for 
		   the header, payload, and signature */
		sMemConnect( &stream, signedCertObject, signedCertObjectLength );
		readSequence( &stream, &totalSize );
		dataStart = sMemBufPtr( &stream );
		sigSize = totalSize - certObjectLength;
		newSigSize = ( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT ) ? \
						( int ) sizeofObject( sigSize ) : \
						( int ) sizeofObject( sizeofObject( sigSize ) );
		sMemDisconnect( &stream );

		/* Next we open up a gap at the start of the data, write the new 
		   total size (SEQ') into the gap, and move the payload (but not the 
		   sig) back down again */
		memmove( dataStart + 16, dataStart, totalSize );
		sMemOpen( &stream, signedCertObject, 16 );
		writeSequence( &stream, certObjectLength + newSigSize );
		memmove( sMemBufPtr( &stream ), dataStart + 16, certObjectLength );
		delta = ( int ) stell( &stream );
		sMemDisconnect( &stream );

		/* Finally, we skip over the payload, write the extra headers around 
		   the signature ([1]{...} or [0]{ SEQUENCE {...}}), and move the 
		   signature into place at the end of the new header */
		sMemOpen( &stream, ( BYTE * ) signedCertObject + delta + \
									  certObjectLength, 8 );
		if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
			writeConstructed( &stream, sigSize, 1 );
		else
			{
			writeConstructed( &stream, ( int ) sizeofObject( sigSize ), 0 );
			writeSequence( &stream, sigSize );
			}
		memmove( sMemBufPtr( &stream ), dataStart + 16 + certObjectLength, 
				 sigSize );
		sMemDisconnect( &stream );
			
		/* Adjust the size of the cert object to account for the extra tag */
		certInfoPtr->certificateSize = ( int ) \
							sizeofObject( certObjectLength + newSigSize );
		}

	/* If it's a certification request, it's now self-signed.  In addition 
	   the signature has been checked, since we just created it */
	if( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
		certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
		certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
	certInfoPtr->flags |= CERT_FLAG_SIGCHECKED;

	/* If it's a cert chain and the root is self-signed, the entire chain 
	   counts as self-signed */
	if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
		{
		int selfSigned;

		status = krnlSendMessage( \
						certInfoPtr->certChain[ certInfoPtr->certChainEnd - 1 ], 
						RESOURCE_IMESSAGE_GETATTRIBUTE, &selfSigned,
						CRYPT_CERTINFO_SELFSIGNED );
		if( cryptStatusOK( status ) && selfSigned )
			certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;
		}

	/* If 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 their position in the cert 
	   can't be determined until the cert has been signed).  If it's a CRMF 
	   request, remember the start of the encoded DN if there is one (the 
	   issuer DN is already set up when the issuer cert is added) */
	if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
		certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
		{
		sMemConnect( &stream, signedCertObject, signedCertObjectLength );
		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 );
		readUniversal( &stream );		/* Subject DN */
		certInfoPtr->publicKeyInfo = sMemBufPtr( &stream );
		assert( sGetStatus( &stream ) == CRYPT_OK );
		sMemDisconnect( &stream );
		}
	if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
		{
		sMemConnect( &stream, signedCertObject, signedCertObjectLength );
		readSequence( &stream, NULL );	/* Outer wrapper */
		readSequence( &stream, NULL );
		readUniversal( &stream );		/* Request ID */
		readSequence( &stream, NULL );	/* Inner wrapper */
		if( peekTag( &stream ) == MAKE_CTAG( 4 ) )
			readUniversal( &stream );	/* Validity */
		if( peekTag( &stream ) == MAKE_CTAG( 5 ) )
			{
			readConstructed( &stream, NULL, 5 );	/* Subj.name wrapper */
			certInfoPtr->subjectDNptr = sMemBufPtr( &stream );
			}
		assert( sGetStatus( &stream ) == CRYPT_OK );
		sMemDisconnect( &stream );
		}

	/* Clean up */
	zeroise( certObjectPtr, certObjectLength );
	if( certObjectPtr != certObjectBuffer )
		free( certObjectPtr );
	return( status );
	}

/****************************************************************************
*																			*
*							Certificate Checking Functions					*
*																			*
****************************************************************************/

/* Generate a nameID or issuerID.  These are needed when storing/retrieving a
   cert to/from a RDBMS, which can't handle the awkward heirarchical ID's
   usually used in certs.  There are two types of ID's, the nameID, which is
   an SHA-1 hash of the DistinguishedName and used for X.509, and the
   issuerID, which is an SHA-1 hash of the IssuerAndSerialNumber and used for
   CRL's and CMS */

static int generateCertID( const void *dnPtr, const void *serialNumber,
						   const int serialNumberLength, BYTE *certID )
	{
	HASHFUNCTION hashFunction;
	STREAM stream;
	BYTE buffer[ 1024 ], *bufPtr = buffer;
	int length = sizeofDN( dnPtr ), payloadSize;
	int hashSize, status;

	/* If it's an issuerID, add the size of the serial number and evaluate 
	   the total size */
	if( serialNumber != NULL )
		{
		payloadSize = length + \
					  sizeofInteger( serialNumber, serialNumberLength );
		length = ( int ) sizeofObject( payloadSize );
		}

	/* Get the hash algorithm information */
	getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );

	/* Allocate a buffer for the ID information if necessary */
	if( length > 1024 && ( bufPtr = malloc( length ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );

	/* Write the relevant information to a buffer and hash the data to get
	   the ID.  Since there are an infinite number of ways to misrepresent
	   DN's and the like, we recode them into the canonical form before
	   generating the ID to ensure that even if other software suddenly
	   changes the way it represents a DN, or the software which generated
	   a message requiring a certain cert encodes the DN differently to the
	   way the software which created the cert encodes it, we still
	   (hopefully) end up with the same ID */
	sMemOpen( &stream, bufPtr, length );
	if( serialNumber == NULL )
		status = writeDN( &stream, dnPtr, DEFAULT_TAG );
	else
		{
		writeSequence( &stream, payloadSize );
		status = writeDN( &stream, dnPtr, DEFAULT_TAG );
		if( cryptStatusOK( status ) )
			status = writeInteger( &stream, serialNumber,
								   serialNumberLength, DEFAULT_TAG );
		}
	if( cryptStatusOK( status ) )
		hashFunction( NULL, certID, bufPtr, length, HASH_ALL );
	sMemClose( &stream );
	if( bufPtr != buffer )
		free( bufPtr );
	if( cryptStatusError( status ) )
		return( status );

	return( CRYPT_OK );
	}

/* Check the entries in an OCSP response object against a cert store.  The
   semantics for this one are a bit odd, the source information for the
   check is from a request, but the destination information is in a response,
   since we don't have a copy-and-verify function we do the checking from
   the response even though, technically, it's the request data which is 
   being checked */

int checkOCSPResponse( CERT_INFO *certInfoPtr, 
					   const CRYPT_KEYSET cryptKeyset )
	{
	REVOCATION_INFO *revocationInfo;
	BOOLEAN isRevoked = FALSE;

	/* Walk down the list of revocation entries fetching status information 
	   on each one from the cert store */
	for( revocationInfo = certInfoPtr->revocations;
		 revocationInfo != NULL; revocationInfo = revocationInfo->next )
		{
		MESSAGE_KEYMGMT_INFO getkeyInfo;
		int status;

		/* Determine the revocation status of the object.  Unfortunateley
		   because of the way OCSP returns status information we can't just
		   return a yes/no response but have to perform multiple queries to
		   determine whether a cert is not revoked, revoked, or unknown.

⌨️ 快捷键说明

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