📄 scert.c
字号:
/****************************************************************************
* *
* cryptlib Cert Management Session Test Routines *
* Copyright Peter Gutmann 1998-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 */
/* If we're running the test with a crypto device, we have to set an extended
timeout because of the long time it takes many devices to generate keys */
#define NET_TIMEOUT 180
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
#ifdef WINDOWS_THREADS
static HANDLE hMutex;
void createMutex( void )
{
hMutex = CreateMutex( NULL, FALSE, NULL );
}
void releaseMutex( void )
{
ReleaseMutex( hMutex );
}
int waitMutex( void )
{
if( WaitForSingleObject( hMutex, 30000 ) == WAIT_TIMEOUT )
return( CRYPT_ERROR_TIMEOUT );
return( CRYPT_OK );
}
void destroyMutex( void )
{
CloseHandle( hMutex );
}
void waitForThread( const HANDLE hThread )
{
if( WaitForSingleObject( hThread, 15000 ) == WAIT_TIMEOUT )
{
puts( "Warning: Server thread is still active due to session "
"negotiation failure,\n this will cause an error "
"condition when cryptEnd() is called due\n to "
"resources remaining allocated. Press a key to continue." );
getchar();
}
CloseHandle( hThread );
}
#else
#define waitMutex() CRYPT_OK
#define releaseMutex()
#endif /* WINDOWS_THREADS */
/* Run a persistent server session, recycling the connection if the client
kept the link open */
static int activatePersistentServerSession( const CRYPT_SESSION cryptSession,
const BOOLEAN showOperationType )
{
BOOLEAN connectionActive = FALSE;
int status;
do
{
/* Activate the connection */
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE,
TRUE );
if( status == CRYPT_ERROR_READ && connectionActive )
/* The other side closed the connection after a previous
successful transaction, this isn't an error */
return( CRYPT_OK );
/* Print connection info and check whether the connection is still
active. If it is, we recycle the session so that we can process
another request */
printConnectInfo( cryptSession );
if( cryptStatusOK( status ) && showOperationType )
{
char userID[ CRYPT_MAX_TEXTSIZE ];
int userIDsize, requestType;
status = cryptGetAttribute( cryptSession,
CRYPT_SESSINFO_CMP_REQUESTTYPE,
&requestType );
if( cryptStatusOK( status ) )
status = cryptGetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME,
userID, &userIDsize );
if( cryptStatusError( status ) )
printf( "cryptGetAttribute/AttributeString() failed with "
"error code %d, line %d.\n", status, __LINE__ );
else
{
userID[ userIDsize ] = '\0';
printf( "SVR: Operation type was %d, user '%s'.\n",
requestType, userID );
}
}
cryptGetAttribute( cryptSession, CRYPT_SESSINFO_CONNECTIONACTIVE,
&connectionActive );
}
while( cryptStatusOK( status ) && connectionActive );
return( status );
}
/* Add a PKI user to the cert store */
static int addPKIUser( const CRYPT_KEYSET cryptCertStore,
const CERT_DATA *pkiUserData,
const BOOLEAN isSCEP )
{
CRYPT_CERTIFICATE cryptPKIUser;
CRYPT_SESSION cryptSession;
C_CHR userID[ CRYPT_MAX_TEXTSIZE + 1 ], issuePW[ CRYPT_MAX_TEXTSIZE + 1 ];
int length, status;
/* Create the PKI user object and add the user's identification
information */
status = cryptCreateCert( &cryptPKIUser, CRYPT_UNUSED,
CRYPT_CERTTYPE_PKIUSER );
if( cryptStatusError( status ) )
{
printf( "cryptCreateCert() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
if( !addCertFields( cryptPKIUser, pkiUserData ) )
return( FALSE );
/* Add the user info to the cert store */
status = cryptCAAddItem( cryptCertStore, cryptPKIUser );
if( status == CRYPT_ERROR_DUPLICATE )
{
C_CHR userCN[ CRYPT_MAX_TEXTSIZE + 1 ];
/* Get the name of the duplicate user */
status = cryptGetAttributeString( cryptPKIUser,
CRYPT_CERTINFO_COMMONNAME,
userCN, &length );
if( cryptStatusError( status ) )
return( attrErrorExit( cryptPKIUser, "cryptGetAttribute()",
status, __LINE__ ) );
#ifdef UNICODE_STRINGS
length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
userCN[ length ] = TEXT( '\0' );
/* The PKI user info was already present, for SCEP this isn't a
problem since we can just re-use the existing info, but for CMP
we can only authorise a single cert issue per user so we have
to delete the existing user info and try again */
if( isSCEP )
{
/* The PKI user info is already present from a previous run, get
the existing info */
puts( "PKI user information is already present from a previous "
"run, reusing existing\n PKI user data..." );
cryptDestroyCert( cryptPKIUser );
status = cryptCAGetItem( cryptCertStore, &cryptPKIUser,
CRYPT_CERTTYPE_PKIUSER, CRYPT_KEYID_NAME,
userCN );
}
else
{
puts( "PKI user information is already present from a previous "
"run, deleting existing\n PKI user data..." );
status = cryptCADeleteItem( cryptCertStore, CRYPT_CERTTYPE_PKIUSER,
CRYPT_KEYID_NAME, userCN );
if( cryptStatusError( status ) )
return( extErrorExit( cryptCertStore, "cryptCADeleteItem()",
status, __LINE__ ) );
status = cryptCAAddItem( cryptCertStore, cryptPKIUser );
}
}
if( cryptStatusError( status ) )
return( extErrorExit( cryptCertStore, "cryptCAAdd/GetItem()", status,
__LINE__ ) );
/* Display the information for the new user and make sure the error-
checking in the user information works. We have to check both
passwords to reduce false positives since it's just a simple integrity
check meant to catch typing errors rather than a cryptographically
strong check */
if( !printCertInfo( cryptPKIUser ) )
return( FALSE );
status = cryptGetAttributeString( cryptPKIUser,
CRYPT_CERTINFO_PKIUSER_ID,
userID, &length );
if( cryptStatusOK( status ) )
{
#ifdef UNICODE_STRINGS
length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
userID[ length ] = '\0';
status = cryptGetAttributeString( cryptPKIUser,
CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD,
issuePW, &length );
}
if( cryptStatusOK( status ) )
{
#ifdef UNICODE_STRINGS
length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
issuePW[ length ] = '\0';
}
else
return( attrErrorExit( cryptPKIUser, "cryptGetAttribute()", status,
__LINE__ ) );
cryptCreateSession( &cryptSession, CRYPT_UNUSED, CRYPT_SESSION_CMP );
if( userID[ 2 ] >= TEXT( 'A' ) && userID[ 2 ] < TEXT( 'Z' ) )
userID[ 2 ]++;
else
userID[ 2 ] = TEXT( 'A' );
if( issuePW[ 8 ] >= TEXT( 'A' ) && issuePW[ 8 ] < TEXT( 'Z' ) )
issuePW[ 8 ]++;
else
issuePW[ 8 ] = TEXT( 'A' );
status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_USERNAME,
userID, paramStrlen( userID ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_PASSWORD,
issuePW, paramStrlen( issuePW ) );
if( cryptStatusOK( status ) )
{
puts( "Integrity check of user ID and password failed to catch "
"errors in the data.\n(This check isn't foolproof and is "
"intended only to catch typing errors when\nentering the "
"data. Try running the test again to see if the problem "
"still\noccurs)." );
return( FALSE );
}
cryptDestroySession( cryptSession );
/* Clean up */
cryptDestroyCert( cryptPKIUser );
return( TRUE );
}
/* Get information on a PKI user */
static int getPkiUserInfo( C_STR userID, C_STR issuePW, C_STR revPW,
C_STR userName )
{
CRYPT_KEYSET cryptCertStore;
CRYPT_CERTIFICATE cryptPKIUser;
int length, status;
/* cryptlib implements per-user (rather than shared interop) IDs and
passwords so we need to read the user ID and password information
before we can perform any operations. First we get the PkiUser
object */
status = cryptKeysetOpen( &cryptCertStore, CRYPT_UNUSED,
CERTSTORE_KEYSET_TYPE, CERTSTORE_KEYSET_NAME,
CRYPT_KEYOPT_NONE );
if( status == CRYPT_ERROR_PARAM3 )
{
/* This type of keyset access isn't available, return a special error
code to indicate that the test wasn't performed, but that this
isn't a reason to abort processing */
puts( "No certificate store available, aborting CMP test.\n" );
return( CRYPT_ERROR_NOTAVAIL );
}
if( cryptStatusError( status ) )
{
printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
status, __LINE__ );
return( status );
}
status = cryptCAGetItem( cryptCertStore, &cryptPKIUser,
CRYPT_CERTTYPE_PKIUSER, CRYPT_KEYID_NAME,
userName );
cryptKeysetClose( cryptCertStore );
if( cryptStatusError( status ) )
{
/* Only report error info if it's not a basic presence check */
if( userID != NULL )
extErrorExit( cryptCertStore, "cryptCAGetItem()", status, __LINE__ );
return( status );
}
/* If it's a presence check only, we're done */
if( userID == NULL )
{
cryptDestroyCert( cryptPKIUser );
return( CRYPT_OK );
}
/* Then we extract the information from the PkiUser object */
status = cryptGetAttributeString( cryptPKIUser,
CRYPT_CERTINFO_PKIUSER_ID,
userID, &length );
if( cryptStatusOK( status ) )
{
userID[ length ] = '\0';
status = cryptGetAttributeString( cryptPKIUser,
CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD,
issuePW, &length );
}
if( cryptStatusOK( status ) )
issuePW[ length ] = '\0';
if( cryptStatusOK( status ) && revPW != NULL )
{
status = cryptGetAttributeString( cryptPKIUser,
CRYPT_CERTINFO_PKIUSER_REVPASSWORD,
revPW, &length );
if( cryptStatusOK( status ) )
revPW[ length ] = '\0';
}
cryptDestroyCert( cryptPKIUser );
if( cryptStatusError( status ) )
{
attrErrorExit( cryptPKIUser, "cryptGetAttribute()", status,
__LINE__ );
return( status );
}
/* We've got what we need, tell the user what we're doing */
printf( "Using user name %s, password %s.\n", userID, issuePW );
return( CRYPT_OK );
}
/* Set up objects and information needed by a server-side PKI session */
static int serverInit( CRYPT_CONTEXT *cryptPrivateKey,
CRYPT_KEYSET *cryptCertStore, const C_STR keyFileName,
const C_STR keyLabel, const CERT_DATA *pkiUserData,
const CERT_DATA *pkiUserCAData,
const char *protocolName )
{
int status;
/* Get the cert store to use with the session. Before we use the store
we perform a cleanup action to remove any leftover requests from
previous runs */
status = cryptKeysetOpen( cryptCertStore, CRYPT_UNUSED,
CERTSTORE_KEYSET_TYPE, CERTSTORE_KEYSET_NAME,
CRYPT_KEYOPT_CREATE );
if( status == CRYPT_ERROR_PARAM3 )
{
/* This type of keyset access isn't available, return a special error
code to indicate that the test wasn't performed, but that this
isn't a reason to abort processing */
printf( "SVR: No certificate store available, aborting %s server "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -