📄 ca_add.c
字号:
/****************************************************************************
* *
* cryptlib DBMS CA Cert Add Interface *
* Copyright Peter Gutmann 1996-2004 *
* *
****************************************************************************/
#include <stdarg.h>
#include <stdio.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
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Check that the request we've been passed is in order */
BOOLEAN checkRequest( const CRYPT_CERTIFICATE iCertRequest,
const CRYPT_CERTACTION_TYPE action )
{
RESOURCE_DATA msgData;
int certType, value, status;
/* Make sure that the request type is consistent with the operation
being performed */
status = krnlSendMessage( iCertRequest, IMESSAGE_GETATTRIBUTE,
&certType, CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusError( status ) )
return( FALSE );
switch( action )
{
case CRYPT_CERTACTION_CERT_CREATION:
case CRYPT_CERTACTION_ISSUE_CERT:
if( certType != CRYPT_CERTTYPE_CERTREQUEST && \
certType != CRYPT_CERTTYPE_REQUEST_CERT )
return( FALSE );
break;
case CRYPT_CERTACTION_REVOKE_CERT:
if( certType != CRYPT_CERTTYPE_REQUEST_REVOCATION )
return( FALSE );
break;
case CRYPT_CERTACTION_NONE:
/* We're performing a straight add of a request to the store,
any request type is permitted */
break;
default:
assert( NOTREACHED );
return( FALSE );
}
/* Make sure that the request is completed and valid. We don't check
the signature on revocation requests since they aren't signed, and
have to be careful with CRMF requests, which can be unsigned for
encryption-only keys */
status = krnlSendMessage( iCertRequest, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_IMMUTABLE );
if( cryptStatusError( status ) || !value )
return( FALSE );
switch( certType )
{
case CRYPT_CERTTYPE_REQUEST_CERT:
if( cryptStatusOK( \
krnlSendMessage( iCertRequest, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_SELFSIGNED ) ) && \
!value )
{
/* It's an unsigned CRMF request, make sure that it really
is an encryption-only key */
status = krnlSendMessage( iCertRequest, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_KEYUSAGE );
if( cryptStatusOK( status ) && \
( value & ( CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
CRYPT_KEYUSAGE_NONREPUDIATION ) ) )
return( FALSE );
break;
}
/* Fall through */
case CRYPT_CERTTYPE_CERTREQUEST:
status = krnlSendMessage( iCertRequest, IMESSAGE_CRT_SIGCHECK,
NULL, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( FALSE );
break;
case CRYPT_CERTTYPE_REQUEST_REVOCATION:
/* Revocation requests are unsigned so we can't perform a sig.
check on them */
break;
default:
assert( NOTREACHED );
return( FALSE );
}
/* Check that required parameters are present. This is necessary for
CRMF requests where every single parameter is optional, for our use
we require that a cert request contains at least a subject DN and
public key and a revocation request contains at least an issuer DN and
serial number */
switch( certType )
{
case CRYPT_CERTTYPE_CERTREQUEST:
case CRYPT_CERTTYPE_REQUEST_CERT:
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCertRequest, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_SUBJECT );
if( cryptStatusError( status ) )
return( FALSE );
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCertRequest, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_SPKI );
if( cryptStatusError( status ) )
return( FALSE );
break;
case CRYPT_CERTTYPE_REQUEST_REVOCATION:
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCertRequest, IMESSAGE_GETATTRIBUTE_S,
&msgData,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusError( status ) )
return( FALSE );
break;
default:
assert( NOTREACHED );
return( FALSE );
}
return( TRUE );
}
/* Check that a revocation request is consistent with information held in the
cert store */
static int checkRevRequest( DBMS_INFO *dbmsInfo,
const CRYPT_CERTIFICATE iCertRequest )
{
char certID[ DBXKEYID_BUFFER_SIZE ], issuerID[ DBXKEYID_BUFFER_SIZE ];
int length, status;
/* Check that the cert being referred to in the request is present and
active */
status = length = getKeyID( issuerID, iCertRequest,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( !cryptStatusError( status ) )
status = dbmsQuery(
"SELECT certData FROM certificates WHERE issuerID = ?",
NULL, 0, issuerID, length, 0,
DBMS_CACHEDQUERY_ISSUERID, DBMS_QUERY_CHECK );
if( cryptStatusOK( status ) )
return( CRYPT_OK );
/* The cert isn't an active cert, it's either not present or not active,
return an appropriate error code. If this request has been entered
into the cert log then it's a duplicate request, otherwise it's a
request to revoke a non-present cert (either that or something really
obscure which is best reported as a non-present cert problem) */
status = length = getKeyID( certID, iCertRequest,
CRYPT_CERTINFO_FINGERPRINT_SHA );
if( !cryptStatusError( status ) )
status = dbmsQuery(
"SELECT certData FROM certLog WHERE certID = ?",
NULL, 0, certID, length, 0,
DBMS_CACHEDQUERY_NONE, DBMS_QUERY_CHECK );
return( cryptStatusOK( status ) ? \
CRYPT_ERROR_DUPLICATE : CRYPT_ERROR_NOTFOUND );
}
/****************************************************************************
* *
* Cert Add Functions *
* *
****************************************************************************/
/* Add a new PKI user to the cert store */
int caAddPKIUser( DBMS_INFO *dbmsInfo, const CRYPT_CERTIFICATE iPkiUser )
{
RESOURCE_DATA msgData;
BYTE certData[ MAX_CERT_SIZE ];
char certID[ DBXKEYID_BUFFER_SIZE ];
int certDataLength, status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( isHandleRangeValid( iPkiUser ) );
/* Extract the information we need from the PKI user object. In
addition to simply obtaining the information for logging purposes we
also need to perform this action to tell the cert management code to
fill in the remainder of the (implicitly-added) user info before we
start querying fields as we add it to the cert store. Because of this
we also need to place the certID fetch after the object export, since
it's in an incomplete state before this point */
setMessageData( &msgData, certData, MAX_CERT_SIZE );
status = krnlSendMessage( iPkiUser, IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_ICERTFORMAT_DATA );
if( cryptStatusOK( status ) )
status = getKeyID( certID, iPkiUser, CRYPT_CERTINFO_FINGERPRINT_SHA );
if( cryptStatusError( status ) )
return( status );
certDataLength = msgData.length;
/* Update the cert store */
status = addCert( dbmsInfo, iPkiUser, CRYPT_CERTTYPE_PKIUSER,
CERTADD_NORMAL, DBMS_UPDATE_BEGIN );
if( cryptStatusOK( status ) )
status = updateCertLog( dbmsInfo, CRYPT_CERTACTION_ADDUSER, certID,
NULL, NULL, certData, certDataLength,
DBMS_UPDATE_COMMIT );
else
/* Something went wrong, abort the transaction */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -