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 + -
显示快捷键?