📄 certimp.c
字号:
/****************************************************************************
* *
* cryptlib Certificate Handling Test Routines *
* Copyright Peter Gutmann 1997-2005 *
* *
****************************************************************************/
#include "cryptlib.h"
#include "test/test.h"
#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 Import Routines Test *
* *
****************************************************************************/
/* Test certificate import code */
static BOOLEAN handleCertError( const CRYPT_CERTIFICATE cryptCert,
const int certNo, const int errorCode )
{
int errorLocus, status;
printf( "\n" );
status = cryptGetAttribute( cryptCert, CRYPT_ATTRIBUTE_ERRORLOCUS,
&errorLocus );
if( cryptStatusError( status ) )
{
puts( "Couldn't get error locus for certificate check failure." );
return( FALSE );
}
/* Some old certs use deprecated or now-broken algorithms which will
produce a CRYPT_ERROR_NOTAVAIL if we try and verify the signature,
treat this as a special case */
if( certNo == 1 && errorCode == CRYPT_ERROR_NOTAVAIL )
{
puts( "Warning: The hash/signature algorithm required to verify "
"this certificate\n isn't enabled in this build of "
"cryptlib, can't verify the cert\n signature." );
return( TRUE );
}
/* Make sure that we don't fail just because the cert that we're using
as a test has expired */
if( errorLocus == CRYPT_CERTINFO_VALIDTO )
{
puts( "Warning: Validity check failed because the certificate has "
"expired." );
return( TRUE );
}
/* RegTP CA certs are marked as non-CA certs, report the problem and
continue */
if( certNo == 4 && errorLocus == CRYPT_CERTINFO_CA )
{
puts( "Warning: Validity check failed due to RegTP CA certificate "
"incorrectly\n marked as non-CA certificate." );
return( TRUE );
}
/* Cert #26 is a special-case test cert used to check the ability to
detect invalid PKCS #1 padding */
if( certNo == 26 )
{
puts( "Warning: Certificate contains invalid PKCS #1 padding for "
"exponent-3 RSA\n key, the certificate signature is "
"invalid." );
if( errorCode == CRYPT_ERROR_BADDATA )
{
puts( " (This is the correct result for this test)." );
return( TRUE );
}
/* Not detecting this is an error */
puts( " (This should have been detected but wasn't)." );
return( FALSE );
}
return( FALSE );
}
static int certImport( const int certNo, const BOOLEAN isBase64 )
{
CRYPT_CERTIFICATE cryptCert;
FILE *filePtr;
BYTE buffer[ BUFFER_SIZE ];
int count, value, status;
printf( "Testing %scertificate #%d import...\n",
isBase64 ? "base64 " : "", certNo );
filenameFromTemplate( buffer, isBase64 ? BASE64CERT_FILE_TEMPLATE : \
CERT_FILE_TEMPLATE, certNo );
if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
{
puts( "Couldn't find certificate file for import test." );
return( FALSE );
}
count = fread( buffer, 1, BUFFER_SIZE, filePtr );
fclose( filePtr );
/* Import the certificate */
status = cryptImportCert( buffer, count, CRYPT_UNUSED,
&cryptCert );
#ifdef __UNIX__
if( status == CRYPT_ERROR_NOTAVAIL || status == CRYPT_ERROR_BADDATA )
{
puts( "The certificate import failed, possibly because you're "
"using an\nolder version of unzip that corrupts "
"certain types of files when it\nextracts them. To fix this, "
"you need to re-extract test/*.der without\nusing the -a "
"option to convert text files.\n" );
return( TRUE ); /* Skip this test and continue */
}
#endif /* __UNIX__ */
if( status == CRYPT_ERROR_NOSECURE && \
( certNo == 5 || certNo == 12 || certNo == 13 || certNo == 20 || \
certNo == 25 ) )
{
/* Some older certs use totally insecure 512-bit keys and can't be
processed unless we deliberately allow insecure keys.
Unfortunately this also blocks out the cert that's used to check
the ability to handle invalid PKCS #1 padding, since this only
uses a 512-bit key, but if necessary it can be tested by lowering
MIN_PKCSIZE when building cryptlib */
puts( "Warning: Certificate import failed because the certificate "
"uses a very short\n (insecure) key." );
return( TRUE );
}
if( cryptStatusError( status ) )
{
printf( "cryptImportCert() for cert #%d failed with error code %d, "
"line %d.\n", certNo, status, __LINE__ );
return( FALSE );
}
status = cryptGetAttribute( cryptCert, CRYPT_CERTINFO_SELFSIGNED,
&value );
if( cryptStatusError( status ) )
{
/* Sanity check to make sure that the cert internal state is
consistent - this should never happen */
printf( "Couldn't get cert.self-signed status, status %d, line "
"%d.\n", status, __LINE__ );
return( FALSE );
}
if( value )
{
printf( "Certificate is self-signed, checking signature... " );
status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
if( cryptStatusError( status ) )
{
if( !handleCertError( cryptCert, certNo, status ) )
return( attrErrorExit( cryptCert, "cryptCheckCert()",
status, __LINE__ ) );
}
else
puts( "signature verified." );
}
else
puts( "Certificate is signed, signature key unknown." );
/* Print information on what we've got */
if( !printCertInfo( cryptCert ) )
return( FALSE );
/* Clean up */
cryptDestroyCert( cryptCert );
puts( "Certificate import succeeded.\n" );
return( TRUE );
}
#if 0 /* Test rig for NISCC cert data */
static void importTestData( void )
{
int i;
for( i = 1; i <= 110000; i++ )
{
CRYPT_CERTIFICATE cryptCert;
FILE *filePtr;
BYTE buffer[ BUFFER_SIZE ];
int count, status;
if( !( i % 100 ) )
printf( "%06d\r", i );
/* filenameFromTemplate( buffer, "/tmp/simple_client/%08d", i ); */
/* filenameFromTemplate( buffer, "/tmp/simple_server/%08d", i ); */
filenameFromTemplate( buffer, "/tmp/simple_rootca/%08d", i );
if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
break;
count = fread( buffer, 1, BUFFER_SIZE, filePtr );
fclose( filePtr );
status = cryptImportCert( buffer, count, CRYPT_UNUSED,
&cryptCert );
if( cryptStatusOK( status ) )
cryptDestroyCert( cryptCert );
}
}
#endif /* 0 */
int testCertImport( void )
{
int i;
for( i = 1; i <= 25; i++ )
{
if( !certImport( i, FALSE ) )
return( FALSE );
}
return( TRUE );
}
static int certReqImport( const int certNo )
{
CRYPT_CERTIFICATE cryptCert;
FILE *filePtr;
BYTE buffer[ BUFFER_SIZE ];
int count, complianceValue, status;
printf( "Testing certificate request #%d import...\n", certNo );
filenameFromTemplate( buffer, CERTREQ_FILE_TEMPLATE, certNo );
if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
{
puts( "Couldn't find certificate file for import test." );
return( FALSE );
}
count = fread( buffer, 1, BUFFER_SIZE, filePtr );
fclose( filePtr );
/* Import the certificate request and check that the signature is valid */
if( certNo == 3 )
{
/* Some of the requests are broken and we have to set the compliance
level to oblivious to handle them */
cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
&complianceValue );
cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
CRYPT_COMPLIANCELEVEL_OBLIVIOUS );
}
status = cryptImportCert( buffer, count, CRYPT_UNUSED,
&cryptCert );
if( certNo == 3 )
cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
complianceValue );
#ifdef __UNIX__
if( status == CRYPT_ERROR_NOTAVAIL || status == CRYPT_ERROR_BADDATA )
{
puts( "The certificate request import failed, probably because "
"you're using an\nolder version of unzip that corrupts "
"certain types of files when it\nextracts them. To fix this, "
"you need to re-extract test/*.der without\nusing the -a "
"option to convert text files.\n" );
return( TRUE ); /* Skip this test and continue */
}
#endif /* __UNIX__ */
if( status == CRYPT_ERROR_NOSECURE && certNo == 1 )
{
puts( "Warning: Cert.request import failed because the request "
"uses a very short\n (insecure) key." );
return( TRUE );
}
if( cryptStatusError( status ) )
{
printf( "cryptImportCert() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
printf( "Checking signature... " );
status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
__LINE__ ) );
puts( "signature verified." );
/* Print information on what we've got */
if( !printCertInfo( cryptCert ) )
return( FALSE );
/* Clean up */
cryptDestroyCert( cryptCert );
puts( "Certificate request import succeeded.\n" );
return( TRUE );
}
int testCertReqImport( void )
{
int i;
for( i = 1; i <= 3; i++ )
if( !certReqImport( i ) )
return( FALSE );
return( TRUE );
}
#define LARGE_CRL_SIZE 32767 /* Large CRL is too big for std.buffer */
static int crlImport( const int crlNo, BYTE *buffer )
{
CRYPT_CERTIFICATE cryptCert;
FILE *filePtr;
int count, status;
filenameFromTemplate( buffer, CRL_FILE_TEMPLATE, crlNo );
if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
{
printf( "Couldn't find CRL file for CRL #%d import test.\n", crlNo );
return( FALSE );
}
count = fread( buffer, 1, LARGE_CRL_SIZE, filePtr );
fclose( filePtr );
printf( "CRL #%d has size %d bytes.\n", crlNo, count );
/* Import the CRL. Since CRL's don't include the signing cert, we can't
(easily) check the signature on it */
status = cryptImportCert( buffer, count, CRYPT_UNUSED,
&cryptCert );
if( cryptStatusError( status ) )
{
printf( "cryptImportCert() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
/* Print information on what we've got and clean up */
if( !printCertInfo( cryptCert ) )
return( FALSE );
cryptDestroyCert( cryptCert );
return( TRUE );
}
int testCRLImport( void )
{
BYTE *bufPtr;
int i;
puts( "Testing CRL import..." );
/* Since we're working with an unusually large cert object we have to
dynamically allocate the buffer for it */
if( ( bufPtr = malloc( LARGE_CRL_SIZE ) ) == NULL )
{
puts( "Out of memory." );
return( FALSE );
}
for( i = 1; i <= 3; i++ )
if( !crlImport( i, bufPtr ) )
return( FALSE );
/* Clean up */
free( bufPtr );
puts( "CRL import succeeded.\n" );
return( TRUE );
}
static BOOLEAN handleCertChainError( const CRYPT_CERTIFICATE cryptCertChain,
const int certNo, const int errorCode )
{
int trustValue = CRYPT_UNUSED, complianceValue = CRYPT_UNUSED;
int errorLocus, status;
/* If the chain contains a single non-CA cert, we'll get a parameter
error since we haven't supplied a signing cert */
if( errorCode == CRYPT_ERROR_PARAM2 )
{
cryptSetAttribute( cryptCertChain, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
CRYPT_CURSOR_FIRST );
if( cryptSetAttribute( cryptCertChain,
CRYPT_CERTINFO_CURRENT_CERTIFICATE,
CRYPT_CURSOR_NEXT ) == CRYPT_ERROR_NOTFOUND )
{
/* There's only a single cert present, we can't do much with
it */
puts( "\nCertificate chain contains only a single standalone "
"cert, skipping\nsignature check..." );
return( TRUE );
}
}
/* If it's not a problem with validity, we can't go any further */
if( errorCode != CRYPT_ERROR_INVALID )
return( attrErrorExit( cryptCertChain, "cryptCheckCert()",
errorCode, __LINE__ ) );
/* Check the nature of the problem */
status = cryptGetAttribute( cryptCertChain, CRYPT_ATTRIBUTE_ERRORLOCUS,
&errorLocus );
if( cryptStatusError( status ) )
{
puts( "Couldn't get error locus for certificate check failure." );
return( FALSE );
}
/* Try to work around the error */
status = errorCode;
if( errorLocus == CRYPT_CERTINFO_TRUSTED_IMPLICIT || \
errorLocus == CRYPT_CERTINFO_TRUSTED_USAGE )
{
/* The error occured because of a problem with the root cert, try
again with an implicitly-trusted root */
if( errorLocus == CRYPT_CERTINFO_TRUSTED_IMPLICIT )
printf( "\nWarning: The certificate chain didn't verify "
"because it didn't end in a\n trusted root "
"certificate. Checking again using an "
"implicitly\n trusted root..." );
else
printf( "\nWarning: The certificate chain didn't verify "
"because the root certificate's\n key isn't "
"enabled for this usage. Checking again using "
"an\n implicitly trusted root..." );
if( cryptStatusError( \
setRootTrust( cryptCertChain, &trustValue, 1 ) ) )
{
printf( "\nAttempt to make chain root implicitly trusted "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -