⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssl_cli.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*					cryptlib SSL v3/TLS Client Management					*
*					   Copyright Peter Gutmann 1998-2003					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "session.h"
  #include "ssl.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../session/session.h"
  #include "../session/ssl.h"
#else
  #include "crypt.h"
  #include "session/session.h"
  #include "session/ssl.h"
#endif /* Compiler-specific includes */

#ifdef USE_SSL

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Most of the SSL packets have fixed formats, so we can construct them by
   copying in a constant template and setting up the variable fields.  The
   following templates are for various packet types */

#define SERVERHELLODONE_TEMPLATE_SIZE		4
#define NOCERTALERT_TEMPLATE_SIZE			7
#define NOCERT_TEMPLATE_SIZE				7

static const FAR_BSS BYTE serverHelloDoneTemplate[] = {
	SSL_HAND_SERVER_HELLODONE,				/* ID */
	0, 0, 0									/* Length */
	};
static const FAR_BSS BYTE noCertAlertSSLTemplate[] = {
	SSL_MSG_ALERT,							/* ID */
	SSL_MAJOR_VERSION, SSL_MINOR_VERSION_SSL,/* Version */
	0, 2,									/* Length */
	SSL_ALERTLEVEL_WARNING, SSL_ALERT_NO_CERTIFICATE
	};
static const FAR_BSS BYTE noCertTLSTemplate[] = {
	SSL_HAND_CERTIFICATE,					/* ID */
	0, 0, 3,								/* Length */
	0, 0, 0									/* Cert list length */
	};

/****************************************************************************
*																			*
*							Client-side Connect Functions					*
*																			*
****************************************************************************/

/* Perform the initial part of the handshake with the server */

int beginClientHandshake( SESSION_INFO *sessionInfoPtr, 
						  SSL_HANDSHAKE_INFO *handshakeInfo )
	{
	RESOURCE_DATA msgData;
	BYTE *bufPtr, *bufMarkPtr, *lengthPtr;
	BOOLEAN resumedSession = FALSE;
	int length, sessionIDlength, cipherSuite, status;

	/* Build the client hello packet:

		byte		ID = 1
		uint24		len
		byte[2]		version = { 0x03, 0x0n }
		uint32		time			| Client nonce
		byte[28]	nonce			|
		byte		sessIDlen
		byte[]		sessID
		uint16		suiteLen
		uint16[]	suite
		byte		coprLen = 1
		byte[]		copr = { 0x00 } 
		[ uint16	extListLen		| RFC 3546
			byte	extType
			uint16	extLen
			byte[]	extData ]

	   Some buggy older versions of IIS that only support crippled crypto 
	   drop the connection when they see a client hello advertising strong
	   crypto, rather than sending an alert as they should.  To work around
	   this, we advertise a dummy cipher suite SSL_RSA_EXPORT_WITH_RC4_40_MD5 
	   as a canary to force IIS to send back a response that we can then turn
	   into an error message.  The need to do this is somewhat unfortunate
	   since it will appear to an observer that cryptlib will use crippled
	   crypto, but there's no other way to detect the buggy IIS apart from
	   completely restarting the session activation at the session level with
	   crippled-crypto advertised in the restarted session */
	setMessageData( &msgData, handshakeInfo->clientNonce, SSL_NONCE_SIZE );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, 
					 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
	bufPtr = sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufStartOfs;
	*bufPtr++ = SSL_HAND_CLIENT_HELLO;
	*bufPtr++ = 0;
	lengthPtr = bufPtr;	/* Low 16 bits of length */
	bufPtr += LENGTH_SIZE - 1;
	*bufPtr++ = SSL_MAJOR_VERSION;
	*bufPtr++ = handshakeInfo->clientOfferedVersion = \
				sessionInfoPtr->version;
	memcpy( bufPtr, handshakeInfo->clientNonce, SSL_NONCE_SIZE );
	bufPtr += SSL_NONCE_SIZE;
	if( sessionInfoPtr->userNameLength > 0 )
		{
		/* If there's a user name present, we're "resuming" a session based 
		   on a shared secret, send the user name as the session ID */
		*bufPtr++ = SESSIONID_SIZE;
		memset( bufPtr, 0, SESSIONID_SIZE );
		memcpy( bufPtr, sessionInfoPtr->userName, 
				min( sessionInfoPtr->userNameLength, SESSIONID_SIZE ) );
		bufPtr += SESSIONID_SIZE;
		}
	else
		*bufPtr++ = '\0';		/* No session ID */
	bufMarkPtr = bufPtr;
	bufPtr += UINT16_SIZE;	/* Leave room for length */
	if( algoAvailable( CRYPT_ALGO_3DES ) )
		{ mputWord( bufPtr, SSL_RSA_WITH_3DES_EDE_CBC_SHA ); }
	if( algoAvailable( CRYPT_ALGO_AES ) )
		{
		mputWord( bufPtr, TLS_RSA_WITH_AES_128_CBC_SHA );
		mputWord( bufPtr, TLS_RSA_WITH_AES_256_CBC_SHA );
		}
	if( algoAvailable( CRYPT_ALGO_IDEA ) )
		{ mputWord( bufPtr, SSL_RSA_WITH_IDEA_CBC_SHA ); }
	if( algoAvailable( CRYPT_ALGO_RC4 ) )
		{
		mputWord( bufPtr, SSL_RSA_WITH_RC4_128_SHA );
		mputWord( bufPtr, SSL_RSA_WITH_RC4_128_MD5 );
		}
	if( algoAvailable( CRYPT_ALGO_DES ) )
		{ mputWord( bufPtr, SSL_RSA_WITH_DES_CBC_SHA ); }
	mputWord( bufPtr, SSL_RSA_EXPORT_WITH_RC4_40_MD5 );	/* Canary for broken servers */
	mputWord( bufMarkPtr, bufPtr - ( bufMarkPtr + UINT16_SIZE ) );
	*bufPtr++ = 1;						/* No compression */
	*bufPtr++ = 0;
#if 0	/* TLS extension test code.  Since no known clients/servers (except
		   maybe some obscure bits of code embedded in cellphones) do this,
		   we have to fake it ourselves for testing purpose.  In addition
		   the RFC rather optimistically expects implementations to 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 */
	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 ) );
	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).  We perform the dual MAC'ing of the client hello in between the
	   network ops where it's effectively free */
	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 );
	status = readPacketSSL( 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			| Server nonce
		byte[28]	nonce			|
		byte		sessIDlen
		byte		sessID
		uint16		suite
		byte		copr = 0 */
	bufPtr = sessionInfoPtr->receiveBuffer;
	length = checkPacketHeader( sessionInfoPtr, &bufPtr, 
								SSL_HAND_SERVER_HELLO, 
								VERSIONINFO_SIZE + SSL_NONCE_SIZE + 1 + \
									UINT16_SIZE + 1, SSL_MAJOR_VERSION );
	if( cryptStatusError( length ) )
		return( length );
	status = processVersionInfo( sessionInfoPtr, *bufPtr++ );
	if( cryptStatusError( status ) )
		return( status );
	memcpy( handshakeInfo->serverNonce, bufPtr, SSL_NONCE_SIZE );
	bufPtr += SSL_NONCE_SIZE;
	sessionIDlength = *bufPtr++;
	if( sessionIDlength < 0 || sessionIDlength > MAX_SESSIONID_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid session ID length %d", sessionIDlength );
	if( length != VERSIONINFO_SIZE + SSL_NONCE_SIZE + \
				  ( 1 + sessionIDlength ) + UINT16_SIZE + 1 )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid header data length %d", length );
	if( sessionIDlength == SESSIONID_SIZE )
		{
		BYTE sessionID[ SESSIONID_SIZE ];

		/* There's a session ID present, check to make sure that it matches 
		   the one we sent */
		memset( sessionID, 0, SESSIONID_SIZE );
		memcpy( sessionID, sessionInfoPtr->userName, 
				min( sessionInfoPtr->userNameLength, SESSIONID_SIZE ) );
		if( !memcmp( bufPtr, sessionID, SESSIONID_SIZE ) )
			{
			/* It's a resumed session, remember the session ID */
			memcpy( handshakeInfo->sessionID, sessionID, SESSIONID_SIZE );
			handshakeInfo->sessionIDlength = SESSIONID_SIZE;
			resumedSession = TRUE;

			/* Create the master secret from the user-supplied password */
			status = createSharedMasterSecret( handshakeInfo->premasterSecret,
											   sessionInfoPtr );
			if( cryptStatusError( status ) )
				retExt( sessionInfoPtr, status, 
						"Couldn't create SSL master secret from shared "
						"secret/password value" );
			}
		}
	bufPtr += sessionIDlength;
	cipherSuite = mgetWord( bufPtr );
	if( cipherSuite == SSL_RSA_EXPORT_WITH_RC4_40_MD5 )
		/* If we got back our method-of-last-resort cipher suite, the server
		   is incapable of handling non-crippled crypto.  Veni, vidi, volo in
		   domum redire */
		retExt( sessionInfoPtr, CRYPT_ERROR_NOSECURE,
				"Server rejected attempt to connect using non-crippled "
				"encryption" );
	status = initCiphersuiteInfo( sessionInfoPtr, handshakeInfo, 
								  cipherSuite );
	if( cryptStatusError( status ) )
		return( status );
	if( *bufPtr++ )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid compression algorithm suite %02X", 
				bufPtr[ -1 ] );

	return( resumedSession ? OK_SPECIAL : CRYPT_OK );
	}

/* Exchange keys with the server */

int exchangeClientKeys( SESSION_INFO *sessionInfoPtr, 
						SSL_HANDSHAKE_INFO *handshakeInfo )
	{
	MECHANISM_WRAP_INFO mechanismInfo;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	RESOURCE_DATA msgData;
	BYTE certFingerprint[ CRYPT_MAX_HASHSIZE ];
	BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
				   sessionInfoPtr->receiveBufPos, *lengthPtr;
	BOOLEAN needClientCert = FALSE;
	int length, chainLength, algorithm, 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 = readPacketSSL( sessionInfoPtr, handshakeInfo,  
								SSL_MSG_HANDSHAKE );
		if( cryptStatusError( status ) )
			return( status );
		bufPtr = sessionInfoPtr->receiveBuffer;
		}		
	length = checkPacketHeader( sessionInfoPtr, &bufPtr, 
								SSL_HAND_CERTIFICATE, 64, 0 );
	if( cryptStatusError( length ) )
		return( length );
	chainLength = mgetWord( bufPtr );
	if( chainLength < 64 || chainLength != length - LENGTH_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid server cert chain length %d", chainLength );

	/* Import the cert chain and get information on it.  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 ) )
		{
		/* There are sufficient numbers of broken certs around that if we 
		   run into a problem importing one we provide a custom error 
		   message telling the user to try again with a reduced compliance 
		   level */
		if( status == CRYPT_ERROR_BADDATA || status == CRYPT_ERROR_INVALID )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -