📄 ssl_svr.c
字号:
/****************************************************************************
* *
* cryptlib SSL v3/TLS Server Management *
* Copyright Peter Gutmann 1998-2008 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "crypt.h"
#include "misc_rw.h"
#include "session.h"
#include "ssl.h"
#else
#include "crypt.h"
#include "misc/misc_rw.h"
#include "session/session.h"
#include "session/ssl.h"
#endif /* Compiler-specific includes */
#ifdef USE_SSL
/****************************************************************************
* *
* Legacy SSLv2 Functions *
* *
****************************************************************************/
#if 0 /* 28/01/08 Disabled since it's now finally removed in MSIE and
Firefox */
/* Process an SSLv2 client hello:
uint16 suiteLen
uint16 sessIDlen
uint16 nonceLen
uint24[] suites
byte[] sessID
byte[] nonce
The v2 type and version have already been processed in readHSPacketSSL()
since this information, which is moved into the header in v3, is part of
the body in v2. What's left for the v2 hello is the remainder of the
payload */
static int processHelloSSLv2( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
STREAM *stream, int *resumedSessionID )
{
int suiteLength, sessionIDlength, nonceLength, status;
/* Clear return values */
*resumedSessionID = SCOREBOARD_UNIQUEID_NONE;
/* Read the SSLv2 hello */
suiteLength = readUint16( stream );
sessionIDlength = readUint16( stream );
nonceLength = readUint16( stream );
if( suiteLength < 3 || ( suiteLength % 3 ) != 0 || \
sessionIDlength < 0 || sessionIDlength > MAX_SESSIONID_SIZE || \
nonceLength < 16 || nonceLength > SSL_NONCE_SIZE )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid legacy SSLv2 hello packet" ) );
}
status = processCipherSuite( sessionInfoPtr, handshakeInfo, stream,
suiteLength / 3 );
if( cryptStatusError( status ) )
return( status );
if( sessionIDlength > 0 )
sSkip( stream, sessionIDlength );
return( sread( stream, handshakeInfo->clientNonce + \
SSL_NONCE_SIZE - nonceLength, nonceLength ) );
}
#endif /* 0 */
/****************************************************************************
* *
* Server-side Connect Functions *
* *
****************************************************************************/
/* Perform the initial part of the handshake with the client */
int beginServerHandshake( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo )
{
STREAM *stream = &handshakeInfo->stream;
MESSAGE_DATA msgData;
int length, resumedSessionID = SCOREBOARD_UNIQUEID_NONE;
int packetOffset, status;
/* Read the hello packet from the client */
status = readHSPacketSSL( sessionInfoPtr, handshakeInfo, &length,
SSL_MSG_FIRST_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
/* Process the client hello. Although this should be a v3 hello,
Netscape always sends a v2 hello (even if SSLv2 is disabled) and
in any case both MSIE and Mozilla still have SSLv2 enabled by
default (!!) so we have to process both types */
sMemConnect( stream, sessionInfoPtr->receiveBuffer, length );
#if 0 /* 28/01/08 Disabled since it's now finally removed in MSIE and
Firefox */
if( handshakeInfo->isSSLv2 )
status = processHelloSSLv2( sessionInfoPtr, handshakeInfo,
stream, &resumedSessionID );
else
#endif /* 0 */
status = processHelloSSL( sessionInfoPtr, handshakeInfo, stream,
TRUE );
sMemDisconnect( stream );
if( cryptStatusError( status ) && status != OK_SPECIAL )
return( status );
/* Handle session resumption */
if( status == OK_SPECIAL )
{
resumedSessionID = \
findScoreboardEntry( sessionInfoPtr->sessionSSL->scoreboardInfoPtr,
handshakeInfo->sessionID, handshakeInfo->sessionIDlength,
handshakeInfo->premasterSecret, SSL_SECRET_SIZE,
&handshakeInfo->premasterSecretSize );
}
if( resumedSessionID == SCOREBOARD_UNIQUEID_NONE )
{
/* It's a new session or the session data has expired from the
cache, generate a new session ID */
setMessageData( &msgData, handshakeInfo->sessionID, SESSIONID_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusError( status ) )
return( status );
handshakeInfo->sessionIDlength = SESSIONID_SIZE;
}
/* Get the nonce that's used to randomise all crypto ops and set up the
server DH context if necessary */
setMessageData( &msgData, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusOK( status ) && isKeyxAlgo( handshakeInfo->keyexAlgo ) )
{
status = initDHcontextSSL( &handshakeInfo->dhContext, NULL, 0,
( handshakeInfo->authAlgo != CRYPT_ALGO_NONE ) ? \
sessionInfoPtr->privateKey : CRYPT_UNUSED );
}
if( cryptStatusError( status ) )
return( status );
/* Build the server hello, cert, optional cert request, and done packets:
byte ID = SSL_HAND_SERVER_HELLO
uint24 len
byte[2] version = { 0x03, 0x0n }
uint32 time | Server nonce
byte[28] nonce |
byte sessIDlen
byte[] sessID
uint16 suite
byte copr = 0
... */
status = openPacketStreamSSL( stream, sessionInfoPtr, CRYPT_USE_DEFAULT,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
packetOffset = continueHSPacketStream( stream, SSL_HAND_SERVER_HELLO );
sputc( stream, SSL_MAJOR_VERSION );
sputc( stream, sessionInfoPtr->version );
swrite( stream, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
sputc( stream, handshakeInfo->sessionIDlength );
if( handshakeInfo->sessionIDlength > 0 )
swrite( stream, handshakeInfo->sessionID,
handshakeInfo->sessionIDlength );
writeUint16( stream, handshakeInfo->cipherSuite );
sputc( stream, 0 ); /* No compression */
#if 0
if( handshakeInfo->hasExtensions )
{
/* TLS extension code. Since almost no clients/servers (except maybe
some obscure bits of code embedded in cellphones) do this, we'll
have to wait for something that implements it to come along so we
can send back the appropriate response. The RFC makes the rather
optimistic assumption that implementations can handle the presence
of unexpected data at the end of the hello packet, since this is
rarely the case we leave the following disabled by default so as
not to confuse clients that leave some garbage at the end of their
client hello and suddenly get back an extension response from the
server */
writeUint16( stream, ID_SIZE + UINT16_SIZE + 1 );
writeUint16( stream, TLS_EXT_MAX_FRAGMENT_LENTH );
writeUint16( stream, 1 );
sputc( stream, 3 );
}
#endif /* 0 */
status = completeHSPacketStream( stream, packetOffset );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
/* If it's a resumed session, the server hello is followed immediately
by the change cipherspec, which is sent by the shared handshake
completion code */
if( resumedSessionID != SCOREBOARD_UNIQUEID_NONE )
{
status = completePacketStreamSSL( stream, 0 );
if( cryptStatusOK( status ) )
status = dualMacDataWrite( handshakeInfo, stream );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
return( OK_SPECIAL ); /* Tell caller that it's a resumed session */
}
/* ... (optional server supplemental data)
byte ID = SSL_HAND_SUPPLEMENTAL_DATA
uint24 len
uint16 type
uint16 len
byte[] value
... */
/* ...
(optional server cert chain)
... */
if( handshakeInfo->authAlgo != CRYPT_ALGO_NONE )
{
status = writeSSLCertChain( sessionInfoPtr, stream );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
}
/* ... (optional server keyex)
byte ID = SSL_HAND_SERVER_KEYEXCHANGE
uint24 len
uint16 dh_pLen
byte[] dh_p
uint16 dh_gLen
byte[] dh_g
uint16 dh_YsLen
byte[] dh_Ys
uint16 signatureLen
byte[] signature */
if( isKeyxAlgo( handshakeInfo->keyexAlgo ) )
{
KEYAGREE_PARAMS keyAgreeParams;
void *keyData = DUMMY_INIT_PTR;
int keyDataOffset, keyDataLength = DUMMY_INIT;
/* Perform phase 1 of the DH key agreement process */
memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
status = krnlSendMessage( handshakeInfo->dhContext,
IMESSAGE_CTX_ENCRYPT, &keyAgreeParams,
sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusError( status ) )
{
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
sMemDisconnect( stream );
return( status );
}
/* Write the DH key parameters and DH public value and sign them */
packetOffset = \
continueHSPacketStream( stream, SSL_HAND_SERVER_KEYEXCHANGE );
keyDataOffset = stell( stream );
status = exportAttributeToStream( stream, handshakeInfo->dhContext,
CRYPT_IATTRIBUTE_KEY_SSL );
if( cryptStatusOK( status ) )
status = writeInteger16U( stream, keyAgreeParams.publicValue,
keyAgreeParams.publicValueLen );
if( cryptStatusOK( status ) )
{
keyDataLength = stell( stream ) - keyDataOffset;
status = sMemGetDataBlockAbs( stream, keyDataOffset, &keyData,
keyDataLength );
}
if( cryptStatusOK( status ) )
{
status = createKeyexSignature( sessionInfoPtr, handshakeInfo,
stream, keyData, keyDataLength );
}
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusOK( status ) )
status = completeHSPacketStream( stream, packetOffset );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
}
/* ... (optional client cert request)
byte ID = SSL_HAND_SERVER_CERTREQUEST
uint24 len
byte certTypeLen = 2
byte[2] certType = { 0x01, 0x02 } (RSA,DSA)
uint16 caNameListLen = 4
uint16 caNameLen = 2
byte[] caName = { 0x30, 0x00 }
... */
if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
{
packetOffset = \
continueHSPacketStream( stream, SSL_HAND_SERVER_CERTREQUEST );
sputc( stream, 2 );
swrite( stream, "\x01\x02", 2 );
writeUint16( stream, 4 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -