📄 keydbx.c
字号:
/****************************************************************************
* *
* cryptlib Database Keyset Test Routines *
* Copyright Peter Gutmann 1995-2005 *
* *
****************************************************************************/
#ifdef _MSC_VER
#include "../cryptlib.h"
#include "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 /* IBM big iron */
#if defined( __ILEC400__ )
#pragma convert( 0 )
#endif /* IBM medium iron */
/* Some LDAP keyset names and names of probably-present certs and CRLs.
These keysets (and their contents) come and go, so we have a variety of
them and try them in turn until something works. There's a list of more
LDAP servers at http://www.dante.net/np/pdi.html, but none of these are
known to contain certificates.
Note that the following strings have to be given on one line in order for
the widechar conversion voodoo to work */
static const struct {
const C_STR url; /* LDAP URL for keyset */
const char *asciiURL; /* URL in ASCII */
const C_STR certName; /* DN for cert and CRL */
const C_STR crlName;
} ldapUrlInfo[] = {
{ 0 },
{ TEXT( "ldap.diginotar.nl" ), "ldap.diginotar.nl",
TEXT( "cn=Root Certificaat Productie, o=DigiNotar Root,c=NL" ),
TEXT( "CN=CRL Productie,O=DigiNotar CRL,C=NL" ) },
{ TEXT( "ds.katalog.posten.se" ), "ds.katalog.posten.se",
TEXT( "cn=Posten CertPolicy_eIDKort_1 CA_nyckel_1, o=Posten_Sverige_AB 556451-4148, c=SE" ),
TEXT( "cn=Posten CertPolicy_eIDKort_1 CA_nyckel_1, o=Posten_Sverige_AB 556451-4148, c=SE" ) },
{ TEXT( "ldap2.zebsign.com" ), "ldap2.zebsign.com",
TEXT( "pssUniqueIdentifier=24090, CN=First ZebSign Community ID CA, O=ZebSign - 983163432, C=NO" ) }
};
#define LDAP_SERVER_NO 1
#define LDAP_ALT_SERVER_NO 2 /* Secondary svr.if main server unavailable */
/****************************************************************************
* *
* 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 */
enum { READ_OPTION_NORMAL, READ_OPTION_MULTIPLE };
static int testKeysetRead( const CRYPT_KEYSET_TYPE keysetType,
const C_STR keysetName,
const CRYPT_KEYID_TYPE keyType,
const C_STR keyName,
const CRYPT_CERTTYPE_TYPE type,
const int option )
{
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, keyType, 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 that 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__ ) );
}
cryptDestroyCert( cryptCert );
/* If we're reading multiple certs using the same (cached) query type,
try re-reading the cert. This can't be easily tested from the
outside because it's database back-end specific, so it'll require
attaching a debugger to the read code to make sure that the cacheing
is working as required */
if( option == READ_OPTION_MULTIPLE )
{
int i;
for( i = 0; i < 3; i++ )
{
status = cryptGetPublicKey( cryptKeyset, &cryptCert, keyType,
keyName );
if( cryptStatusError( status ) )
{
printf( "cryptGetPublicKey() with cached query failed with "
"error code %d, line %d.\n", status, __LINE__ );
return( FALSE );
}
cryptDestroyCert( cryptCert );
}
}
/* 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 );
}
static int testKeysetWrite( const CRYPT_KEYSET_TYPE keysetType,
const C_STR keysetName )
{
CRYPT_KEYSET cryptKeyset;
CRYPT_CERTIFICATE cryptCert;
C_CHR filenameBuffer[ FILENAME_BUFFER_SIZE ];
C_CHR 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 ) )
{
#ifdef UNICODE_STRINGS
length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
name[ length ] = TEXT( '\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 ) )
{
#ifdef UNICODE_STRINGS
length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
name[ length ] = TEXT( '\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..." );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -