📄 ssl_svr.c
字号:
/* Build the server hello, cert, optional cert request, and done packets:
byte ID = 2
uint24 len
byte[2] version = { 0x03, 0x0n }
uint32 time | Server nonce
byte[28] nonce |
byte sessIDlen
byte[] sessID
uint16 suite
byte copr = 0
... */
setMessageData( &msgData, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusError( status ) )
return( status );
bufPtr = sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufStartOfs;
*bufPtr++ = SSL_HAND_SERVER_HELLO;
*bufPtr++ = 0;
lengthPtr = bufPtr; /* Low 16 bits of length */
bufPtr += LENGTH_SIZE - 1;
*bufPtr++ = SSL_MAJOR_VERSION;
*bufPtr++ = sessionInfoPtr->version;
memcpy( bufPtr, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
bufPtr += SSL_NONCE_SIZE;
*bufPtr++ = handshakeInfo->sessionIDlength;
memcpy( bufPtr, handshakeInfo->sessionID,
handshakeInfo->sessionIDlength );
bufPtr += handshakeInfo->sessionIDlength;
mputWord( bufPtr, handshakeInfo->cipherSuite );
*bufPtr++ = 0; /* No compression */
if( isExtendedHello )
{
#if 0 /* TLS extension code. Since no known 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 */
mputWord( bufPtr, ID_SIZE + UINT16_SIZE + 1 );
*bufPtr++ = TLS_EXT_MAX_FRAGMENT_LENTH;
mputWord( bufPtr, 1 );
*bufPtr++ = 3;
#endif /* 0 */
}
length = bufPtr - \
( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufStartOfs );
mputWord( lengthPtr, length - ( ID_SIZE + LENGTH_SIZE ) );
/* If it's not a resumed session, write the server and optional client
cert information and server hello done */
if( !resumedSessionID )
{
/* ...
(server cert chain)
... */
status = writeSSLCertChain( sessionInfoPtr, bufPtr );
if( cryptStatusError( status ) )
return( status );
bufPtr += status;
/* ... ( optional client cert request)
byte ID = 0x0D
uint24 len = 7
byte certTypeLen = 2
byte[2] certType = { 0x01, 0x02 }
uint16 caNameListLen = 4
uint16 caNameLen = 2
byte[] caName = { 0x30, 0x00 }
... */
if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
{
memcpy( bufPtr, serverCertRequestTemplate,
SERVERCERTREQUEST_TEMPLATE_SIZE );
bufPtr += SERVERCERTREQUEST_TEMPLATE_SIZE;
}
/* ...
byte ID = 0x0E
uint24 len = 0 */
memcpy( bufPtr, serverHelloDoneTemplate,
SERVERHELLODONE_TEMPLATE_SIZE );
bufPtr += SERVERHELLODONE_TEMPLATE_SIZE;
}
/* Send the combined server packets to the client. We perform the dual
MAC'ing of the client hello in between the network ops where it's
effectively free */
length = bufPtr - \
( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufStartOfs );
wrapHandshakePacket( sessionInfoPtr->sendBuffer, length,
sessionInfoPtr->version );
status = swrite( &sessionInfoPtr->stream, sessionInfoPtr->sendBuffer,
sessionInfoPtr->sendBufStartOfs + length );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
return( status );
}
dualMacData( handshakeInfo, sessionInfoPtr->sendBuffer + \
sessionInfoPtr->sendBufStartOfs, length );
return( resumedSessionID ? OK_SPECIAL : CRYPT_OK );
}
/* Exchange keys with the client */
int exchangeServerKeys( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo )
{
MECHANISM_WRAP_INFO mechanismInfo;
BYTE *bufPtr;
int length, status;
/* Read the response from the client and, if we're expecting a client
cert, make sure that it's present */
status = readPacketSSL( sessionInfoPtr, handshakeInfo,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
bufPtr = sessionInfoPtr->receiveBuffer;
if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
MESSAGE_KEYMGMT_INFO getkeyInfo;
RESOURCE_DATA msgData;
BYTE certID[ KEYID_SIZE ];
int chainLength;
/* Make sure that the client has sent us a cert chain */
length = checkPacketHeader( sessionInfoPtr, &bufPtr,
SSL_HAND_CERTIFICATE, 64, 0 );
if( cryptStatusError( length ) )
return( length );
if( length == 0 || length == 3 )
{
/* SSLv3 sent an SSL_ALERT_NO_CERTIFICATE alert to indicate that
the client doesn't have a cert, which is handled by the
readPacketSSL() call. TLS changed this to send an empty cert
packet instead, supposedly because it lead to implementation
problems (presumably it's necessary to create a state machine-
based implementation to reproduce these problems, whatever
they are). The spec is ambiguous as to what constitutes an
empty packet, it could be either a packet with a length of
zero or a packet containing a zero-length cert list so we
check for both. We also fake the error indicators for
consistency with the status obtained from an SSLv3 no-cert
alert */
sessionInfoPtr->errorCode = SSL_ALERT_NO_CERTIFICATE;
retExt( sessionInfoPtr, CRYPT_ERROR_PERMISSION,
( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL ) ? \
"Received SSL alert message: No certificate" : \
"Received TLS alert message: No certificate" );
}
chainLength = mgetWord( bufPtr );
if( chainLength < 64 || LENGTH_SIZE + chainLength != length )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid client cert chain length %d", chainLength );
/* Import the cert chain. This isn't a true cert chain (in the sense
of being degenerate PKCS #7 SignedData) but a special-case SSL-
encoded cert chain */
setMessageCreateObjectIndirectInfo( &createInfo, bufPtr, chainLength,
CRYPT_ICERTTYPE_SSL_CERTCHAIN );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
bufPtr += chainLength;
sessionInfoPtr->iKeyexAuthContext = createInfo.cryptHandle;
/* Make sure that the cert is valid for signing data, which the
client will need to do when it authenticates itself */
status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext,
IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_SIGCHECK );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
"Client supplied a certificate that can't be used for "
"client authentication" );
/* 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 ) )
retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
"Client certificate is not trusted for client "
"authentication" );
/* Read the next packet(s) if necessary */
if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
{
status = readPacketSSL( sessionInfoPtr, handshakeInfo,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
bufPtr = sessionInfoPtr->receiveBuffer;
}
}
/* Process the client key exchange packet:
byte ID = 0x10
uint24 len
RSA:
[ uint16 encKeyLen - TLS only ]
byte[] rsaPKCS1( byte[2] { 0x03, 0x0n } || byte[46] random )
DH:
uint16 yLen
byte[] y */
length = checkPacketHeader( sessionInfoPtr, &bufPtr,
SSL_HAND_CLIENT_KEYEXCHANGE, 64,
CRYPT_UNUSED );
if( cryptStatusError( length ) )
return( length );
if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
{
int innerLength;
/* 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 */
innerLength = mgetWord( bufPtr );
if( UINT16_SIZE + innerLength != length )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid encrypted key length %d vs.inner length %d",
length, innerLength );
length = innerLength;
}
if( length < bitsToBytes( MIN_PKCSIZE_BITS ) || \
length > CRYPT_MAX_PKCSIZE )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid encrypted key length %d", length );
/* Decrypt the encrypted premaster secret and make sure that it looks OK.
Note that the version that we check for at this point is the version
originally offered by the client in its hello message, not the version
eventually negotiated for the connection. This is designed to prevent
rollback attacks. In theory we could explicitly defend against
Bleichenbacher-type attacks at this point by setting the premaster
secret to a pseudorandom value if we get a bad data or incorrect
version error and continuing as normal, however the attack depends on
the server returning information required to pinpoint the cause of
the failure and cryptlib just returns a generic "failed" response for
any handshake failure, so this explicit defence isn't really
necessary */
setMechanismWrapInfo( &mechanismInfo, bufPtr, length,
handshakeInfo->premasterSecret, SSL_SECRET_SIZE,
CRYPT_UNUSED, sessionInfoPtr->privateKey,
CRYPT_UNUSED );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_IMPORT,
&mechanismInfo, MECHANISM_PKCS1_RAW );
if( cryptStatusOK( status ) && \
mechanismInfo.keyDataLength != SSL_SECRET_SIZE )
status = CRYPT_ERROR_BADDATA;
clearMechanismInfo( &mechanismInfo );
if( cryptStatusError( status ) )
return( status );
if( handshakeInfo->premasterSecret[ 0 ] != SSL_MAJOR_VERSION || \
handshakeInfo->premasterSecret[ 1 ] != handshakeInfo->clientOfferedVersion )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid premaster secret version data 0x%02X 0x%02X, "
"expected 0x03 0x%02X",
handshakeInfo->premasterSecret[ 0 ],
handshakeInfo->premasterSecret[ 1 ],
handshakeInfo->clientOfferedVersion );
bufPtr += length;
/* If we're expecting a client cert, process the client cert verify */
if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
{
/* Read the next packet if necessary */
if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
{
status = readPacketSSL( sessionInfoPtr, handshakeInfo,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
bufPtr = sessionInfoPtr->receiveBuffer;
}
/* Process the client cert verify packet:
byte ID = 0x0F
uint24 len
byte[] signature */
length = checkPacketHeader( sessionInfoPtr, &bufPtr,
SSL_HAND_CLIENT_CERTVERIFY, 64,
CRYPT_UNUSED );
if( cryptStatusError( length ) )
return( length );
status = processCertVerify( sessionInfoPtr, handshakeInfo, bufPtr,
length, 0 );
if( cryptStatusError( status ) )
return( status );
}
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 + -