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

📄 ssl.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*					cryptlib SSL v3/TLS Session Management					*
*					   Copyright Peter Gutmann 1998-2004					*
*																			*
****************************************************************************/

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

#ifdef USE_SSL

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

/* Initialise and destroy the handshake state information */

static void destroyHandshakeInfo( SSL_HANDSHAKE_INFO *handshakeInfo )
	{
	/* Destroy any active contexts.  We need to do this here (even though
	   it's also done in the general session code) to provide a clean exit in
	   case the session activation fails, so that a second activation attempt
	   doesn't overwrite still-active contexts */
	destroyHandshakeCryptInfo( handshakeInfo );

	zeroise( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) );
	}

static int initHandshakeInfo( SESSION_INFO *sessionInfoPtr,
							  SSL_HANDSHAKE_INFO *handshakeInfo,
							  const BOOLEAN isServer )
	{
	memset( handshakeInfo, 0, sizeof( SSL_HANDSHAKE_INFO ) );
	if( isServer )
		{
		initSSLserverProcessing( handshakeInfo );

		/* Check whether the server key is signature-capable.  If it is,
		   it can be used to authenticate a DH key exchange (the default
		   server key encryption capability only handles RSA key 
		   exchange) */
		if( cryptStatusOK( \
				krnlSendMessage( sessionInfoPtr->privateKey, 
								 IMESSAGE_CHECK, NULL, 
								 MESSAGE_CHECK_PKC_SIGN ) ) )
			handshakeInfo->serverSigKey = TRUE;
		}
	else
		initSSLclientProcessing( handshakeInfo );
	return( initHandshakeCryptInfo( handshakeInfo ) );
	}

/* SSL uses 24-bit lengths in some places even though the maximum packet 
   length is only 16 bits (actually it's limited even further by the spec
   to 14 bits).  To handle this odd length, we define our own read/
   writeUint24() functions that always set the high byte to zero */

int readUint24( STREAM *stream )
	{
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	status = sgetc( stream );
	if( cryptStatusError( status ) )
		return( status );
	if( status != 0 )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	return( readUint16( stream ) );
	}

int writeUint24( STREAM *stream, const int length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length >= 0 && length < CRYPT_MAX_IVSIZE + MAX_PACKET_SIZE + \
									CRYPT_MAX_HASHSIZE + CRYPT_MAX_IVSIZE );

	sputc( stream, 0 );
	return( writeUint16( stream, length ) );
	}

/* Choose the best cipher suite from a list of suites.  There are a pile of
   DH cipher suites, in practice only DHE is used, DH requires the use of
   X9.42 DH certs (there aren't any) and DH_anon uses unauthenticated DH 
   which implementers seem to have an objection to even though it's not much
   different in effect from the way RSA cipher suites are used in practice.
   
   To keep things simple for the caller, we only allow RSA auth for DH key
   agreement and not DSA, since the former also automatically works for the
   far more common RSA key exchange that's usually used for key setup */

int processCipherSuite( SESSION_INFO *sessionInfoPtr, 
						SSL_HANDSHAKE_INFO *handshakeInfo, 
						STREAM *stream, const int noSuites )
	{
	const static struct {
		const int cipherSuite;
		const CRYPT_ALGO_TYPE keyexAlgo, authAlgo, cryptAlgo, macAlgo;
		const int cryptKeySize, macBlockSize;
		} cipherSuiteInfo[] = {
		/* PSK suites */
		{ TLS_PSK_WITH_3DES_EDE_CBC_SHA,
		  CRYPT_ALGO_NONE, CRYPT_ALGO_NONE, CRYPT_ALGO_3DES,
		  CRYPT_ALGO_HMAC_SHA, 24, SHA1MAC_SIZE },
		{ TLS_PSK_WITH_AES_256_CBC_SHA,
		  CRYPT_ALGO_NONE, CRYPT_ALGO_NONE, CRYPT_ALGO_AES,
		  CRYPT_ALGO_HMAC_SHA, 32, SHA1MAC_SIZE },
		{ TLS_PSK_WITH_AES_128_CBC_SHA,
		  CRYPT_ALGO_NONE, CRYPT_ALGO_NONE, CRYPT_ALGO_AES,
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE },
		{ TLS_PSK_WITH_RC4_128_SHA,
		  CRYPT_ALGO_NONE, CRYPT_ALGO_NONE, CRYPT_ALGO_RC4,
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE },
#ifdef PREFER_DH_SUITES
		/* 3DES with DH */
		{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 
		  CRYPT_ALGO_DH, CRYPT_ALGO_RSA, CRYPT_ALGO_3DES, 
		  CRYPT_ALGO_HMAC_SHA, 24, SHA1MAC_SIZE },
/*		{ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
		  CRYPT_ALGO_DH, CRYPT_ALGO_DSA, CRYPT_ALGO_3DES, 
		  CRYPT_ALGO_HMAC_SHA, 24, SHA1MAC_SIZE }, */

		/* AES with DH */
		{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 
		  CRYPT_ALGO_DH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 32, SHA1MAC_SIZE },
/*		{ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
		  CRYPT_ALGO_DH, CRYPT_ALGO_DSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 32, SHA1MAC_SIZE }, */
		{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 
		  CRYPT_ALGO_DH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE },
/*		{ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
		  CRYPT_ALGO_RSA, CRYPT_ALGO_DSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE }, */

		/* 3DES with RSA */
		{ SSL_RSA_WITH_3DES_EDE_CBC_SHA, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_3DES, 
		  CRYPT_ALGO_HMAC_SHA, 24, SHA1MAC_SIZE },

		/* AES with RSA */
		{ TLS_RSA_WITH_AES_256_CBC_SHA, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 32, SHA1MAC_SIZE },
		{ TLS_RSA_WITH_AES_128_CBC_SHA, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE },
#else
		/* 3DES with RSA */
		{ SSL_RSA_WITH_3DES_EDE_CBC_SHA, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_3DES, 
		  CRYPT_ALGO_HMAC_SHA, 24, SHA1MAC_SIZE },

		/* AES with RSA */
		{ TLS_RSA_WITH_AES_256_CBC_SHA, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 32, SHA1MAC_SIZE },
		{ TLS_RSA_WITH_AES_128_CBC_SHA, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE },

		/* 3DES with DH */
		{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 
		  CRYPT_ALGO_DH, CRYPT_ALGO_RSA, CRYPT_ALGO_3DES, 
		  CRYPT_ALGO_HMAC_SHA, 24, SHA1MAC_SIZE },
/*		{ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
		  CRYPT_ALGO_DH, CRYPT_ALGO_DSA, CRYPT_ALGO_3DES, 
		  CRYPT_ALGO_HMAC_SHA, 24, SHA1MAC_SIZE }, */

		/* AES with DH */
		{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 
		  CRYPT_ALGO_DH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 32, SHA1MAC_SIZE },
/*		{ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
		  CRYPT_ALGO_DH, CRYPT_ALGO_DSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 32, SHA1MAC_SIZE }, */
		{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 
		  CRYPT_ALGO_DH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE },
/*		{ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
		  CRYPT_ALGO_RSA, CRYPT_ALGO_DSA, CRYPT_ALGO_AES, 
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE }, */
#endif /* PREFER_DH_SUITES */

		/* IDEA + RSA */
		{ SSL_RSA_WITH_IDEA_CBC_SHA, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_IDEA, 
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE },

		/* RC4 + RSA */
		{ SSL_RSA_WITH_RC4_128_SHA, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_RC4, 
		  CRYPT_ALGO_HMAC_SHA, 16, SHA1MAC_SIZE },
		{ SSL_RSA_WITH_RC4_128_MD5, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_RC4, 
		  CRYPT_ALGO_HMAC_MD5, 16, MD5MAC_SIZE },

		/* DES + RSA */
		{ SSL_RSA_WITH_DES_CBC_SHA, 
		  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_DES, 
		  CRYPT_ALGO_HMAC_SHA, 8, SHA1MAC_SIZE },
		{ TLS_DHE_RSA_WITH_DES_CBC_SHA, 
		  CRYPT_ALGO_DH, CRYPT_ALGO_RSA, CRYPT_ALGO_DES, 
		  CRYPT_ALGO_HMAC_SHA, 8, SHA1MAC_SIZE },
/*		{ TLS_DHE_DSS_WITH_DES_CBC_SHA, 
		  CRYPT_ALGO_DH, CRYPT_ALGO_DSA, CRYPT_ALGO_DES, 
		  CRYPT_ALGO_HMAC_SHA, 8, SHA1MAC_SIZE }, */

		/* End-of-list marker */
		{ SSL_NULL_WITH_NULL, 
		  CRYPT_ALGO_NONE, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE, 0, 0 }
		};
	CRYPT_QUERY_INFO queryInfo;
	const BOOLEAN isServer = ( sessionInfoPtr->flags & SESSION_ISSERVER ) ? \
							 TRUE : FALSE;
	int currentSuiteIndex = 999, i, status;

	for( i = 0; i < noSuites; i++ )
		{
		int currentSuite, suiteInfoIndex;

		/* If we're reading an SSLv2 hello and it's an SSLv2 suite (the high 
		   byte is nonzero), skip it and continue */
		if( handshakeInfo->isSSLv2 )
			{
			currentSuite = sgetc( stream );
			if( cryptStatusError( currentSuite ) )
				retExt( sessionInfoPtr, currentSuite,
						"Invalid cipher suite information" );
			if( currentSuite != 0 )
				{
				readUint16( stream );
				continue;
				}
			}

		/* Get the cipher suite info */
		currentSuite = readUint16( stream );
		if( cryptStatusError( currentSuite ) )
			retExt( sessionInfoPtr, currentSuite,
					"Invalid cipher suite information" );

#if 0	/* When resuming a cached session, the client is required to offer 
		   as one of its suites the original suite that was used.  There is 
		   no good reason for this requirement (it's probable that the spec 
		   is intending that there be at least one cipher suite, and that if 
		   there's only one it should really be the one originally 
		   negotiated) and it complicates implementation of shared-secret 
		   key sessions, so we don't perform this check */
		/* If we have to match a specific suite and this isn't it, 
		   continue */
		if( requiredSuite > 0 && requiredSuite != currentSuite )
			continue;
#endif /* 0 */

		/* If we're the client and we got back our canary method-of-last-
		   resort suite from the server, the server is incapable of handling 
		   non-crippled crypto.  Veni, vidi, volo in domum redire */
		if( !isServer && currentSuite == SSL_RSA_EXPORT_WITH_RC4_40_MD5 )
			retExt( sessionInfoPtr, CRYPT_ERROR_NOSECURE,
					"Server rejected attempt to connect using non-crippled "
					"encryption" );

		/* Try and find the info for the proposed cipher suite */
		for( suiteInfoIndex = 0; \
			 cipherSuiteInfo[ suiteInfoIndex ].cipherSuite != SSL_NULL_WITH_NULL && \
			 cipherSuiteInfo[ suiteInfoIndex ].cipherSuite != currentSuite; \
			 suiteInfoIndex++ );
		if( cipherSuiteInfo[ suiteInfoIndex ].cipherSuite == SSL_NULL_WITH_NULL )
			continue;

		/* If the new suite is less preferred than the existing one, don't 
		   try and work with it */
		if( suiteInfoIndex >= currentSuiteIndex )
			continue;

		/* Make sure that the required algorithms are available.  We don't 
		   have to check the MAC algorithms since MD5 and SHA-1 are always
		   available as they're required for the handshake */
		if( !algoAvailable( cipherSuiteInfo[ suiteInfoIndex ].cryptAlgo ) )
			continue;
		if( ( cipherSuiteInfo[ suiteInfoIndex ].keyexAlgo != \
			  cipherSuiteInfo[ suiteInfoIndex ].authAlgo ) && \
			!algoAvailable( cipherSuiteInfo[ suiteInfoIndex ].keyexAlgo ) )
			continue;

		/* If it's a DH suite and the server key can't be used for signing 
		   (needed to authenticate the DH exchange), we can't use the DH
		   suite */
		if( isServer && !handshakeInfo->serverSigKey && \
			cipherSuiteInfo[ suiteInfoIndex ].keyexAlgo == CRYPT_ALGO_DH )
			continue;

		/* We've found a more-preferred available suite, go with that */
		currentSuiteIndex = suiteInfoIndex;
		}
	if( currentSuiteIndex > 50 )
		/* We couldn't find anything to use, exit */
		retExt( sessionInfoPtr, CRYPT_ERROR_NOTAVAIL,
				"No encryption algorithm compatible with the remote system "
				"could be found" );

	/* We got a cipher suite that we can handle, set up the crypto info */
	handshakeInfo->cipherSuite = cipherSuiteInfo[ currentSuiteIndex ].cipherSuite;
	handshakeInfo->keyexAlgo = cipherSuiteInfo[ currentSuiteIndex ].keyexAlgo;
	handshakeInfo->authAlgo = cipherSuiteInfo[ currentSuiteIndex ].authAlgo;
	handshakeInfo->cryptKeysize = cipherSuiteInfo[ currentSuiteIndex ].cryptKeySize;
	sessionInfoPtr->cryptAlgo = cipherSuiteInfo[ currentSuiteIndex ].cryptAlgo;
	sessionInfoPtr->integrityAlgo = cipherSuiteInfo[ currentSuiteIndex ].macAlgo;
	if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
		/* SSL uses a proto-HMAC which requires that we synthesize it from
		   raw hash functionality */
		sessionInfoPtr->integrityAlgo = \
			( sessionInfoPtr->integrityAlgo == CRYPT_ALGO_HMAC_MD5 ) ? \
			CRYPT_ALGO_MD5 : CRYPT_ALGO_SHA;
	sessionInfoPtr->authBlocksize = cipherSuiteInfo[ currentSuiteIndex ].macBlockSize;
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_QUERYCAPABILITY, &queryInfo,
							  sessionInfoPtr->cryptAlgo );
	if( cryptStatusError( status ) )
		return( status );
	sessionInfoPtr->cryptBlocksize = queryInfo.blockSize;

	return( CRYPT_OK );
	}

/* Process RFC 3546 TLS extensions:

	uint16		extListLen		| RFC 3546
		uint16	extType
		uint16	extLen
		byte[]	extData */

static int processExtensions( SESSION_INFO *sessionInfoPtr, STREAM *stream,
							  const int length )
	{
	int endPos = stell( stream ) + length, extListLen;

	/* Read the extension header and make sure that it's valid */
	if( length < UINT16_SIZE + UINT16_SIZE + UINT16_SIZE + 1 )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"TLS hello contains %d bytes extraneous data", length );
	extListLen = readUint16( stream );
	if( cryptStatusError( extListLen ) || \
		extListLen != length - UINT16_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid TLS extension data length %d, should be %d", 
				extListLen, length - UINT16_SIZE );

	/* Process the extensions */
	while( stell( stream ) < endPos )
		{
		int type, extLen, value;

		/* Get the next extension */
		type = readUint16( stream );
		extLen = readUint16( stream );
		if( cryptStatusError( extLen ) || extLen < 1 )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid TLS extension list item header" );

		/* Process the extension data.  The internal structure of some of 
		   these things shows that they were created by ASN.1 people... */
		switch( type )
			{
			case TLS_EXT_SERVER_NAME:
				{
				int listLen;

				/* Response: Send zero-length reply to peer:
				
					uint16		listLen
						byte	nameType
						uint16	nameLen 
						byte[]	name */
				listLen = readUint16( stream );
				if( cryptStatusError( listLen ) || \
					listLen != extLen - UINT16_SIZE || \
					listLen < 1 + UINT16_SIZE || \
					cryptStatusError( sSkip( stream, listLen ) ) )
					retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
							"Invalid TLS host name extension" );
				/* Parsing of further SEQUENCE OF SEQUENCE data omitted */
				break;
				}

			case TLS_EXT_MAX_FRAGMENT_LENTH:
				{

⌨️ 快捷键说明

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