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

📄 cryptdbx.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*						 cryptlib Key Database Routines						*
*						Copyright Peter Gutmann 1995-2002					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
  #include "keyset.h"
  #include "asn1_rw.h"
  #include "asn1s_rw.h"
#else
  #include "keyset/keyset.h"
  #include "misc/asn1_rw.h"
  #include "misc/asn1s_rw.h"
#endif /* Compiler-specific includes */

#ifdef USE_KEYSETS

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Exit after setting extended error information */

static int exitError( KEYSET_INFO *keysetInfoPtr,
					  const CRYPT_ATTRIBUTE_TYPE errorLocus,
					  const CRYPT_ERRTYPE_TYPE errorType, const int status )
	{
	setErrorInfo( keysetInfoPtr, errorLocus, errorType );
	return( status );
	}

static int exitErrorNotFound( KEYSET_INFO *keysetInfoPtr,
							  const CRYPT_ATTRIBUTE_TYPE errorLocus )
	{
	return( exitError( keysetInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
					   CRYPT_ERROR_NOTFOUND ) );
	}

static int exitErrorIncomplete( KEYSET_INFO *keysetInfoPtr,
								const CRYPT_ATTRIBUTE_TYPE errorLocus )
	{
	return( exitError( keysetInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_PRESENT,
					   CRYPT_ERROR_INCOMPLETE ) );
	}

/* Exit after saving a detailed error message.  This is used by lower-level 
   keyset code to provide more information to the caller than a basic error 
   code */

int retExtFnKeyset( KEYSET_INFO *keysetInfoPtr, const int status, 
					const char *format, ... )
	{
	char *errorMessagePtr;

	switch( keysetInfoPtr->type )
		{
		case KEYSET_HTTP:
			errorMessagePtr = keysetInfoPtr->keysetHTTP->errorMessage;
			break;

		case KEYSET_LDAP:
			errorMessagePtr = keysetInfoPtr->keysetLDAP->errorMessage;
			break;

		case KEYSET_DBMS:
			errorMessagePtr = keysetInfoPtr->keysetDBMS->errorMessage;
			break;

		default:
			errorMessagePtr = NULL;
		}
	if( errorMessagePtr != NULL )
		{
		va_list argPtr;

		va_start( argPtr, format );
		vsprintf( errorMessagePtr, format, argPtr ); 
		va_end( argPtr );
		}
	assert( !cryptArgError( status ) );	/* Catch leaks */
	return( cryptArgError( status ) ? CRYPT_ERROR_FAILED : status );
	}

/* Prepare to update a keyset, performing various access checks and pre-
   processing of information */

typedef struct {
	CRYPT_KEYID_TYPE keyIDtype;		/* KeyID type */
	const void *keyID;				/* KeyID value */
	int keyIDlength;
	} KEYID_INFO;

static int initKeysetUpdate( KEYSET_INFO *keysetInfoPtr, 
							 KEYID_INFO *keyIDinfo, void *keyIDbuffer,
							 const BOOLEAN isRead )
	{
	/* If we're in the middle of a query, we can't do anything else */
	if( keysetInfoPtr->isBusyFunction != NULL && \
		keysetInfoPtr->isBusyFunction( keysetInfoPtr ) )
		return( exitErrorIncomplete( keysetInfoPtr, CRYPT_KEYINFO_QUERY ) );

	/* If we've been passed a full issuerAndSerialNumber as a key ID and the 
	   keyset needs an issuerID, convert it */
	if( keyIDinfo != NULL && \
		keyIDinfo->keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER && \
		( keysetInfoPtr->type == KEYSET_DBMS || \
		  ( keysetInfoPtr->type == KEYSET_FILE && \
		    keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 ) ) )
		{
		HASHFUNCTION hashFunction;
		int hashSize;

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

		/* Hash the full iAndS to get an issuerID and use that for the keyID */
		hashFunction( NULL, keyIDbuffer, keyIDinfo->keyID, 
					  keyIDinfo->keyIDlength, HASH_ALL );
		keyIDinfo->keyIDtype = CRYPT_IKEYID_ISSUERID;
		keyIDinfo->keyID = keyIDbuffer;
		keyIDinfo->keyIDlength = hashSize;
		}

	/* If this is a read access, there's nothing further to do */
	if( isRead )
		return( CRYPT_OK );

	/* This is a write update, make sure that we can write to the keyset.  
	   This covers all possibilities, both keyset types for which writing 
	   isn't supported and individual keysets that we can't write to 
	   because of things like file permissions, so once we pass this check 
	   we know we can write to the keyset */
	if( keysetInfoPtr->options == CRYPT_KEYOPT_READONLY )
		return( CRYPT_ERROR_PERMISSION );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Flat-file Keyset Functions						*
*																			*
****************************************************************************/

/* Identify a flat-file keyset type */

#ifdef USE_PGP
  #if defined( INC_ALL )
	#include "pgp.h"
	#include "misc_rw.h"
  #else
	#include "envelope/pgp.h"
	#include "misc/misc_rw.h"
  #endif /* Compiler-specific includes */
#endif /* USE_PGP */

static KEYSET_SUBTYPE getKeysetType( STREAM *stream )
	{
	long length;
	int value, status;

	/* Try and guess the basic type */
	value = sPeek( stream );
	if( value == BER_SEQUENCE )
		{

		/* Read the length of the object.  This should be between 64 and 64K
		   bytes in size.  We have to allow for very tiny files to handle 
		   PKCS #15 files that contain only config data, and rather large 
		   ones to handle the existence of large numbers of trusted certs,
		   with a maximum of 32 objects * ~2K per object we can get close to
		   64K in size.  The length may also be zero if the indefinite 
		   encoding form is used.  Although PKCS #15 specifies the use of 
		   DER, it doesn't hurt to allow this at least for the outer wrapper.  
		   If Microsoft ever move to PKCS #15 they're bound to get it wrong */
		status = readLongSequence( stream, &length );
		if( cryptStatusError( status ) || \
			( length != CRYPT_UNUSED && ( length < 64 || length > 65535L ) ) )
			return( KEYSET_SUBTYPE_ERROR );

		/* Check for a PKCS #12/#15 file */
		if( peekTag( stream ) == BER_INTEGER )
			{
			long version;

			/* Check for a PKCS #12 version number */
			if( cryptStatusError( readShortInteger( stream, &version ) ) || \
				version != 3 )
				return( KEYSET_SUBTYPE_ERROR );
			return( KEYSET_SUBTYPE_PKCS12 );
			}

		/* Check for a PKCS #15 OID */
		if( !cryptStatusError( readOID( stream, OID_PKCS15_CONTENTTYPE ) ) )
			return( KEYSET_SUBTYPE_PKCS15 );

		/* It's something DER-encoded, but not PKCS #12 or PKCS #15 */
		return( KEYSET_SUBTYPE_ERROR );
		}
#ifdef USE_PGP
	if( getCTB( value ) == PGP_PACKET_PUBKEY || \
		getCTB( value ) == PGP_PACKET_SECKEY )
		{
		KEYSET_SUBTYPE type;

		/* Determine the file type based on the initial CTB */
		type = ( getCTB( value ) == PGP_PACKET_PUBKEY ) ? \
			   KEYSET_SUBTYPE_PGP_PUBLIC : KEYSET_SUBTYPE_PGP_PRIVATE;

		/* Perform a sanity check to make sure that the rest looks like a 
		   PGP keyring */
		status = pgpReadPacketHeader( stream, &value, &length );
		if( cryptStatusError( status ) )
			return( KEYSET_SUBTYPE_ERROR );
		if( type == KEYSET_SUBTYPE_PGP_PUBLIC )
			{
			if( length < 64 || length > 1024  )
				return( KEYSET_SUBTYPE_ERROR );
			}
		else
			if( length < 200 || length > 4096 )
				return( KEYSET_SUBTYPE_ERROR );
		value = sgetc( stream );
		if( value != PGP_VERSION_2 && value != PGP_VERSION_3 && \
			value != PGP_VERSION_OPENPGP )
			return( KEYSET_SUBTYPE_ERROR );
		return( type );
		}
#endif /* USE_PGP */

	/* "It doesn't look like anything from here" */
	return( KEYSET_SUBTYPE_ERROR );
	}

/* Open a flat-file keyset */

static int openKeysetStream( STREAM *stream, const char *name,
							 const CRYPT_KEYOPT_TYPE options,
							 CRYPT_KEYOPT_TYPE *keysetOptions, 
							 KEYSET_SUBTYPE *keysetSubType )
	{
	KEYSET_SUBTYPE subType = KEYSET_SUBTYPE_PKCS15;
	const int suffixPos = strlen( name ) - 4;
	int openMode, status;

	/* Get the expected subtype based on the keyset name */
	if( suffixPos > 0 && \
		( name[ suffixPos ] == '.' || name[ suffixPos ] == ' ' ) )
		{
		if( !strCompare( name + suffixPos + 1, "pgp", 3 ) || \
			!strCompare( name + suffixPos + 1, "gpg", 3 ) || \
			!strCompare( name + suffixPos + 1, "pkr", 3 ) )
			subType = KEYSET_SUBTYPE_PGP_PUBLIC;
		if( !strCompare( name + suffixPos + 1, "skr", 3 ) )
			subType = KEYSET_SUBTYPE_PGP_PRIVATE;
		if( !strCompare( name + suffixPos + 1, "pfx", 3 ) || \
			!strCompare( name + suffixPos + 1, "p12", 3 ) )
			subType = KEYSET_SUBTYPE_PKCS12;
		}

	/* If the file is read-only, put the keyset into read-only mode */
	if( fileReadonly( name ) )
		{
		/* If we want to create a new file, we can't do it if we don't have
		   write permission */
		if( options == CRYPT_KEYOPT_CREATE )
			return( CRYPT_ERROR_PERMISSION );

		/* Open the file in read-only mode */
		*keysetOptions = CRYPT_KEYOPT_READONLY;
		openMode = FILE_READ;
		}
	else
		/* If we're creating the file, open it in write-only mode.  Since
		   we'll (presumably) be storing private keys in it, we mark it as
		   both private (owner-access-only ACL) and sensitive (store in
		   secure storage if possible) */
		if( options == CRYPT_KEYOPT_CREATE )
			openMode = FILE_WRITE | FILE_EXCLUSIVE_ACCESS | \
					   FILE_PRIVATE | FILE_SENSITIVE;
		else
			/* Open it for read or read/write depending on whether the
			   readonly flag is set */
			openMode = ( options == CRYPT_KEYOPT_READONLY ) ? \
					   FILE_READ : FILE_READ | FILE_WRITE;
	if( options == CRYPT_IKEYOPT_EXCLUSIVEACCESS )
		openMode |= FILE_EXCLUSIVE_ACCESS;

	/* Pre-open the file containing the keyset.  This initially opens it in
	   read-only mode for auto-detection of the file type so we can check for
	   various problems */
	status = sFileOpen( stream, name, FILE_READ );
	if( cryptStatusError( status ) )
		{
		/* The file doesn't exist, if the create-new-file flag isn't set
		   return an error.  If it is set, make sure that we're trying to 
		   create a writeable keyset type */
		if( options != CRYPT_KEYOPT_CREATE )
			return( status );
		if( !isWriteableFileKeyset( subType ) )
			return( CRYPT_ERROR_NOTAVAIL );

		/* Try and create a new file */
		status = sFileOpen( stream, name, openMode );
		if( cryptStatusError( status ) )
			/* The file isn't open at this point so we have to exit 
			   explicitly rather than falling through to the error handler
			   below */
			return( status );
		}
	else
		{
		/* If we're opening an existing keyset, get its type and make sure
		   that it's valid */
		if( options != CRYPT_KEYOPT_CREATE )
			{
			BYTE buffer[ 512 ];

			sioctl( stream, STREAM_IOCTL_IOBUFFER, buffer, 512 );
			subType = getKeysetType( stream );
			if( subType == KEYSET_SUBTYPE_ERROR )
				{
				/* "It doesn't look like anything from here" */
				sFileClose( stream );
				return( CRYPT_ERROR_BADDATA );
				}
			sseek( stream, 0 );
			sioctl( stream, STREAM_IOCTL_IOBUFFER, NULL, 0 );
			}

		/* If it's a cryptlib keyset we can open it in any mode */
		if( isWriteableFileKeyset( subType ) )
			{
			/* If we're opening it something other than read-only mode, 
			   reopen it in that mode */
			if( openMode != FILE_READ )
				{
				sFileClose( stream );
				status = sFileOpen( stream, name, openMode );
				if( cryptStatusError( status ) )
					return( status );	/* Exit with file closed */
				}
			}
		else
			/* If it's a non-cryptlib keyset we can't open it for anything 
			   other than read-only access.  We return a not-available error 
			   rather than a permission error since this isn't a problem with
			   access permissions for the file but the fact that the code to
			   write the key doesn't exist */
			if( options != CRYPT_KEYOPT_READONLY )
				status = CRYPT_ERROR_NOTAVAIL;
		}
	if( cryptStatusError( status ) )
		sFileClose( stream );
	else
		*keysetSubType = subType;
	return( status );
	}

/****************************************************************************
*																			*
*						Keyset Attribute Handling Functions					*
*																			*
****************************************************************************/

/* Handle data sent to or read from a keyset object */

static int processGetAttribute( KEYSET_INFO *keysetInfoPtr,
								void *messageDataPtr, const int messageValue )
	{
	int *valuePtr = ( int * ) messageDataPtr;

	switch( messageValue )
		{
		case CRYPT_ATTRIBUTE_ERRORTYPE:
			*valuePtr = keysetInfoPtr->errorType;
			return( CRYPT_OK );

		case CRYPT_ATTRIBUTE_ERRORLOCUS:
			*valuePtr = keysetInfoPtr->errorLocus;
			return( CRYPT_OK );

		case CRYPT_ATTRIBUTE_INT_ERRORCODE:	
			switch( keysetInfoPtr->type )
				{
				case KEYSET_HTTP:
					*valuePtr = keysetInfoPtr->keysetHTTP->errorCode;
					break;

				case KEYSET_LDAP:
					*valuePtr = keysetInfoPtr->keysetLDAP->errorCode;
					break;

⌨️ 快捷键说明

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