📄 certstore.c
字号:
/****************************************************************************
* *
* cryptlib HTTP Certstore Session Management *
* Copyright Peter Gutmann 1998-2004 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "misc_rw.h"
#include "session.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../misc/misc_rw.h"
#include "session.h"
#else
#include "crypt.h"
#include "misc/misc_rw.h"
#include "session/session.h"
#endif /* Compiler-specific includes */
#ifdef USE_CERTSTORE
/* Processing flags for query data */
#define CERTSTORE_FLAG_NONE 0x00 /* No special processing */
#define CERTSTORE_FLAG_BASE64 0x01 /* Data must be base64 */
/* Table mapping a query submitted as an HTTP GET to a cryptlib-internal
keyset query. Note that the first letter must be lowercase for the
case-insensitive quick match */
typedef struct {
const char *attrName; /* Attribute name from HTTP GET */
const int attrNameLen; /* Attribute name length */
const CRYPT_ATTRIBUTE_TYPE attribute; /* cryptlib attribute ID */
const int flags; /* Processing flags */
} CERTSTORE_READ_INFO;
static const CERTSTORE_READ_INFO certstoreReadInfo[] = {
{ "certHash", 8, CRYPT_IKEYID_CERTID, CERTSTORE_FLAG_BASE64 },
{ "name", 4, CRYPT_KEYID_NAME, CERTSTORE_FLAG_NONE },
{ "uri", 3, CRYPT_KEYID_URI, CERTSTORE_FLAG_NONE },
{ "email", 5, CRYPT_KEYID_URI, CERTSTORE_FLAG_NONE },
{ "sHash", 5, CRYPT_IKEYID_ISSUERID, CERTSTORE_FLAG_BASE64 },
{ "iHash", 5, CRYPT_IKEYID_ISSUERID, CERTSTORE_FLAG_BASE64 },
{ "iAndSHash", 9, CRYPT_IKEYID_ISSUERANDSERIALNUMBER, CERTSTORE_FLAG_BASE64 },
{ "sKIDHash", 8, CRYPT_IKEYID_KEYID, CERTSTORE_FLAG_BASE64 },
{ NULL, CRYPT_KEYID_NONE, CERTSTORE_FLAG_NONE },
};
/****************************************************************************
* *
* Init/Shutdown Functions *
* *
****************************************************************************/
/* Send an error response to the client. This is mapped at the HTTP layer to
an appropriate HTTP response. We don't return a status from this since
the caller already has an error status available */
static void sendErrorResponse( SESSION_INFO *sessionInfoPtr,
const int errorStatus )
{
BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
mputWord( bufPtr, errorStatus );
swrite( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer, 2 );
}
/* Read a value from the HTTP GET */
static int readValue( STREAM *stream, char **valuePtrPtr, int *valueLen )
{
int status;
/* Clear return values */
if( valuePtrPtr != NULL )
{
*valuePtrPtr = NULL;
*valueLen = 0;
}
/* Read the { length, data } information */
status = readUint16( stream );
if( cryptStatusError( status ) )
return( status );
if( status <= 0 )
/* If we're not interested in the data then a length of zero (item
not present) is OK, otherwise it's an error */
return( ( valuePtrPtr == NULL ) ? \
CRYPT_OK : CRYPT_ERROR_UNDERFLOW );
if( status > CRYPT_MAX_TEXTSIZE )
return( CRYPT_ERROR_OVERFLOW );
if( valuePtrPtr != NULL )
{
char *valuePtr = sMemBufPtr( stream );
valuePtr[ status ] = '\0';
*valuePtrPtr = valuePtr;
*valueLen = status;
}
return( sSkip( stream, status ) );
}
/* Exchange data with an HTTP client */
static int serverTransact( SESSION_INFO *sessionInfoPtr )
{
const CERTSTORE_READ_INFO *certstoreInfoPtr;
MESSAGE_KEYMGMT_INFO getkeyInfo;
RESOURCE_DATA msgData;
STREAM stream;
BYTE buffer[ 128 ];
char *attrPtr, *valuePtr, certIdBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
char firstChar;
int attrLen, valueLen, length, i, status;
/* Read the request data from the client. Note that we do a direct read
rather than using readPkiDatagram() since we're reading an idempotent
HTTP GET request and not a PKI datagram submitted via an HTTP POST */
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_IDEMPOTENT, NULL, TRUE );
length = sread( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufSize );
if( cryptStatusError( length ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
return( length );
}
/* Read the { attribute, value } pair from the HTTP GET:
word uriLen
byte[] uri
word attrLen
byte[] attr
word valueLen
byte[] value */
sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
status = readValue( &stream, NULL, NULL );
if( cryptStatusOK( status ) )
status = readValue( &stream, &attrPtr, &attrLen );
if( cryptStatusOK( status ) )
status = readValue( &stream, &valuePtr, &valueLen );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
/* This shouldn't ever occur since it would mean that the HTTP layer
has sent us invalid data */
assert( NOTREACHED );
retExt( sessionInfoPtr, status, "Invalid cert store query data" );
}
/* Save a copy of the requested cert ID for later in case we have to
report an error in locating the cert */
strcpy( certIdBuffer, valuePtr );
/* Convert the search attribute type into a cryptlib key ID */
firstChar = toLower( *attrPtr );
for( i = 0;
certstoreReadInfo[ i ].attrName != NULL && \
( attrLen != certstoreReadInfo[ i ].attrNameLen || \
certstoreReadInfo[ i ].attrName[ 0 ] != firstChar || \
strCompare( attrPtr, certstoreReadInfo[ i ].attrName, \
certstoreReadInfo[ i ].attrNameLen ) );
i++ );
certstoreInfoPtr = &certstoreReadInfo[ i ];
if( certstoreInfoPtr->attrName == NULL )
{
sendErrorResponse( sessionInfoPtr, CRYPT_ERROR_BADDATA );
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid cert store query attribute '%s'",
sanitiseString( attrPtr ) );
}
/* If the value was base64-encoded in transit, decode it to get the
actual query data */
if( certstoreInfoPtr->flags & CERTSTORE_FLAG_BASE64 )
{
status = base64decode( buffer, 64, valuePtr, valueLen,
CRYPT_CERTFORMAT_NONE );
if( cryptStatusError( status ) )
{
sendErrorResponse( sessionInfoPtr, CRYPT_ERROR_BADDATA );
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid base64-encoded query value '%s'",
sanitiseString( certIdBuffer ) );
}
valuePtr = buffer;
valueLen = status;
}
/* Try and fetch the requested cert */
setMessageKeymgmtInfo( &getkeyInfo, certstoreInfoPtr->attribute,
valuePtr, valueLen, NULL, 0, KEYMGMT_FLAG_NONE );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_GETKEY, &getkeyInfo,
KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusError( status ) )
{
/* Not finding a cert in response to a request isn't a real error so
all we do is return a warning to the caller */
sendErrorResponse( sessionInfoPtr, status );
retExt( sessionInfoPtr, CRYPT_OK,
"Warning: Couldn't find certificate for '%s'",
sanitiseString( certIdBuffer ) );
}
memset( sessionInfoPtr->receiveBuffer, 0, 2 ); /* Returned status value */
setMessageData( &msgData, sessionInfoPtr->receiveBuffer + 2,
sessionInfoPtr->receiveBufSize - 2 );
status = krnlSendMessage( getkeyInfo.cryptHandle, IMESSAGE_CRT_EXPORT,
&msgData, CRYPT_CERTFORMAT_CERTIFICATE );
krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DESTROY );
if( cryptStatusError( status ) )
{
sendErrorResponse( sessionInfoPtr, status );
retExt( sessionInfoPtr, status,
"Couldn't export requested certificate for '%s'",
sanitiseString( certIdBuffer ) );
}
/* Send the result to the client */
status = swrite( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer,
msgData.length + 2 );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
return( status );
}
return( CRYPT_OK ); /* swrite() returns a byte count */
}
/****************************************************************************
* *
* Session Access Routines *
* *
****************************************************************************/
int setAccessMethodCertstore( SESSION_INFO *sessionInfoPtr )
{
static const PROTOCOL_INFO protocolInfo = {
/* General session information */
TRUE, /* Request-response protocol */
SESSION_ISHTTPTRANSPORT, /* Flags */
80, /* HTTP port */
0, /* Client flags */
SESSION_NEEDS_KEYSET | /* Server flags */
SESSION_NEEDS_CERTSOURCE,
1, 1, 1, /* Version 1 */
"application/pkix-cert", /* Client content-type */
"application/pkix-cert", /* Server content-type */
/* Protocol-specific information */
};
/* Set the access method pointers */
sessionInfoPtr->protocolInfo = &protocolInfo;
if( sessionInfoPtr->flags & SESSION_ISSERVER )
sessionInfoPtr->transactFunction = serverTransact;
else
return( CRYPT_ERROR_NOTAVAIL );
return( CRYPT_OK );
}
#endif /* USE_CERTSTORE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -