📄 ca_add.c
字号:
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( isReadPtr( keyID, keyIDlength ) );
REQUIRES( keyIDtype == CRYPT_KEYID_NAME || \
keyIDtype == CRYPT_KEYID_URI );
REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
keyIDlength < MAX_ATTRIBUTE_SIZE );
REQUIRES( errorInfo != NULL );
/* Get information on the PKI user that we're about to delete */
status = getItemData( dbmsInfo, &iPkiUser, &dummy,
KEYMGMT_ITEM_PKIUSER, keyIDtype,
keyID, keyIDlength, KEYMGMT_FLAG_NONE,
errorInfo );
if( cryptStatusOK( status ) )
{
status = getKeyID( certID, ENCODED_DBXKEYID_SIZE, &certIDlength,
iPkiUser, CRYPT_CERTINFO_FINGERPRINT_SHA );
krnlSendNotifier( iPkiUser, IMESSAGE_DECREFCOUNT );
}
if( cryptStatusError( status ) )
{
retExtErr( status,
( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
"Couldn't get information on PKI user to be "
"deleted: " ) );
}
/* Delete the PKI user information and record the deletion */
initBoundData( boundDataPtr );
setBoundData( boundDataPtr, 0, certID, certIDlength );
status = dbmsUpdate(
"DELETE FROM pkiUsers WHERE certID = ?",
boundDataPtr, DBMS_UPDATE_BEGIN );
if( cryptStatusOK( status ) )
status = updateCertLog( dbmsInfo, CRYPT_CERTACTION_DELETEUSER,
NULL, 0, NULL, 0, certID, certIDlength,
NULL, 0, DBMS_UPDATE_COMMIT );
else
{
/* Something went wrong, abort the transaction */
dbmsUpdate( NULL, NULL, DBMS_UPDATE_ABORT );
retExtErr( status,
( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
"PKI user delete operation failed: " ) );
}
return( status );
}
/* Add a certificate issue or revocation request to the certificate store */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
int caAddCertRequest( INOUT DBMS_INFO *dbmsInfo,
IN_HANDLE const CRYPT_CERTIFICATE iCertRequest,
IN_ENUM( CRYPT_CERTTYPE ) \
const CRYPT_CERTTYPE_TYPE requestType,
const BOOLEAN isRenewal,
INOUT ERROR_INFO *errorInfo )
{
BYTE certData[ MAX_CERT_SIZE + 8 ];
char certID[ ENCODED_DBXKEYID_SIZE + 8 ];
char reqCertID[ ENCODED_DBXKEYID_SIZE + 8 ], *reqCertIDptr = reqCertID;
int certIDlength, reqCertIDlength = DUMMY_INIT;
int certDataLength = DUMMY_INIT, status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
REQUIRES( isHandleRangeValid( iCertRequest ) );
REQUIRES( requestType == CRYPT_CERTTYPE_CERTREQUEST || \
requestType == CRYPT_CERTTYPE_REQUEST_CERT || \
requestType == CRYPT_CERTTYPE_REQUEST_REVOCATION );
REQUIRES( errorInfo != NULL );
/* Make sure that the request is OK and if it's a revocation request
make sure that it refers to a certificate which is both present in
the store and currently active */
if( !checkRequest( iCertRequest, CRYPT_CERTACTION_NONE ) )
{
retExtArg( CRYPT_ARGERROR_NUM1,
( CRYPT_ARGERROR_NUM1, errorInfo,
"Certificate request information "
"inconsistent/invalid" ) );
}
if( requestType == CRYPT_CERTTYPE_REQUEST_REVOCATION )
{
status = checkRevRequest( dbmsInfo, iCertRequest );
if( cryptStatusError( status ) )
retExt( status,
( status, errorInfo,
"Revocation request doesn't correspond to a currently "
"active certificate" ) );
}
/* Extract the information that we need from the certificate request */
status = getKeyID( certID, ENCODED_DBXKEYID_SIZE, &certIDlength,
iCertRequest, CRYPT_CERTINFO_FINGERPRINT_SHA );
if( cryptStatusOK( status ) )
{
status = extractCertData( iCertRequest,
( requestType == CRYPT_CERTTYPE_REQUEST_REVOCATION ) ? \
CRYPT_ICERTFORMAT_DATA : \
CRYPT_CERTFORMAT_CERTIFICATE,
certData, MAX_CERT_SIZE, &certDataLength );
}
if( cryptStatusOK( status ) )
{
status = getKeyID( reqCertID, ENCODED_DBXKEYID_SIZE, &reqCertIDlength,
iCertRequest, CRYPT_IATTRIBUTE_AUTHCERTID );
if( cryptStatusError( status ) )
{
/* If the request is being added directly by the user, there's no
authorising certificate/PKI user information present */
reqCertIDptr = NULL;
reqCertIDlength = 0;
status = CRYPT_OK;
}
}
if( cryptStatusError( status ) )
{
retExt( status,
( status, errorInfo,
"Couldn't extract certificate request data to add to "
"certificate store" ) );
}
/* Check that the PKI user who authorised this certificate issue still
exists. If the CA has deleted them all further requests for
certificates fail */
if( reqCertIDptr != NULL )
{
CRYPT_CERTIFICATE iPkiUser;
status = caGetIssuingUser( dbmsInfo, &iPkiUser, reqCertID,
reqCertIDlength, errorInfo );
if( cryptStatusOK( status ) )
krnlSendNotifier( iPkiUser, IMESSAGE_DECREFCOUNT );
else
{
updateCertErrorLog( dbmsInfo, CRYPT_ERROR_DUPLICATE,
"Certificate request submitted for "
"nonexistent PKI user", NULL, 0,
reqCertID, reqCertIDlength, NULL, 0,
NULL, 0 );
retExt( CRYPT_ERROR_PERMISSION,
( CRYPT_ERROR_PERMISSION, errorInfo,
"Certificate request submitted for nonexistent PKI "
"user" ) );
}
}
/* If there's an authorising PKI user present make sure that it hasn't
already been used to authorise the issuance of a certificate. This
is potentially vulnerable to the following race condition:
1: check authCertID -> OK
2: check authCertID -> OK
1: add
2: add
In theory we could detect this by requiring the reqCertID to be
unique, however a PKI user can be used to request both a certificate
and a revocation for the certificate and a signing certificate can
be used to request an update or revocation of both itself and one or
more associated encryption certificates. We could probably handle
this via the ID-mangling used for certIDs but this makes tracing
events through the audit log complex since there'll now be different
effective IDs for the authorising certificate depending on what it
was authorising.
In addition it's not certain how many further operations a
certificate (rather than a PKI user) can authorise, in theory a
single signing certificate can authorise at least four further
operations, these being the update of itself, the update of an
associated encryption certificate, and the revocation of itself and
the encryption certificate. In addition its possible that a signing
certificate could be used to authorise a series of short-duration
encryption certificates or a variety of other combinations of
operations.
Because of these issues we can't use a uniqueness constraint on the
reqCertID to enforce a single use of issuing authorisation by the
database ifself but have to do a manual check here, checking
specifically for the case where a PKI user authorises a certificate
issue */
#if 0 /* This check is too restrictive because it blocks any further
certificate issues after the first one. This is because as soon
as a single issue has been authorised for a user there'll be a
request for that user logged so all further attempts to submit a
request (for example for a renewal, or an encryption certificate
to go with a signing one) will fail */
if( reqCertIDptr != NULL )
{
initBoundData( boundDataPtr );
setBoundData( boundDataPtr, 0, reqCertID, reqCertIDlength );
status = dbmsQuery(
"SELECT certID FROM certLog WHERE reqCertID = ? "
"AND action = " TEXT_CERTACTION_REQUEST_CERT,
NULL, 0, NULL, boundDataPtr,
DBMS_CACHEDQUERY_NONE, DBMS_QUERY_CHECK );
if( cryptStatusOK( status ) )
{
/* This user has already authorised the issue of a certificate,
it can't be used to issue a second certificate */
updateCertErrorLog( dbmsInfo, CRYPT_ERROR_DUPLICATE,
"Attempt to authorise additional certificate "
"issue when a certificate for this user has "
"already been issued", NULL, 0,
reqCertID, reqCertIDlength, NULL, 0, NULL, 0 );
retExt( CRYPT_ERROR_DUPLICATE,
( CRYPT_ERROR_DUPLICATE, errorInfo,
"Attempt to authorise additional certificate issue "
"when a certificate for this user has already been "
"issued" ) );
}
}
#endif /* 0 */
/* Update the certificate store. Since a revocation request generally
won't have any fields of any significance set we have to use a
special cut-down insert statement that doesn't expect to find any
fields except the certificate ID */
if( requestType == CRYPT_CERTTYPE_REQUEST_REVOCATION )
{
BOUND_DATA boundData[ BOUND_DATA_MAXITEMS ], *boundDataPtr = boundData;
char encodedCertData[ MAX_ENCODED_CERT_SIZE + 8 ];
initBoundData( boundDataPtr );
setBoundData( boundDataPtr, 0, certID, certIDlength );
if( hasBinaryBlobs( dbmsInfo ) )
{
setBoundDataBlob( boundDataPtr, 1, certData, certDataLength );
}
else
{
int encodedCertDataLength;
status = base64encode( encodedCertData, MAX_ENCODED_CERT_SIZE,
&encodedCertDataLength, certData,
certDataLength, CRYPT_CERTTYPE_NONE );
if( cryptStatusError( status ) )
{
assert( DEBUG_WARN );
return( status );
}
setBoundData( boundDataPtr, 1, encodedCertData,
encodedCertDataLength );
}
status = dbmsUpdate(
"INSERT INTO certRequests VALUES ("
TEXT_CERTTYPE_REQUEST_REVOCATION ", '', '', '', '', '', '', "
"'', ?, ?)", boundDataPtr, DBMS_UPDATE_BEGIN );
}
else
{
status = addCert( dbmsInfo, iCertRequest, CRYPT_CERTTYPE_REQUEST_CERT,
CERTADD_NORMAL, DBMS_UPDATE_BEGIN, errorInfo );
}
if( cryptStatusOK( status ) )
{
status = updateCertLog( dbmsInfo,
( requestType == CRYPT_CERTTYPE_REQUEST_REVOCATION ) ? \
CRYPT_CERTACTION_REQUEST_REVOCATION : \
( isRenewal ) ? \
CRYPT_CERTACTION_REQUEST_RENEWAL : \
CRYPT_CERTACTION_REQUEST_CERT,
certID, certIDlength, reqCertIDptr, reqCertIDlength,
NULL, 0, certData, certDataLength,
DBMS_UPDATE_COMMIT );
}
else
{
/* Something went wrong, abort the transaction */
dbmsUpdate( NULL, NULL, DBMS_UPDATE_ABORT );
retExtErr( status,
( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
"Certificate request add operation failed: " ) );
}
return( status );
}
#endif /* USE_DBMS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -