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

📄 certio.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
	sMemDisconnect( &stream );
	if( tag == BER_SEQUENCE || \
		( tag >= MAKE_CTAG( 0 ) && tag <= MAKE_CTAG( 3 ) ) )
		{
		*objectType = CRYPT_CERTTYPE_OCSP_REQUEST;
		return( CRYPT_OK );
		}
	if( tag == BER_OCTETSTRING )
		{
		*objectType = CRYPT_CERTTYPE_OCSP_RESPONSE;
		return( CRYPT_OK );
		}

	/* It's nothing identifiable */
	return( CRYPT_ERROR_BADDATA );
	}

/****************************************************************************
*																			*
*								Import/Export Functions						*
*																			*
****************************************************************************/

/* Import a certificate object.  If the import type is set to create a data-
   only cert, its publicKeyInfo pointer is set to the start of the encoded 
   public key to allow it to be decoded later.  Returns the length of the 
   certificate */

int importCert( const void *certObject, const int certObjectLength,
				CRYPT_CERTIFICATE *certificate,
				const CRYPT_USER cryptOwner,
				const CRYPT_KEYID_TYPE keyIDtype,
				const void *keyID, const int keyIDlength,
				const CERTFORMAT_TYPE formatType )
	{
	CERT_INFO *certInfoPtr;
	CRYPT_CERTTYPE_TYPE type;
	STREAM stream;
	int ( *readCertObjectFunction )( STREAM *stream, CERT_INFO *certInfoPtr );
	void *certObjectPtr = ( void * ) certObject, *certBuffer;
	int complianceLevel, length, offset = 0, initStatus = CRYPT_OK, i, status;

	*certificate = CRYPT_ERROR;

	/* Determine how much checking we need to perform */
	status = krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE, 
							  &complianceLevel, 
							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusError( status ) )
		return( status );

	/* If it's not a pre-specified or special-case format, check whether it's 
	   some form of encoded certificate object */
	if( formatType == CRYPT_CERTTYPE_NONE )
		{
		const CRYPT_CERTFORMAT_TYPE format = \
				base64checkHeader( certObject, certObjectLength, &offset );

		if( format == CRYPT_ICERTFORMAT_SMIME_CERTIFICATE || \
			format == CRYPT_CERTFORMAT_TEXT_CERTIFICATE )
			{
			const char *certObjectDataPtr = \
								( const char * ) certObject + offset;
			int decodedLength;

			/* It's base64/PEM/SMIME-encoded, decode it into a temporary 
			   buffer */
			decodedLength = base64decodeLen( certObjectDataPtr, 
											 certObjectLength );
			if( decodedLength <= 128 || decodedLength > 8192 )
				return( CRYPT_ERROR_BADDATA );
			if( ( certObjectPtr = clAlloc( "importCert",
										   decodedLength ) ) == NULL )
				return( CRYPT_ERROR_MEMORY );
			if( !base64decode( certObjectPtr, certObjectDataPtr, 0, 
							   format ) )
				{
				clFree( "importCert", certObjectPtr );
				return( CRYPT_ERROR_BADDATA );
				}
			}
		}

	/* Determine the object's type and length and check the encoding unless
	   we're running in oblivious mode */
	status = getCertObjectInfo( certObjectPtr, certObjectLength, &offset, 
								&length, &type, formatType );
	if( cryptStatusOK( status ) && \
		complianceLevel > CRYPT_COMPLIANCELEVEL_OBLIVIOUS && \
		formatType != CRYPT_ICERTTYPE_SSL_CERTCHAIN )
		status = checkObjectEncoding( ( BYTE * ) certObjectPtr + offset, 
									  length );
	if( cryptStatusError( status ) )
		{
		if( certObjectPtr != certObject )
			clFree( "importCert", certObjectPtr );
		return( status );
		}
	status = CRYPT_OK;	/* checkEncoding() returns a length */

	/* If it's a cert chain, this is handled specially since we need to
	   import a plurality of certs at once */
	if( type == CRYPT_CERTTYPE_CERTCHAIN || \
		type == CRYPT_ICERTTYPE_CMS_CERTSET || \
		type == CRYPT_ICERTTYPE_SSL_CERTCHAIN )
		{
		/* Read the cert chain into a collection of internal cert objects
		   This returns a handle to the leaf cert in the chain, with the
		   remaining certs being accessible within it via the cert cursor
		   functions.  Because the different chain types are only used to
		   distinguish the chain wrapper type on import, the final object
		   type which is created is always a CRYPT_CERTTYPE_CERTCHAIN no
		   matter what the import format was */
		sMemConnect( &stream, ( BYTE * ) certObjectPtr + offset, length );
		if( type == CRYPT_CERTTYPE_CERTCHAIN )
			readSequence( &stream, NULL );	/* Skip the outer wrapper */
		status = readCertChain( &stream, certificate, cryptOwner, type, 
								keyIDtype, keyID, keyIDlength, 
								( formatType == CERTFORMAT_DATAONLY ||
								  formatType == CERTFORMAT_CTL ) ? \
									TRUE : FALSE );
		sMemDisconnect( &stream );
		if( certObjectPtr != certObject )
			clFree( "importCert", certObjectPtr );
		return( status );
		}

	assert( keyIDtype == CRYPT_KEYID_NONE && keyID == NULL && \
			keyIDlength == 0 );

	/* Select the function to use to read the certificate object */
	for( i = 0; certReadTable[ i ].type != type && \
				certReadTable[ i ].type != CRYPT_CERTTYPE_NONE; i++ );
	if( certReadTable[ i ].type == CRYPT_CERTTYPE_NONE || \
		certReadTable[ i ].readFunction == NULL )
		{
		assert( NOTREACHED );
		return( CRYPT_ERROR_NOTAVAIL );
		}
	readCertObjectFunction = certReadTable[ i ].readFunction;

	/* Allocate a buffer to store a copy of the object so we can preserve the
	   original for when it's needed again later, and try and create the
	   certificate object.  All the objects (including the CMS attributes,
	   that in theory aren't needed for anything further) need to be kept
	   around in their encoded form, which is often incorrect and therefore
	   can't be reconstructed from the decoded info.  The readXXX() functions 
	   record pointers to the required encoded fields so they can be 
	   recovered later in their (possibly incorrect) form, and these pointers 
	   need to be to a persistent copy of the encoded object.  In addition the 
	   cert objects need to be kept around anyway for sig checks and possible 
	   re-export */
	if( ( certBuffer = clAlloc( "importCert", length ) ) == NULL )
		status = CRYPT_ERROR_MEMORY;
	else
		/* Create the certificate object */
		status = createCertificateInfo( &certInfoPtr, cryptOwner, type );
	if( cryptStatusError( status ) )
		{
		if( certObjectPtr != certObject )
			clFree( "importCert", certObjectPtr );
		clFree( "importCert", certBuffer );
		return( status );
		}
	*certificate = status;

	/* If we're doing a deferred read of the public key components (they'll
	   be decoded later when we know whether we need them), set the data-only
	   flag to ensure we don't try to decode them */
	if( formatType == CERTFORMAT_DATAONLY || formatType == CERTFORMAT_CTL )
		certInfoPtr->flags |= CERT_FLAG_DATAONLY;

	/* If we're reading a single entry from a CRL, indicate that the 
	   resulting object is a standalone single CRL entry rather than a proper
	   CRL */
	if( formatType == CERTFORMAT_REVINFO )
		certInfoPtr->flags |= CERT_FLAG_CRLENTRY;

	/* Copy in the certificate object for later use */
	memcpy( certBuffer, ( BYTE * ) certObjectPtr + offset, length );
	certInfoPtr->certificate = certBuffer;
	certInfoPtr->certificateSize = length;

	/* Parse the object into the certificate.  Note that we have to use the
	   copy in the certBuffer rather than the original since the readXXX()
	   functions record pointers to various encoded fields */
	sMemConnect( &stream, certBuffer, length );
	if( type != CRYPT_CERTTYPE_CMS_ATTRIBUTES && \
		type != CRYPT_CERTTYPE_RTCS_REQUEST && \
		type != CRYPT_CERTTYPE_RTCS_RESPONSE )
		/* Skip the outer wrapper */
		readLongSequence( &stream, NULL );
	status = readCertObjectFunction( &stream, certInfoPtr );
	sMemDisconnect( &stream );
	if( certObjectPtr != certObject )
		clFree( "importCert", certObjectPtr );
	if( cryptStatusError( status ) )
		{
		/* The import failed, make sure that the object gets destroyed when 
		   we notify the kernel that the setup process is complete.  We also
		   have to explicitly destroy the attached context since at this
		   point it hasn't been associated with the certificate yet, so it
		   won't be automatically destroyed by the kernel when the cert is 
		   destroyed */
		krnlSendNotifier( *certificate, IMESSAGE_DESTROY );
		if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
			{
			krnlSendNotifier( certInfoPtr->iPubkeyContext, 
							  IMESSAGE_DECREFCOUNT );
			certInfoPtr->iPubkeyContext = CRYPT_ERROR;
			}
		initStatus = status;
		}

	/* We've finished setting up the object-type-specific info, tell the 
	   kernel that the object is ready for use */
	status = krnlSendMessage( *certificate, IMESSAGE_SETATTRIBUTE, 
							  MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
	if( cryptStatusError( initStatus ) || cryptStatusError( status ) )
		{
		*certificate = CRYPT_ERROR;
		return( cryptStatusError( initStatus ) ? initStatus : status );
		}

	/* If this is a type of object that has a public key associated with it, 
	   notify the kernel that the given context is attached to the cert.  
	   Note that we can only do this at this point because the cert object
	   can't receive general messages until its status is set to OK.  In 
	   addition since this is an internal object used only by the cert we 
	   tell the kernel not to increment its reference count when it attaches
	   it to the cert object.  Finally, we're ready to go so we mark the 
	   object as initialised (we can't do this before the initialisation is 
	   complete because the kernel won't forward the message to a not-ready-
	   for-use object)*/
	if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
		krnlSendMessage( *certificate, IMESSAGE_SETDEPENDENT,
						 &certInfoPtr->iPubkeyContext, 
						 SETDEP_OPTION_NOINCREF );
	return( krnlSendMessage( *certificate, IMESSAGE_SETATTRIBUTE,
							 MESSAGE_VALUE_UNUSED, 
							 CRYPT_IATTRIBUTE_INITIALISED ) );
	}

/* Export a certificate/certification request.  This just writes the
   internal encoded object to an external buffer.  For cert/cert chain export
   the possibilities are as follows:

						Export
	Type  |		Cert				Chain
	------+--------------------+---------------
	Cert  | Cert			   | Cert as chain
		  |					   |
	Chain | Currently selected | Chain
		  | cert in chain	   |					*/

int exportCert( void *certObject, int *certObjectLength,
				const CRYPT_CERTFORMAT_TYPE certFormatType,
				const CERT_INFO *certInfoPtr, const int maxLength )
	{
	const CRYPT_CERTFORMAT_TYPE baseFormatType = \
		( certFormatType == CRYPT_CERTFORMAT_TEXT_CERTIFICATE || \
		  certFormatType == CRYPT_CERTFORMAT_XML_CERTIFICATE ) ? \
			CRYPT_CERTFORMAT_CERTIFICATE : \
		( certFormatType == CRYPT_CERTFORMAT_TEXT_CERTCHAIN || \
		  certFormatType == CRYPT_CERTFORMAT_XML_CERTCHAIN ) ? \
			CRYPT_CERTFORMAT_CERTCHAIN : \
			certFormatType;
	STREAM stream;
	void *buffer;
	int length, encodedLength, status;

	/* If it's an internal format, write it and exit */
	if( certFormatType == CRYPT_ICERTFORMAT_CERTSET || \
		certFormatType == CRYPT_ICERTFORMAT_CERTSEQUENCE )
		{
		*certObjectLength = ( int ) sizeofCertSet( certInfoPtr );
		if( certObject == NULL )
			return( CRYPT_OK );
		if( *certObjectLength > maxLength )
			return( CRYPT_ERROR_OVERFLOW );
		sMemOpen( &stream, certObject, *certObjectLength );
		if( certFormatType == CRYPT_ICERTFORMAT_CERTSET )
			status = writeCertSet( &stream, certInfoPtr );
		else
			status = writeCertSequence( &stream, certInfoPtr );
		sMemDisconnect( &stream );
		return( status );
		}

	/* Determine how big the output object will be */
	if( baseFormatType == CRYPT_CERTFORMAT_CERTCHAIN )
		{
		STREAM nullStream;

		assert( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
				certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );

		sMemOpen( &nullStream, NULL, 0 );
		status = writeCertChain( &nullStream, certInfoPtr );
		length = stell( &nullStream );
		sMemClose( &nullStream );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		length = certInfoPtr->certificateSize;
	encodedLength = ( baseFormatType != certFormatType ) ? \
					base64encodeLen( length, certInfoPtr->type ) : length;

	/* Set up the length information */
	*certObjectLength = encodedLength;
	if( certObject == NULL )
		return( CRYPT_OK );
	if( encodedLength > maxLength )
		return( CRYPT_ERROR_OVERFLOW );
	if( checkBadPtrWrite( certObject, encodedLength ) )
		return( CRYPT_ARGERROR_STR1 );

	/* If it's a simple object, write either the DER-encoded object or its
	   base64 / S/MIME-encoded form directly to the output */
	if( certFormatType == CRYPT_CERTFORMAT_CERTIFICATE || \
		certFormatType == CRYPT_ICERTFORMAT_DATA )
		{
		memcpy( certObject, certInfoPtr->certificate, length );
		return( CRYPT_OK );
		}
	if( certFormatType == CRYPT_CERTFORMAT_TEXT_CERTIFICATE || \
		certFormatType == CRYPT_CERTFORMAT_XML_CERTIFICATE )
		{
		base64encode( certObject, certInfoPtr->certificate,
					  certInfoPtr->certificateSize, certInfoPtr->type );
		return( CRYPT_OK );
		}

	/* It's a straight cert chain, write it directly to the output */
	if( certFormatType == CRYPT_CERTFORMAT_CERTCHAIN )
		{
		sMemOpen( &stream, certObject, length );
		status = writeCertChain( &stream, certInfoPtr );
		sMemDisconnect( &stream );
		return( status );
		}

	/* It's a base64 / S/MIME-encoded cert chain, write it to a temporary
	   buffer and then encode it to the output */
	assert( certFormatType == CRYPT_CERTFORMAT_TEXT_CERTCHAIN || \
			certFormatType == CRYPT_CERTFORMAT_XML_CERTCHAIN );
	if( ( buffer = clAlloc( "exportCert", length ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	sMemOpen( &stream, buffer, length );
	status = writeCertChain( &stream, certInfoPtr );
	if( cryptStatusOK( status ) )
		base64encode( certObject, buffer, length, CRYPT_CERTTYPE_CERTCHAIN );
	sMemClose( &stream );
	clFree( "exportCert", buffer );

	return( status );
	}

⌨️ 快捷键说明

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