📄 dbx_misc.c
字号:
assert( ( keyIDtype == CRYPT_CERTINFO_FINGERPRINT_SHA || \
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_CERTINFO_FINGERPRINT_SHA || \
keyIDtype == CRYPT_IATTRIBUTE_AUTHCERTID )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, hashBuffer, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, keyIDtype );
if( cryptStatusError( status ) )
return( status );
assert( msgData.length == KEYID_SIZE );
}
else
{
DYNBUF idDB;
HASHFUNCTION hashFunction;
int hashSize;
/* Get the attribute data and hash it to get the ID */
status = dynCreate( &idDB, cryptHandle, keyIDtype );
if( cryptStatusError( status ) )
return( status );
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
hashFunction( NULL, hashBuffer, dynData( idDB ), dynLength( idDB ),
HASH_ALL );
assert( hashSize == KEYID_SIZE );
dynDestroy( &idDB );
}
return( makeKeyID( keyIDbuffer, DBXKEYID_BUFFER_SIZE,
CRYPT_IKEYID_CERTID, hashBuffer, KEYID_SIZE ) );
}
/* Get a keyID for a certificate */
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 that 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( !cryptStatusError( status ) )
return( status );
/* 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 ) );
}
/* Some internal actions set extended error codes as a result of their
operation that the user shouldn't really see. For example performing a
cert cleanup will return a no-data-found error once the last cert is
reached, which will be read by the user the next time they read the
CRYPT_ATTRIBUTE_INT_ERRORCODE/CRYPT_ATTRIBUTE_INT_ERRORMESSAGE, even
though the error came from a previous internal operation. To avoid
this problem, we clean up the error status info when it's been set by
an internal operation */
int resetErrorInfo( DBMS_INFO *dbmsInfo )
{
dbmsInfo->errorCode = 0;
memset( dbmsInfo->errorMessage, 0, MAX_ERRMSG_SIZE );
return( CRYPT_OK );
}
/* Get names and IDs for various items */
char *getKeyName( const CRYPT_KEYID_TYPE keyIDtype )
{
switch( keyIDtype )
{
case CRYPT_KEYID_NAME:
return( "CN" );
case CRYPT_KEYID_URI:
return( "email" );
case CRYPT_IKEYID_KEYID:
return( "keyID" );
case CRYPT_IKEYID_ISSUERID:
return( "issuerID" );
case CRYPT_IKEYID_CERTID:
return( "certID" );
}
assert( NOTREACHED );
return( "XXXX" ); /* Get rid of compiler warning */
}
char *getTableName( const KEYMGMT_ITEM_TYPE itemType )
{
switch( itemType )
{
case KEYMGMT_ITEM_REQUEST:
return( "certRequests" );
case KEYMGMT_ITEM_PKIUSER:
return( "pkiUsers" );
case KEYMGMT_ITEM_PUBLICKEY:
return( "certificates" );
case KEYMGMT_ITEM_REVOCATIONINFO:
return( "CRLs" );
}
assert( NOTREACHED );
return( "XXXX" ); /* Get rid of compiler warning */
}
/****************************************************************************
* *
* Database Access Functions *
* *
****************************************************************************/
/* Create a new key database */
static int createDatabase( DBMS_INFO *dbmsInfo,
const BOOLEAN hasPermissions )
{
int updateProgress = 0, status;
/* Create tables for certs, CRLs, cert requests, PKI users, and CA logs.
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 */
status = dbmsStaticUpdate(
"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( isCertStore( dbmsInfo ) )
/* 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, the nameID
which is used to force clustering of entries for each CA, and the
ID of the cert being revoked, which isn't available if we're
creating it from a raw CRL */
status = dbmsStaticUpdate(
"CREATE TABLE CRLs ("
"expiryDate DATETIME NOT NULL, "
"nameID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL,"
"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"certData BLOB NOT NULL)" );
else
status = dbmsStaticUpdate(
"CREATE TABLE CRLs ("
"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL,"
"certData BLOB NOT NULL)" );
if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
{
updateProgress++;
status = dbmsStaticUpdate(
"CREATE TABLE pkiUsers ("
"C CHAR(2), "
"SP VARCHAR(64), "
"L VARCHAR(64), "
"O VARCHAR(64), "
"OU VARCHAR(64), "
"CN VARCHAR(64), "
"nameID 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( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
{
updateProgress++;
status = dbmsStaticUpdate(
"CREATE TABLE certRequests ("
"type SMALLINT NOT NULL, "
"C CHAR(2), "
"SP VARCHAR(64), "
"L VARCHAR(64), "
"O VARCHAR(64), "
"OU VARCHAR(64), "
"CN VARCHAR(64), "
"email VARCHAR(64), "
"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"certData BLOB NOT NULL)" );
}
if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
{
updateProgress++;
status = dbmsStaticUpdate(
"CREATE TABLE certLog ("
"action SMALLINT NOT NULL, "
"actionTime DATETIME NOT NULL, "
"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
"reqCertID CHAR(" TEXT_DBXKEYID_SIZE "), "
"subjCertID CHAR(" TEXT_DBXKEYID_SIZE "), "
"certData BLOB)" );
}
if( cryptStatusError( status ) )
{
/* Undo the previous table creations */
dbmsStaticUpdate( "DROP TABLE certificates" );
if( updateProgress > 0 )
dbmsStaticUpdate( "DROP TABLE CRLs" );
if( updateProgress > 1 )
dbmsStaticUpdate( "DROP TABLE pkiUsers" );
if( updateProgress > 2 )
dbmsStaticUpdate( "DROP TABLE certRequests" );
return( status );
}
/* Create an index for the email address, nameID, issuerID, keyID, and
certID in the certificates table, the issuerID and certID in the CRLs
table (the CRL nameID isn't indexed since we only use it for linear
scans), the nameID and keyID in the PKI users table (the former isn't
used but is made a UNIQUE INDEX to ensure that the same entry can't
be added more than once) and the certID in the cert log (this also
isn't used but is made a UNIQUE INDEX to ensure that the same entry
can't be added more than once). We have to give these unique names
since some databases don't allow two indexes to have the same name,
even if they're in a different table. Since most of the fields in
the tables are supposed to be unique, we can specify this for the
indexes we're creating, however we can't do it for the email address
or the nameID in the certs table since there could be multiple certs
present that differ only in key usage. We don't index the other
tables since indexes consume space and we don't expect to access any
of these much */
status = dbmsStaticUpdate(
"CREATE INDEX emailIdx ON certificates(email)" );
if( cryptStatusOK( status ) )
status = dbmsStaticUpdate(
"CREATE INDEX nameIDIdx ON certificates(nameID)" );
if( cryptStatusOK( status ) )
status = dbmsStaticUpdate(
"CREATE UNIQUE INDEX issuerIDIdx ON certificates(issuerID)" );
if( cryptStatusOK( status ) )
status = dbmsStaticUpdate(
"CREATE UNIQUE INDEX keyIDIdx ON certificates(keyID)" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -