📄 cryptdbx.c
字号:
/****************************************************************************
* *
* cryptlib Key Database Routines *
* Copyright Peter Gutmann 1995-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
#include "asn1.h"
#include "keyset.h"
#else
#include "keymgmt/asn1.h"
#include "misc/keyset.h"
#endif /* Compiler-specific includes */
/* Prototypes for misc key read functions */
int getKeysetType( STREAM *stream );
/* Some keysets aren't supported on some platforms so we alias the calls out */
#if !( defined( __WINDOWS__ ) || defined( __UNIX__ ) )
#define setAccessMethodDBMS( x, y ) CRYPT_ARGERROR_NUM1
#endif /* !( __WINDOWS__ || __UNIX__ ) */
#ifndef DBX_LDAP
#define setAccessMethodLDAP( x ) CRYPT_ARGERROR_NUM1
#endif /* DBX_LDAP */
#ifndef NET_TCP
#define setAccessMethodHTTP( x ) CRYPT_ARGERROR_NUM1
#endif /* NET_TCP */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Initialise and down any databases we're working with */
void dbxInitODBC( void );
void dbxEndODBC( void );
void dbxInitLDAP( void );
void dbxEndLDAP( void );
void initKeysets( void )
{
#if defined( __WINDOWS__ ) && !defined( NT_DRIVER )
#ifdef DBX_ODBC
dbxInitODBC();
#endif /* DBX_ODBC */
#ifdef DBX_LDAP
dbxInitLDAP();
#endif /* DBX_LDAP */
#endif /* __WINDOWS__ && !NT_DRIVER */
}
void shutdownKeysets( void )
{
#if defined( __WINDOWS__ ) && !defined( NT_DRIVER )
#ifdef DBX_ODBC
dbxEndODBC();
#endif /* DBX_ODBC */
#ifdef DBX_LDAP
dbxEndLDAP();
#endif /* DBX_LDAP */
#endif /* __WINDOWS__ && !NT_DRIVER */
}
/****************************************************************************
* *
* Keyset API Functions *
* *
****************************************************************************/
/* Handle a message sent to a keyset object */
static int keysetMessageFunction( const CRYPT_KEYSET cryptKeyset,
const RESOURCE_MESSAGE_TYPE message,
void *messageDataPtr,
const int messageValue )
{
KEYSET_INFO *keysetInfoPtr;
getCheckInternalResource( cryptKeyset, keysetInfoPtr, OBJECT_TYPE_KEYSET );
/* Process the destroy object message */
if( message == RESOURCE_MESSAGE_DESTROY )
{
/* If the keyset is active, perform any required cleanup functions */
if( keysetInfoPtr->isOpen )
{
/* Shut down the keyset if required */
if( keysetInfoPtr->shutdownFunction != NULL )
keysetInfoPtr->shutdownFunction( keysetInfoPtr );
/* If the keyset is implemented as a file, close it (the keyset-
specific handler sees only an I/O stream and doesn't perform
any file-level functions). Because we cache all information
in a PKCS #15 keyset and close the stream immediately
afterwards if we've opened it in read-only mode, we only
close the stream for a PKCS #15 keyset if it's been opened in
R/W mode (note the distinction between the keyset being active
and the stream being active, for PKCS #15 the keyset can be
active without being associated with an open stream) */
if( keysetInfoPtr->type == CRYPT_KEYSET_FILE && \
!( keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 && \
keysetInfoPtr->options == CRYPT_KEYOPT_READONLY ) )
{
/* Since the update may have changed the overall size, we
need to clear any leftover data from the previous
version of the keyset before we close the file */
if( keysetInfoPtr->isDirty )
fileClearToEOF( &keysetInfoPtr->keysetFile.stream );
sFileClose( &keysetInfoPtr->keysetFile.stream );
/* If it's a newly-created empty keyset file (this can occur
if there's some sort of error on writing and no keys are
ever written to the keyset) or one in which all the keys
have been deleted, remove it */
if( keysetInfoPtr->isEmpty )
fileUnlink( keysetInfoPtr->keysetFile.fileName );
}
}
/* Delete the objects locking variables and the object itself */
unlockResource( keysetInfoPtr );
deleteResourceLock( keysetInfoPtr );
zeroise( keysetInfoPtr, sizeof( KEYSET_INFO ) );
free( keysetInfoPtr );
return( CRYPT_OK );
}
/* Process attribute get/set/delete messages */
if( message == RESOURCE_MESSAGE_SETATTRIBUTE )
{
assert( messageValue == CRYPT_IATTRIBUTE_INITIALISED );
/* It's an initialisation message, there's nothing to do */
unlockResourceExit( keysetInfoPtr, CRYPT_OK );
}
if( message == RESOURCE_MESSAGE_SETATTRIBUTE_S )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
int status;
/* If it's encoded cryptlib-specific data, pass it through to the
keyset */
if( messageValue == CRYPT_IATTRIBUTE_CONFIGDATA || \
messageValue == CRYPT_IATTRIBUTE_USERINDEX || \
messageValue == CRYPT_IATTRIBUTE_USERID || \
messageValue == CRYPT_IATTRIBUTE_USERINFO )
{
assert( keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
assert( keysetInfoPtr->setItemFunction != NULL );
status = keysetInfoPtr->setItemFunction( keysetInfoPtr,
CRYPT_UNUSED, KEYMGMT_ITEM_DATA,
msgData->data, msgData->length, messageValue );
if( cryptStatusOK( status ) && \
messageValue != CRYPT_IATTRIBUTE_USERID )
{
/* The update succeeded, remember that the data in the keyset
has changed, unless it's a userID which just modifies
existing data */
keysetInfoPtr->isDirty = TRUE;
keysetInfoPtr->isEmpty = FALSE;
}
unlockResourceExit( keysetInfoPtr, status );
}
assert( messageValue == CRYPT_KEYINFO_QUERY || \
messageValue == CRYPT_KEYINFO_QUERY_REQUESTS );
/* Make sure this access type is valid for this keyset */
if( keysetInfoPtr->getFirstItemFunction == NULL )
unlockResourceExit( keysetInfoPtr, CRYPT_ARGERROR_VALUE );
if( messageValue == CRYPT_KEYINFO_QUERY_REQUESTS && \
keysetInfoPtr->certMgmtFunction == NULL )
unlockResourceExit( keysetInfoPtr, CRYPT_ARGERROR_VALUE );
/* If we're in the middle of an existing query the user needs to
cancel it before starting another one */
if( keysetInfoPtr->queryInProgress &&
( msgData->length != 6 || \
strnicmp( msgData->data, "cancel", msgData->length ) ) )
return( CRYPT_ERROR_INCOMPLETE );
/* Send the query to the data source */
status = keysetInfoPtr->getFirstItemFunction( keysetInfoPtr, NULL,
NULL, CRYPT_KEYID_NAME, msgData->data, msgData->length,
( messageValue == CRYPT_KEYINFO_QUERY_REQUESTS ) ? \
KEYMGMT_ITEM_REQUEST : KEYMGMT_ITEM_PUBLICKEY,
KEYMGMT_FLAG_NONE );
unlockResourceExit( keysetInfoPtr, status );
}
if( message == RESOURCE_MESSAGE_GETATTRIBUTE )
{
int *valuePtr = ( int * ) messageDataPtr;
switch( messageValue )
{
case CRYPT_ATTRIBUTE_ERRORTYPE:
*valuePtr = keysetInfoPtr->errorType;
break;
case CRYPT_ATTRIBUTE_ERRORLOCUS:
*valuePtr = keysetInfoPtr->errorLocus;
break;
case CRYPT_ATTRIBUTE_INT_ERRORCODE:
*valuePtr = keysetInfoPtr->errorCode;
break;
default:
assert( NOTREACHED );
}
unlockResourceExit( keysetInfoPtr, CRYPT_OK );
}
if( message == RESOURCE_MESSAGE_GETATTRIBUTE_S )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
int status;
/* If it's encoded cryptlib-specific data, fetch it from to the
keyset */
if( messageValue == CRYPT_IATTRIBUTE_CONFIGDATA || \
messageValue == CRYPT_IATTRIBUTE_USERINDEX || \
messageValue == CRYPT_IATTRIBUTE_USERINFO || \
messageValue == CRYPT_IATTRIBUTE_TRUSTEDCERT || \
messageValue == CRYPT_IATTRIBUTE_TRUSTEDCERT_NEXT )
{
assert( keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
status = keysetInfoPtr->getItemFunction( keysetInfoPtr,
NULL, KEYMGMT_ITEM_DATA,
CRYPT_KEYID_NONE, NULL, 0,
msgData->data, &msgData->length,
messageValue );
unlockResourceExit( keysetInfoPtr, status );
}
assert( messageValue == CRYPT_ATTRIBUTE_INT_ERRORMESSAGE );
if( !*keysetInfoPtr->errorMessage )
status = CRYPT_ERROR_NOTFOUND;
else
status = attributeCopy( msgData, keysetInfoPtr->errorMessage,
strlen( keysetInfoPtr->errorMessage ) );
unlockResourceExit( keysetInfoPtr, status );
}
/* Process messages which check a keyset */
if( message == RESOURCE_MESSAGE_CHECK )
{
if( ( messageValue == RESOURCE_MESSAGE_CHECK_PKC_PRIVATE || \
messageValue == RESOURCE_MESSAGE_CHECK_PKC_DECRYPT || \
messageValue == RESOURCE_MESSAGE_CHECK_PKC_SIGN ) && \
( keysetInfoPtr->type == KEYSET_DBMS || \
keysetInfoPtr->type == KEYSET_LDAP || \
keysetInfoPtr->type == KEYSET_HTTP ) )
/* Public-key keysets can't contain objects which can perform
private-key ops */
unlockResourceExit( keysetInfoPtr, CRYPT_ARGERROR_OBJECT );
unlockResourceExit( keysetInfoPtr, CRYPT_OK );
}
/* Process object-specific messages */
if( message == RESOURCE_MESSAGE_KEY_GETKEY )
{
MESSAGE_KEYMGMT_INFO *getkeyInfo = \
( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
CRYPT_KEYID_TYPE keyIDtype = getkeyInfo->keyIDtype;
BYTE keyIDbuffer[ KEYID_SIZE ];
const void *keyID = getkeyInfo->keyID;
int keyIDlength = getkeyInfo->keyIDlength, status;
assert( keyIDtype != CRYPT_KEYID_NONE && \
keyID != NULL && getkeyInfo->keyIDlength > 0 );
assert( keysetInfoPtr->getItemFunction != NULL );
assert( messageValue != KEYMGMT_ITEM_PRIVATEKEY || \
keysetInfoPtr->type == KEYSET_FILE );
assert( ( messageValue != KEYMGMT_ITEM_SECRETKEY && \
messageValue != KEYMGMT_ITEM_DATA ) || \
( keysetInfoPtr->type == KEYSET_FILE && \
keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 ) );
assert( ( messageValue != KEYMGMT_ITEM_REQUEST && \
messageValue != KEYMGMT_ITEM_REVOCATIONINFO && \
messageValue != KEYMGMT_ITEM_PKIUSER ) || \
keysetInfoPtr->type == KEYSET_DBMS );
assert( ( messageValue != KEYMGMT_ITEM_REQUEST && \
messageValue != KEYMGMT_ITEM_PKIUSER ) || \
keysetInfoPtr->certMgmtFunction != NULL );
/* If we're in the middle of a query, we can't do anything else */
if( keysetInfoPtr->queryInProgress )
return( CRYPT_ERROR_INCOMPLETE );
/* If we've been passed a full issuerAndSerialNumber as a key ID and
the keyset needs an issuerID, convert it */
if( 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, ( BYTE * ) keyID, keyIDlength,
HASH_ALL );
keyIDtype = CRYPT_IKEYID_ISSUERID;
keyID = keyIDbuffer;
keyIDlength = hashSize;
}
/* Get the key */
status = keysetInfoPtr->getItemFunction( keysetInfoPtr,
&getkeyInfo->cryptHandle, messageValue,
keyIDtype, keyID, keyIDlength,
getkeyInfo->auxInfo, &getkeyInfo->auxInfoLength,
getkeyInfo->flags );
unlockResourceExit( keysetInfoPtr, status );
}
if( message == RESOURCE_MESSAGE_KEY_SETKEY )
{
MESSAGE_KEYMGMT_INFO *setkeyInfo = \
( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
int status;
assert( messageValue != KEYMGMT_ITEM_PRIVATEKEY || \
keysetInfoPtr->type == KEYSET_FILE );
assert( ( messageValue != KEYMGMT_ITEM_SECRETKEY && \
messageValue != KEYMGMT_ITEM_DATA ) || \
( keysetInfoPtr->type == KEYSET_FILE && \
keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 ) );
assert( ( messageValue != KEYMGMT_ITEM_REQUEST && \
messageValue != KEYMGMT_ITEM_REVOCATIONINFO && \
messageValue != KEYMGMT_ITEM_PKIUSER ) || \
( keysetInfoPtr->type == KEYSET_DBMS ) );
assert( ( messageValue != KEYMGMT_ITEM_REQUEST && \
messageValue != KEYMGMT_ITEM_PKIUSER ) || \
keysetInfoPtr->certMgmtFunction != NULL );
/* Make sure we can write to the keyset. This covers all
possibilities (both keyset types for which writing isn't
supported, and individual keysets which 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 )
unlockResourceExit( keysetInfoPtr, CRYPT_ERROR_PERMISSION );
if( keysetInfoPtr->setItemFunction == NULL )
unlockResourceExit( keysetInfoPtr, CRYPT_ERROR_NOTAVAIL );
/* Cert stores can't have certificates or CRLs inserted directly
into them (there's a specific check for allowed item types in the
cert store-specific code, but we perform a quick check here for
explicitly disallowed items so we can return a more appropriate
permission error rather than a generic bad item error) */
if( keysetInfoPtr->keysetDBMS.isCertStore && \
( messageValue == KEYMGMT_ITEM_PUBLICKEY || \
messageValue == KEYMGMT_ITEM_REVOCATIONINFO ) )
unlockResourceExit( keysetInfoPtr, CRYPT_ERROR_PERMISSION );
/* If we're in the middle of a query, we can't do anything else */
if( keysetInfoPtr->queryInProgress )
return( CRYPT_ERROR_INCOMPLETE );
/* Set the key */
status = keysetInfoPtr->setItemFunction( keysetInfoPtr,
setkeyInfo->cryptHandle, messageValue,
setkeyInfo->auxInfo, setkeyInfo->auxInfoLength,
setkeyInfo->flags );
if( cryptStatusOK( status ) )
{
/* The update succeeded, remember that the data in the keyset has
changed */
keysetInfoPtr->isDirty = TRUE;
keysetInfoPtr->isEmpty = FALSE;
}
unlockResourceExit( keysetInfoPtr, status );
}
if( message == RESOURCE_MESSAGE_KEY_DELETEKEY )
{
MESSAGE_KEYMGMT_INFO *deletekeyInfo = \
( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
CRYPT_KEYID_TYPE keyIDtype = deletekeyInfo->keyIDtype;
BYTE keyIDbuffer[ KEYID_SIZE ];
const void *keyID = deletekeyInfo->keyID;
int keyIDlength = deletekeyInfo->keyIDlength, status;
/* Make sure we can write to the keyset. This covers all
possibilities (both keyset types for which writing isn't supported,
and individual keysets which 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 )
unlockResourceExit( keysetInfoPtr, CRYPT_ERROR_PERMISSION );
if( keysetInfoPtr->deleteItemFunction == NULL )
unlockResourceExit( keysetInfoPtr, CRYPT_ERROR_NOTAVAIL );
/* If we're in the middle of a query, we can't do anything else */
if( keysetInfoPtr->queryInProgress )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -