📄 ssl.c
字号:
/****************************************************************************
* *
* cryptlib SSL v3/TLS Session Management *
* Copyright Peter Gutmann 1998-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "stream.h"
#include "session.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../keymgmt/stream.h"
#include "../session/session.h"
#else
#include "crypt.h"
#include "keymgmt/stream.h"
#include "session/session.h"
#endif /* Compiler-specific includes */
/* Default SSL port */
#define SSL_PORT 443
/* SSL constants */
#define ID_SIZE 1 /* ID byte */
#define UINT16_SIZE 2 /* 16 bits */
#define LENGTH_SIZE 3 /* 24 bits */
#define VERSIONINFO_SIZE 2 /* 0x03, 0x0n */
#define ALERTINFO_SIZE 2 /* level + description */
#define SSL_HEADER_SIZE 5 /* Type, version, length */
#define SSL_NONCE_SIZE 32 /* Size of client/svr nonce */
#define SSL_SECRET_SIZE 48 /* Size of premaster/master secret */
#define MIN_SSL_PACKET_SIZE 4 /* Server hello done */
#define MAX_KEYBLOCK_SIZE ( ( 20 + 24 + 8 ) * 2 ) /* 3DES + SHA-1 */
#define MD5MAC_SIZE 16 /* Size of MD5 proto-HMAC */
#define SHA1MAC_SIZE 20 /* Size of SHA-1 proto-HMAC */
#define TLS_HASHEDMAC_SIZE 12 /* Size of TLS PRF( MD5 + SHA1 ) */
#define APPLICATION_DATA_OFFSET ( 3 * SSL_HEADER_SIZE )
/* Start of app.data in packet */
/* Default SSL send/receive buffer size */
#define BUFFER_SIZE ( 16384 + 64 )
/* Maximum SSL header size, used to determine how much space we need to
reserve at the start of the buffer when encoding data packets */
#define MAX_HEADER_SIZE ( SSL_HEADER_SIZE * 3 )
/* SSL message types */
#define SSL_MSG_CHANGE_CIPHER_SPEC 20
#define SSL_MSG_ALERT 21
#define SSL_MSG_HANDSHAKE 22
#define SSL_MSG_APPLICATION_DATA 23
#define SSL_MSG_FIRST 20
#define SSL_MSG_LAST 23
/* Special-case expected-packet-type values which are passed to readPacket()
to handle situations where more than one return value is valid (the client
handshake is supposed to be a v3 handshake but is usually a hacked v2 one
with forwards-compatibility kludges, since this looks nothing like a
normal v3 packet we have to treat is specially) */
#define SSL_MSG_SPECIAL_HANDSHAKE 0x80
/* SSL handshake message subtypes */
#define SSL_HAND_CLIENT_HELLO 0x01
#define SSL_HAND_SERVER_HELLO 0x02
#define SSL_HAND_SERVER_CERT 0x0B
#define SSL_HAND_SERVER_HELLODONE 0x0E
#define SSL_HAND_SERVER_CERTREQUEST 0x0D
#define SSL_HAND_CLIENT_CERTVERIFY 0x0F
#define SSL_HAND_CLIENT_KEYEXCHANGE 0x10
#define SSL_HAND_FINISHED 0x14
/* SSL alert levels and types */
#define SSL_ALERTLEVEL_WARNING 1
#define SSL_ALERTLEVEL_FATAL 2
#define SSL_ALERT_CLOSE_NOTIFY 0
#define SSL_ALERT_UNEXPECTED_MESSAGE 10
#define SSL_ALERT_BAD_RECORD_MAC 20
#define TLS_ALERT_DECRYPTION_FAILED 21
#define TLS_ALERT_RECORD_OVERFLOW 22
#define SSL_ALERT_DECOMPRESSION_FAILURE 30
#define SSL_ALERT_HANDSHAKE_FAILURE 40
#define SSL_ALERT_NO_CERTIFICATE 41
#define SSL_ALERT_BAD_CERTIFICATE 42
#define SSL_ALERT_UNSUPPORTED_CERTIFICATE 43
#define SSL_ALERT_CERTIFICATE_REVOKED 44
#define SSL_ALERT_CERTIFICATE_EXPIRED 45
#define SSL_ALERT_CERTIFICATE_UNKNOWN 46
#define SSL_ALERT_ILLEGAL_PARAMETER 47
#define TLS_ALERT_UNKNOWN_CA 48
#define TLS_ALERT_ACCESS_DENIED 49
#define TLS_ALERT_DECODE_ERROR 50
#define TLS_ALERT_DECRYPT_ERROR 51
#define TLS_ALERT_EXPORT_RESTRICTION 60
#define TLS_ALERT_PROTOCOL_VERSION 70
#define TLS_ALERT_INSUFFICIENT_SECURITY 71
#define TLS_ALERT_INTERNAL_ERROR 80
#define TLS_ALERT_USER_CANCELLED 90
#define TLS_ALERT_NO_RENEGOTIATION 100
/* SSL cipher suites */
typedef enum {
SSL_NULL_WITH_NULL, SSL_RSA_WITH_NULL_MD5, SSL_RSA_WITH_NULL_SHA,
SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_WITH_RC4_128_MD5,
SSL_RSA_WITH_RC4_128_SHA, SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
SSL_RSA_WITH_IDEA_CBC_SHA, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,
SSL_RSA_WITH_DES_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA,
SSL_LAST } SSL_CIPHERSUITE_TYPE;
/* SSL and TLS major and minor version numbers */
#define SSL_MAJOR_VERSION 3
#define SSL_MINOR_VERSION 0
#define TLS_MINOR_VERSION 1
/* SSL sender label values for the finished message MAC */
#define SSL_SENDER_CLIENTLABEL "CLNT"
#define SSL_SENDER_SERVERLABEL "SRVR"
#define SSL_SENDERLABEL_SIZE 4
/* Proto-HMAC padding data */
#define PROTOHMAC_PAD1 "\x36\x36\x36\x36\x36\x36\x36\x36" \
"\x36\x36\x36\x36\x36\x36\x36\x36" \
"\x36\x36\x36\x36\x36\x36\x36\x36" \
"\x36\x36\x36\x36\x36\x36\x36\x36" \
"\x36\x36\x36\x36\x36\x36\x36\x36" \
"\x36\x36\x36\x36\x36\x36\x36\x36"
#define PROTOHMAC_PAD2 "\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C"
/* SSL handshake state information. This is passed around various
subfunctions which handle individual parts of the handshake */
typedef struct {
/* Client and server proto-HMAC contexts */
CRYPT_CONTEXT clientMD5context, clientSHA1context;
CRYPT_CONTEXT serverMD5context, serverSHA1context;
/* Client and server nonces */
BYTE clientNonce[ SSL_NONCE_SIZE ], serverNonce[ SSL_NONCE_SIZE ];
/* Premaster secret */
BYTE premasterSecret[ SSL_SECRET_SIZE ];
/* Other info */
int cryptKeysize; /* Size of session key */
} SSL_HANDSHAKE_INFO;
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Most of the SSL packets have fixed formats, so we can construct them by
copying in a constant template and setting up the variable fields. The
following templates are for various packet types */
#define SERVERHELLODONE_TEMPLATE_SIZE 4
#define SERVERCERTREQUEST_TEMPLATE_SIZE 13
#define CHANGECIPHERSPEC_TEMPLATE_SIZE 6
#define FINISHED_TEMPLATE_SIZE 4
#define CLOSEALERT_TEMPLATE_SIZE 7
#define HANDSHAKEFAILALERT_TEMPLATE_SIZE 7
#define NOCERTALERT_TEMPLATE_SIZE 7
#define NOCERT_TEMPLATE_SIZE 7
static const BYTE serverHelloDoneTemplate[] = {
SSL_HAND_SERVER_HELLODONE, /* ID */
0, 0, 0 /* Length */
};
static const BYTE serverCertRequestTemplate[] = {
SSL_HAND_SERVER_CERTREQUEST, /* ID */
0, 0, 9, /* Length */
2, /* Cert type length */
1, 2, /* RSA, DSA */
0, 4, /* CA name list length */
0, 2, /* CA name length */
0x30, 0x00 /* CA name */
};
static const BYTE changeCipherSpecSSLTemplate[] = {
SSL_MSG_CHANGE_CIPHER_SPEC, /* ID */
SSL_MAJOR_VERSION, SSL_MINOR_VERSION, /* Version */
0, 1, /* Length */
1 /* Data */
};
static const BYTE changeCipherSpecTLSTemplate[] = {
SSL_MSG_CHANGE_CIPHER_SPEC, /* ID */
SSL_MAJOR_VERSION, TLS_MINOR_VERSION, /* Version */
0, 1, /* Length */
1 /* Data */
};
static const BYTE finishedSSLTemplate[] = {
SSL_HAND_FINISHED, /* ID */
0, 0, MD5MAC_SIZE + SHA1MAC_SIZE /* Length */
};
static const BYTE finishedTLSTemplate[] = {
SSL_HAND_FINISHED, /* ID */
0, 0, TLS_HASHEDMAC_SIZE /* Length */
};
static const BYTE closeAlertSSLTemplate[] = {
SSL_MSG_ALERT, /* ID */
SSL_MAJOR_VERSION, SSL_MINOR_VERSION, /* Version */
0, 2, /* Length */
SSL_ALERTLEVEL_WARNING, SSL_ALERT_CLOSE_NOTIFY
};
static const BYTE closeAlertTLSTemplate[] = {
SSL_MSG_ALERT, /* ID */
SSL_MAJOR_VERSION, TLS_MINOR_VERSION, /* Version */
0, 2, /* Length */
SSL_ALERTLEVEL_WARNING, SSL_ALERT_CLOSE_NOTIFY
};
static const BYTE handshakeFailAlertSSLTemplate[] = {
SSL_MSG_ALERT, /* ID */
SSL_MAJOR_VERSION, SSL_MINOR_VERSION, /* Version */
0, 2, /* Length */
SSL_ALERTLEVEL_FATAL, SSL_ALERT_HANDSHAKE_FAILURE
};
static const BYTE handshakeFailAlertTLSTemplate[] = {
SSL_MSG_ALERT, /* ID */
SSL_MAJOR_VERSION, TLS_MINOR_VERSION, /* Version */
0, 2, /* Length */
SSL_ALERTLEVEL_FATAL, SSL_ALERT_HANDSHAKE_FAILURE
};
static const BYTE noCertAlertSSLTemplate[] = {
SSL_MSG_ALERT, /* ID */
SSL_MAJOR_VERSION, SSL_MINOR_VERSION, /* Version */
0, 2, /* Length */
SSL_ALERTLEVEL_WARNING, SSL_ALERT_NO_CERTIFICATE
};
static const BYTE noCertTLSTemplate[] = {
SSL_HAND_SERVER_CERT, /* ID */
0, 0, 3, /* Length */
0, 0, 0 /* Cert list length */
};
/* Set up the information implied by an SSL cipher suite */
static int initCiphersuiteInfo( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
const int cipherSuite )
{
const CRYPT_ALGO integrityAlgoMD5 = \
( sessionInfoPtr->version == CRYPT_PROTOCOLVERSION_SSL ) ? \
CRYPT_ALGO_MD5 : CRYPT_ALGO_HMAC_MD5;
const CRYPT_ALGO integrityAlgoSHA = \
( sessionInfoPtr->version == CRYPT_PROTOCOLVERSION_SSL ) ? \
CRYPT_ALGO_SHA : CRYPT_ALGO_HMAC_SHA;
if( cipherSuite == SSL_RSA_WITH_3DES_EDE_CBC_SHA )
{
sessionInfoPtr->cryptAlgo = CRYPT_ALGO_3DES;
sessionInfoPtr->integrityAlgo = integrityAlgoSHA;
sessionInfoPtr->cryptBlocksize = 8;
handshakeInfo->cryptKeysize = 24;
sessionInfoPtr->authBlocksize = SHA1MAC_SIZE;
return( CRYPT_OK );
}
if( cipherSuite == SSL_RSA_WITH_RC4_128_SHA )
{
sessionInfoPtr->cryptAlgo = CRYPT_ALGO_RC4;
sessionInfoPtr->integrityAlgo = integrityAlgoSHA;
sessionInfoPtr->cryptBlocksize = 1;
handshakeInfo->cryptKeysize = 16;
sessionInfoPtr->authBlocksize = SHA1MAC_SIZE;
return( CRYPT_OK );
}
if( cipherSuite == SSL_RSA_WITH_RC4_128_MD5 )
{
sessionInfoPtr->cryptAlgo = CRYPT_ALGO_RC4;
sessionInfoPtr->integrityAlgo = integrityAlgoMD5;
sessionInfoPtr->cryptBlocksize = 1;
handshakeInfo->cryptKeysize = 16;
sessionInfoPtr->authBlocksize = MD5MAC_SIZE;
return( CRYPT_OK );
}
if( cipherSuite == SSL_RSA_WITH_IDEA_CBC_SHA )
{
sessionInfoPtr->cryptAlgo = CRYPT_ALGO_IDEA;
sessionInfoPtr->integrityAlgo = integrityAlgoSHA;
sessionInfoPtr->cryptBlocksize = 8;
handshakeInfo->cryptKeysize = 16;
sessionInfoPtr->authBlocksize = SHA1MAC_SIZE;
return( CRYPT_OK );
}
if( cipherSuite == SSL_RSA_WITH_DES_CBC_SHA )
{
sessionInfoPtr->cryptAlgo = CRYPT_ALGO_DES;
sessionInfoPtr->integrityAlgo = integrityAlgoSHA;
sessionInfoPtr->cryptBlocksize = 8;
handshakeInfo->cryptKeysize = 64;
sessionInfoPtr->authBlocksize = SHA1MAC_SIZE;
return( CRYPT_OK );
}
return( CRYPT_ERROR_NOTAVAIL );
}
/* Choose the best cipher suite from a list of suites */
const int chooseCipherSuite( const BYTE *suitePtr, const int noSuites,
const BOOLEAN isV2 )
{
int suite = SSL_NULL_WITH_NULL, i;
for( i = 0; i < noSuites; i++ )
{
int ch, currentSuite;
/* Get the cipher suite info, if it's a v2 suite (the high byte is
nonzero), skip it and continue */
if( isV2 )
ch = *suitePtr++;
currentSuite = mgetBWord( suitePtr );
if( isV2 && ch )
continue;
/* Pick out the best suite available. The order is 3DES, IDEA,
RC4/128, DES */
switch( currentSuite )
{
case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
if( algoAvailable( CRYPT_ALGO_3DES ) )
suite = currentSuite;
break;
case SSL_RSA_WITH_IDEA_CBC_SHA:
if( suite != SSL_RSA_WITH_3DES_EDE_CBC_SHA && \
algoAvailable( CRYPT_ALGO_IDEA ) )
suite = currentSuite;
break;
case SSL_RSA_WITH_RC4_128_MD5:
case SSL_RSA_WITH_RC4_128_SHA:
if( suite != SSL_RSA_WITH_3DES_EDE_CBC_SHA && \
suite != SSL_RSA_WITH_IDEA_CBC_SHA && \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -