ssl.c
来自「提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发」· C语言 代码 · 共 1,778 行 · 第 1/5 页
C
1,778 行
}
else
if( length != ALERTINFO_SIZE )
return( CRYPT_ERROR_BADDATA );
return( processAlert( sessionInfoPtr, length ) );
}
return( status );
}
static int readPacket( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
const int packetType )
{
BYTE buffer[ 128 ], *bufPtr = buffer;
BOOLEAN isV2handshake = FALSE;
int totalLength, ch, status;
/* Read and process the header. We don't have to check for status == 0
meaning no data was read at this point since all reads during the
handshake phase are nonblocking */
status = readPacketHeader( sessionInfoPtr, buffer );
if( cryptStatusError( status ) )
return( status );
/* Decode the SSL packet header:
SSLv3/TLS SSLv2
byte type uint16 length code = { 0x80, len }
byte[2] vers = { 0x03, 0x0n } byte type = 1
uint16 length byte[2] vers = { 0x03, 0x0n } */
ch = *bufPtr++;
if( packetType == SSL_MSG_SPECIAL_HANDSHAKE && ch == packetType )
isV2handshake = TRUE;
if( ch != packetType && ( packetType == SSL_MSG_SPECIAL_HANDSHAKE && \
ch != SSL_MSG_HANDSHAKE ) )
return( CRYPT_ERROR_BADDATA );
if( isV2handshake )
{
totalLength = *bufPtr++;
if( handshakeInfo != NULL )
/* Due to the different ordering of header fields in SSLv2,
the type and version is regarded as part of the payload which
needs to be hashed rather than the header as in SSLv3 */
dualMacData( handshakeInfo, bufPtr, 3 );
if( *bufPtr++ != SSL_HAND_CLIENT_HELLO )
return( CRYPT_ERROR_BADDATA );
totalLength -= ID_SIZE + VERSIONINFO_SIZE;
}
if( *bufPtr++ != SSL_MAJOR_VERSION )
return( CRYPT_ERROR_BADDATA );
ch = *bufPtr++;
if( ch != SSL_MINOR_VERSION && ch != TLS_MINOR_VERSION )
return( CRYPT_ERROR_BADDATA );
if( !isV2handshake )
{ totalLength = mgetBWord( bufPtr ); }
if( ( packetType != SSL_MSG_CHANGE_CIPHER_SPEC && \
totalLength < MIN_SSL_PACKET_SIZE ) || totalLength > BUFFER_SIZE )
return( CRYPT_ERROR_BADDATA );
/* Read the payload packet(s) */
status = sread( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer,
totalLength );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
return( status );
}
sessionInfoPtr->receiveBufPos = 0;
sessionInfoPtr->receiveBufEnd = totalLength;
if( handshakeInfo != NULL )
dualMacData( handshakeInfo, sessionInfoPtr->receiveBuffer,
totalLength );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Client-side Connect Functions *
* *
****************************************************************************/
/* Perform the initial part of the handshake with the server */
static int beginClientHandshake( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo )
{
BYTE *bufPtr, *bufMarkPtr, *lengthPtr;
int length, cipherSuite, ch, status;
/* Build the client hello packet:
byte ID = 1
uint24 len
byte[2] version = { 0x03, 0x0n }
uint32 time | Session ID
byte[28] nonce |
byte sessIDlen = 0 | May receive nonzero len +
uint16 suiteLen | <len> bytes data
uint16[] suite
byte coprLen = 1
byte[] copr = { 0x00 } */
getNonce( handshakeInfo->clientNonce, SSL_NONCE_SIZE );
bufPtr = sessionInfoPtr->sendBuffer + SSL_HEADER_SIZE;
*bufPtr++ = SSL_HAND_CLIENT_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->clientNonce, SSL_NONCE_SIZE );
bufPtr += SSL_NONCE_SIZE;
*bufPtr++ = '\0'; /* No session ID */
bufMarkPtr = bufPtr;
bufPtr += UINT16_SIZE; /* Leave room for length */
if( algoAvailable( CRYPT_ALGO_3DES ) )
{
mputBWord( bufPtr, SSL_RSA_WITH_3DES_EDE_CBC_SHA );
}
if( algoAvailable( CRYPT_ALGO_RC4 ) )
{
mputBWord( bufPtr, SSL_RSA_WITH_RC4_128_SHA );
mputBWord( bufPtr, SSL_RSA_WITH_RC4_128_MD5 );
}
if( algoAvailable( CRYPT_ALGO_IDEA ) )
{
mputBWord( bufPtr, SSL_RSA_WITH_IDEA_CBC_SHA );
}
if( algoAvailable( CRYPT_ALGO_DES ) )
{
mputBWord( bufPtr, SSL_RSA_WITH_DES_CBC_SHA );
}
mputBWord( bufMarkPtr, bufPtr - ( bufMarkPtr + UINT16_SIZE ) );
*bufPtr++ = 1; /* No compression */
*bufPtr++ = 0;
length = bufPtr - ( sessionInfoPtr->sendBuffer + SSL_HEADER_SIZE );
mputBWord( lengthPtr, length - ( ID_SIZE + LENGTH_SIZE ) );
wrapHandshakePacket( sessionInfoPtr->sendBuffer, length,
sessionInfoPtr->version );
/* Send the client hello to the server and read back and process the
server's data (server hello, cert or key mgt. packets, and server
done) */
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 );
status = readPacket( sessionInfoPtr, handshakeInfo, SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
/* Process the server hello:
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 */
bufPtr = sessionInfoPtr->receiveBuffer;
if( *bufPtr++ != SSL_HAND_SERVER_HELLO || *bufPtr++ != 0 )
return( CRYPT_ERROR_BADDATA );
length = mgetBWord( bufPtr );
if( length < VERSIONINFO_SIZE + SSL_NONCE_SIZE + 1 + UINT16_SIZE + 1 || \
*bufPtr++ != SSL_MAJOR_VERSION )
return( CRYPT_ERROR_BADDATA );
sessionInfoPtr->receiveBufPos = ID_SIZE + LENGTH_SIZE + length;
ch = *bufPtr++;
if( ch == SSL_MINOR_VERSION )
{
if( sessionInfoPtr->version == CRYPT_PROTOCOLVERSION_TLS )
/* If the server 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->serverNonce, 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 */
cipherSuite = mgetBWord( bufPtr );
status = initCiphersuiteInfo( sessionInfoPtr, handshakeInfo,
cipherSuite );
if( cryptStatusError( status ) )
return( status );
if( *bufPtr++ )
return( CRYPT_ERROR_BADDATA );
return( CRYPT_OK );
}
/* Exchange keys with the server */
static int exchangeClientKeys( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo )
{
MECHANISM_WRAP_INFO mechanismInfo;
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
sessionInfoPtr->receiveBufPos;
BOOLEAN needClientCert = FALSE;
int length, keySize, status;
/* Process the server cert chain:
byte ID = 0x0B
uint24 len
uint24 certLen | 1...n certs ordered
byte[] cert | leaf -> root */
if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
{
status = readPacket( sessionInfoPtr, handshakeInfo,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
bufPtr = sessionInfoPtr->receiveBuffer;
}
if( *bufPtr++ != SSL_HAND_SERVER_CERT || *bufPtr++ != 0 )
return( CRYPT_ERROR_BADDATA );
length = mgetBWord( bufPtr );
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->iKeyexCryptContext = createInfo.cryptHandle;
/* Make sure we can encrypt using the key we've been given (this performs
a variety of checks alongside the obvious one, so it's a good general
health check before we go any further). If this fails, we convert the
result to a wrong key error rather than a check failure */
status = krnlSendMessage( createInfo.cryptHandle,
RESOURCE_IMESSAGE_CHECK, NULL,
RESOURCE_MESSAGE_CHECK_PKC_ENCRYPT );
if( cryptStatusError( status ) )
return( CRYPT_ERROR_WRONGKEY );
krnlSendMessage( sessionInfoPtr->iKeyexCryptContext,
RESOURCE_IMESSAGE_GETATTRIBUTE, &keySize,
CRYPT_CTXINFO_KEYSIZE );
/* Process optional server cert request and server hello done:
byte ID = 0x0E
uint24 len = 0 */
if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
{
status = readPacket( sessionInfoPtr, handshakeInfo,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
bufPtr = sessionInfoPtr->receiveBuffer;
}
if( *bufPtr == SSL_HAND_SERVER_CERTREQUEST )
{
/* The server wants a client cert. We don't really care what's in
the cert request packet since the contents are irrelevant, all we
do is remember that we need to submit a cert later on */
needClientCert = TRUE;
if( *bufPtr++ != SSL_HAND_SERVER_CERTREQUEST || *bufPtr++ != 0 )
return( CRYPT_ERROR_BADDATA );
length = mgetBWord( bufPtr );
if( length < 4 || length > BUFFER_SIZE )
return( CRYPT_ERROR_BADDATA );
sessionInfoPtr->receiveBufPos += ID_SIZE + LENGTH_SIZE + length;
bufPtr += length;
if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
{
status = readPacket( sessionInfoPtr, handshakeInfo,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
}
}
if( memcmp( bufPtr, serverHelloDoneTemplate,
SERVERHELLODONE_TEMPLATE_SIZE ) )
return( CRYPT_ERROR_BADDATA );
sessionInfoPtr->receiveBufPos += SERVERHELLODONE_TEMPLATE_SIZE;
/* If we need a client cert, build the client cert packet */
bufPtr = sessionInfoPtr->sendBuffer + SSL_HEADER_SIZE;
if( needClientCert )
{
/* If we haven't got a cert available, tell the server. SSL and TLS
differ here, SSL sends a no-certificate alert while TLS sends an
empty client cert packet */
if( sessionInfoPtr->privateKey == CRYPT_ERROR )
{
if( sessionInfoPtr->version == CRYPT_PROTOCOLVERSION_SSL )
swrite( &sessionInfoPtr->stream, noCertAlertSSLTemplate,
NOCERTALERT_TEMPLATE_SIZE );
else
{
memcpy( bufPtr, noCertTLSTemplate, NOCERT_TEMPLATE_SIZE );
bufPtr += NOCERT_TEMPLATE_SIZE;
}
}
else
{
/* Write the client cert chain */
status = length = writeSSLCertChain( sessionInfoPtr, bufPtr );
if( cryptStatusError( status ) )
return( status );
bufPtr += status;
}
}
else
/* No client cert packet */
length = 0;
/* Build the client key exchange packet:
byte ID = 0x10
uint24 len
[ uint16 encKeyLen - TLS only ]
byte[] rsaPKCS1( byte[2] { 0x03, 0x0n } || byte[46] random ) */
*bufPtr++ = SSL_HAND_CLIENT_KEYEXCHANGE;
*bufPtr++ = 0;
if( sessionInfoPtr->version == CRYPT_PROTOCOLVERSION_TLS )
{
/* 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 (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 */
mputBWord( bufPtr, UINT16_SIZE + keySize );
}
mputBWord( bufPtr, keySize );
/* Create the premaster secret and wrap it using the server's public
key */
handshakeInfo->premasterSecret[ 0 ] = SSL_MAJOR_VERSION;
handshakeInfo->premasterSecret[ 1 ] = \
( sessionInfoPtr->version == CRYPT_PROTOCOLVERSION_SSL ) ? \
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?