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

📄 ssl.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*					cryptlib SSL v3/TLS Session Management					*
*					   Copyright Peter Gutmann 1998-2008					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
  #include "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 );

		/* If we're using a server key (it isn't necessary for TLS-PSK),
		   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( ( sessionInfoPtr->privateKey != CRYPT_ERROR ) && \
			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 )
	{
	typedef struct {
		const int cipherSuite;
		const CRYPT_ALGO_TYPE keyexAlgo, authAlgo, cryptAlgo, macAlgo;
		const int cryptKeySize, macBlockSize;
		} CIPHERSUITE_INFO;
	const static CIPHERSUITE_INFO 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 },
		{ 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 = isServer( sessionInfoPtr ) ? TRUE : FALSE;
	int currentSuiteIndex = 999, i, status;

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

#if 0	/* 28/01/08 Disabled since it's now finally removed in MSIE and 
		   Firefox */
		/* 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( currentSuite,
						( currentSuite, SESSION_ERRINFO, 
						  "Invalid cipher suite information" ) );
				}
			if( currentSuite != 0 )
				{
				readUint16( stream );
				continue;
				}
			}
#endif /* 0 */

		/* Get the cipher suite info */
		currentSuite = readUint16( stream );
		if( cryptStatusError( currentSuite ) )
			{
			retExt( currentSuite,
					( currentSuite, SESSION_ERRINFO, 
					  "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( CRYPT_ERROR_NOSECURE,
					( CRYPT_ERROR_NOSECURE, SESSION_ERRINFO, 
					  "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 < FAILSAFE_ARRAYSIZE( cipherSuiteInfo, CIPHERSUITE_INFO ); \
			 suiteInfoIndex++ );
		if( suiteInfoIndex >= FAILSAFE_ARRAYSIZE( cipherSuiteInfo, CIPHERSUITE_INFO ) )
			retIntError();
		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;

		/* If we're only able to do basic TLS-PSK because there's no private
		   key present and the suite requires a private key, we can't use
		   this suite */
		if( isServer && sessionInfoPtr->privateKey == CRYPT_ERROR && \
			cipherSuiteInfo[ suiteInfoIndex ].keyexAlgo != CRYPT_ALGO_NONE )
			continue;

		/* We've found a more-preferred available suite, go with that */
		currentSuiteIndex = suiteInfoIndex;
		}
	if( currentSuiteIndex >= FAILSAFE_ARRAYSIZE( cipherSuiteInfo, \
												 CIPHERSUITE_INFO ) )
		{
		/* We couldn't find anything to use, exit.  The range comparison 
		   above is actually for whether it's still set to the original 
		   value of 999 but some source analysis tools think that it's an 
		   index check so we compare to the upper bound of the array size 
		   instead */
		retExt( CRYPT_ERROR_NOTAVAIL,
				( CRYPT_ERROR_NOTAVAIL, SESSION_ERRINFO, 
				  "No encryption mechanism 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_SHA1;
		}

⌨️ 快捷键说明

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