📄 certs.c
字号:
/****************************************************************************
* *
* cryptlib Certificate Handling Test Routines *
* Copyright Peter Gutmann 1997-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 */
/* 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 ( 0x3A000000L + 2082844800L )
#define CERTTIME_Y2KTEST ( 0x46300C01L + 2082844800L )
#else
#define CERTTIME_DATETEST 0x3A000000L
#define CERTTIME_Y2KTEST 0x46300C01L
#endif /* Macintosh-specific weird epoch */
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Set the trust setting for the root CA in a cert chain. This is required
for the self-test in order to allow signature checks for chains signed by
arbitrary CAs to work */
static int setRootTrust( const CRYPT_CERTIFICATE cryptCertChain,
BOOLEAN *oldTrustValue,
const BOOLEAN newTrustValue )
{
int status;
status = cryptSetAttribute( cryptCertChain,
CRYPT_CERTINFO_CURRENT_CERTIFICATE,
CRYPT_CURSOR_LAST );
if( cryptStatusError( status ) )
return( status );
if( oldTrustValue != NULL )
cryptGetAttribute( cryptCertChain, CRYPT_CERTINFO_TRUSTED_IMPLICIT,
oldTrustValue );
return( cryptSetAttribute( cryptCertChain,
CRYPT_CERTINFO_TRUSTED_IMPLICIT,
newTrustValue ) );
}
/****************************************************************************
* *
* 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, TEXT( "NZ" ) },
{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
/* Self-signed X.509v3 certificate (technically it'd be an X.509v1, but
cryptlib automatically adds some required standard attributes so it
becomes an X.509v3 cert) */
{ 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, TEXT( "Dave Taylor" ),
paramStrlen( TEXT( "Dave Taylor" ) ) );
/* Sign the certificate and print information on what we got */
status = cryptSignCert( cryptCert, privKeyContext );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptSignCert()", status,
__LINE__ ) );
destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
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, 0, &value, CRYPT_CERTFORMAT_CERTIFICATE,
cryptCert );
if( cryptStatusOK( status ) )
status = cryptExportCert( certBuffer, BUFFER_SIZE, &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 that 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, TEXT( "Dave's Wetaburgers and CA" ) },
{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Himself" ) },
{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Certification Division" ) },
{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "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, TEXT( "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, TEXT( "This policy isn't worth the paper it's not printed on." ) },
{ CRYPT_CERTINFO_CERTPOLICY_ORGANIZATION, IS_STRING, 0, TEXT( "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 and print information on what we got */
status = cryptSignCert( cryptCert, privKeyContext );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptSignCert()", status,
__LINE__ ) );
destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
if( !printCertInfo( cryptCert ) )
return( FALSE );
/* Export the cert, this time with base64 encoding to make sure that
this works. As before, we perform a length check using a null
buffer to make sure that this facility is working as required */
status = cryptExportCert( NULL, 0, &value,
CRYPT_CERTFORMAT_TEXT_CERTIFICATE, cryptCert );
if( cryptStatusOK( status ) )
status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
CRYPT_CERTFORMAT_TEXT_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( "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 that 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 "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -