📄 dbx_wr.c
字号:
/****************************************************************************
* *
* cryptlib DBMS Interface *
* Copyright Peter Gutmann 1996-2004 *
* *
****************************************************************************/
#include <stdarg.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "keyset.h"
#include "dbms.h"
#include "asn1.h"
#include "rpc.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../keyset/keyset.h"
#include "../keyset/dbms.h"
#include "../misc/asn1.h"
#include "../misc/rpc.h"
#else
#include "crypt.h"
#include "keyset/keyset.h"
#include "keyset/dbms.h"
#include "misc/asn1.h"
#include "misc/rpc.h"
#endif /* Compiler-specific includes */
#ifdef USE_DBMS
/* Get a commonName or commonName-equivalent from a certificate */
static int getCommonName( CRYPT_CERTIFICATE iCryptCert, char *CN,
const char *OU, const char *O )
{
RESOURCE_DATA msgData;
char buffer[ MAX_ATTRIBUTE_SIZE ], *strPtr;
int status;
/* First, we try for a CN */
setMessageData( &msgData, CN, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_COMMONNAME );
if( cryptStatusOK( status ) )
{
CN[ msgData.length ] = '\0';
return( CRYPT_OK );
}
/* If that fails, we try for either a pseudonym or givenName + surname.
Since these are part of the vast collection of oddball DN attributes
that aren't handled directly, we have to get the encoded DN form and
look for them by OID */
setMessageData( &msgData, buffer, MAX_ATTRIBUTE_SIZE - 1 );
status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_DN );
if( cryptStatusError( status ) )
return( status );
buffer[ msgData.length ] = '\0';
/* Look for a pseudonym */
strPtr = strstr( buffer, "oid.2.5.4.65=" );
if( strPtr != NULL )
{
int length;
strPtr += 13; /* Skip type indicator */
for( length = 0; strPtr[ length ] != '\0' && \
strPtr[ length ] != ',' && \
strPtr[ length ] != '+'; length++ );
if( length > 0 && strPtr[ length ] == '+' && \
strPtr[ length - 1 ] == ' ' )
length--; /* Strip trailing space */
if( length <= CRYPT_MAX_TEXTSIZE )
{
memcpy( CN, strPtr, length );
CN[ length ] = '\0';
return( CRYPT_OK );
}
}
/* Look for givenName + surname */
strPtr = strstr( buffer, "G=" );
if( strPtr != NULL )
{
char *surnameStrPtr;
int length, surnameLength;
strPtr += 2; /* Skip type indicator */
for( length = 0; \
strPtr[ length ] != '\0' && \
strPtr[ length ] != ',' && \
strPtr[ length ] != '+'; \
length++ );
if( length > 0 && strPtr[ length ] == '+' && \
strPtr[ length - 1 ] == ' ' )
length--; /* Strip trailing space */
surnameStrPtr = strstr( buffer, "S=" );
if( surnameStrPtr != NULL )
{
surnameStrPtr += 2; /* Skip type indicator */
for( surnameLength = 0; \
surnameStrPtr[ surnameLength ] != '\0' && \
surnameStrPtr[ surnameLength ] != ',' && \
surnameStrPtr[ length ] != '+'; \
surnameLength++ );
if( surnameLength > 0 && \
surnameStrPtr[ surnameLength ] == '+' && \
surnameStrPtr[ surnameLength - 1 ] == ' ' )
surnameLength--; /* Strip trailing space */
if( length + surnameLength <= CRYPT_MAX_TEXTSIZE )
{
memcpy( CN, strPtr, length );
memcpy( CN + length, surnameStrPtr, surnameLength );
CN[ length + surnameLength ] = '\0';
return( CRYPT_OK );
}
}
}
/* It's possible (although highly unlikely) that a certificate won't
have a usable CN-equivalent in some form, in which case we use the OU
instead. If that also fails, we use the O. This gets a bit messy,
but duplicating the OU / O into the CN seems to be the best way to
handle this */
strcpy( CN, *OU ? OU : O );
return( CRYPT_OK );
}
/* Add a certificate object (cert, cert request, PKI user) to a database.
Normally existing rows would be overwritten if we added duplicate entries,
but the UNIQUE constraint on the indices will catch this */
int addCert( DBMS_INFO *dbmsInfo, const CRYPT_HANDLE iCryptHandle,
const CRYPT_CERTTYPE_TYPE certType, const CERTADD_TYPE addType,
const DBMS_UPDATE_TYPE updateType )
{
RESOURCE_DATA msgData;
BYTE certData[ MAX_CERT_SIZE ];
char sqlBuffer[ MAX_SQL_QUERY_SIZE ];
char nameID[ DBXKEYID_BUFFER_SIZE ], issuerID[ DBXKEYID_BUFFER_SIZE ];
char keyID[ DBXKEYID_BUFFER_SIZE ], certID[ DBXKEYID_BUFFER_SIZE ];
char C[ CRYPT_MAX_TEXTSIZE + 1 ], SP[ CRYPT_MAX_TEXTSIZE + 1 ],
L[ CRYPT_MAX_TEXTSIZE + 1 ], O[ CRYPT_MAX_TEXTSIZE + 1 ],
OU[ CRYPT_MAX_TEXTSIZE + 1 ], CN[ CRYPT_MAX_TEXTSIZE + 1 ],
uri[ CRYPT_MAX_TEXTSIZE + 1 ];
time_t boundDate = 0;
int certDataLength, status;
assert( certType == CRYPT_CERTTYPE_CERTIFICATE || \
certType == CRYPT_CERTTYPE_REQUEST_CERT || \
certType == CRYPT_CERTTYPE_PKIUSER );
*C = *SP = *L = *O = *OU = *CN = *uri = '\0';
/* Extract the DN and altName (URI) components. This changes the
currently selected DN components, but this is OK since we've got
the cert locked and the prior state will be restored when we unlock
it */
krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED, CRYPT_CERTINFO_SUBJECTNAME );
setMessageData( &msgData, C, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_COUNTRYNAME );
if( cryptStatusOK( status ) )
C[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, SP, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_STATEORPROVINCENAME );
if( cryptStatusOK( status ) )
SP[ msgData.length ] = '\0';
}
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, L, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_LOCALITYNAME );
if( cryptStatusOK( status ) )
L[ msgData.length ] = '\0';
}
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, O, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_ORGANIZATIONNAME );
if( cryptStatusOK( status ) )
O[ msgData.length ] = '\0';
}
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, OU, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_ORGANIZATIONALUNITNAME );
if( cryptStatusOK( status ) )
OU[ msgData.length ] = '\0';
}
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
/* The handling of the CN (or CN-equivalent) is somewhat complex so
we use a separate function for this */
status = getCommonName( iCryptHandle, CN, OU, O );
}
if( ( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND ) && \
( certType != CRYPT_CERTTYPE_PKIUSER ) )
{
static const int value = CRYPT_CERTINFO_SUBJECTALTNAME;
/* Get the URI for this cert, in order of likelihood of occurrence */
setMessageData( &msgData, uri, CRYPT_MAX_TEXTSIZE );
krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
( void * ) &value, CRYPT_ATTRIBUTE_CURRENT );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_RFC822NAME );
if( status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, uri, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData,
CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER );
}
if( status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, uri, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_DNSNAME );
}
if( cryptStatusOK( status ) )
{
int i;
/* Force the URI (as stored) to lowercase to make case-
insensitive matching easier. In most cases we could ask the
back-end to do this, but this complicates indexing and
there's no reason why we can't do it here */
for( i = 0; i < msgData.length; i++ )
uri[ i ] = toLower( uri[ i ] );
uri[ msgData.length ] = '\0';
}
}
if( ( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND ) && \
( certType == CRYPT_CERTTYPE_CERTIFICATE ) )
{
setMessageData( &msgData, &boundDate, sizeof( time_t ) );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_VALIDTO );
}
else
if( status == CRYPT_ERROR_NOTFOUND )
status = CRYPT_OK;
if( cryptStatusError( status ) )
/* Convert any low-level cert-specific error into something generic
that makes a bit more sense to the caller */
return( CRYPT_ARGERROR_NUM1 );
/* Get the ID information and cert data for the cert */
if( certType == CRYPT_CERTTYPE_CERTIFICATE )
{
status = getKeyID( nameID, iCryptHandle, CRYPT_IATTRIBUTE_SUBJECT );
if( !cryptStatusError( status ) )
status = getKeyID( issuerID, iCryptHandle,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( !cryptStatusError( status ) )
{
status = getCertKeyID( keyID, iCryptHandle );
if( !cryptStatusError( status ) )
status = CRYPT_OK; /* getCertKeyID() returns a length */
}
}
if( certType == CRYPT_CERTTYPE_PKIUSER )
{
char encKeyID[ 128 ];
/* Get the PKI user ID. We can't read this directly since it's
returned in text form for use by end users so we have to read the
encoded form, decode it, and then turn the decoded binary value
into a key ID. We identify the result as a keyID,
(== subjectKeyIdentifier, which it isn't really) but we need to
use this to ensure that it's hashed/expanded out to the correct
size */
setMessageData( &msgData, encKeyID, 128 );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_PKIUSER_ID );
if( cryptStatusOK( status ) )
{
BYTE binaryKeyID[ 128 ];
int length;
status = length = decodePKIUserValue( binaryKeyID, encKeyID,
msgData.length );
if( !cryptStatusError( status ) )
{
status = CRYPT_OK; /* decodePKIUserValue() returns a length */
makeKeyID( keyID, DBXKEYID_BUFFER_SIZE, CRYPT_IKEYID_KEYID,
binaryKeyID, length );
}
}
if( cryptStatusOK( status ) )
{
status = getKeyID( nameID, iCryptHandle, CRYPT_IATTRIBUTE_SUBJECT );
if( !cryptStatusError( status ) )
status = CRYPT_OK; /* getKeyID() returns a length */
}
}
if( cryptStatusOK( status ) )
{
status = getKeyID( certID, iCryptHandle,
CRYPT_CERTINFO_FINGERPRINT_SHA );
if( !cryptStatusError( status ) )
status = CRYPT_OK; /* getKeyID() returns a length */
}
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, certData, MAX_CERT_SIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_CRT_EXPORT,
&msgData, ( certType == CRYPT_CERTTYPE_PKIUSER ) ? \
CRYPT_ICERTFORMAT_DATA : CRYPT_CERTFORMAT_CERTIFICATE );
certDataLength = msgData.length;
}
if( cryptStatusError( status ) )
/* Convert any low-level cert-specific error into something generic
that makes a bit more sense to the caller */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -