📄 testkeyd.c
字号:
/****************************************************************************
* *
* cryptlib Database Keyset Test Routines *
* Copyright Peter Gutmann 1995-2003 *
* *
****************************************************************************/
#ifdef _MSC_VER
#include "../cryptlib.h"
#include "../test/test.h"
#else
#include "cryptlib.h"
#include "test/test.h"
#endif /* Braindamaged MSC include handling */
#if defined( __MVS__ ) || defined( __VMCMS__ )
/* Suspend conversion of literals to ASCII. */
#pragma convlit( suspend )
#endif /* EBCDIC systems */
/****************************************************************************
* *
* Database Keyset Read/Write Tests *
* *
****************************************************************************/
/* Read/write a certificate from a public-key keyset. Returns
CRYPT_ERROR_NOTAVAIL if this keyset type isn't available from this
cryptlib build, CRYPT_ERROR_FAILED if the keyset/data source access
failed */
static int testKeysetRead( const CRYPT_KEYSET_TYPE keysetType,
const char *keysetName,
const char *keyName,
const CRYPT_CERTTYPE_TYPE type )
{
CRYPT_KEYSET cryptKeyset;
CRYPT_CERTIFICATE cryptCert;
int value, status;
/* Open the keyset with a check to make sure this access method exists
so we can return an appropriate error message */
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType,
keysetName, CRYPT_KEYOPT_READONLY );
if( status == CRYPT_ERROR_PARAM3 )
/* This type of keyset access not available */
return( CRYPT_ERROR_NOTAVAIL );
if( cryptStatusError( status ) )
{
printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
status, __LINE__ );
return( CRYPT_ERROR_FAILED );
}
/* Read the certificate from the keyset */
status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_NAME,
keyName );
if( cryptStatusError( status ) )
{
/* The access to network-accessible keysets can be rather
temperamental and can fail at this point even though it's not a
fatal error. The calling code knows this and will continue the
self-test with an appropriate warning, so we explicitly clean up
after ourselves to make sure we don't get a CRYPT_ORPHAN on
shutdown */
if( keysetType == CRYPT_KEYSET_HTTP && \
status == CRYPT_ERROR_NOTFOUND )
{
/* 404's are relatively common, and non-fatal */
extErrorExit( cryptKeyset, "cryptGetPublicKey()", status, __LINE__ );
puts( " (404 is a common HTTP error, and non-fatal)." );
return( TRUE );
}
return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status,
__LINE__ ) );
}
/* Make sure we got what we were expecting */
cryptGetAttribute( cryptCert, CRYPT_CERTINFO_CERTTYPE, &value );
if( value != type )
{
printf( "Expecting certificate object type %d, got %d.", type, value );
return( FALSE );
}
if( value == CRYPT_CERTTYPE_CERTCHAIN || value == CRYPT_CERTTYPE_CRL )
{
const BOOLEAN isCertChain = ( value == CRYPT_CERTTYPE_CERTCHAIN ) ? \
TRUE : FALSE;
value = 0;
cryptSetAttribute( cryptCert, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
CRYPT_CURSOR_FIRST );
do
value++;
while( cryptSetAttribute( cryptCert,
CRYPT_CERTINFO_CURRENT_CERTIFICATE,
CRYPT_CURSOR_NEXT ) == CRYPT_OK );
printf( isCertChain ? "Cert chain length = %d.\n" : \
"CRL has %d entries.\n", value );
}
/* Check the cert against the CRL. Any kind of error is a failure since
the cert isn't in the CRL */
if( keysetType != CRYPT_KEYSET_LDAP && \
keysetType != CRYPT_KEYSET_HTTP )
{
puts( "Checking certificate against CRL." );
status = cryptCheckCert( cryptCert, cryptKeyset );
if( cryptStatusError( status ) )
return( extErrorExit( cryptKeyset, "cryptCheckCert() (for CRL "
"in keyset)", status, __LINE__ ) );
}
/* Close the keyset */
status = cryptKeysetClose( cryptKeyset );
if( cryptStatusError( status ) )
{
printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
cryptDestroyCert( cryptCert );
return( TRUE );
}
static int testKeysetWrite( const CRYPT_KEYSET_TYPE keysetType,
const char *keysetName )
{
CRYPT_KEYSET cryptKeyset;
CRYPT_CERTIFICATE cryptCert;
BYTE buffer[ BUFFER_SIZE ];
char name[ CRYPT_MAX_TEXTSIZE + 1 ];
int length, status;
/* Import the certificate from a file - this is easier than creating one
from scratch. We use one of the later certs in the text set, since
this contains an email address, which the earlier ones don't */
status = importCertFromTemplate( &cryptCert, CERT_FILE_TEMPLATE, 5 );
if( cryptStatusError( status ) )
{
puts( "Couldn't read certificate from file, skipping test of keyset "
"write..." );
return( TRUE );
}
/* Create the database keyset with a check to make sure this access
method exists so we can return an appropriate error message. If the
database table already exists, this will return a duplicate data
error so we retry the open with no flags to open the existing database
keyset for write access */
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType,
keysetName, CRYPT_KEYOPT_CREATE );
if( cryptStatusOK( status ) )
printf( "Created new certificate database '%s'.\n", keysetName );
if( status == CRYPT_ERROR_PARAM3 )
{
/* This type of keyset access isn't available, return a special error
code to indicate that the test wasn't performed, but that this
isn't a reason to abort processing */
cryptDestroyCert( cryptCert );
return( CRYPT_ERROR_NOTAVAIL );
}
if( status == CRYPT_ERROR_DUPLICATE )
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType,
keysetName, 0 );
if( cryptStatusError( status ) )
{
cryptDestroyCert( cryptCert );
printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
status, __LINE__ );
if( status == CRYPT_ERROR_OPEN )
return( CRYPT_ERROR_FAILED );
return( FALSE );
}
/* Write the key to the database */
puts( "Adding certificate." );
status = cryptAddPublicKey( cryptKeyset, cryptCert );
if( status == CRYPT_ERROR_DUPLICATE )
{
/* The key is already present, delete it and retry the write */
status = cryptGetAttributeString( cryptCert,
CRYPT_CERTINFO_COMMONNAME, name, &length );
if( cryptStatusOK( status ) )
{
name[ length ] = '\0';
status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name );
}
if( cryptStatusError( status ) )
return( extErrorExit( cryptKeyset, "cryptDeleteKey()", status,
__LINE__ ) );
status = cryptAddPublicKey( cryptKeyset, cryptCert );
}
if( cryptStatusError( status ) )
{
printExtError( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ );
/* LDAP writes can fail due to the chosen directory not supporting the
schema du jour, so we're a bit more careful about cleaning up since
we'll skip the error and continue processing */
cryptDestroyCert( cryptCert );
cryptKeysetClose( cryptKeyset );
return( FALSE );
}
cryptDestroyCert( cryptCert );
/* Add a second cert with C=US so that we've got enough certs to properly
exercise the query code. This cert is highly unusual in that it
doesn't have a DN, so we have to move up the DN looking for higher-up
values, in this case the OU */
if( keysetType != CRYPT_KEYSET_LDAP )
{
status = importCertFromTemplate( &cryptCert, CERT_FILE_TEMPLATE, 2 );
if( cryptStatusError( status ) )
{
puts( "Couldn't read second certificate from file, skipping "
"remaining keyset write tests..." );
cryptKeysetClose( cryptKeyset );
return( TRUE );
}
status = cryptAddPublicKey( cryptKeyset, cryptCert );
if( status == CRYPT_ERROR_DUPLICATE )
{
status = cryptGetAttributeString( cryptCert,
CRYPT_CERTINFO_COMMONNAME, name, &length );
if( cryptStatusError( status ) )
status = cryptGetAttributeString( cryptCert,
CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, name, &length );
if( cryptStatusOK( status ) )
{
name[ length ] = '\0';
status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name );
}
if( cryptStatusOK( status ) )
status = cryptAddPublicKey( cryptKeyset, cryptCert );
}
if( cryptStatusError( status ) )
return( extErrorExit( cryptKeyset, "cryptAddPublicKey()",
status, __LINE__ ) );
cryptDestroyCert( cryptCert );
}
/* Now try the same thing with a CRL. This code also tests the
duplicate-detection mechanism, if we don't get a duplicate error
there's a problem */
puts( "Adding CRL." );
status = importCertFromTemplate( &cryptCert, CRL_FILE_TEMPLATE, 1 );
if( cryptStatusError( status ) )
{
puts( "Couldn't read CRL from file, skipping test of keyset "
"write..." );
return( TRUE );
}
status = cryptAddPublicKey( cryptKeyset, cryptCert );
if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status,
__LINE__ ) );
status = cryptAddPublicKey( cryptKeyset, cryptCert );
if( status != CRYPT_ERROR_DUPLICATE )
{
puts( "Addition of duplicate item to keyset failed to produce "
"CRYPT_ERROR_DUPLICATE" );
return( FALSE );
}
cryptDestroyCert( cryptCert );
/* Finally, try it with a cert chain */
puts( "Adding cert chain." );
filenameFromTemplate( buffer, CERTCHAIN_FILE_TEMPLATE, 1 );
status = importCertFile( &cryptCert, buffer );
if( cryptStatusError( status ) )
{
puts( "Couldn't read cert chain from file." );
return( FALSE );
}
status = cryptAddPublicKey( cryptKeyset, cryptCert );
if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status,
__LINE__ ) );
cryptDestroyCert( cryptCert );
/* In addition to the other certs we also add the generic user cert,
which is used later in other tests. Since it may have been added
earlier, we try and delete it first (we can't use the existing
version since the issuerAndSerialNumber won't match the one in the
private-key keyset) */
status = getPublicKey( &cryptCert, USER_PRIVKEY_FILE,
USER_PRIVKEY_LABEL );
if( cryptStatusError( status ) )
{
puts( "Couldn't read user cert from file." );
return( FALSE );
}
cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_COMMONNAME,
name, &length );
name[ length ] = '\0';
do
status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name );
while( cryptStatusOK( status ) );
status = cryptAddPublicKey( cryptKeyset, cryptCert );
if( status == CRYPT_ERROR_NOTFOUND )
/* This can occur if a database keyset is defined but hasn't been
initialised yet so the necessary tables don't exist, it can be
opened but an attempt to add a key will return a not found error
since it's the table itself rather than any item within it that
isn't being found */
status = CRYPT_OK;
if( cryptStatusError( status ) )
return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status,
__LINE__ ) );
cryptDestroyCert( cryptCert );
/* Make sure the deletion code works properly. This is an artifact of
the way RDBMS' work, the delete query can execute successfully but
not delete anything so we make sure the glue code correctly
translates this into a CRYPT_DATA_NOTFOUND */
status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME,
"Mr.Not Appearing in this Keyset" );
if( status != CRYPT_ERROR_NOTFOUND )
{
puts( "Attempt to delete a nonexistant key reports success, the "
"database backend glue\ncode needs to be fixed to handle this "
"correctly." );
return( FALSE );
}
/* Close the keyset */
status = cryptKeysetClose( cryptKeyset );
if( cryptStatusError( status ) )
printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
status, __LINE__ );
return( TRUE );
}
/* Perform a general keyset query */
int testQuery( const CRYPT_KEYSET_TYPE keysetType, const char *keysetName )
{
CRYPT_KEYSET cryptKeyset;
int count = 0, status;
/* Open the database keyset */
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType,
keysetName, CRYPT_KEYOPT_READONLY );
if( cryptStatusError( status ) )
{
printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
status, __LINE__ );
if( status == CRYPT_ERROR_OPEN )
return( CRYPT_ERROR_FAILED );
return( FALSE );
}
/* Send the query to the database and read back the results */
status = cryptSetAttributeString( cryptKeyset, CRYPT_KEYINFO_QUERY,
"$C='US'", 7 );
if( cryptStatusError( status ) )
return( extErrorExit( cryptKeyset, "Keyset query", status,
__LINE__ ) );
do
{
CRYPT_CERTIFICATE cryptCert;
status = cryptGetPublicKey( cryptKeyset, &cryptCert,
CRYPT_KEYID_NONE, NULL );
if( cryptStatusOK( status ) )
{
count++;
cryptDestroyCert( cryptCert );
}
}
while( cryptStatusOK( status ) );
if( cryptStatusError( status ) && status != CRYPT_ERROR_COMPLETE )
return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status,
__LINE__ ) );
if( count < 2 )
{
puts( "Only one certificate was returned, this indicates that the "
"database backend\nglue code isn't processing ongoing queries "
"correctly." );
return( FALSE );
}
printf( "%d certificate(s) matched the query.\n", count );
/* Close the keyset */
status = cryptKeysetClose( cryptKeyset );
if( cryptStatusError( status ) )
{
printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
return( TRUE );
}
/* Read/write/query a certificate from a database keyset */
int testReadCert( void )
{
CRYPT_CERTIFICATE cryptCert;
char name[ CRYPT_MAX_TEXTSIZE + 1 ];
int length, status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -