📄 certutil.c
字号:
/****************************************************************************
* *
* cryptlib Certificate Utility Routines *
* Copyright Peter Gutmann 1997-2002 *
* *
****************************************************************************/
#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 /* EBCDIC systems */
/* Define the following to build a standalone cert utility program. Note
that the code for the standalone version exists only as a debugging tool
intended for use during cryptlib development. THIS CODE IS NOT
MAINTAINED, AND ITS USE IS NOT SUPPORTED */
/* #define STANDALONE_PROGRAM /**/
/* Define the following to wrap the main() function in the standalone program
with a simple wrapper that tests various options */
/* #define WRAP_STANDALONE /**/
/* Generic I/O buffer size. This has to be of a reasonable size so we can
handle cert chains */
#if defined( __MSDOS__ ) && defined( __TURBOC__ )
#define BUFFER_SIZE 3072
#else
#define BUFFER_SIZE 8192
#endif /* __MSDOS__ && __TURBOC__ */
/* Various useful types */
#define BOOLEAN int
#define BYTE unsigned char
#ifndef TRUE
#define FALSE 0
#define TRUE !FALSE
#endif /* TRUE */
/* There are a few OS's broken enough not to define the standard exit codes
(SunOS springs to mind) so we define some sort of equivalent here just
in case */
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#define EXIT_FAILURE !EXIT_SUCCESS
#endif /* EXIT_SUCCESS */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Import a certificate object */
int importCertFile( CRYPT_CERTIFICATE *cryptCert, const char *fileName )
{
FILE *filePtr;
BYTE buffer[ BUFFER_SIZE ];
int count;
if( ( filePtr = fopen( 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 char *fileTemplate, const int number )
{
BYTE buffer[ BUFFER_SIZE ];
filenameFromTemplate( buffer, fileTemplate, number );
return( importCertFile( cryptCert, buffer ) );
}
/* 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' );
}
/* Check that a file is accessible. This is a generic sanity check to make
sure 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( 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 );
}
/* Read a key from a key file */
int getPublicKey( CRYPT_CONTEXT *cryptContext, const char *keysetName,
const char *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 char *keysetName,
const char *keyName, const char *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 );
if( status == CRYPT_ERROR_WRONGKEY )
{
char passwordBuffer[ CRYPT_MAX_TEXTSIZE ];
/* We need a password for this private key, get it from the user and
get the key again */
getText( passwordBuffer, "private key password" );
status = cryptGetPrivateKey( cryptKeyset, cryptContext,
CRYPT_KEYID_NAME, keyName,
passwordBuffer );
}
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 );
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( " ********************" );
}
return( CRYPT_OK );
}
/* 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 );
}
/* 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,
strlen( 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"
"value '%s', failed with error code %d, line %d.\n",
certData[ i ].type, certData[ i ].stringValue,
status, __LINE__ );
break;
#endif /* HAS_WIDECHAR */
case IS_TIME:
status = cryptSetAttributeString( certificate,
certData[ i ].type, &certData[ i ].timeValue,
sizeof( time_t ) );
if( cryptStatusError( status ) )
printf( "cryptSetAttributeString() for field ID %d,\n"
"value 0x%lX, failed with error code %d, line %d.\n",
certData[ i ].type, certData[ i ].timeValue,
status, __LINE__ );
break;
default:
assert( FALSE );
return( FALSE );
}
if( cryptStatusError( status ) )
{
printErrorAttributeInfo( certificate );
return( FALSE );
}
}
return( TRUE );
}
/* Populate a key database with the contents of a directory. This is a
rather OS-specific utility function for setting up test databases that
only works under Win32 */
#if defined( _MSC_VER ) && defined( _WIN32 )
void loadCertificates( void )
{
WIN32_FIND_DATA findData;
HANDLE searchHandle;
searchHandle = FindFirstFile( "d:/tmp/certs/*.der", &findData );
if( searchHandle == INVALID_HANDLE_VALUE )
return;
do
{
CRYPT_CERTIFICATE cryptCert;
int status;
printf( "Adding cert %s.\n", findData.cFileName );
status = importCertFile( &cryptCert, findData.cFileName );
if( cryptStatusOK( status ) )
{
cryptDestroyCert( cryptCert );
}
}
while( FindNextFile( searchHandle, &findData ) );
FindClose( searchHandle );
}
#endif /* Win32 */
/* Write an object to a file for debugging purposes */
#ifdef _MSC_VER
#include <direct.h>
#include <io.h>
#endif /* VC++ */
void debugDump( const char *fileName, const void *data, const int dataLength )
{
FILE *filePtr;
#ifdef __UNIX__
const char *tmpPath = getenv( "TMPDIR" );
char fileNameBuffer[ 1024 ];
const int tmpPathLen = ( tmpPath != NULL ) ? strlen( tmpPath ) : 0;
#else
char fileNameBuffer[ 128 ];
#endif /* __UNIX__ */
const int length = strlen( fileName );
#if defined( _MSC_VER )
if( access( "d:/tmp/", 6 ) == -1 )
mkdir( "d:/tmp" );
strcpy( fileNameBuffer, "d:/tmp/" );
#elif defined( __UNIX__ )
if( tmpPathLen > 3 && tmpPathLen < 768 )
{
strcpy( fileNameBuffer, tmpPath );
if( fileNameBuffer[ tmpPathLen - 1 ] != '/' )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -