📄 utils.c
字号:
/****************************************************************************
* *
* cryptlib Self-test Utility Routines *
* Copyright Peter Gutmann 1997-2004 *
* *
****************************************************************************/
#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 */
/****************************************************************************
* *
* Import/Export Functions *
* *
****************************************************************************/
/* Check that a file is accessible. This is a generic sanity check to make
sure that access to keyset files is functioning */
int checkFileAccess( void )
{
CRYPT_KEYSET cryptKeyset;
FILE *filePtr;
int status;
/* First, check that the file actually exists so that we can return an
appropriate error message */
if( ( filePtr = fopen( convertFileName( CA_PRIVKEY_FILE ),
"rb" ) ) == NULL )
{
printf( "Couldn't access cryptlib keyset file %s. Please make "
"sure\nthat all the cryptlib files have been installed "
"correctly, and the cryptlib\nself-test is being run from "
"the correct directory.\n", CA_PRIVKEY_FILE );
return( FALSE );
}
fclose( filePtr );
/* The file exists and is accessible, now try and open it using the
cryptlib file access functions */
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
CA_PRIVKEY_FILE, CRYPT_KEYOPT_READONLY );
if( cryptStatusError( status ) )
{
printf( "Couldn't access cryptlib keyset file %s even though the "
"file\nexists and is readable. Please make sure that the "
"cryptlib self-test is\nbeing run from the correct "
"directory.\n", CA_PRIVKEY_FILE );
return( FALSE );
}
cryptKeysetClose( cryptKeyset );
return( TRUE );
}
/* Import a certificate object */
int importCertFile( CRYPT_CERTIFICATE *cryptCert, const C_STR fileName )
{
FILE *filePtr;
BYTE buffer[ BUFFER_SIZE ];
int count;
if( ( filePtr = fopen( convertFileName( fileName ), "rb" ) ) == NULL )
return( CRYPT_ERROR_OPEN );
count = fread( buffer, 1, BUFFER_SIZE, filePtr );
fclose( filePtr );
if( count == BUFFER_SIZE ) /* Item too large for buffer */
return( CRYPT_ERROR_OVERFLOW );
/* Import the certificate */
return( cryptImportCert( buffer, count, CRYPT_UNUSED, cryptCert ) );
}
int importCertFromTemplate( CRYPT_CERTIFICATE *cryptCert,
const C_STR fileTemplate, const int number )
{
BYTE filenameBuffer[ FILENAME_BUFFER_SIZE ];
#ifdef UNICODE_STRINGS
wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ];
#endif /* UNICODE_STRINGS */
filenameFromTemplate( filenameBuffer, fileTemplate, number );
#ifdef UNICODE_STRINGS
mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 );
return( importCertFile( cryptCert, wcBuffer ) );
#else
return( importCertFile( cryptCert, filenameBuffer ) );
#endif /* UNICODE_STRINGS */
}
/* Get a line of text from the user */
static void getText( char *input, const char *prompt )
{
printf( "Enter %s: ", prompt );
fflush( stdout );
fgets( input, CRYPT_MAX_TEXTSIZE - 1, stdin );
putchar( '\n' );
}
/* Read a key from a key file */
int getPublicKey( CRYPT_CONTEXT *cryptContext, const C_STR keysetName,
const C_STR keyName )
{
CRYPT_KEYSET cryptKeyset;
int status;
/* Read the key from the keyset */
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
keysetName, CRYPT_KEYOPT_READONLY );
if( cryptStatusError( status ) )
return( status );
status = cryptGetPublicKey( cryptKeyset, cryptContext, CRYPT_KEYID_NAME,
keyName );
cryptKeysetClose( cryptKeyset );
return( status );
}
int getPrivateKey( CRYPT_CONTEXT *cryptContext, const C_STR keysetName,
const C_STR keyName, const C_STR password )
{
CRYPT_KEYSET cryptKeyset;
time_t validFrom, validTo;
int dummy, status;
/* Read the key from the keyset */
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
keysetName, CRYPT_KEYOPT_READONLY );
if( cryptStatusError( status ) )
return( status );
status = cryptGetPrivateKey( cryptKeyset, cryptContext, CRYPT_KEYID_NAME,
keyName, password );
cryptKeysetClose( cryptKeyset );
if( cryptStatusError( status ) )
return( status );
/* If the key has a cert attached, make sure it's still valid before we
hand it back to the self-test functions that will report the problem
as being with the self-test rather than with the cert */
status = cryptGetAttributeString( *cryptContext,
CRYPT_CERTINFO_VALIDFROM, &validFrom, &dummy );
if( cryptStatusError( status ) )
/* There's no cert there, this isn't an error */
return( CRYPT_OK );
cryptGetAttributeString( *cryptContext,
CRYPT_CERTINFO_VALIDTO, &validTo, &dummy );
#ifndef _WIN32_WCE
if( ( validTo - validFrom > ( 86400 * 30 ) ) && \
validTo - time( NULL ) <= ( 86400 * 30 ) )
{
puts( " ********************" );
if( validTo <= time( NULL ) )
puts( "Warning: This key has expired. Certificate-related "
"operations may fail or\n result in error "
"messages from the test code." );
else
if( validTo - time( NULL ) <= 86400 )
puts( "Warning: This key expires today. Certificate-"
"related operations may fail\n or result in "
"error messages from the test code." );
else
printf( "Warning: This key will expire in %ld days. "
"Certificate-related operations\n may fail "
"or result in error messages from the test code.\n",
( validTo - time( NULL ) ) / 86400 );
puts( " ********************" );
}
#endif /* _WIN32_WCE */
return( CRYPT_OK );
}
/****************************************************************************
* *
* OS Helper Functions *
* *
****************************************************************************/
#if defined( __BORLANDC__ ) && ( __BORLANDC__ <= 0x310 )
/* BC++ 3.x doesn't have mbstowcs() in the default library, and also defines
wchar_t as char (!!) so we fake it here */
size_t mbstowcs( char *pwcs, const char *s, size_t n )
{
memcpy( pwcs, s, n );
return( n );
}
#endif /* BC++ 3.1 or lower */
/* When using multiple threads we need to delay one thread for a small
amount of time, unfortunately there's no easy way to do this with pthreads
so we have to provide the following wrapper function that makes an
(implementation-specific) attempt at it */
#if defined( UNIX_THREADS ) || defined( WINDOWS_THREADS ) || defined( OS2_THREADS )
#if defined( UNIX_THREADS )
/* This include must be outside the function to avoid weird compiler errors
on some systems */
#include <sys/time.h>
#endif /* UNIX_THREADS */
void delayThread( const int seconds )
{
#if defined( UNIX_THREADS )
struct timeval tv = { 0 };
/* The following should put a thread to sleep for a second on most
systems since the select() should be a thread-safe one in the
presence of pthreads */
tv.tv_sec = seconds;
select( 1, NULL, NULL, NULL, &tv );
#elif defined( WINDOWS_THREADS )
Sleep( seconds * 1000 );
#endif /* Threading system-specific delay functions */
}
#endif /* Systems with threading support */
/* Helper functions to make tracking down errors on systems with no console
a bit less painful. These just use the debug console as stdout */
#ifdef _WIN32_WCE
void wcPrintf( const char *format, ... )
{
wchar_t wcBuffer[ 1024 ];
char buffer[ 1024 ];
va_list argPtr;
va_start( argPtr, format );
vsprintf( buffer, format, argPtr );
va_end( argPtr );
mbstowcs( wcBuffer, buffer, strlen( buffer ) + 1 );
NKDbgPrintfW( wcBuffer );
}
void wcPuts( const char *string )
{
wcPrintf( "%s\n", string );
}
#endif /* Console-less environments */
/* Conversion functions used to get Unicode input into generic ASCII
output */
#ifdef UNICODE_STRINGS
/* Get a filename in an appropriate format for the C runtime library */
const char *convertFileName( const C_STR fileName )
{
static char fileNameBuffer[ FILENAME_BUFFER_SIZE ];
wcstombs( fileNameBuffer, fileName, wcslen( fileName ) + 1 );
return( fileNameBuffer );
}
/* Map a filename template to an actual filename, input in Unicode, output in
ASCII */
void filenameFromTemplate( char *buffer, const wchar_t *fileTemplate,
const int count )
{
wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ];
int length;
length = _snwprintf( wcBuffer, FILENAME_BUFFER_SIZE, fileTemplate,
count );
wcstombs( buffer, wcBuffer, length + 1 );
}
void filenameParamFromTemplate( wchar_t *buffer,
const wchar_t *fileTemplate,
const int count )
{
int length;
length = _snwprintf( buffer, FILENAME_BUFFER_SIZE, fileTemplate,
count );
}
#endif /* UNICODE_STRINGS */
/****************************************************************************
* *
* Error-handling Functions *
* *
****************************************************************************/
/* Print extended error attribute information */
void printErrorAttributeInfo( const CRYPT_HANDLE cryptHandle )
{
int errorType, errorLocus;
int status;
status = cryptGetAttribute( cryptHandle, CRYPT_ATTRIBUTE_ERRORTYPE,
&errorType );
cryptGetAttribute( cryptHandle, CRYPT_ATTRIBUTE_ERRORLOCUS, &errorLocus );
if( cryptStatusOK( status ) && errorType != CRYPT_ERRTYPE_NONE )
printf( " Error info attributes report locus %d, type %d.\n",
errorLocus, errorType );
}
/* Print extended object error information */
void printExtError( const CRYPT_HANDLE cryptHandle,
const char *functionName, const int functionStatus,
const int lineNo )
{
char errorMessage[ 512 ];
int errorCode, errorMessageLength, status, msgStatus;
printf( "%s failed with error code %d, line %d.\n", functionName,
functionStatus, lineNo );
status = cryptGetAttribute( cryptHandle, CRYPT_ATTRIBUTE_INT_ERRORCODE,
&errorCode );
msgStatus = cryptGetAttributeString( cryptHandle,
CRYPT_ATTRIBUTE_INT_ERRORMESSAGE,
errorMessage, &errorMessageLength );
if( cryptStatusError( status ) )
{
printf( "Read of error attributes failed with error code %d, "
"line %d.\n", status, __LINE__ );
return;
}
if( !errorCode && cryptStatusError( msgStatus ) )
{
puts( " No extended error information available." );
printErrorAttributeInfo( cryptHandle );
return;
}
printf( " Extended error code = %d (0x%X)", errorCode, errorCode );
if( cryptStatusOK( msgStatus ) )
{
errorMessage[ errorMessageLength ] = '\0';
printf( ", error message = %s'%s'.\n",
( errorMessageLength > 40 ) ? "\n " : "", errorMessage );
}
else
puts( "." );
printErrorAttributeInfo( cryptHandle );
}
/* Exit with an error message. attrErrorExit() prints the locus and type,
extErrorExit() prints the extended error code and message */
BOOLEAN attrErrorExit( const CRYPT_HANDLE cryptHandle,
const char *functionName, const int errorCode,
const int lineNumber )
{
printf( "%s failed with error code %d, line %d.\n", functionName,
errorCode, lineNumber );
printErrorAttributeInfo( cryptHandle );
return( FALSE );
}
BOOLEAN extErrorExit( const CRYPT_HANDLE cryptHandle,
const char *functionName, const int errorCode,
const int lineNumber )
{
printExtError( cryptHandle, functionName, errorCode, lineNumber );
cryptDestroyObject( cryptHandle );
return( FALSE );
}
/****************************************************************************
* *
* Misc. Functions *
* *
****************************************************************************/
/* Some algorithms can be disabled to eliminate patent problems or reduce the
size of the code. The following functions are used to select generally
equivalent alternatives if the required algorithm isn't available. These
selections make certain assumptions (that the given algorithms are always
available, which is virtually guaranteed, and that they have the same
general properties as the algorithms they're replacing, which is also
usually the case - Blowfish for IDEA, RC2, or RC5, and MD5 for MD4) */
CRYPT_ALGO_TYPE selectCipher( const CRYPT_ALGO_TYPE algorithm )
{
if( cryptStatusOK( cryptQueryCapability( algorithm, NULL ) ) )
return( algorithm );
return( CRYPT_ALGO_BLOWFISH );
}
/* Add a collection of fields to a certificate */
int addCertFields( const CRYPT_CERTIFICATE certificate,
const CERT_DATA *certData )
{
int i;
for( i = 0; certData[ i ].type != CRYPT_ATTRIBUTE_NONE; i++ )
{
int status;
switch( certData[ i ].componentType )
{
case IS_NUMERIC:
status = cryptSetAttribute( certificate,
certData[ i ].type, certData[ i ].numericValue );
if( cryptStatusError( status ) )
printf( "cryptSetAttribute() for field ID %d, value %d, "
"failed with error code %d, line %d.\n",
certData[ i ].type, certData[ i ].numericValue,
status, __LINE__ );
break;
case IS_STRING:
status = cryptSetAttributeString( certificate,
certData[ i ].type, certData[ i ].stringValue,
certData[ i ].numericValue ? \
certData[ i ].numericValue : \
paramStrlen( certData[ i ].stringValue ) );
if( cryptStatusError( status ) )
printf( "cryptSetAttributeString() for field ID %d,\n"
"value '%s', failed with error code %d, line %d.\n",
certData[ i ].type,
( char * ) certData[ i ].stringValue, status,
__LINE__ );
break;
#ifdef HAS_WIDECHAR
case IS_WCSTRING:
status = cryptSetAttributeString( certificate,
certData[ i ].type, certData[ i ].stringValue,
wcslen( certData[ i ].stringValue ) * sizeof( wchar_t ) );
if( cryptStatusError( status ) )
printf( "cryptSetAttributeString() for field ID %d,\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -