📄 ssl.c
字号:
/****************************************************************************
* *
* cryptlib SSL/TLS Routines *
* Copyright Peter Gutmann 1998-2004 *
* *
****************************************************************************/
#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 */
/* We can run the SSL/TLS self-test with a large variety of options, rather
than using dozens of boolean option flags to control them all we define
various test classes that exercise each option type.
Two of the tests aren't run as part of the normal self-test since their
use of random threads results in somewhat nondeterministic behaviour that
would require extensive extra locking to resolve. SSL_TEST_DUALTHREAD
starts the SSL server with one thread and has the server session return
control to the caller for the password check. The initial server thread
then exits and a second thread takes over for the rest of the connect.
SSL_TEST_MULTITHREAD is just a multithreaded client and server test.
This is even more nondeterministic, with thread pileups possible due to
the lack of extensive locking on the client side */
typedef enum {
SSL_TEST_NORMAL, /* Standard SSL/TLS test */
SSL_TEST_BULKTRANSER, /* Bulk data transfer */
SSL_TEST_CLIENTCERT, /* User auth.with client cert */
SSL_TEST_PSK, /* User auth.with shared key */
SSL_TEST_PSK_SVRONLY, /* Client = no PSK, server = TLS-PSK */
SSL_TEST_PSK_CLIONLY, /* Client = TLS-PSK, server = no PSK */
SSL_TEST_PSK_WRONGKEY, /* User auth.with incorrect shared key */
SSL_TEST_STARTTLS, /* STARTTLS/STLS/AUTH TLS */
SSL_TEST_DUALTHREAD, /* Two-phase connect via different threads */
SSL_TEST_MULTITHREAD /* Multiple server threads */
} SSL_TEST_TYPE;
#if defined( TEST_SESSION ) || defined( TEST_SESSION_LOOPBACK )
/****************************************************************************
* *
* SSL/TLS Routines Test *
* *
****************************************************************************/
/* If we're using local sockets, we have to pull in the winsock defines */
#if defined( __WINDOWS__ ) && !defined( _WIN32_WCE )
#include <winsock.h>
#endif /* __WINDOWS__ && !_WIN32_WCE */
/* There are various servers running that we can use for testing, the
following remapping allows us to switch between them. Notes:
Server 1: Local loopback.
Server 2: Generic test server.
Server 3: ~40K data returned.
Server 4: Sends zero-length blocks (actually a POP server).
Server 5: Novell GroupWise, requires CRYPT_OPTION_CERT_COMPLIANCELEVEL =
CRYPT_COMPLIANCELEVEL_OBLIVIOUS due to b0rken certs.
Server 6: (Causes MAC failure during handshake when called from PMail,
works OK when called here).
Server 7: Can only do crippled crypto (not even conventional crippled
crypto but RC4-56) and instead of sending an alert for this
just drops the connection (this may be caused by the NetApp
NetCache it's using). This site is also running an Apache
server that claims it's optimised for MSIE, and that the page
won't work properly for non-MSIE browsers. The mind boggles...
Server 8: Server ("Hitachi Web Server 02-00") can only do SSL, when
cryptlib is set to perform a TLS handshake (i.e. cryptlib is
told to expect TLS but falls back to SSL), goes through the
full handshake, then returns a handshake failure alert. The
same occurs for other apps (e.g. MSIE) when TLS is enabled.
Server 9: Buggy older IIS that can only do crippled crypto and drops
the connection as soon as it sees the client hello advertising
strong crypto only.
Server 10: Newer IIS (certificate is actually for akamai.net, so the SSL
may not be Microsoft's at all).
Server 11: IBM (Websphere?).
Server 12: Server is running TLS with SSL disabled, drops connection
when it sees an SSL handshake. MSIE in its default config
(TLS disabled) can't connect to this server.
Server 13: GnuTLS.
Server 14: GnuTLS test server with TLS 1.1.
Server 15: Can only do SSLv2, server hangs when sent an SSLv3 handshake.
Server 16: Can't handle TLS 1.1 handshake (drops connection).
Server 17: Can't handle TLS 1.1 handshake (drops connection). Both of
these servers are sitting behind NetApp NetCache's (see also
server 7), which could be the cause of the problem.
Server 18: Generic OpenSSL server.
Server 19: Crippled crypto using NS Server 3.6.
Server 20: Apache with Thawte certs, requires
CRYPT_OPTION_CERT_COMPLIANCELEVEL =
CRYPT_COMPLIANCELEVEL_REDUCED due to b0rken certs.
Server 21: Supports TLS-ext, max-fragment-size extension, session
tickets, TLS 1.2, and assorted other odds and ends (server
listens on both 443 and 4433).
Server 22: GnuTLS server supporting all sorts of oddities (PGP certs,
SRP, compression, TLS-ext, and others, see
http://www.gnu.org/software/gnutls/server.html for details) */
#define SSL_SERVER_NO 2
#define TLS_SERVER_NO 2
#define TLS11_SERVER_NO 2
#define TLS12_SERVER_NO 21
static const struct {
const C_STR name;
const char FAR_BSS *path;
} FAR_BSS sslInfo[] = {
{ NULL, NULL },
/* 1 */ { TEXT( "localhost" ), "/" },
/* 2 */ { TEXT( "https://www.amazon.com" ), "/" },
/* 3 */ { TEXT( "https://www.cs.berkeley.edu" ), "/~daw/people/crypto.html" },
/* 4 */ { TEXT( "pop.web.de:995" ), "/" },
/* 5 */ { TEXT( "imap4-gw.uni-regensburg.de:993" ), "/" },
/* 6 */ { TEXT( "securepop.t-online.de:995" ), "/" },
/* 7 */ { TEXT( "https://homedir.wlv.ac.uk" ), "/" },
/* 8 */ { TEXT( "https://www.horaso.com:20443" ), "/" },
/* 9 */ { TEXT( "https://homedir.wlv.ac.uk" ), "/" },
/* 10 */ { TEXT( "https://www.microsoft.com" ), "/" },
/* 11 */ { TEXT( "https://alphaworks.ibm.com/" ), "/" },
/* 12 */ { TEXT( "https://webmount.turbulent.ca/" ), "/" },
/* 13 */ { TEXT( "https://www.gnutls.org/" ), "/" },
/* 14 */ { TEXT( "https://www.gnutls.org:5555/" ), "/" },
/* 15 */ { TEXT( "https://www.networksolutions.com/" ), "/" },
/* 16 */ { TEXT( "https://olb.westpac.com.au/" ), "/" },
/* 17 */ { TEXT( "https://www.hertz.com/" ), "/" },
/* 18 */ { TEXT( "https://www.openssl.org/" ), "/" },
/* 19 */ { TEXT( "https://secureads.ft.com/" ), "/" },
/* 20 */ { TEXT( "https://mail.maine.edu/" ), "/" },
/* 21 */ { TEXT( "https://www.mikestoolbox.net:4433/" ), "/" },
/* 22 */ { TEXT( "https://test.gnutls.org:5556/" ), "/" },
{ NULL, NULL }
};
/* Various servers used for STARTTLS/STLS/AUTH TLS testing. Notes:
Server 1: SMTP: mailbox.ucsd.edu:25 (132.239.1.57) requires a client cert.
Server 2: POP: pop.cae.wisc.edu:1110 (144.92.240.11) OK.
Server 3: SMTP: smtpauth.cae.wisc.edu:25 (144.92.12.93) requires a client
cert.
Server 4: SMTP: send.columbia.edu:25 (128.59.59.23) returns invalid cert
(lower compliance level to fix).
Server 5: POP: pop3.myrealbox.com:110 (192.108.102.201) returns invalid
cert (lower compliance level to fix).
Server 6: Encrypted POP: securepop.t-online.de:995 (194.25.134.46) direct
SSL connect.
Server 7: FTP: ftp.windsorchapel.net:21 (68.38.166.195) sends redundant
client cert request with invalid length.
Server 8: POP: webmail.chm.tu-dresden.de:110 (141.30.198.37), another
GroupWise server (see the server comments above) with b0rken
certs.
To test FTP with SSL/TLS manually: Disable auto-login with FTP,
then send an RFC 2389 FEAT command to check security facilities.
If this is supported, one of the responses will be either
AUTH SSL or AUTH TLS, use this to turn on SSL/TLS. If FEAT
isn't supported, AUTH TLS should usually work:
ftp -n ftp.windsorchapel.net
quote feat
quote auth ssl
or just:
telnet ftp.windsorchapel.net 21
auth ssl
Server 9: SMTP: mailer.gwdg.de:25 (134.76.10.26), sends each SSL message
as a discrete packet, providing a nice test of cryptlib's on-
demand buffer refill.
Server 10: Encrypted POP: mrdo.vosn.net:995 (209.151.91.6), direct SSL
connect, sends a CA cert which is also used for encryption,
but with no keyUsage flags set.
Server 11: POP: pop.gmail.com:110 (64.233.167.111), convenient always-
available server */
#define STARTTLS_SERVER_NO 2
typedef enum { PROTOCOL_NONE, PROTOCOL_SMTP, PROTOCOL_POP,
PROTOCOL_IMAP, PROTOCOL_POP_DIRECT, PROTOCOL_FTP
} PROTOCOL_TYPE;
static const struct {
const C_STR name;
const int port;
PROTOCOL_TYPE protocol;
} FAR_BSS starttlsInfo[] = {
{ NULL, 0 },
/* 1 */ { TEXT( "132.239.1.57" ), 25, PROTOCOL_SMTP },
/* 2 */ { TEXT( "144.92.240.11" ), 1110, PROTOCOL_POP },
/* 3 */ { TEXT( "144.92.12.93" ), 25, PROTOCOL_SMTP },
/* 4 */ { TEXT( "128.59.59.23" ), 25, PROTOCOL_SMTP },
/* 5 */ { TEXT( "192.108.102.201" ), 110, PROTOCOL_POP },
/* 6 */ { TEXT( "194.25.134.46" ), 995, PROTOCOL_POP_DIRECT },
/* 7 */ { TEXT( "68.38.166.195" ), 21, PROTOCOL_FTP },
/* 8 */ { TEXT( "141.30.198.37" ), 110, PROTOCOL_POP },
/* 9 */ { TEXT( "134.76.10.26" ), 25, PROTOCOL_SMTP },
/* 10 */ { TEXT( "209.151.91.6" ), 995, PROTOCOL_POP_DIRECT },
/* 11 */ { TEXT( "64.233.167.111" ), 110, PROTOCOL_POP },
{ NULL, 0 }
};
/* If we're testing dual-thread handling of sessions, we need to provide a
forward declaration of the threading function since it's called from
within the SSL connect code */
#ifdef WINDOWS_THREADS
unsigned __stdcall tlsServerDualThread2( void *dummy );
#endif /* WINDOWS_THREADS */
/* Large buffer size to test bulk data transfer capability for secure
sessions */
#if defined( __MSDOS16__ ) || defined( __WIN16__ )
#define BULKDATA_BUFFER_SIZE 20000
#else
#define BULKDATA_BUFFER_SIZE 300000L
#endif /* 16-bit VC++ */
static int checksumData( const void *data, const int dataLength )
{
const BYTE *dataPtr = data;
int sum1 = 0, sum2 = 0, i;
/* Calculate a 16-bit Fletcher-like checksum of the data (it doesn't
really matter if it's not exactly right, as long as the behaviour is
the same for all data) */
for( i = 0; i < dataLength; i++ )
{
sum1 += dataPtr[ i ];
sum2 += sum1;
}
return( sum2 & 0xFFFF );
}
static BOOLEAN handleBulkBuffer( BYTE *buffer, const BOOLEAN isInit )
{
int checkSum, i;
/* If we're initialising the buffer, fill it with [0...256]* followed by
a checksum of the buffer contents */
if( isInit )
{
for( i = 0; i < BULKDATA_BUFFER_SIZE - 2; i++ )
buffer[ i ] = i & 0xFF;
checkSum = checksumData( buffer, BULKDATA_BUFFER_SIZE - 2 );
buffer[ BULKDATA_BUFFER_SIZE - 2 ] = ( checkSum >> 8 ) & 0xFF;
buffer[ BULKDATA_BUFFER_SIZE - 1 ] = checkSum & 0xFF;
return( TRUE );
}
/* We're being sent an initialised buffer, make sure that it's OK */
for( i = 0; i < BULKDATA_BUFFER_SIZE - 2; i++ )
if( buffer[ i ] != ( i & 0xFF ) )
return( FALSE );
checkSum = checksumData( buffer, BULKDATA_BUFFER_SIZE - 2 );
if( buffer[ BULKDATA_BUFFER_SIZE - 2 ] != ( ( checkSum >> 8 ) & 0xFF ) || \
buffer[ BULKDATA_BUFFER_SIZE - 1 ] != ( checkSum & 0xFF ) )
return( FALSE );
return( TRUE );
}
/* Negotiate through a STARTTLS */
#if defined( __WINDOWS__ ) && \
!( defined( __WIN16__ ) || defined( _WIN32_WCE ) )
static int readLine( SOCKET netSocket, char *buffer )
{
int bufPos, status = CRYPT_OK;
for( bufPos = 0; \
status >= 0 && bufPos < 1024 && \
( bufPos < 1 || buffer[ bufPos -1 ] != '\n' );
bufPos++ )
status = recv( netSocket, buffer + bufPos, 1, 0 );
while( bufPos > 1 && isspace( buffer[ bufPos - 1 ] ) )
bufPos--;
if( bufPos >= 3 )
{
while( bufPos > 1 && isspace( buffer[ bufPos - 1 ] ) )
bufPos--;
buffer[ min( bufPos, 56 ) ] = '\0';
}
return( bufPos );
}
static int negotiateSTARTTLS( int *protocol )
{
SOCKET netSocket;
struct sockaddr_in serverAddr;
char buffer[ 1024 ];
int bufPos, status;
puts( "Negotiating SMTP/POP/IMAP/FTP session through to TLS start..." );
*protocol = starttlsInfo[ STARTTLS_SERVER_NO ].protocol;
/* Connect to a generally-available server to test STARTTLS/STLS
functionality */
memset( &serverAddr, 0, sizeof( struct sockaddr_in ) );
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons( ( u_short ) starttlsInfo[ STARTTLS_SERVER_NO ].port );
serverAddr.sin_addr.s_addr = inet_addr( starttlsInfo[ STARTTLS_SERVER_NO ].name );
netSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( netSocket == INVALID_SOCKET )
{
printf( "Couldn't create socket, line %d.\n", __LINE__ );
return( CRYPT_ERROR_FAILED );
}
status = connect( netSocket, ( struct sockaddr * ) &serverAddr,
sizeof( struct sockaddr_in ) );
if( status == SOCKET_ERROR )
{
closesocket( netSocket );
printf( "Couldn't connect socket, line %d.\n", __LINE__ );
return( CRYPT_OK );
}
/* If it's a direct connect, there's nothing left to do */
if( *protocol == PROTOCOL_POP_DIRECT )
{
*protocol = PROTOCOL_POP;
return( netSocket );
}
/* Perform (very crude) SMTP/POP/IMAP negotiation to switch to TLS */
bufPos = readLine( netSocket, buffer );
if( bufPos < 3 || ( strncmp( buffer, "220", 3 ) && \
strncmp( buffer, "+OK", 3 ) && \
strncmp( buffer, "OK", 2 ) ) )
{
closesocket( netSocket );
printf( "Got response '%s', line %d.\n", buffer, __LINE__ );
return( CRYPT_OK );
}
printf( " Server said: '%s'\n", buffer );
assert( ( *protocol == PROTOCOL_SMTP && !strncmp( buffer, "220", 3 ) ) || \
( *protocol == PROTOCOL_POP && !strncmp( buffer, "+OK", 3 ) ) || \
( *protocol == PROTOCOL_IMAP && !strncmp( buffer, "OK", 2 ) ) || \
( *protocol == PROTOCOL_FTP && !strncmp( buffer, "220", 3 ) ) || \
*protocol == PROTOCOL_NONE );
switch( *protocol )
{
case PROTOCOL_POP:
send( netSocket, "STLS\r\n", 6, 0 );
puts( " We said: 'STLS'" );
break;
case PROTOCOL_IMAP:
/* It's possible for some servers that we may need to explicitly
send a CAPABILITY command first to enable STARTTLS:
a001 CAPABILITY
> CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED
> OK CAPABILITY completed */
send( netSocket, "a001 STARTTLS\r\n", 15, 0 );
puts( " We said: 'STARTTLS'" );
break;
case PROTOCOL_SMTP:
send( netSocket, "EHLO foo.bar.com\r\n", 18, 0 );
puts( " We said: 'EHLO foo.bar.com'" );
do
{
bufPos = readLine( netSocket, buffer );
if( bufPos < 3 || strncmp( buffer, "250", 3 ) )
{
closesocket( netSocket );
printf( "Got response '%s', line %d.\n", buffer,
__LINE__ );
return( CRYPT_OK );
}
printf( " Server said: '%s'\n", buffer );
}
while( !strncmp( buffer, "250-", 4 ) );
send( netSocket, "STARTTLS\r\n", 10, 0 );
puts( " We said: 'STARTTLS'" );
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -