📄 testcert.c
字号:
/****************************************************************************
* *
* cryptlib Certificate Handling Test Routines *
* Copyright Peter Gutmann 1997-2002 *
* *
****************************************************************************/
#ifdef _MSC_VER
#include "../cryptlib.h"
#include "../test/test.h"
#else
#include "cryptlib.h"
#include "test/test.h"
#endif /* Braindamaged MSC include handling */
/* Certificate times. Unlike every other system on the planet, the Mac
takes the time_t epoch as 1904 rather than 1970 (even VMS, MVS, VM/CMS,
the AS/400, Tandem NSK, and God knows what other sort of strangeness
stick to 1970 as the time_t epoch). ANSI and ISO C are very careful to
avoid specifying what the epoch actually is, so it's legal to do this in
the same way that it's legal for Microsoft to break Kerberos because the
standard doesn't say they can't */
#if defined( __MWERKS__ ) || defined( SYMANTEC_C ) || defined( __MRC__ )
#define CERTTIME_DATETEST ( 0x38000000L + 2082844800L )
#define CERTTIME_Y2KTEST ( 0x46300C01L + 2082844800L )
#else
#define CERTTIME_DATETEST 0x38000000L
#define CERTTIME_Y2KTEST 0x46300C01L
#endif /* Macintosh-specific weird epoch */
/****************************************************************************
* *
* Certificate Creation Routines Test *
* *
****************************************************************************/
BYTE FAR_BSS certBuffer[ BUFFER_SIZE ];
int certificateLength;
/* Create a series of self-signed certs */
static const CERT_DATA certData[] = {
/* Identification information */
{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, "NZ" },
{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, "Dave's Wetaburgers" },
{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, "Procurement" },
{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, "Dave Smith" },
/* Self-signed X.509v1 certificate */
{ CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
};
int testCert( void )
{
CRYPT_CERTIFICATE cryptCert;
CRYPT_CONTEXT pubKeyContext, privKeyContext;
int value, status;
#if defined( _MSC_VER ) && ( _MSC_VER <= 800 )
time_t testTime = time( NULL ), newTime;
newTime = mktime( localtime( &testTime ) );
if( newTime == testTime )
{
puts( "Illogical local/GMT time detected. VC++ 1.5x occasionally "
"exhibits a bug in\nits time zone handling in which it thinks "
"that the local time zone is GMT and\nGMT itself is some "
"negative offset from the current time. This upsets\n"
"cryptlibs certificate date validity checking, since "
"certificates appear to\nhave inconsistent dates. Deleting "
"all the temporary files and rebuilding\ncryptlib after "
"restarting your machine may fix this.\n" );
return( FALSE );
}
#endif /* VC++ 1.5 bug check */
puts( "Testing certificate creation/export..." );
/* Create the RSA en/decryption contexts */
if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
return( FALSE );
/* Create the certificate */
status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
CRYPT_CERTTYPE_CERTIFICATE );
if( cryptStatusError( status ) )
{
printf( "cryptCreateCert() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
/* Add some certificate components */
status = cryptSetAttribute( cryptCert,
CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
__LINE__ ) );
if( !addCertFields( cryptCert, certData ) )
return( FALSE );
/* Delete a component and replace it with something else */
status = cryptDeleteAttribute( cryptCert, CRYPT_CERTINFO_COMMONNAME );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptDeleteAttribute()", status,
__LINE__ ) );
cryptSetAttributeString( cryptCert,
CRYPT_CERTINFO_COMMONNAME, "Dave Taylor", 11 );
/* Sign the certificate. Since we're creating a self-signed cert, we need
to make it an X.509v1 cert because the default X.509v3 keyUsage doesn't
allow cert signing unless this is explicitly set */
cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_CREATEV3CERT, &value );
cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_CREATEV3CERT, FALSE );
status = cryptSignCert( cryptCert, privKeyContext );
cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_CREATEV3CERT, value );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptSignCert()", status,
__LINE__ ) );
destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
/* Print information on what we've got */
if( !printCertInfo( cryptCert ) )
return( FALSE );
/* Check the signature. Since it's self-signed, we don't need to pass in
a signature check key */
status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
__LINE__ ) );
/* Set the cert usage to untrusted for any purpose, which should result
in the signature check failing */
cryptSetAttribute( cryptCert, CRYPT_CERTINFO_TRUSTED_USAGE,
CRYPT_KEYUSAGE_NONE );
status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
if( cryptStatusOK( status ) )
{
puts( "Untrusted cert signature check succeeded, should have "
"failed." );
return( FALSE );
}
cryptDeleteAttribute( cryptCert, CRYPT_CERTINFO_TRUSTED_USAGE );
/* Export the cert. We perform a length check using a null buffer to
make sure that this facility is working as required */
status = cryptExportCert( NULL, &value, CRYPT_CERTFORMAT_CERTIFICATE,
cryptCert );
if( cryptStatusOK( status ) )
status = cryptExportCert( certBuffer, &certificateLength,
CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptExportCert()", status,
__LINE__ ) );
if( value != certificateLength )
{
puts( "Exported certificate size != actual data size." );
return( FALSE );
}
printf( "Exported certificate is %d bytes long.\n", certificateLength );
debugDump( "cert", certBuffer, certificateLength );
/* Destroy the certificate */
status = cryptDestroyCert( cryptCert );
if( cryptStatusError( status ) )
{
printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
/* Make sure we can read what we created */
status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
&cryptCert );
if( cryptStatusError( status ) )
{
printf( "cryptImportCert() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
__LINE__ ) );
cryptDestroyCert( cryptCert );
/* Clean up */
puts( "Certificate creation succeeded.\n" );
return( TRUE );
}
static const CERT_DATA cACertData[] = {
/* Identification information. Note the non-heirarchical order of the
components to test the automatic arranging of the DN */
{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, "Dave's Wetaburgers and CA" },
{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, "Dave Himself" },
{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, "Certification Division" },
{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, "NZ" },
/* Self-signed X.509v3 certificate */
{ CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
/* Start date set to a fixed value to check for problems in date/time
conversion routines, expiry date set to > Y2K (with the start date set
to before Y2K) to test for Y2K problems */
{ CRYPT_CERTINFO_VALIDFROM, IS_TIME, 0, NULL, CERTTIME_DATETEST },
{ CRYPT_CERTINFO_VALIDTO, IS_TIME, 0, NULL, CERTTIME_Y2KTEST },
/* CA extensions. Policies are very much CA-specific and currently
undefined, so we use a dummy OID for a nonexistant private org for
now */
{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC,
CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
{ CRYPT_CERTINFO_CA, IS_NUMERIC, TRUE },
{ CRYPT_CERTINFO_CERTPOLICYID, IS_STRING, 0, "1 3 6 1 4 1 9999 1" },
/* Blank line needed due to bug in Borland C++ parser */
{ CRYPT_CERTINFO_CERTPOLICY_EXPLICITTEXT, IS_STRING, 0, "This policy "
"isn't worth the paper it's not printed on." },
{ CRYPT_CERTINFO_CERTPOLICY_ORGANIZATION, IS_STRING, 0, "Honest Joe's "
"used cars and certification authority" },
{ CRYPT_CERTINFO_CERTPOLICY_NOTICENUMBERS, IS_NUMERIC, 1 },
{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
};
int testCACert( void )
{
CRYPT_CERTIFICATE cryptCert;
CRYPT_CONTEXT pubKeyContext, privKeyContext;
time_t startTime, endTime;
int value, status;
puts( "Testing CA certificate creation/export..." );
/* Create the RSA en/decryption contexts */
if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
return( FALSE );
/* Create the certificate */
status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
CRYPT_CERTTYPE_CERTIFICATE );
if( cryptStatusError( status ) )
{
printf( "cryptCreateCert() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
/* Add some certificate components */
status = cryptSetAttribute( cryptCert,
CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
__LINE__ ) );
if( !addCertFields( cryptCert, cACertData ) )
return( FALSE );
/* Sign the certificate */
status = cryptSignCert( cryptCert, privKeyContext );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptSignCert()", status,
__LINE__ ) );
destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
/* Print information on what we've got */
if( !printCertInfo( cryptCert ) )
return( FALSE );
/* Export the cert, this time with base64 encoding to make sure this
works */
status = cryptExportCert( certBuffer, &certificateLength,
CRYPT_CERTFORMAT_TEXT_CERTIFICATE, cryptCert );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptExportCert()", status,
__LINE__ ) );
printf( "Exported certificate is %d bytes long.\n", certificateLength );
debugDump( "cacert", certBuffer, certificateLength );
/* Destroy the certificate */
status = cryptDestroyCert( cryptCert );
if( cryptStatusError( status ) )
{
printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
/* Make sure we can read what we created. We make the second parameter
to the check function the cert (rather than CRYPT_UNUSED as done for
the basic self-signed cert) to check that this option works as
required */
status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
&cryptCert );
if( cryptStatusError( status ) )
{
printf( "cryptImportCert() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
status = cryptCheckCert( cryptCert, cryptCert );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
__LINE__ ) );
status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_VALIDFROM,
&startTime, &value );
if( cryptStatusOK( status ) )
status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_VALIDTO,
&endTime, &value );
if( cryptStatusError( status ) )
{
printf( "Cert time read failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
if( startTime != CERTTIME_DATETEST )
{
printf( "Warning: cert start time is wrong, got %lX, should be "
"%lX.\n This is probably due to problems in the "
"system time handling routines.\n",
startTime, CERTTIME_DATETEST );
}
if( endTime != CERTTIME_Y2KTEST )
printf( "Warning: cert end time is wrong, got %lX, should be "
"%lX.\n This is probably due to problems in the "
"system time handling routines.\n",
endTime, CERTTIME_Y2KTEST );
cryptDestroyCert( cryptCert );
#if defined( __WINDOWS__ ) || defined( __linux__ ) || defined( sun )
if( ( startTime != CERTTIME_DATETEST && \
( startTime - CERTTIME_DATETEST != 3600 && \
startTime - CERTTIME_DATETEST != -3600 ) ) || \
( endTime != CERTTIME_Y2KTEST && \
( endTime - CERTTIME_Y2KTEST != 3600 && \
endTime - CERTTIME_Y2KTEST != -3600 ) ) )
/* If the time is off by exactly one hour this isn't a problem
because the best we can do is get the time adjusted for DST
now rather than DST when the cert was created, a problem which
is more or less undecidable. In addition we don't automatically
abort for arbitrary systems since date problems usually arise
from incorrectly configured time zone info or bugs in the system
date-handling routines or who knows what, aborting on every
random broken system would lead to a flood of unnecessary "bug"
reports */
return( FALSE );
#endif /* System with known-good time handling */
/* Clean up */
puts( "CA certificate creation succeeded.\n" );
return( TRUE );
}
static const CERT_DATA xyzzyCertData[] = {
/* Identification information */
{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, "Dave Smith" },
/* XYZZY certificate */
{ CRYPT_CERTINFO_XYZZY, IS_NUMERIC, TRUE },
{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
};
int testXyzzyCert( void )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -