📄 ssl_svr.c
字号:
length > 0 && !handshakeInfo->sessionID[ length - 1 ];
length-- ); /* Strip zero-padding */
updateSessionAttribute( &sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME,
handshakeInfo->sessionID, length,
CRYPT_MAX_TEXTSIZE, ATTR_FLAG_NONE );
resumedSessionID = -resumedSessionID; /* Fix ID polarity */
}
#endif /* 0 */
}
else
{
/* 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 );
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
... */
openPacketStreamSSL( stream, sessionInfoPtr, CRYPT_USE_DEFAULT,
SSL_MSG_HANDSHAKE );
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 */
completeHSPacketStream( stream, packetOffset );
/* 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 != 0 )
{
completePacketStreamSSL( stream, 0 );
dualMacData( handshakeInfo, stream, FALSE );
return( OK_SPECIAL ); /* Tell caller it's a resumed session */
}
/* ...
(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;
const void *keyData;
int keyDataOffset;
/* 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 );
keyData = sMemBufPtr( stream );
keyDataOffset = stell( stream );
status = exportAttributeToStream( stream, handshakeInfo->dhContext,
CRYPT_IATTRIBUTE_KEY_SSL,
CRYPT_USE_DEFAULT );
if( cryptStatusOK( status ) )
{
writeInteger16U( stream, keyAgreeParams.publicValue,
keyAgreeParams.publicValueLen );
status = createKeyexSignature( sessionInfoPtr, handshakeInfo,
stream, keyData,
stell( stream ) - keyDataOffset );
}
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
completeHSPacketStream( stream, packetOffset );
}
/* ... (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 );
writeUint16( stream, 2 );
swrite( stream, "\x30\x00", 2 );
completeHSPacketStream( stream, packetOffset );
}
/* ...
byte ID = SSL_HAND_SERVER_HELLODONE
uint24 len = 0 */
packetOffset = \
continueHSPacketStream( stream, SSL_HAND_SERVER_HELLODONE );
completeHSPacketStream( stream, packetOffset );
/* Send the combined server packets to the client. We perform the dual
MAC'ing of the packets in between the network ops where it's
effectively free */
status = sendPacketSSL( sessionInfoPtr, stream, FALSE );
dualMacData( handshakeInfo, stream, FALSE );
sMemDisconnect( stream );
return( status );
}
/* Exchange keys with the client */
int exchangeServerKeys( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo )
{
STREAM *stream = &handshakeInfo->stream;
int length, status;
/* Read the response from the client and, if we're expecting a client
cert, make sure that it's present */
length = readPacketSSL( sessionInfoPtr, handshakeInfo,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( length ) )
return( length );
sMemConnect( stream, sessionInfoPtr->receiveBuffer, length );
if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
{
MESSAGE_KEYMGMT_INFO getkeyInfo;
RESOURCE_DATA msgData;
BYTE certID[ KEYID_SIZE + 8 ];
int status;
/* Process the client cert chain */
status = readSSLCertChain( sessionInfoPtr, handshakeInfo,
stream, &sessionInfoPtr->iKeyexAuthContext,
TRUE );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
/* Make sure that the client cert is present in our cert store.
Since we've already got a copy of the cert, we only do a presence
check rather than actually fetching the cert */
setMessageData( &msgData, certID, KEYID_SIZE );
status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_FINGERPRINT_SHA );
if( cryptStatusOK( status ) )
{
setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID, certID,
KEYID_SIZE, NULL, 0,
KEYMGMT_FLAG_CHECK_ONLY );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_GETKEY, &getkeyInfo,
KEYMGMT_ITEM_PUBLICKEY );
}
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
"Client certificate is not trusted for client "
"authentication" );
}
/* Read the next packet(s) if necessary */
status = refreshHSStream( sessionInfoPtr, handshakeInfo );
if( cryptStatusError( status ) )
return( status );
}
/* Process the client key exchange packet:
byte ID = SSL_HAND_CLIENT_KEYEXCHANGE
uint24 len
DH:
uint16 yLen
byte[] y
PSK:
uint16 userIDLen
byte[] userID
RSA:
[ uint16 encKeyLen - TLS only ]
byte[] rsaPKCS1( byte[2] { 0x03, 0x0n } || byte[46] random ) */
length = checkHSPacketHeader( sessionInfoPtr, stream,
SSL_HAND_CLIENT_KEYEXCHANGE,
UINT16_SIZE + 1 );
if( cryptStatusError( length ) )
{
sMemDisconnect( stream );
return( length );
}
if( isKeyxAlgo( handshakeInfo->keyexAlgo ) )
{
KEYAGREE_PARAMS keyAgreeParams;
memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
status = readInteger16U( stream, keyAgreeParams.publicValue,
&keyAgreeParams.publicValueLen,
bitsToBytes( MIN_PKCSIZE_BITS ),
CRYPT_MAX_PKCSIZE );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid DH key agreement data" );
}
/* Perform phase 2 of the DH key agreement */
status = krnlSendMessage( handshakeInfo->dhContext,
IMESSAGE_CTX_DECRYPT, &keyAgreeParams,
sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusError( status ) )
{
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
sMemDisconnect( stream );
return( status );
}
memcpy( handshakeInfo->premasterSecret, keyAgreeParams.wrappedKey,
keyAgreeParams.wrappedKeyLen );
handshakeInfo->premasterSecretSize = keyAgreeParams.wrappedKeyLen;
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
}
else
if( handshakeInfo->authAlgo == CRYPT_ALGO_NONE )
{
BYTE userID[ CRYPT_MAX_TEXTSIZE + 8 ];
/* Read the client user ID and remember it for later */
length = readUint16( stream );
if( length < 1 || length > CRYPT_MAX_TEXTSIZE || \
cryptStatusError( sread( stream, userID, length ) ) )
{
sMemDisconnect( stream );
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid client user ID" );
}
updateSessionAttribute( &sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME,
handshakeInfo->sessionID, length,
CRYPT_MAX_TEXTSIZE, ATTR_FLAG_NONE );
/* Create the shared premaster secret from the user password */
status = createSharedPremasterSecret( \
handshakeInfo->premasterSecret,
&handshakeInfo->premasterSecretSize,
sessionInfoPtr );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't create SSL master secret from shared "
"secret/password value" );
}
else
{
BYTE wrappedKey[ CRYPT_MAX_PKCSIZE + 8 ];
if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
{
/* The original Netscape SSL implementation didn't provide a
length for the encrypted key and everyone copied that so
it became the de facto standard way to do it (Sic faciunt
omnes. The spec itself is ambiguous on the topic). This
was fixed in TLS (although the spec is still ambigous) so
the encoding differs slightly between SSL and TLS */
if( length < bitsToBytes( MIN_PKCSIZE_BITS ) || \
length > CRYPT_MAX_PKCSIZE || \
cryptStatusError( sread( stream, wrappedKey, length ) ) )
status = CRYPT_ERROR_BADDATA;
}
else
status = readInteger16U( stream, wrappedKey, &length,
bitsToBytes( MIN_PKCSIZE_BITS ),
CRYPT_MAX_PKCSIZE );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid RSA encrypted key data" );
}
/* Decrypt the pre-master secret */
status = unwrapPremasterSecret( sessionInfoPtr, handshakeInfo,
wrappedKey, length );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
}
/* If we're expecting a client cert, process the client cert verify */
if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
{
/* Read the next packet(s) if necessary */
status = refreshHSStream( sessionInfoPtr, handshakeInfo );
if( cryptStatusError( status ) )
return( status );
/* Process the client cert verify packet:
byte ID = SSL_HAND_CLIENT_CERTVERIFY
uint24 len
byte[] signature */
length = checkHSPacketHeader( sessionInfoPtr, stream,
SSL_HAND_CLIENT_CERTVERIFY,
bitsToBytes( MIN_PKCSIZE_BITS ) );
if( cryptStatusError( length ) )
{
sMemDisconnect( stream );
return( length );
}
status = checkCertVerify( sessionInfoPtr, handshakeInfo, stream,
length );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
}
sMemDisconnect( stream );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Session Access Routines *
* *
****************************************************************************/
void initSSLserverProcessing( SSL_HANDSHAKE_INFO *handshakeInfo )
{
handshakeInfo->beginHandshake = beginServerHandshake;
handshakeInfo->exchangeKeys = exchangeServerKeys;
}
#endif /* USE_SSL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -