📄 ssl.c
字号:
/****************************************************************************
* *
* cryptlib SSL v3/TLS Session Management *
* Copyright Peter Gutmann 1998-2003 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "session.h"
#include "ssl.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../session/session.h"
#include "../session/ssl.h"
#else
#include "crypt.h"
#include "session/session.h"
#include "session/ssl.h"
#endif /* Compiler-specific includes */
#ifdef USE_SSL
/****************************************************************************
* *
* 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 CHANGECIPHERSPEC_TEMPLATE_SIZE 6
#define FINISHED_TEMPLATE_SIZE 4
#define CLOSEALERT_TEMPLATE_SIZE 7
#define HANDSHAKEFAILALERT_TEMPLATE_SIZE 7
static const FAR_BSS SSL_MESSAGE_TEMPLATE changeCipherSpecTemplate = {
/* byte type = 20 (change cipherspec)
byte[2] version = { 0x03, 0x0n }
uint16 len = 1
byte 1 */
{ SSL_MSG_CHANGE_CIPHER_SPEC, SSL_MAJOR_VERSION, SSL_MINOR_VERSION_SSL, 0, 1, 1 },
{ SSL_MSG_CHANGE_CIPHER_SPEC, SSL_MAJOR_VERSION, SSL_MINOR_VERSION_TLS, 0, 1, 1 },
{ SSL_MSG_CHANGE_CIPHER_SPEC, SSL_MAJOR_VERSION, SSL_MINOR_VERSION_TLS11, 0, 1, 1 }
};
static const FAR_BSS SSL_MESSAGE_TEMPLATE finishedTemplate[] = {
/* byte ID = 0x14
uint24 len = 16 + 20 (SSL), 12 (TLS) */
{ SSL_HAND_FINISHED, 0, 0, MD5MAC_SIZE + SHA1MAC_SIZE },
{ SSL_HAND_FINISHED, 0, 0, TLS_HASHEDMAC_SIZE },
{ SSL_HAND_FINISHED, 0, 0, TLS_HASHEDMAC_SIZE },
};
static const FAR_BSS SSL_MESSAGE_TEMPLATE closeAlertTemplate[] = {
/* byte type = 21 (alert)
byte[2] version = { 0x03, 0x0n }
uint16 len = 2
byte level = 1 (warning)
byte description = 0 (close_notify) */
{ SSL_MSG_ALERT, SSL_MAJOR_VERSION, SSL_MINOR_VERSION_SSL, 0, 2,
SSL_ALERTLEVEL_WARNING, SSL_ALERT_CLOSE_NOTIFY },
{ SSL_MSG_ALERT, SSL_MAJOR_VERSION, SSL_MINOR_VERSION_TLS, 0, 2,
SSL_ALERTLEVEL_WARNING, SSL_ALERT_CLOSE_NOTIFY },
{ SSL_MSG_ALERT, SSL_MAJOR_VERSION, SSL_MINOR_VERSION_TLS11, 0, 2,
SSL_ALERTLEVEL_WARNING, SSL_ALERT_CLOSE_NOTIFY },
};
static const FAR_BSS SSL_MESSAGE_TEMPLATE handshakeFailAlertTemplate[] = {
/* byte type = 21 (alert)
byte[2] version = { 0x03, 0x0n }
uint16 len = 2
byte level = 2 (fatal)
byte description = 40 (handshake_failure) */
{ SSL_MSG_ALERT, SSL_MAJOR_VERSION, SSL_MINOR_VERSION_SSL, 0, 2,
SSL_ALERTLEVEL_FATAL, SSL_ALERT_HANDSHAKE_FAILURE },
{ SSL_MSG_ALERT, SSL_MAJOR_VERSION, SSL_MINOR_VERSION_TLS, 0, 2,
SSL_ALERTLEVEL_FATAL, SSL_ALERT_HANDSHAKE_FAILURE },
{ SSL_MSG_ALERT, SSL_MAJOR_VERSION, SSL_MINOR_VERSION_TLS11, 0, 2,
SSL_ALERTLEVEL_FATAL, SSL_ALERT_HANDSHAKE_FAILURE },
};
/* Set up the information implied by an SSL cipher suite */
int initCiphersuiteInfo( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
const int cipherSuite )
{
const CRYPT_ALGO_TYPE integrityAlgoMD5 = \
( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL ) ? \
CRYPT_ALGO_MD5 : CRYPT_ALGO_HMAC_MD5;
const CRYPT_ALGO_TYPE integrityAlgoSHA = \
( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL ) ? \
CRYPT_ALGO_SHA : CRYPT_ALGO_HMAC_SHA;
if( cipherSuite == TLS_RSA_WITH_AES_128_CBC_SHA || \
cipherSuite == TLS_RSA_WITH_AES_256_CBC_SHA )
{
sessionInfoPtr->cryptAlgo = CRYPT_ALGO_AES;
sessionInfoPtr->integrityAlgo = integrityAlgoSHA;
sessionInfoPtr->cryptBlocksize = 16;
handshakeInfo->cryptKeysize = \
( cipherSuite == TLS_RSA_WITH_AES_128_CBC_SHA ) ? 16 : 32;
sessionInfoPtr->authBlocksize = SHA1MAC_SIZE;
return( CRYPT_OK );
}
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 = 8;
sessionInfoPtr->authBlocksize = SHA1MAC_SIZE;
return( CRYPT_OK );
}
return( CRYPT_ERROR_NOTAVAIL );
}
/* Initialise and destroy the handshake state information */
static void destroyHandshakeInfo( SSL_HANDSHAKE_INFO *handshakeInfo )
{
/* Destroy any active contexts. We need to do this here (even though
it's also done in the general session code) to provide a clean exit in
case the session activation fails, so that a second activation attempt
doesn't overwrite still-active contexts */
if( handshakeInfo->clientMD5context != CRYPT_ERROR )
krnlSendNotifier( handshakeInfo->clientMD5context,
IMESSAGE_DECREFCOUNT );
if( handshakeInfo->serverMD5context != CRYPT_ERROR )
krnlSendNotifier( handshakeInfo->serverMD5context,
IMESSAGE_DECREFCOUNT );
if( handshakeInfo->clientSHA1context != CRYPT_ERROR )
krnlSendNotifier( handshakeInfo->clientSHA1context,
IMESSAGE_DECREFCOUNT );
if( handshakeInfo->serverSHA1context != CRYPT_ERROR )
krnlSendNotifier( handshakeInfo->serverSHA1context,
IMESSAGE_DECREFCOUNT );
zeroise( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) );
}
static int initHandshakeInfo( SSL_HANDSHAKE_INFO *handshakeInfo,
const BOOLEAN isServer )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
int status;
/* Initialise the handshake state info values */
memset( handshakeInfo, 0, sizeof( SSL_HANDSHAKE_INFO ) );
handshakeInfo->clientMD5context = \
handshakeInfo->serverMD5context = \
handshakeInfo->clientSHA1context = \
handshakeInfo->serverSHA1context = CRYPT_ERROR;
if( isServer )
initSSLserverProcessing( handshakeInfo );
else
initSSLclientProcessing( handshakeInfo );
/* Create the MAC/dual-hash contexts for incoming and outgoing data.
SSL uses a pre-HMAC variant for which we can't use real HMAC but have
to construct it ourselves from MD5 and SHA-1, TLS uses a straight dual
hash and MACs that once a MAC key is available */
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_MD5 );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusOK( status ) )
{
handshakeInfo->clientMD5context = createInfo.cryptHandle;
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_MD5 );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
}
if( cryptStatusOK( status ) )
{
handshakeInfo->serverMD5context = createInfo.cryptHandle;
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_SHA );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
}
if( cryptStatusOK( status ) )
{
handshakeInfo->clientSHA1context = createInfo.cryptHandle;
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_SHA );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
}
if( cryptStatusOK( status ) )
{
handshakeInfo->serverSHA1context = createInfo.cryptHandle;
return( CRYPT_OK );
}
/* One or more of the contexts couldn't be created, destroy all the
contexts that have been created so far */
destroyHandshakeInfo( handshakeInfo );
return( status );
}
/* Initialise and destroy the security contexts */
static void destroySecurityContexts( SESSION_INFO *sessionInfoPtr )
{
/* Destroy any active contexts */
if( sessionInfoPtr->iKeyexCryptContext != CRYPT_ERROR )
{
krnlSendNotifier( sessionInfoPtr->iKeyexCryptContext,
IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iKeyexCryptContext = CRYPT_ERROR;
}
if( sessionInfoPtr->iAuthInContext != CRYPT_ERROR )
{
krnlSendNotifier( sessionInfoPtr->iAuthInContext,
IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iAuthInContext = CRYPT_ERROR;
}
if( sessionInfoPtr->iAuthOutContext != CRYPT_ERROR )
{
krnlSendNotifier( sessionInfoPtr->iAuthOutContext,
IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iAuthOutContext = CRYPT_ERROR;
}
if( sessionInfoPtr->iCryptInContext != CRYPT_ERROR )
{
krnlSendNotifier( sessionInfoPtr->iCryptInContext,
IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCryptInContext = CRYPT_ERROR;
}
if( sessionInfoPtr->iCryptOutContext != CRYPT_ERROR )
{
krnlSendNotifier( sessionInfoPtr->iCryptOutContext,
IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCryptOutContext = CRYPT_ERROR;
}
}
static int initSecurityContexts( SESSION_INFO *sessionInfoPtr )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
int status;
setMessageCreateObjectInfo( &createInfo, sessionInfoPtr->integrityAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusOK( status ) )
{
sessionInfoPtr->iAuthInContext = createInfo.cryptHandle;
setMessageCreateObjectInfo( &createInfo, sessionInfoPtr->integrityAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
}
if( cryptStatusOK( status ) )
{
sessionInfoPtr->iAuthOutContext = createInfo.cryptHandle;
setMessageCreateObjectInfo( &createInfo, sessionInfoPtr->cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
}
if( cryptStatusOK( status ) )
{
sessionInfoPtr->iCryptInContext = createInfo.cryptHandle;
setMessageCreateObjectInfo( &createInfo, sessionInfoPtr->cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
}
if( cryptStatusOK( status ) )
sessionInfoPtr->iCryptOutContext = createInfo.cryptHandle;
else
/* One or more of the contexts couldn't be created, destroy all the
contexts that have been created so far */
destroySecurityContexts( sessionInfoPtr );
return( status );
}
/* Create the master secret from a shared secret value, typically a
password. The expandSharedSecret function uses a slightly different
coding style because it's taken directly from the RFC */
static void expandSharedSecret( BYTE *premaster_secret,
const BYTE *shared_secret,
const int shared_secret_length )
{
int premaster_index;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -