📄 ca_misc.c
字号:
/****************************************************************************
* *
* cryptlib DBMS CA Certificate Misc Interface *
* Copyright Peter Gutmann 1996-2007 *
* *
****************************************************************************/
#include <stdio.h> /* For snprintf() */
#if defined( INC_ALL )
#include "crypt.h"
#include "keyset.h"
#include "dbms.h"
#include "asn1.h"
#else
#include "crypt.h"
#include "keyset/keyset.h"
#include "keyset/dbms.h"
#include "misc/asn1.h"
#endif /* Compiler-specific includes */
#ifdef USE_DBMS
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
#if 0
/* Get the ultimate successor certificate for one that's been superseded */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int getSuccessorCert( INOUT DBMS_INFO *dbmsInfo,
OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCertificate,
IN_BUFFER( initialCertIDlength ) \
const char *initialCertID,
IN_LENGTH_SHORT const int initialCertIDlength )
{
char certID[ ENCODED_DBXKEYID_SIZE + 8 ];
int chainingLevel, status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( isWritePtr( *iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
assert( isReadPtr( initialCertID, initialCertIDlength ) );
/* Walk through the chain of renewals in the certificate store log until
we find the ultimate successor certificate to the current one */
memcpy( certID, initialCertID, initialCertIDlength );
for( chainingLevel = 0, status = CRYPT_ERROR_NOTFOUND;
status == CRYPT_ERROR_NOTFOUND && \
chainingLevel < FAILSAFE_ITERATIONS_MED;
chainingLevel++ )
{
BYTE keyCertID[ DBXKEYID_SIZE + 8 ];
char certData[ MAX_QUERY_RESULT_SIZE + 8 ];
int certDataLength, length, dummy;
/* Find the request to renew this certificate */
status = dbmsQuery(
"SELECT certID FROM certLog WHERE subjCertID = ? "
"AND action = " TEXT_CERTACTION_REQUEST_RENEWAL,
certData, &certDataLength, certID,
strlen( certID ), 0, DBMS_CACHEDQUERY_NONE,
DBMS_QUERY_NORMAL );
if( cryptStatusError( status ) )
return( status );
/* Find the resulting certificate */
memcpy( certID, certData,
min( certDataLength, ENCODED_DBXKEYID_SIZE + 1 ) );
certID[ MAX_ENCODED_DBXKEYID_SIZE ] = '\0';
status = dbmsQuery(
"SELECT certID FROM certLog WHERE reqCertID = ? "
"AND action = " TEXT_CERTACTION_CERT_CREATION,
certData, &certDataLength, certID,
strlen( certID ), 0, DBMS_CACHEDQUERY_NONE,
DBMS_QUERY_NORMAL );
if( cryptStatusOK( status ) )
{
status = length = \
base64decode( keyCertID, certData,
min( certDataLength, ENCODED_DBXKEYID_SIZE ),
CRYPT_CERTFORMAT_NONE );
assert( !cryptStatusError( status ) );
}
if( cryptStatusError( status ) )
return( status );
/* Try and get the replacement certificate */
status = getItemData( dbmsInfo, iCertificate, &dummy,
getKeyName( CRYPT_IKEYID_CERTID ),
keyCertID, length, KEYMGMT_ITEM_PUBLICKEY,
KEYMGMT_FLAG_NONE, errorInfo );
}
if( chainingLevel >= FAILSAFE_ITERATIONS_MED )
{
/* We've chained through too many entries, bail out */
return( CRYPT_ERROR_OVERFLOW );
}
return( status );
}
#endif /* 0 */
/****************************************************************************
* *
* Logging Functions *
* *
****************************************************************************/
/* Add an entry to the CA log */
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int updateCertLog( INOUT DBMS_INFO *dbmsInfo,
IN_ENUM( CRYPT_CERTACTION ) const CRYPT_CERTACTION_TYPE action,
IN_BUFFER_OPT( certIDlength ) const char *certID,
IN_LENGTH_SHORT_Z const int certIDlength,
IN_BUFFER_OPT( reqCertIDlength ) const char *reqCertID,
IN_LENGTH_SHORT_Z const int reqCertIDlength,
IN_BUFFER_OPT( subjCertIDlength ) const char *subjCertID,
IN_LENGTH_SHORT_Z const int subjCertIDlength,
IN_BUFFER_OPT( dataLength ) const void *data,
IN_LENGTH_SHORT_Z const int dataLength,
IN_ENUM( DBMS_UPDATE ) const DBMS_UPDATE_TYPE updateType )
{
BOUND_DATA boundData[ BOUND_DATA_MAXITEMS ], *boundDataPtr = boundData;
char sqlBuffer[ MAX_SQL_QUERY_SIZE + 8 ];
char certIDbuffer[ ENCODED_DBXKEYID_SIZE + 8 ];
char encodedCertData[ MAX_ENCODED_CERT_SIZE + 8 ];
const time_t boundDate = getApproxTime();
int localCertIDlength = certIDlength, sqlOffset, sqlLength, boundDataIndex;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( ( certID == NULL && certIDlength == 0 ) || \
isReadPtr( certID, certIDlength ) );
assert( ( reqCertID == NULL && reqCertIDlength == 0 ) || \
isReadPtr( reqCertID, reqCertIDlength ) );
assert( ( subjCertID == NULL && subjCertIDlength == 0 ) || \
isReadPtr( subjCertID, subjCertIDlength ) );
assert( ( data == NULL && dataLength == 0 ) || \
isReadPtr( data, dataLength ) );
REQUIRES( action > CRYPT_CERTACTION_NONE && \
action < CRYPT_CERTACTION_LAST );
REQUIRES( ( certID == NULL && certIDlength == 0 ) || \
( certID != NULL && \
certIDlength > 0 && \
certIDlength < MAX_INTLENGTH_SHORT ) );
REQUIRES( ( reqCertID == NULL && reqCertIDlength == 0 ) || \
( reqCertID != NULL && \
reqCertIDlength > 0 && \
reqCertIDlength < MAX_INTLENGTH_SHORT ) );
REQUIRES( ( subjCertID == NULL && subjCertIDlength == 0 ) || \
( subjCertID != NULL && \
subjCertIDlength > 0 && \
subjCertIDlength < MAX_INTLENGTH_SHORT ) );
REQUIRES( ( data == NULL && dataLength == 0 ) || \
( data != NULL && \
dataLength > 0 && \
dataLength < MAX_INTLENGTH_SHORT ) );
REQUIRES( updateType > DBMS_UPDATE_NONE && \
updateType < DBMS_UPDATE_LAST );
/* Build up the necessary SQL format string required to insert the log
entry. This is complicated somewhat by the fact that some of the
values may be NULL so we have to insert them by naming the columns
(some databases allow the use of the DEFAULT keyword but this isn't
standardised enough to be safe) */
strlcpy_s( sqlBuffer, MAX_SQL_QUERY_SIZE,
"INSERT INTO certLog (action, actionTime, certID" );
if( reqCertID != NULL )
strlcat_s( sqlBuffer, MAX_SQL_QUERY_SIZE, ", reqCertID" );
if( subjCertID != NULL )
strlcat_s( sqlBuffer, MAX_SQL_QUERY_SIZE, ", subjCertID" );
if( data != NULL )
strlcat_s( sqlBuffer, MAX_SQL_QUERY_SIZE, ", certData" );
strlcat_s( sqlBuffer, MAX_SQL_QUERY_SIZE, ") VALUES (" );
sqlOffset = strlen( sqlBuffer );
sqlLength = MAX_SQL_QUERY_SIZE - sqlOffset;
sprintf_s( sqlBuffer + sqlOffset, sqlLength, "%d, ?, ?", action );
if( reqCertID != NULL )
strlcat_s( sqlBuffer + sqlOffset, sqlLength, ", ?" );
if( subjCertID != NULL )
strlcat_s( sqlBuffer + sqlOffset, sqlLength, ", ?" );
if( data != NULL )
strlcat_s( sqlBuffer + sqlOffset, sqlLength, ", ?" );
strlcat_s( sqlBuffer + sqlOffset, sqlLength, ")" );
/* If we're not worried about the certID we just insert a nonce value
which is used to meet the constraints for a unique entry. In order
to ensure that it doesn't clash with a real certID we set the first
four characters to an out-of-band value */
if( certID == NULL )
{
MESSAGE_DATA msgData;
BYTE nonce[ KEYID_SIZE + 8 ];
int status;
setMessageData( &msgData, nonce, KEYID_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusOK( status ) )
status = base64encode( certIDbuffer, ENCODED_DBXKEYID_SIZE,
&localCertIDlength, nonce, DBXKEYID_SIZE,
CRYPT_CERTTYPE_NONE );
if( cryptStatusError( status ) )
{
/* Normally this is a should-never-occur error, however if
cryptlib has been shut down from another thread the kernel
will fail all non shutdown-related calls with a permission
error. To avoid false alarms, we mask out failures due to
permission errors */
assert( ( status == CRYPT_ERROR_PERMISSION ) || DEBUG_WARN );
return( status );
}
memset( certIDbuffer, '-', 4 );
certID = certIDbuffer;
}
/* Set up the parameter information and update the certificate store
log */
initBoundData( boundDataPtr );
setBoundDataDate( boundDataPtr, 0, &boundDate );
setBoundData( boundDataPtr, 1, certID, localCertIDlength );
boundDataIndex = 2;
if( reqCertID != NULL )
setBoundData( boundDataPtr, boundDataIndex++, reqCertID,
reqCertIDlength );
if( subjCertID != NULL )
setBoundData( boundDataPtr, boundDataIndex++, subjCertID,
subjCertIDlength );
if( data != NULL )
{
if( hasBinaryBlobs( dbmsInfo ) )
{
setBoundDataBlob( boundDataPtr, boundDataIndex,
data, dataLength );
}
else
{
int encodedDataLength, status;
status = base64encode( encodedCertData, MAX_ENCODED_CERT_SIZE,
&encodedDataLength, data, dataLength,
CRYPT_CERTTYPE_NONE );
if( cryptStatusError( status ) )
{
assert( DEBUG_WARN );
return( status );
}
setBoundData( boundDataPtr, boundDataIndex,
encodedCertData, encodedDataLength );
}
}
return( dbmsUpdate( sqlBuffer, boundDataPtr, updateType ) );
}
RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int updateCertErrorLog( INOUT DBMS_INFO *dbmsInfo,
IN_ERROR const int errorStatus,
IN_STRING const char *errorString,
IN_BUFFER_OPT( certIDlength ) const char *certID,
IN_LENGTH_SHORT_Z const int certIDlength,
IN_BUFFER_OPT( reqCertIDlength ) const char *reqCertID,
IN_LENGTH_SHORT_Z const int reqCertIDlength,
IN_BUFFER_OPT( subjCertIDlength ) const char *subjCertID,
IN_LENGTH_SHORT_Z const int subjCertIDlength,
IN_BUFFER_OPT( dataLength ) const void *data,
IN_LENGTH_SHORT_Z const int dataLength )
{
STREAM stream;
BYTE errorData[ 64 + MAX_CERT_SIZE + 8 ];
const int errorStringLength = strlen( errorString );
int errorDataLength = DUMMY_INIT, status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( ( certID == NULL && certIDlength == 0 ) || \
isReadPtr( certID, certIDlength ) );
assert( ( reqCertID == NULL && reqCertIDlength == 0 ) || \
isReadPtr( reqCertID, reqCertIDlength ) );
assert( ( subjCertID == NULL && subjCertIDlength == 0 ) || \
isReadPtr( subjCertID, subjCertIDlength ) );
assert( ( data == NULL && dataLength == 0 ) || \
isReadPtr( data, dataLength ) );
REQUIRES( cryptStatusError( errorStatus ) );
REQUIRES( errorString != NULL );
REQUIRES( ( certID == NULL && certIDlength == 0 ) || \
( certID != NULL && \
certIDlength > 0 && \
certIDlength < MAX_INTLENGTH_SHORT ) );
REQUIRES( ( reqCertID == NULL && reqCertIDlength == 0 ) || \
( reqCertID != NULL && \
reqCertIDlength > 0 && \
reqCertIDlength < MAX_INTLENGTH_SHORT ) );
REQUIRES( ( subjCertID == NULL && subjCertIDlength == 0 ) || \
( subjCertID != NULL && \
subjCertIDlength > 0 && \
subjCertIDlength < MAX_INTLENGTH_SHORT ) );
REQUIRES( ( data == NULL && dataLength == 0 ) || \
( data != NULL && \
dataLength > 0 && \
dataLength < MAX_INTLENGTH_SHORT ) );
/* Encode the error information:
SEQUENCE {
errorStatus INTEGER,
errorString UTF8String,
certData ANY OPTIONAL
}
Note that the buffer we use is slightly larger than MAX_CERT_SIZE in
order to accomodate the error status information alongside the
largest possible certificate, in theory this means that if the database
back-end doesn't support binary blobs there won't be enough room in
the logging code to text-encode this worst-case scenario, but the use
of non-binary-blob capable database should be fairly rare so it's
easier to just rely on the logging code to catch this unlikely
scenario than to try and special-case around it */
sMemOpen( &stream, errorData, 64 + MAX_CERT_SIZE );
writeSequence( &stream, sizeofShortInteger( -errorStatus ) + \
( int ) sizeofObject( errorStringLength ) + \
dataLength );
writeShortInteger( &stream, -errorStatus, DEFAULT_TAG );
status = writeCharacterString( &stream, errorString, errorStringLength,
BER_STRING_UTF8 );
if( dataLength > 0 )
status = swrite( &stream, data, dataLength );
if( cryptStatusOK( status ) )
errorDataLength = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -