📄 dbx_misc.c
字号:
}
/* Get a certID for a certificate */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int getCertKeyID( OUT_BUFFER( keyIdMaxLen, *keyIdLen ) char *keyID,
IN_LENGTH_SHORT_MIN( 16 ) const int keyIdMaxLen,
OUT_LENGTH_SHORT_Z int *keyIdLen,
IN_HANDLE const CRYPT_CERTIFICATE iCryptCert )
{
int status;
assert( isWritePtr( keyID, keyIdMaxLen ) );
assert( isWritePtr( keyIdLen, sizeof( int ) ) );
REQUIRES( keyIdMaxLen >= 16 && keyIdMaxLen < MAX_INTLENGTH_SHORT );
REQUIRES( isHandleRangeValid( iCryptCert ) );
/* Clear return values */
memset( keyID, 0, min( 16, keyIdMaxLen ) );
*keyIdLen = 0;
/* 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 certificate 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, keyIdMaxLen, keyIdLen, iCryptCert,
CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
if( cryptStatusOK( 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 certificate (either a standalone certificate 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 certificate */
return( getKeyID( keyID, keyIdMaxLen, keyIdLen, iCryptCert,
CRYPT_IATTRIBUTE_SPKI ) );
}
/* Extract certificate data from a certificate object. Note that the
formatType is given as an int rather than an enumerated type because
it can be either a CRYPT_CERTFORMAT_TYPE or a CRYPT_ATTRIBUTE_TYPE */
CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 5 ) ) \
int extractCertData( IN_HANDLE const CRYPT_CERTIFICATE iCryptCert,
IN_INT const int formatType,
OUT_BUFFER( certDataMaxLength, *certDataLength ) \
void *certDataBuffer,
IN_LENGTH_SHORT_MIN( MIN_CRYPT_OBJECTSIZE ) \
const int certDataMaxLength,
OUT_LENGTH_SHORT_Z int *certDataLength )
{
MESSAGE_DATA msgData;
int status;
assert( isWritePtr( certDataBuffer, certDataMaxLength ) );
assert( isWritePtr( certDataLength, sizeof( int ) ) );
REQUIRES( isHandleRangeValid( iCryptCert ) );
REQUIRES( formatType == CRYPT_CERTFORMAT_CERTIFICATE || \
formatType == CRYPT_ICERTFORMAT_DATA || \
formatType == CRYPT_IATTRIBUTE_CRLENTRY );
REQUIRES( certDataMaxLength >= MIN_CRYPT_OBJECTSIZE && \
certDataMaxLength < MAX_INTLENGTH_SHORT );
/* Make sure that there's no collision in format type values (although
the switch() statement will also catch this by producing a compile
error */
assert( CRYPT_CERTFORMAT_CERTIFICATE != CRYPT_ICERTFORMAT_DATA && \
CRYPT_CERTFORMAT_CERTIFICATE != CRYPT_IATTRIBUTE_CRLENTRY );
/* Clear return values */
memset( certDataBuffer, 0, min( 16, certDataMaxLength ) );
*certDataLength = 0;
/* Extract the certificate object data */
setMessageData( &msgData, certDataBuffer, certDataMaxLength );
switch( formatType )
{
case CRYPT_CERTFORMAT_CERTIFICATE:
case CRYPT_ICERTFORMAT_DATA:
status = krnlSendMessage( iCryptCert, IMESSAGE_CRT_EXPORT,
&msgData, formatType );
break;
case CRYPT_IATTRIBUTE_CRLENTRY:
status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
&msgData, formatType );
break;
default:
retIntError();
}
if( cryptStatusError( status ) )
return( status );
*certDataLength = msgData.length;
return( CRYPT_OK );
}
/* Some internal actions set extended error codes as a result of their
operation that the user shouldn't really see. For example performing a
certificate cleanup will return a no-data-found error once the last
certificate is reached, which will be read by the user the next time that
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 information when it's been set
by an internal operation */
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int resetErrorInfo( INOUT DBMS_INFO *dbmsInfo )
{
DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
ERROR_INFO *errorInfo = &dbmsStateInfo->errorInfo;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
memset( errorInfo, 0, sizeof( ERROR_INFO ) );
return( CRYPT_OK );
}
/* Get names for various items */
CHECK_RETVAL_PTR \
char *getKeyName( IN_KEYID const CRYPT_KEYID_TYPE keyIDtype )
{
REQUIRES_N( keyIDtype > CRYPT_KEYID_NONE && \
keyIDtype <= CRYPT_KEYID_LAST );
/* CRYPT_KEYID_LAST is mapped to the database-use-only
lookup value "nameID" */
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" );
case CRYPT_KEYID_LAST:
return( "nameID" );
}
retIntError_Null();
}
/****************************************************************************
* *
* Database Access Functions *
* *
****************************************************************************/
/* Create a new key database */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int createDatabase( INOUT DBMS_INFO *dbmsInfo,
const BOOLEAN hasPermissions,
INOUT ERROR_INFO *errorInfo )
{
int updateProgress = 0, status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
REQUIRES( errorInfo != NULL );
/* Create tables for certificates, CRLs, certificate 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 ) )
{
retExtErr( status,
( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
"Couldn't create certificate database: " ) );
}
if( isCertStore( dbmsInfo ) )
{
/* The certificate 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 certificate 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)" );
if( cryptStatusOK( status ) )
{
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 ) )
{
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 ) )
{
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)" );
}
}
else
{
status = dbmsStaticUpdate(
"CREATE TABLE CRLs ("
"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL,"
"certData BLOB NOT NULL)" );
}
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" );
retExtErr( status,
( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
"Couldn't create certificate%s database: ",
isCertStore( dbmsInfo ) ? " store" : "" ) );
}
/* 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 certificate 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 that we're creating, however we can't do it for the email
address or the nameID in the certificates table since there could be
multiple certificates 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)" );
if( cryptStatusOK( status ) )
status = dbmsStaticUpdate(
"CREATE UNIQUE INDEX certIDIdx ON certificates(certID)" );
if( cryptStatusOK( status ) )
status = dbmsStaticUpdate(
"CREATE UNIQUE INDEX crlIssuerIDIdx ON CRLs (issuerID)" );
if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
status = dbmsStaticUpdate(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -