/*********************************************************************
 *
 *                  SSLv3 Module Headers
 *
 *********************************************************************
 * FileName:        SSL.h
 * Dependencies:    None
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 *					Microchip C30 v3.12 or higher
 *					Microchip C18 v3.30 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 *		ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 *		used in conjunction with a Microchip ethernet controller for
 *		the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date     Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Elliott Wood			6/20/07	 Original
 * Elliott Wood			12/17/07 Rewritten to integrate with TCP
 *								  and support both client & server
 ********************************************************************/

#ifndef __SSL_H
#define __SSL_H

/****************************************************************************
  Section:
	Configuration Settings
  ***************************************************************************/
	#define SSL_VERSION				(0x0300u)	// SSL version number
	#define SSL_VERSION_HI			(0x03u)		// SSL version number (high byte)
	#define SSL_VERSION_LO			(0x00u)		// SSL version number (low byte)
	
	#define SSL_INVALID_ID			(0xFFu)		// Identifier for invalid SSL allocations
	
	// Minimum lifetime for SSL Sessions
	// Sessions cannot be reallocated until this much time has elapsed
	#define SSL_MIN_SESSION_LIFETIME	(1*TICK_SECOND)
	
	// Lifetime extension for RSA operations
	// Sessions lifetime is extended by this amount when an RSA calculation is made
	#define SSL_RSA_LIFETIME_EXTENSION	(8*TICK_SECOND)
	
	
/****************************************************************************
  Section:
	SSL Commands and Responses
  ***************************************************************************/

	#define SSL_CHANGE_CIPHER_SPEC	20u		// Protocol code for Change Cipher Spec records
	#define SSL_ALERT				21u		// Protocol code for Alert records
	#define SSL_HANDSHAKE			22u		// Protocol code for Handshake records
	#define SSL_APPLICATION			23u		// Protocol code for Application data records
	
	// Describes the types of SSL messages (handshake and alerts)
	typedef enum
	{
		SSL_HELLO_REQUEST				= 0u,	// HelloRequest handshake message (not currently supported)
		SSL_CLIENT_HELLO				= 1u,	// ClientHello handshake message
		SSL_ANTIQUE_CLIENT_HELLO		= 18u,	// SSLv2 ClientHello handshake message (Supported for backwards compatibility.  This is an internally defined value.)
		SSL_SERVER_HELLO				= 2u,	// ServerHello handshake message
		SSL_CERTIFICATE					= 11u,	// ServerCertifiate handshake message
		SSL_SERVER_HELLO_DONE			= 14u,	// ServerHelloDone handshake message
		SSL_CLIENT_KEY_EXCHANGE			= 16u,	// ClientKeyExchange handshake message
		SSL_FINISHED					= 20u,	// Finished handshake message
		
		// Alert Messages
		SSL_ALERT_CLOSE_NOTIFY			= 0u  + 0x80,	// CloseNotify alert message (dummy value used internally)
		SSL_ALERT_UNEXPECTED_MESSAGE	= 10u + 0x80,	// UnexpectedMessage alert message (dummy value used internally)
		SSL_ALERT_BAD_RECORD_MAC		= 20u + 0x80,	// BadRecordMAC alert message (dummy value used internally)
		SSL_ALERT_HANDSHAKE_FAILURE		= 40u + 0x80,	// HandshakeFailure alert message (dummy value used internally)
		
		// No Message
		SSL_NO_MESSAGE					= 0xff			// No message is currently requested (internally used value)
		
	} SSL_MESSAGES;
	
	// Describes the two types of Alert records
	typedef enum
	{
		SSL_ALERT_WARNING 	= 1u,	// Alert message is a warning (session can be resumed)
		SSL_ALERT_FATAL		= 2u	// Alert message is fatal (session is non-resumable)
	} SSL_ALERT_LEVEL;

	// SSL Session Type Enumeration
	typedef enum
	{
		SSL_CLIENT,			// Local device is the SSL client
		SSL_SERVER			// Local device is the SSL host
	} SSL_SESSION_TYPE;	


/****************************************************************************
  Section:
	State Machines
  ***************************************************************************/
	
	// State machine for SSLRxServerHello
	typedef enum
	{
		RX_SERVER_CERT_START = 0u,
		RX_SERVER_CERT_FIND_KEY,
		RX_SERVER_CERT_FIND_N,
		RX_SERVER_CERT_READ_N,
		RX_SERVER_CERT_READ_E,
		RX_SERVER_CERT_CLEAR
	} SM_SSL_RX_SERVER_HELLO;


/****************************************************************************
  Section:
	Connection Struct Definitions
  ***************************************************************************/

	// Memory holder for general information associated with
	// an SSL connections.
	typedef struct
	{
		WORD wRxBytesRem;					// Bytes left to read in current record
		WORD wRxHsBytesRem;					// Bytes left to read in current Handshake submessage
		
		BYTE rxProtocol;					// Protocol for message being read
		BYTE rxHSType;						// Handshake message being received
		
		BYTE idSession;						// ID for associated session
		BYTE idMD5, idSHA1;					// ID for current hashes
		BYTE idRxHash;						// ID for MAC hash (TX needs no persistence)
		BYTE idRxBuffer, idTxBuffer;		// ID for current buffers (Sboxes)
		
		DWORD_VAL dwTemp;					// Used for state machine in RxCertificate
		
		struct
		{
			unsigned char bIsServer					: 1;	// We are the server
			unsigned char bClientHello				: 1;	// ClientHello has been sent/received
			unsigned char bServerHello				: 1;	// ServerHello has been sent/received
			unsigned char bServerCertificate		: 1;	// ServerCertificate has been sent/received
			unsigned char bServerHelloDone			: 1;	// ServerHelloDone has been sent/received
			unsigned char bClientKeyExchange		: 1;	// ClientKeyExchange has been sent/received
			unsigned char bRemoteChangeCipherSpec	: 1;	// Remote node has sent a ChangeCipherSpec message
			unsigned char bRemoteFinished			: 1;	// Remote node has sent a Finished message
			unsigned char bLocalChangeCipherSpec	: 1;	// We have sent a ChangeCipherSpec message
			unsigned char bLocalFinished			: 1;	// We have sent a Finished message
			unsigned char bExpectingMAC				: 1;	// We expect a MAC at end of message
			unsigned char bNewSession				: 1;	// TRUE if a new session, FALSE if resuming
			unsigned char bCloseNotify				: 1;	// Whether or not a CloseNotify has been sent/received
			unsigned char bDone						: 1;	// TRUE if the connection is closed
			unsigned char bRSAInProgress			: 1;	// TRUE when RSA op is in progress
			unsigned char bKeysValid				: 1;	// TRUE if the session keys have been generated
		} Flags;
		
		BYTE requestedMessage;				// Currently requested message to send, or 0xff
	} SSL_STUB;

	// Memory definition for SSL keys.  This area is split into Local and
	// Remote areas.  During the handshake, Local.random and Remote.random
	// hold the ServerRandom and ClientRandom values.  Once the session keys
	// are calculated, the Local.app and Remote.app contain the MAC
	// secret, record sequence number, and encryption context for the
	// ARCFOUR module.
	typedef struct
	{
		union
		{
			struct
			{
				BYTE MACSecret[16];			// Server's MAC write secret
				DWORD sequence;				// Server's write sequence number
				ARCFOUR_CTX cryptCtx;		// Server's write encryption context
				BYTE reserved[8];			// Future expansion
			}app;
			BYTE random[32];				// Server.random value
		} Local;
		
		union
		{
			struct
			{
				BYTE MACSecret[16];			// Client's MAC write secret
				DWORD sequence;				// Client's write sequence number
				ARCFOUR_CTX cryptCtx;		// Client's write encryption context
				BYTE reserved[8];			// Future expansion
			}app;
			BYTE random[32];				// Client.random value
		} Remote;		
	} SSL_KEYS;

	// Generic buffer space for SSL.  The hashRounds element is used
	// when this buffer is needed for handshake hash calculations, and
	// the full element is used as the Sbox for ARCFOUR calculations.
	typedef union
	{
		struct
		{
			HASH_SUM hash;
			BYTE md5_hash[16];
			BYTE sha_hash[20];
			BYTE temp[256-sizeof(HASH_SUM)-16-20];
		} hashRounds;
		BYTE full[256];
	} SSL_BUFFER;
	
	// Storage space for SSL Session identifiers.  (The SessionID and MasterSecret)
	typedef struct
	{
		BYTE sessionID[32];					// The SSL Session ID for this session
		BYTE masterSecret[48];				// Associated Master Secret for this session
	} SSL_SESSION;

	// Stub value for an SSL_SESSION.  The tag associates this session with a 
	// remote node, either by matching to a remote IP address when we are
	// the client or the first 3 bytes of the session ID when we are the host.
	// When a session is free/expired, the tag is 0x00000000.  The lastUsed
	// value is the Tick count when the session was last used so that 
	// older sessions may be overwritten first.
	typedef struct
	{
		DWORD_VAL tag;						// Identifying tag for connection
											// When we're a client, this is the remote IP
											// When we're a host, this is 0x00 followed by first 3 bytes of session ID
											// When this stub is free/expired, this is 0x00
		DWORD lastUsed;						// Tick count when session was last used
	} SSL_SESSION_STUB;

	
	#define SSL_STUB_SIZE		((DWORD)sizeof(SSL_STUB))				// Amount of space needed by a single SSL stub
	#define SSL_STUB_SPACE		(SSL_STUB_SIZE*MAX_SSL_CONNECTIONS)		// Amount of space needed by all SSL stubs
	#define SSL_KEYS_SIZE		((DWORD)sizeof(SSL_KEYS))				// Amount of space needed by a single SSL key
	#define SSL_KEYS_SPACE		(SSL_KEYS_SIZE*MAX_SSL_CONNECTIONS)		// Amount of space needed by all SSL key
	#define SSL_HASH_SIZE		((DWORD)sizeof(HASH_SUM))				// Amount of space needed by a single SSL hash
	#define SSL_HASH_SPACE		((DWORD)(SSL_HASH_SIZE*MAX_SSL_HASHES))	// Amount of space needed by all SSL hash
	#define SSL_BUFFER_SIZE		((DWORD)sizeof(SSL_BUFFER))				// Amount of space needed by a single SSL buffer
	#define SSL_BUFFER_SPACE	(SSL_BUFFER_SIZE*MAX_SSL_BUFFERS)		// Amount of space needed by all SSL buffer
	#define SSL_SESSION_SIZE	((DWORD)sizeof(SSL_SESSION))			// Amount of space needed by a single SSL session
	#define SSL_SESSION_SPACE	(SSL_SESSION_SIZE*MAX_SSL_SESSIONS)		// Amount of space needed by all SSL session
	
	// Total space needed by all SSL storage requirements
	#define RESERVED_SSL_MEMORY ((DWORD)(SSL_STUB_SPACE + SSL_KEYS_SPACE + SSL_HASH_SPACE + SSL_BUFFER_SPACE + SSL_SESSION_SPACE))


/****************************************************************************
  Section:
	Function Prototypes
  ***************************************************************************/

void SSLInit(void);

BYTE SSLStartSession(TCP_SOCKET hTCP);
void SSLTerminate(BYTE sslStubId);
void SSLPeriodic(TCP_SOCKET hTCP, BYTE sslStubID);
WORD SSLRxRecord(TCP_SOCKET hTCP, BYTE sslStubID);
void SSLRxHandshake(TCP_SOCKET hTCP);
void SSLTxRecord(TCP_SOCKET hTCP, BYTE sslStubID, BYTE txProtocol);
void SSLTxMessage(TCP_SOCKET hTCP, BYTE sslStubID, BYTE msg);

void SSLMACBegin(BYTE* MACSecret, DWORD seq, BYTE protocol, WORD len);
void SSLMACAdd(BYTE* data, WORD len);
void SSLMACCalc(BYTE* MACSecret, BYTE* result);

#if defined(STACK_USE_SSL_SERVER)
	void SSLStartPartialRecord(TCP_SOCKET hTCP, BYTE sslStubID, BYTE txProtocol, WORD wLen);
	#define SSLFlushPartialRecord(a)		TCPSSLPutRecordHeader(a, NULL, FALSE);
	#define SSLFinishPartialRecord(a)		TCPSSLPutRecordHeader(a, NULL, TRUE);
#endif

#endif
