📄 ssl.c
字号:
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_PRIVATEKEY,
privateKey );
cryptDestroyContext( privateKey );
}
if( cryptStatusOK( status ) && useClientCert )
{
CRYPT_KEYSET cryptKeyset;
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
DATABASE_KEYSET_TYPE, DATABASE_KEYSET_NAME,
CRYPT_KEYOPT_READONLY );
if( cryptStatusError( status ) )
{
printf( "SVR: Client cert keyset open failed with error code "
"%d, line %d.\n", status, __LINE__ );
return( FALSE );
}
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_KEYSET,
cryptKeyset );
cryptKeysetClose( cryptKeyset );
}
}
else
{
if( localSocket )
{
/* Testing this fully requires a lot of OS-specific juggling so
unless we're running under Windows we just supply the handle
to stdin, which will return a read/write error during the
connect. This checks that the handle has been assigned
corectly without requiring a lot of OS-specific socket
handling code. Under Windows, we use a (very cut-down) set
of socket calls to set up a minimal socket. Since there's
very little error-checking done, we don't treat a failure
as fatal */
#if defined( __WINDOWS__ ) && !defined( _WIN32_WCE )
WSADATA wsaData;
if( WSAStartup( 2, &wsaData ) )
{
printf( "Couldn't initialise sockets interface, line %d.\n",
__LINE__ );
return( FALSE );
}
/* Try and negotiate a STARTTLS session. We don't treat most
types of failure as fatal since there are a great many minor
things that can go wrong that we don't want to have to handle
without writing half an MUA */
netSocket = negotiateSTARTTLS( &protocol );
if( netSocket <= 0 )
{
cryptDestroySession( cryptSession );
WSACleanup();
if( netSocket == CRYPT_OK )
{
puts( "This is a nonfatal error (a great many other "
"things can go wrong while\nnegotiating through "
"to the TLS upgrade).\n" );
return( TRUE );
}
return( FALSE );
}
/* Hand the socket to cryptlib */
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_NETWORKSOCKET, netSocket );
#elif defined( DDNAME_IO )
/* The fileno() function doesn't work for DDNAMEs */
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_NETWORKSOCKET, 0 );
#elif defined( _WIN32_WCE )
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_NETWORKSOCKET, 1 );
#else
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_NETWORKSOCKET, fileno( stdin ) );
#endif /* OS-specific local socket handling */
}
else
{
if( localSession )
{
if( !setLocalConnect( cryptSession, 443 ) )
return( FALSE );
}
else
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_SERVER_NAME, serverName,
paramStrlen( serverName ) );
}
if( cryptStatusOK( status ) && useClientCert )
{
CRYPT_CONTEXT privateKey;
status = getPrivateKey( &privateKey, USER_PRIVKEY_FILE,
USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
if( cryptStatusOK( status ) )
{
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_PRIVATEKEY, privateKey );
cryptDestroyContext( privateKey );
}
}
#if 0 /* Optional proxy for net access */
status = cryptSetAttributeString( CRYPT_UNUSED,
CRYPT_OPTION_NET_HTTP_PROXY, "[Autodetect]",
12 );
#endif /* 0 */
}
if( cryptStatusOK( status ) && sharedKey )
{
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, SSL_USER_NAME,
paramStrlen( SSL_USER_NAME ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD, SSL_PASSWORD,
paramStrlen( SSL_PASSWORD ) );
if( isServer )
{
#if 0 /* Old PSK mechanism */
/* If it's a server session, set an additional username/password
to test the ability of the session cache to store multiple
shared secrets */
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, TEXT( "0000" ),
paramStrlen( TEXT( "0000" ) ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD, TEXT( "0000" ),
paramStrlen( TEXT( "0000" ) ) );
if( cryptStatusOK( status ) && \
cryptStatusOK( \
cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, TEXT( "0000" ),
paramStrlen( TEXT( "0000" ) ) ) ) )
{
printf( "SVR: Addition of duplicate entry to SSL session "
"cache wasn't detected, line %d.\n", __LINE__ );
return( FALSE );
}
#endif /* 0 */
#if 0 /* Check the functioning of the session cache's LRU mechanism */
{
int i;
for( i = 0; i < 1024 + 2000; i++ )
{
char userName[ 64 ];
sprintf( userName, "user%04d", i );
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, userName,
paramStrlen( userName ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD, userName,
paramStrlen( userName ) );
if( cryptStatusError( status ) )
{
printf( "SVR: Error %d during SSL server cache LRU "
"test, line %d.\n", status, __LINE__ );
return( FALSE );
}
}
}
#endif /* 0 */
}
}
if( cryptStatusError( status ) )
{
if( localSocket )
{
#if defined( __WINDOWS__ ) && !defined( _WIN32_WCE )
closesocket( netSocket );
WSACleanup();
#else
/* Creating a socket in a portable manner is too difficult so
we've passed in a stdio handle, this should return an error
since it's not a blocking socket */
return( TRUE );
#endif /* __WINDOWS__ && !_WIN32_WCE */
}
printf( "cryptSetAttribute/AttributeString() failed with error code "
"%d, line %d.\n", status, __LINE__ );
return( FALSE );
}
#if ( SSL_SERVER_NO == 5 ) || ( STARTTLS_SERVER_NO == 8 )
cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
&version );
cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
CRYPT_COMPLIANCELEVEL_OBLIVIOUS );
#endif /* SSL servers with b0rken certs */
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
#if ( SSL_SERVER_NO == 5 ) || ( STARTTLS_SERVER_NO == 8 )
cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
version );
#endif /* SSL server with b0rken certs */
if( isServer )
{
if( !printConnectInfo( cryptSession ) )
return( FALSE );
}
if( cryptStatusError( status ) )
{
char strBuffer[ 128 ];
if( localSocket )
{
#if defined( __WINDOWS__ ) && !defined( _WIN32_WCE )
closesocket( netSocket );
WSACleanup();
#else
/* If we're using a dummy local socket, we'll get a R/W error at
this point since it's not connected to anything, so we
intercept it before it gets any further */
if( status == CRYPT_ERROR_READ || status == CRYPT_ERROR_WRITE )
{
cryptDestroySession( cryptSession );
return( TRUE );
}
#endif /* __WINDOWS__ && !_WIN32_WCE */
}
sprintf( strBuffer, "%sAttempt to activate %s%s session",
isServer ? "SVR: " : "", localSession ? "local " : "",
versionStr[ version ] );
printExtError( cryptSession, strBuffer, status, __LINE__ );
cryptDestroySession( cryptSession );
if( bulkTransfer )
free( bulkBuffer );
if( status == CRYPT_ERROR_OPEN || status == CRYPT_ERROR_NOTFOUND )
{
/* These servers are constantly appearing and disappearing so if
we get a straight connect error we don't treat it as a serious
failure */
puts( " (Server could be down, faking it and continuing...)\n" );
return( CRYPT_ERROR_FAILED );
}
return( FALSE );
}
/* Report the session security info */
if( !printSecurityInfo( cryptSession, isServer, !sharedKey ) )
return( FALSE );
if( ( !localSession && !isServer ) ||
( localSession && isServer && useClientCert ) )
{
CRYPT_CERTIFICATE cryptCertificate;
status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
&cryptCertificate );
if( cryptStatusError( status ) )
{
printf( "%sCouldn't get %s certificate, status %d, line %d.\n",
isServer ? "SVR: " : "", isServer ? "client" : "server",
status, __LINE__ );
return( FALSE );
}
puts( localSession ? "SVR: Client cert details are:" : \
"Server cert details are:" );
printCertChainInfo( cryptCertificate );
cryptDestroyCert( cryptCertificate );
}
if( isServer && sharedKey )
{
C_CHR userNameBuffer[ CRYPT_MAX_TEXTSIZE + 1 ];
int length;
status = cryptGetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME,
userNameBuffer, &length );
if( cryptStatusError( status ) )
{
printf( "SVR: Couldn't read client user name, status %d, line "
"%d.\n", status, __LINE__ );
return( FALSE );
}
#ifdef UNICODE_STRINGS
userNameBuffer[ length / sizeof( wchar_t ) ] = TEXT( '\0' );
printf( "SVR: Client user name = '%S'.\n", userNameBuffer );
#else
userNameBuffer[ length ] = '\0';
printf( "SVR: Client user name = '%s'.\n", userNameBuffer );
#endif /* UNICODE_STRINGS */
}
/* Send data over the SSL/TLS link. If we're doing a bulk transfer
we use fully asynchronous I/O to verify the timeout handling in
the session code */
#if SSL_SERVER_NO == 3
/* This server has a large amount of data on it, used to test high-
latency bulk transfers, so we set a larger timeout for the read */
status = cryptSetAttribute( cryptSession, CRYPT_OPTION_NET_READTIMEOUT,
15 );
#else
status = cryptSetAttribute( cryptSession, CRYPT_OPTION_NET_READTIMEOUT,
bulkTransfer ? 0 : 5 );
#endif /* SSL_SERVER_NO == 3 */
if( bulkTransfer )
{
if( isServer )
{
long byteCount = 0;
do
{
status = cryptPushData( cryptSession, bulkBuffer + byteCount,
BULKDATA_BUFFER_SIZE - byteCount,
&bytesCopied );
byteCount += bytesCopied;
}
while( ( cryptStatusOK( status ) || \
status == CRYPT_ERROR_TIMEOUT ) && \
byteCount < BULKDATA_BUFFER_SIZE );
if( cryptStatusError( status ) )
{
printExtError( cryptSession,
"SVR: Send of bulk data to client", status,
__LINE__ );
return( FALSE );
}
status = cryptFlushData( cryptSession );
if( cryptStatusError( status ) )
{
printExtError( cryptSession,
"SVR: Flush of bulk data to client", status,
__LINE__ );
return( FALSE );
}
if( byteCount != BULKDATA_BUFFER_SIZE )
{
printf( "Only sent %ld of %ld bytes.\n", byteCount,
BULKDATA_BUFFER_SIZE );
return( FALSE );
}
}
else
{
long byteCount = 0;
do
{
status = cryptPopData( cryptSession, bulkBuffer + byteCount,
BULKDATA_BUFFER_SIZE - byteCount,
&bytesCopied );
byteCount += bytesCopied;
}
while( ( cryptStatusOK( status ) || \
status == CRYPT_ERROR_TIMEOUT ) && \
byteCount < BULKDATA_BUFFER_SIZE );
if( cryptStatusError( status ) )
{
char strBuffer[ 256 ];
sprintf( strBuffer, "Read of bulk data from server aborted "
"after %d of %d bytes were read\n(last "
"read = %d bytes), transfer",
byteCount, BULKDATA_BUFFER_SIZE,
bytesCopied );
printExtError( cryptSession, strBuffer, status, __LINE__ );
return( FALSE );
}
if( byteCount != BULKDATA_BUFFER_SIZE )
{
printf( "Only received %ld of %ld bytes.\n", byteCount,
BULKDATA_BUFFER_SIZE );
return( FALSE );
}
if( !handleBulkBuffer( bulkBuffer, FALSE ) )
{
puts( "Received buffer contents don't match sent buffer "
"contents." );
return( FALSE );
}
}
free( bulkBuffer );
}
else
/* It's a standard transfer, send/receive and HTTP request/response.
We clean up if we exit due to an error, if we're running a local
loopback test the client and server threads can occasionally lose
sync, which isn't a fatal error but can turn into a
CRYPT_ERROR_INCOMPLETE once all the tests are finished */
if( isServer )
{
#if defined( __MVS__ ) || defined( __VMCMS__ )
#pragma convlit( resume )
#endif /* IBM big iron */
#if defined( __ILEC400__ )
#pragma convert( 819 )
#endif /* IBM medium iron */
const char serverReply[] = \
"HTTP/1.0 200 OK\n"
"Date: Fri, 7 June 2005 20:02:07 GMT\n"
"Server: cryptlib SSL/TLS test\n"
"Content-Type: text/html\n"
"Connection: Close\n"
"\n"
"<!DOCTYPE HTML SYSTEM \"html.dtd\">\n"
"<html>\n"
"<head>\n"
"<title>cryptlib SSL/TLS test page</title>\n"
"<body>\n"
"Test message from the cryptlib SSL/TLS server<p>\n"
"</body>\n"
"</html>\n";
#if defined( __MVS__ ) || defined( __VMCMS__ )
#pragma convlit( suspend )
#endif /* IBM big iron */
#if defined( __ILEC400__ )
#pragma convert( 0 )
#endif /* IBM medium iron */
/* Print the text of the request from the client */
status = cryptPopData( cryptSession, buffer, FILEBUFFER_SIZE,
&bytesCopied );
if( cryptStatusError( status ) )
{
printExtError( cryptSession, "SVR: Attempt to read data "
"from client", status, __LINE__ );
cryptDestroySession( cryptSession );
return( FALSE );
}
buffer[ bytesCopied ] = '\0';
#if defined( __MVS__ ) || defined( __VMCMS__ )
asciiToEbcdic( buffer, bytesCopied );
#endif /* EBCDIC systems */
printf( "---- Client sent %d bytes ----\n", bytesCopied );
puts( buffer );
puts( "---- End of output ----" );
/* Send a reply */
status = cryptPushData( cryptSession, serverReply,
sizeof( serverReply ) - 1, &bytesCopied );
if( cryptStatusOK( status ) )
status = cryptFlushData( cryptSession );
if( cryptStatusError( status ) || \
bytesCopied != sizeof( serverReply ) - 1 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -