📄 ssl.c
字号:
SSL_MINOR_VERSION : TLS_MINOR_VERSION;
setResourceData( &msgData,
handshakeInfo->premasterSecret + VERSIONINFO_SIZE,
SSL_SECRET_SIZE - VERSIONINFO_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM );
if( cryptStatusError( status ) )
return( status );
setMechanismWrapInfo( &mechanismInfo, bufPtr, CRYPT_MAX_PKCSIZE,
handshakeInfo->premasterSecret, SSL_SECRET_SIZE,
CRYPT_UNUSED, sessionInfoPtr->iKeyexCryptContext,
CRYPT_UNUSED );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_EXPORT, &mechanismInfo,
MECHANISM_PKCS1_RAW );
if( cryptStatusError( status ) )
return( status );
bufPtr += keySize;
length += ID_SIZE + LENGTH_SIZE + keySize;
if( sessionInfoPtr->version == CRYPT_PROTOCOLVERSION_TLS )
length += UINT16_SIZE; /* See earlier comment */
/* If we need a client cert, send the signature generated with the client
cert to prove possession of the private key */
if( needClientCert )
{
int verifyInfoLength, status;
/* Write the packet header and drop in the signature data */
*bufPtr++ = SSL_HAND_CLIENT_CERTVERIFY;
status = verifyInfoLength = \
processCertVerify( sessionInfoPtr, handshakeInfo,
bufPtr + LENGTH_SIZE, 0, TRUE );
if( cryptStatusError( status ) )
return( status );
*bufPtr++ = 0;
mputBWord( bufPtr, verifyInfoLength );
length += ID_SIZE + LENGTH_SIZE + verifyInfoLength;
}
/* Send the client information to the server */
wrapHandshakePacket( sessionInfoPtr->sendBuffer, length,
sessionInfoPtr->version );
status = swrite( &sessionInfoPtr->stream, sessionInfoPtr->sendBuffer,
SSL_HEADER_SIZE + length );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
return( status );
}
dualMacData( handshakeInfo, sessionInfoPtr->sendBuffer + SSL_HEADER_SIZE,
length );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Server-side Connect Functions *
* *
****************************************************************************/
/* Perform the initial part of the handshake with the client */
static int beginServerHandshake( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo )
{
BYTE *bufPtr, *lengthPtr;
int length, suite, status;
/* Wait for the hello packet from the client */
status = readPacket( sessionInfoPtr, handshakeInfo,
SSL_MSG_SPECIAL_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) so we
have to process both types. The v2 type and version have already
been processed in readPacket(), 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:
SSLv2 SSLv3/TLS
uint16 suiteLen byte ID = 1
uint16 sessIDlen = 0 uint24 len
uint16 nonceLen byte[2] version = { 0x03, 0x0n }
byte[] suite uint32 time | Session ID
byte[] sessID byte[28] nonce |
byte[] nonce byte sessIDlen = 0
uint16 suiteLen
byte[] suites
byte coprLen = 1
byte copr = 0 */
bufPtr = sessionInfoPtr->receiveBuffer;
if( *bufPtr == SSL_HAND_CLIENT_HELLO )
{
int ch, suiteLength;
/* SSLv3/TLS hello */
bufPtr += 2; /* Skip type, length MSB */
length = mgetBWord( bufPtr );
if( length < VERSIONINFO_SIZE + SSL_NONCE_SIZE + 1 + \
( UINT16_SIZE * 2 ) + 1 + 1 || \
length > 256 || *bufPtr++ != SSL_MAJOR_VERSION )
return( CRYPT_ERROR_BADDATA );
ch = *bufPtr++;
if( ch == SSL_MINOR_VERSION )
{
if( sessionInfoPtr->version == CRYPT_PROTOCOLVERSION_TLS )
/* If the client can't do TLS, fall back to SSL */
sessionInfoPtr->version = CRYPT_PROTOCOLVERSION_SSL;
}
else
if( ch != TLS_MINOR_VERSION )
return( CRYPT_ERROR_BADDATA );
memcpy( handshakeInfo->clientNonce, bufPtr, SSL_NONCE_SIZE );
bufPtr += SSL_NONCE_SIZE;
length = *bufPtr++; /* Session ID length */
if( length > 32 )
return( CRYPT_ERROR_BADDATA );
bufPtr += length; /* Skip session ID */
suiteLength = mgetBWord( bufPtr );
if( suiteLength == 0 || ( suiteLength % 2 ) != 0 )
return( CRYPT_ERROR_BADDATA );
suite = chooseCipherSuite( bufPtr, suiteLength / 2, FALSE );
if( suite == SSL_NULL_WITH_NULL )
return( CRYPT_ERROR_NOTAVAIL );
bufPtr += suiteLength;
status = initCiphersuiteInfo( sessionInfoPtr, handshakeInfo, suite );
if( cryptStatusError( status ) )
return( status );
if( *bufPtr++ != 1 || *bufPtr++ )
return( CRYPT_ERROR_BADDATA );
}
else
{
int suiteLength, sessIDlength, nonceLength;
/* SSLv2 hello from Netscape */
suiteLength = mgetBWord( bufPtr );
sessIDlength = mgetBWord( bufPtr );
nonceLength = mgetBWord( bufPtr );
if( suiteLength == 0 || ( suiteLength % 3 ) != 0 || \
nonceLength < 16 || nonceLength > SSL_NONCE_SIZE || \
suiteLength + sessIDlength + nonceLength > \
sessionInfoPtr->receiveBufEnd )
return( CRYPT_ERROR_BADDATA );
suite = chooseCipherSuite( bufPtr, suiteLength / 3, TRUE );
if( suite == SSL_NULL_WITH_NULL )
return( CRYPT_ERROR_NOTAVAIL );
bufPtr += suiteLength;
status = initCiphersuiteInfo( sessionInfoPtr, handshakeInfo, suite );
if( cryptStatusError( status ) )
return( status );
if( sessIDlength )
bufPtr += sessIDlength;
memcpy( handshakeInfo->clientNonce + SSL_NONCE_SIZE - nonceLength,
bufPtr, nonceLength );
}
/* Build the server hello, cert, optional cert request, and done packets
byte ID = 2
uint24 len
byte[2] version = { 0x03, 0x0n }
uint32 time | Session ID
byte[28] nonce |
byte sessIDlen = 0
uint16 suite
byte copr = 0
... */
getNonce( handshakeInfo->serverNonce, SSL_NONCE_SIZE );
bufPtr = sessionInfoPtr->sendBuffer + SSL_HEADER_SIZE;
*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 == CRYPT_PROTOCOLVERSION_SSL ) ? \
SSL_MINOR_VERSION : TLS_MINOR_VERSION;
memcpy( bufPtr, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
bufPtr += SSL_NONCE_SIZE;
*bufPtr++ = '\0'; /* No session ID */
mputBWord( bufPtr, suite );
*bufPtr++ = 0; /* No compression */
length = bufPtr - ( sessionInfoPtr->sendBuffer + SSL_HEADER_SIZE );
mputBWord( lengthPtr, length - ( ID_SIZE + LENGTH_SIZE ) );
/* ...
(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 and read back and
process the client's data */
length = bufPtr - ( sessionInfoPtr->sendBuffer + SSL_HEADER_SIZE );
wrapHandshakePacket( sessionInfoPtr->sendBuffer, length,
sessionInfoPtr->version );
status = swrite( &sessionInfoPtr->stream, sessionInfoPtr->sendBuffer,
SSL_HEADER_SIZE + length );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
return( status );
}
dualMacData( handshakeInfo, sessionInfoPtr->sendBuffer + SSL_HEADER_SIZE,
length );
return( CRYPT_OK );
}
/* Exchange keys with the client */
static 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 it's present */
status = readPacket( sessionInfoPtr, handshakeInfo, SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
{
/* If we've asked for a client cert and there's none available, tell
the client they can't come in. Although in theory only an SSL
client should send a no-certificates alert, it's quite possible
that we'll get one from upgraded-to-TLS SSL code, so we handle
both possibilities here */
if( sessionInfoPtr->errorCode == SSL_ALERT_NO_CERTIFICATE )
sendHandshakeFailAlert( sessionInfoPtr );
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 ];
/* Make sure the client has sent us a cert chain */
if( *bufPtr++ != SSL_HAND_SERVER_CERT || *bufPtr++ != 0 )
return( CRYPT_ERROR_BADDATA );
length = mgetBWord( bufPtr );
if( length == 0 || length == 3 )
{
/* Sending an empty cert packet is another way to indicate that
the client doesn't have a cert. The spec is ambiguous on 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 a no-cert alert */
sendHandshakeFailAlert( sessionInfoPtr );
sessionInfoPtr->errorCode = SSL_ALERT_NO_CERTIFICATE;
strcpy( sessionInfoPtr->errorMessage,
( sessionInfoPtr->version == CRYPT_PROTOCOLVERSION_SSL ) ? \
"Received SSL alert message: No certificate" : \
"Received TLS alert message: No certificate" );
return( CRYPT_ERROR_PERMISSION );
}
if( length < 64 || length > BUFFER_SIZE || \
*bufPtr++ != 0 )
return( CRYPT_ERROR_BADDATA );
sessionInfoPtr->receiveBufPos = ID_SIZE + LENGTH_SIZE + length;
length = mgetBWord( bufPtr ); /* Length of cert chain */
/* Import the cert chain. Since this isn't a true cert chain (in
the sense of being degenerate PKCS #7 SignedData) but a special-
case SSL-encoded cert chain, we notify the cert management code
of this when it performs the import */
setMessageCreateObjectIndirectInfo( &createInfo, bufPtr, length );
createInfo.arg1 = CERTFORMAT_SSLCHAIN;
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
bufPtr += length;
sessionInfoPtr->iKeyexAuthContext = createInfo.cryptHandle;
/* Make sure 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 */
setResourceData( &msgData, certID, KEYID_SIZE );
status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_CERTID );
if( cryptStatusOK( status ) )
{
setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID, certID,
KEYID_SIZE, NULL, 0,
KEYMGMT_FLAG_CHECK_ONLY );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
RESOURCE_IMESSAGE_KEY_GETKEY,
&getkeyInfo, KEYMGMT_ITEM_PUBLICKEY );
}
if( cryptStatusError( status ) )
{
sendHandshakeFailAlert( sessionInfoPtr );
return( CRYPT_ERROR_INVALID );
}
/* Read the next packet(s) if necessary */
if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
{
status = readPacket( sessionInfoPtr, handshakeInfo,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
bufPtr = sessionInfoPtr->receiveBuffer;
}
}
/* Process the client key exchange packet:
byte ID = 0x10
uint24 len
[ uint16 encKeyLen - TLS only ]
byte[] rsaPKCS1( byte[2] { 0x03, 0x0n } || byte[46] random ) */
if( *bufPtr++ != SSL_HAND_CLIENT_KEYEXCHANGE || *bufPtr++ != 0 )
return( CRYPT_ERROR_BADDATA );
length = mgetBWord( bufPtr );
if( length < 64 || length > CRYPT_MAX_P
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -