📄 lib_dbms.c
字号:
const int maxLength )
{
int inPos = 0, outPos = 0, status = CRYPT_OK;
while( inPos < inputLength )
{
if( input[ inPos ] == '$' )
{
const char *fieldName = &input[ inPos + 1 ];
const char *outputFieldName;
const int fieldPos = inPos + 1;
int length;
inPos++; /* Skip '$' */
/* Extract the field name and translate it into the table
column name */
while( isalpha( input[ inPos ] ) )
inPos++;
length = inPos - fieldPos;
if( length <= 0 )
{
status = CRYPT_ERROR_BADDATA;
break;
}
if( !strnicmp( fieldName, "C", length ) )
outputFieldName = "C";
else
if( !strnicmp( fieldName, "SP", length ) )
outputFieldName = "SP";
else
if( !strnicmp( fieldName, "L", length ) )
outputFieldName = "L";
else
if( !strnicmp( fieldName, "O", length ) )
outputFieldName = "O";
else
if( !strnicmp( fieldName, "OU", length ) )
outputFieldName = "OU";
else
if( !strnicmp( fieldName, "CN", length ) )
outputFieldName = "CN";
else
if( !strnicmp( fieldName, "email", length ) )
outputFieldName = "email";
else
if( !strnicmp( fieldName, "date", length ) )
outputFieldName = "validTo";
else
{
status = CRYPT_ERROR_BADDATA;
break;
}
length = strlen( outputFieldName );
/* Copy the translated name to the output buffer */
if( outPos + length >= maxLength - 1 )
{
status = CRYPT_ERROR_OVERFLOW;
break;
}
strcpy( output + outPos, outputFieldName );
outPos += length;
}
else
{
const char ch = input[ inPos++ ];
/* Just copy the char over, with a length check */
if( outPos > maxLength - 1 )
{
outPos = 0;
break;
}
#ifdef __WINDOWS__
/* Bypass the ODBC security problem mentioned above */
if( ch != '|' )
#endif /* __WINDOWS__ */
output[ outPos++ ] = ch;
}
}
if( cryptStatusError( status ) )
outPos = 0;
output[ outPos++ ] = '\0'; /* Add der terminador */
return( status );
}
/* Set up key ID information for a query. There are two variations of
this, makeKeyID() encodes an existing keyID value and getKeyID() reads an
attribute from an object and encodes it */
static void makeKeyID( char *keyIDbuffer, const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength )
{
const int idLength = min( keyIDlength, ( CRYPT_MAX_TEXTSIZE * 2 ) - 1 );
assert( ( keyIDtype == CRYPT_KEYID_NAME || \
keyIDtype == CRYPT_KEYID_EMAIL ) || \
( keyIDtype == CRYPT_IKEYID_KEYID || \
keyIDtype == CRYPT_IKEYID_ISSUERID || \
keyIDtype == CRYPT_IKEYID_CERTID ) );
/* Name and email address are used as is */
if( keyIDtype == CRYPT_KEYID_NAME || \
keyIDtype == CRYPT_KEYID_EMAIL )
{
memcpy( keyIDbuffer, keyID, idLength );
keyIDbuffer[ idLength ] = '\0';
}
/* A keyID is just a subjectKeyIdentifier, which is supposed to be an
SHA-1 hash anyway but which in practice can be almost anything so we
always hash it to a fixed-length value */
if( keyIDtype == CRYPT_IKEYID_KEYID )
{
HASHFUNCTION hashFunction;
BYTE hashBuffer[ CRYPT_MAX_HASHSIZE ];
int hashSize;
/* Get the hash algorithm information and hash the keyID to get
the fixed-length keyID */
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
hashFunction( NULL, hashBuffer, ( void * ) keyID, keyIDlength,
HASH_ALL );
base64encode( keyIDbuffer, hashBuffer, DBXKEYID_SIZE,
CRYPT_CERTTYPE_NONE );
keyIDbuffer[ MAX_ENCODED_DBXKEYID_SIZE ] = '\0';
return;
}
if( keyIDtype == CRYPT_IKEYID_ISSUERID || \
keyIDtype == CRYPT_IKEYID_CERTID )
{
assert( ( keyIDtype == CRYPT_IKEYID_CERTID && \
keyIDlength == DBXKEYID_SIZE ) || \
( keyIDtype != CRYPT_IKEYID_CERTID ) );
/* base64-encode the key ID so we can use it with database queries.
Since we only store 128 bits of a (usually 160 bit) ID to save
space (particularly where it's used in indices) and speed lookups,
this encoding step has a side-effect of truncating the ID down to
the correct size */
base64encode( keyIDbuffer, keyID, DBXKEYID_SIZE, CRYPT_CERTTYPE_NONE );
keyIDbuffer[ MAX_ENCODED_DBXKEYID_SIZE ] = '\0';
return;
}
}
static int getKeyID( char *keyIDbuffer, const CRYPT_HANDLE cryptHandle,
const CRYPT_ATTRIBUTE_TYPE keyIDtype )
{
RESOURCE_DATA msgData;
BYTE hashBuffer[ CRYPT_MAX_HASHSIZE ];
int status;
assert( ( keyIDtype == CRYPT_IATTRIBUTE_CERTID || \
keyIDtype == CRYPT_IATTRIBUTE_AUTHCERTID ) || \
( keyIDtype == CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER || \
keyIDtype == CRYPT_IATTRIBUTE_ISSUER || \
keyIDtype == CRYPT_IATTRIBUTE_SUBJECT || \
keyIDtype == CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER || \
keyIDtype == CRYPT_IATTRIBUTE_SPKI ) );
/* Get the attribute from the cert and hash it unless it's already a
hash */
if( keyIDtype != CRYPT_IATTRIBUTE_CERTID && \
keyIDtype == CRYPT_IATTRIBUTE_AUTHCERTID )
{
setResourceData( &msgData, hashBuffer, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( cryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, keyIDtype );
assert( msgData.length == KEYID_SIZE );
if( cryptStatusError( status ) )
return( status );
}
else
{
BYTE buffer[ 1024 ], *bufPtr = buffer;
HASHFUNCTION hashFunction;
int hashSize;
/* Get the attribute data */
setResourceData( &msgData, NULL, 0 );
status = krnlSendMessage( cryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, keyIDtype );
if( cryptStatusError( status ) )
return( status );
if( msgData.length > 1024 && \
( bufPtr = malloc( msgData.length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
msgData.data = bufPtr;
status = krnlSendMessage( cryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, keyIDtype );
if( cryptStatusError( status ) )
{
if( bufPtr != buffer )
free( bufPtr );
return( status );
}
/* Get the hash algorithm information and hash the attribute to get
the ID */
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
hashFunction( NULL, hashBuffer, bufPtr, msgData.length, HASH_ALL );
assert( hashSize == KEYID_SIZE );
if( bufPtr != buffer )
free( bufPtr );
}
/* base64-encode the key ID so we can use it with database queries.
Since we only store 128 bits of a (usually 160 bit) ID to save space
(particularly where it's used in indices) and speed lookups, this
encoding step has a side-effect of truncating the ID down to the
correct size */
base64encode( keyIDbuffer, hashBuffer, DBXKEYID_SIZE,
CRYPT_CERTTYPE_NONE );
keyIDbuffer[ MAX_ENCODED_DBXKEYID_SIZE ] = '\0';
return( CRYPT_OK );
}
static char *getKeyName( const CRYPT_KEYID_TYPE keyIDtype )
{
switch( keyIDtype )
{
case CRYPT_KEYID_NAME:
return( "CN" );
case CRYPT_KEYID_EMAIL:
return( "email" );
case CRYPT_IKEYID_KEYID:
return( "keyID" );
case CRYPT_IKEYID_ISSUERID:
return( "issuerID" );
case CRYPT_IKEYID_CERTID:
return( "certID" );
}
assert( NOTREACHED );
return( NULL ); /* Get rid of compiler warning */
}
/* Get a keyID for a certificate */
static int getCertKeyID( char *keyID, const CRYPT_CERTIFICATE iCryptCert )
{
int status;
/* Certificate keyID handling isn't quite as simple as just reading an
attribute from the certificate since the subjectKeyIdentifier (if
present) may not be the same as the keyID if the cert has come from
a CA which does strange things with the sKID. To resolve this we try
and build the key ID from the sKID, if this isn't present we use the
keyID (the sKID may have a nonstandard length since it's possible to
stuff anything in there, getKeyID() will hash it to the standard size
if the length is wrong) */
status = getKeyID( keyID, iCryptCert,
CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
if( cryptStatusOK( status ) )
return( CRYPT_OK );
/* There's no subjectKeyIdentifier, use the keyID. Note that we can't
just read the CRYPT_IATTRIBUTE_KEYID attribute directly since this
may be a data-only cert (either a standalone cert or one from the
middle of a chain), so we have to generate it indirectly by hashing
the SubjectPublicKeyInfo, which is equivalent to the keyID and is
always present in a cert */
return( getKeyID( keyID, iCryptCert, CRYPT_IATTRIBUTE_SPKI ) );
}
/* Create a new key database */
static int createDatabase( KEYSET_INFO *keysetInfo )
{
int status;
/* Create tables for public keys, CRL's, revoked certs, and cert requests.
We use CHAR rather than VARCHAR for the ID fields since these always
have a fixed length and CHAR is faster than VARCHAR. In addition we
make as many columns as possible NOT NULL since these fields should
always be present, and because this is faster for most databases. The
BLOB type is nonstandard, this is rewritten by the database interface
layer to the type which is appropriate for the database.
If the one of the tables is deleted outside of cryptlib and others
left in place then creation will fail because one or more tables
already exist. This is an anomalous situation (the users shouldn't
modify the tables outside cryptlib), but in the interests of luser-
friendliness we ignore a CRYPT_ERROR_DUPLICATE for the other tables if
the basic cert table creation succeeded */
status = performStaticUpdate( &keysetInfo->keysetDBMS,
"CREATE TABLE certificates ("
"C CHAR(2), "
"SP VARCHAR(64), "
"L VARCHAR(64), "
"O VARCHAR(64), "
"OU VARCHAR(64), "
"CN VARCHAR(64), "
"email VARCHAR(64), "
"validTo DATETIME NOT NULL, "
"nameID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"keyID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"certData BLOB NOT NULL)" );
if( cryptStatusError( status ) )
return( status );
if( keysetInfo->keysetDBMS.isCertStore )
/* The cert store contains in addition to the other CRL fields the
certificate expiry time which is used to remove the entry from
the CRL table once the certificate has expired anyway and the
nameID which is used to force clustering of entries for each CA */
status = performStaticUpdate( &keysetInfo->keysetDBMS,
"CREATE TABLE CRLs ("
"expiryDate DATETIME NOT NULL, "
"nameID CHAR(" TEXT_DBXKEYID_SIZE ") PRIMARY KEY NOT NULL, "
"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL,"
"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"certData BLOB NOT NULL)" );
else
status = performStaticUpdate( &keysetInfo->keysetDBMS,
"CREATE TABLE CRLs ("
"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL,"
"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"certData BLOB NOT NULL)" );
if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
{
/* Undo the certificate table creation */
performStaticUpdate( &keysetInfo->keysetDBMS,
"DROP TABLE certificates" );
return( status );
}
if( keysetInfo->keysetDBMS.isCertStore )
{
status = performStaticUpdate( &keysetInfo->keysetDBMS,
"CREATE TABLE pkiUsers ("
"C CHAR(2), "
"SP VARCHAR(64), "
"L VARCHAR(64), "
"O VARCHAR(64), "
"OU VARCHAR(64), "
"CN VARCHAR(64), "
"keyID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"certData BLOB NOT NULL)" );
if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
{
/* Undo the previous table creations */
performStaticUpdate( &keysetInfo->keysetDBMS,
"DROP TABLE certificates" );
performStaticUpdate( &keysetInfo->keysetDBMS,
"DROP TABLE CRLs" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -