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

📄 ssl_svr.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*					cryptlib SSL v3/TLS Server 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							*
*																			*
****************************************************************************/

/* Many 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 SERVERCERTREQUEST_TEMPLATE_SIZE		13

static const FAR_BSS BYTE serverHelloDoneTemplate[] = {
	SSL_HAND_SERVER_HELLODONE,				/* ID */
	0, 0, 0									/* Length */
	};
static const FAR_BSS BYTE serverCertRequestTemplate[] = {
	SSL_HAND_SERVER_CERTREQUEST,			/* ID */
	0, 0, 9,								/* Length */
	2,										/* Cert type length */
	1, 2,									/* RSA, DSA */
	0, 4,									/* CA name list length */
	0, 2,									/* CA name length */
	0x30, 0x00								/* CA name */
	};

/* Choose the best cipher suite from a list of suites */

static int chooseCipherSuite( const BYTE *suitePtr, const int noSuites, 
							  const BOOLEAN isV2 )
	{
	int suite = SSL_NULL_WITH_NULL, i;

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

		/* Get the cipher suite info.  If it's a v2 suite (the high byte is 
		   nonzero), skip it and continue */
		if( isV2 )
			ch = *suitePtr++;
		currentSuite = mgetWord( suitePtr );
		if( isV2 && ch )
			continue;

#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 */

		/* Pick out the best suite available.  The order is 3DES, AES, IDEA, 
		   RC4/128, DES */
		switch( currentSuite )
			{
			case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
				if( algoAvailable( CRYPT_ALGO_3DES ) )
					suite = currentSuite;
				break;

			case TLS_RSA_WITH_AES_128_CBC_SHA:
			case TLS_RSA_WITH_AES_256_CBC_SHA:
				if( suite != SSL_RSA_WITH_3DES_EDE_CBC_SHA && \
					algoAvailable( CRYPT_ALGO_AES ) )
					suite = currentSuite;
				break;

			case SSL_RSA_WITH_IDEA_CBC_SHA:
				if( suite != SSL_RSA_WITH_3DES_EDE_CBC_SHA && \
					suite != TLS_RSA_WITH_AES_128_CBC_SHA && \
					suite != TLS_RSA_WITH_AES_256_CBC_SHA && \
					algoAvailable( CRYPT_ALGO_IDEA ) )
					suite = currentSuite;
				break;

			case SSL_RSA_WITH_RC4_128_MD5:
			case SSL_RSA_WITH_RC4_128_SHA:
				if( ( suite == SSL_NULL_WITH_NULL || \
					  suite == SSL_RSA_WITH_DES_CBC_SHA ) && \
					algoAvailable( CRYPT_ALGO_RC4 ) )
					suite = currentSuite;
				break;

			case SSL_RSA_WITH_DES_CBC_SHA:
				if( suite == SSL_NULL_WITH_NULL && \
					algoAvailable( CRYPT_ALGO_DES ) )
					suite = currentSuite;
				break;
			}
		}

	return( suite );
	}

/* Process TLS extensions */

static int processExtensions( SESSION_INFO *sessionInfoPtr, 
							  const BYTE *extListPtr, const int extListLen )
	{
	int length = extListLen;

	/* Process the extensions */
	while( length > ID_SIZE + UINT16_SIZE )
		{
		int type, extLen, value;

		/* Get the next extension */
		type = *extListPtr++;
		extLen = mgetWord( extListPtr );
		if( length < ID_SIZE + UINT16_SIZE + extLen || extLen < 1 )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid TLS extension length %d, total length %d", 
					extLen, length );
		length -= ID_SIZE + UINT16_SIZE;

		/* 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 client */
				listLen = mgetWord( extListPtr );
				if( extLen != listLen + UINT16_SIZE )
					retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
							"Invalid host name TLS extension data "
							"length %d", listLen );
				/* Parsing of further SEQUENCE OF SEQUENCE data omitted */
				break;
				}

			case TLS_EXT_MAX_FRAGMENT_LENTH:
				/* Response: If frag-size == 3 or 4, send same to client */
				value = *extListPtr++;
				if( extLen != 1 || value < 1 || value > 4 )
					retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
							"Invalid fragment length TLS extension data "
							"%02X, length %d", value, extLen );
				break;

			case TLS_EXT_TRUNCATED_HMAC:
				break;

			/* Default: Ignore the extension */
			}

		/* Move on to the next extension */
		extListPtr += extLen;
		length -= extLen;
		}

	/* Make sure that we consumed all of the data */
	if( length != 0 )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Extraneous TLS extension data %d bytes", length );
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*									Session Cache							*
*																			*
****************************************************************************/

/* Session cache data and index information */

typedef BYTE SESSIONCACHE_DATA[ SSL_SECRET_SIZE ];
typedef struct {
	/* Identification information: The checksum and hash of the session ID */
	int checkValue;
	BYTE hashValue[ 20 ];

	/* Misc info */
	time_t expiryTime;		/* Time entry expires from the cache */
	int uniqueID;			/* Unique ID for this entry */
	BOOLEAN fixedEntry;		/* Whether entry was added manually */
	} SESSIONCACHE_INDEX;

/* A template used to initialise session cache entries */

static const SESSIONCACHE_INDEX SESSIONCACHE_INDEX_TEMPLATE = \
								{ 0, { 0 }, 0, 0, 0 };

/* The action to perform on the cache */

typedef enum { CACHE_ACTION_NONE, CACHE_ACTION_PRESENCECHECK, 
			   CACHE_ACTION_LOOKUP, CACHE_ACTION_ADD, 
			   CACHE_ACTION_LAST } CACHE_ACTION;

/* Session cache information */

static SESSIONCACHE_INDEX *sessionCacheIndex;
static SESSIONCACHE_DATA *sessionCacheData;
static int sessionCacheLastEntry;
static int sesionCacheUniqueID;

/* Hash data */

static void hashData( BYTE *hash, const void *data, const int dataLength )
	{
	static HASHFUNCTION hashFunction = NULL;

	/* Get the hash algorithm information if necessary */
	if( hashFunction == NULL )
		getHashParameters( CRYPT_ALGO_SHA, &hashFunction, NULL );

	/* Hash the data */
	hashFunction( NULL, hash, ( BYTE * ) data, dataLength, HASH_ALL );
	}

/* Handle the session cache.  This function currently uses a straightforward 
   linear search with entries clustered towards the start of the cache.  
   Although this may seem somewhat suboptimal, since cryptlib isn't a high-
   performance server the cache will rarely contain more than a handful of 
   entries (if any).  In any case a quick scan through a small number of 
   integers is probably still faster than the complex in-memory database 
   lookup schemes used by many servers, and is also required to handle things 
   like cache LRU management */

static int handleSessionCache( const void *sessionID, 
							   const int sessionIDlength, void *masterKey, 
							   const BOOLEAN isFixedEntry,
							   const CACHE_ACTION cacheAction )
	{
	BYTE hashValue[ 20 ];
	BOOLEAN dataHashed = FALSE;
	const time_t currentTime = getTime();
	time_t oldestTime = currentTime;
	const int checkValue = checksumData( sessionID, sessionIDlength );
	int nextFreeEntry = CRYPT_ERROR, lastUsedEntry = 0, oldestEntry;
	int cachePos, uniqueID = 0, i;

	assert( sessionID != NULL && sessionIDlength >= 8 );
	assert( ( cacheAction == CACHE_ACTION_PRESENCECHECK && masterKey == NULL ) || \
			( cacheAction == CACHE_ACTION_LOOKUP && masterKey != NULL ) || \
			( cacheAction == CACHE_ACTION_ADD && masterKey != NULL ) );
	assert( isWritePtr( sessionCacheIndex, 
						SESSIONCACHE_SIZE * sizeof( SESSIONCACHE_INDEX ) ) );
	assert( isWritePtr( sessionCacheData, 
						SESSIONCACHE_SIZE * sizeof( SESSIONCACHE_DATA ) ) );

	/* If there's something wrong with the time, we can't perform (time-
	   based) cache management */
	if( currentTime < MIN_TIME_VALUE )
		return( 0 );

	enterMutex( MUTEX_SESSIONCACHE );

	for( i = 0; i < sessionCacheLastEntry; i++ )
		{
		SESSIONCACHE_INDEX *sessionCacheInfo = &sessionCacheIndex[ i ];

		/* If this entry has expired, delete it */
		if( sessionCacheInfo->expiryTime < currentTime )
			{
			sessionCacheIndex[ i ] = SESSIONCACHE_INDEX_TEMPLATE;
			zeroise( sessionCacheData[ i ], sizeof( SESSIONCACHE_DATA ) );
			}

		/* Check for a free entry and the oldest non-free entry.  We could
		   perform an early-out once we find a free entry, but this would
		   prevent any following expired entries from being deleted */
		if( sessionCacheInfo->expiryTime <= 0 )
			{
			if( nextFreeEntry == CRYPT_ERROR )
				nextFreeEntry = i;
			continue;
			}
		lastUsedEntry = i;
		if( sessionCacheInfo->expiryTime < oldestTime )
			{
			oldestTime = sessionCacheInfo->expiryTime;
			oldestEntry = i;
			}

		/* Perform a quick check using a checksum of the name to weed out
		   most entries */
		if( sessionCacheInfo->checkValue == checkValue )
			{
			if( !dataHashed )	
				{
				hashData( hashValue, sessionID, sessionIDlength );
				dataHashed = TRUE;
				}
			if( !memcmp( sessionCacheInfo->hashValue, hashValue, 20 ) )
				{
				uniqueID = sessionCacheInfo->uniqueID;

				/* We've found a matching entry in the cache, if we're
				   looking for an existing entry return its data */
				if( cacheAction == CACHE_ACTION_LOOKUP )
					{
					memcpy( masterKey, sessionCacheData[ i ], SSL_SECRET_SIZE );
					sessionCacheInfo->expiryTime = \
										currentTime + SESSIONCACHE_TIMEOUT;
					if( sessionCacheInfo->fixedEntry )
						/* Indicate that this entry corresponds to a fixed 
						   entry that was added manually rather than a true 
						   resumed session */
						uniqueID = -uniqueID;
					}

⌨️ 快捷键说明

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