/*
 *	matrixInternal.h
 *	Release $Name: MATRIXSSL_1_2_4_OPEN $
 *
 *	Internal header file used for the MatrixSSL implementation.
 *	Only modifiers of the library should be intersted in this file
 */
/*
 *	Copyright (c) PeerSec Networks, 2002-2005. All Rights Reserved.
 *	The latest version of this code is available at http://www.matrixssl.org
 *
 *	This software is open source; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This General Public License does NOT permit incorporating this software 
 *	into proprietary programs.  If you are unable to comply with the GPL, a 
 *	commercial license for this software may be purchased from PeerSec Networks
 *	at http://www.peersec.com
 *	
 *	This program is distributed in WITHOUT ANY WARRANTY; without even the 
 *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *	See the GNU General Public License for more details.
 *	
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *	http://www.gnu.org/copyleft/gpl.html
 */
/******************************************************************************/

#ifndef _h_MATRIXINTERNAL
#define _h_MATRIXINTERNAL

/******************************************************************************/
/*
	Include the configuration header to define the features we're using
*/
#include "matrixConfig.h"

/******************************************************************************/
/*
	The top level source relies on the os and crypto layers.  Include them
*/
#include "os/osLayer.h"
#include "crypto/cryptoLayer.h"

#ifdef __cplusplus
extern "C" {
#endif

/******************************************************************************/

#if WIN32
#define				fcntl(A, B, C)
#define				MSG_NOSIGNAL	0
#endif /* WIN32 */

#define	SSL_FLAGS_SERVER		0x1		/* Must match value in matrixSsl.h */
#define	SSL_FLAGS_READ_SECURE	0x2
#define	SSL_FLAGS_WRITE_SECURE	0x4
#define SSL_FLAGS_PUBLIC_SECURE	0x8
#define SSL_FLAGS_RESUMED		0x10	
#define SSL_FLAGS_CLOSED		0x20
#define SSL_FLAGS_NEED_ENCODE	0x40
#define SSL_FLAGS_ERROR			0x80
#define SSL_FLAGS_CLIENT_AUTH	0x200	/* Must match value in matrixSsl.h */
	
/*
	matrixSslSetSessionOption defines
*/
#define	SSL_OPTION_DELETE_SESSION		0	/* Must match matrixSsl.h */

#define SSL2_HEADER_LEN				2
#define SSL3_HEADER_LEN				5
#define SSL3_HANDSHAKE_HEADER_LEN	4

/*
	These are defines rather than enums because we want to store them as char,
	not int32 (enum size)
*/
#define SSL_RECORD_TYPE_CHANGE_CIPHER_SPEC	20
#define SSL_RECORD_TYPE_ALERT				21
#define SSL_RECORD_TYPE_HANDSHAKE			22
#define SSL_RECORD_TYPE_APPLICATION_DATA	23

#define SSL_HS_HELLO_REQUEST		0
#define SSL_HS_CLIENT_HELLO			1
#define SSL_HS_SERVER_HELLO			2
#define SSL_HS_CERTIFICATE			11
#define SSL_HS_SERVER_KEY_EXCHANGE	12
#define SSL_HS_CERTIFICATE_REQUEST	13
#define SSL_HS_SERVER_HELLO_DONE	14
#define SSL_HS_CERTIFICATE_VERIFY	15
#define SSL_HS_CLIENT_KEY_EXCHANGE	16
#define SSL_HS_FINISHED				20
#define SSL_HS_DONE					255	/* Handshake complete (internal) */

#define	INIT_ENCRYPT_CIPHER		0
#define INIT_DECRYPT_CIPHER		1

#define RSA_SIGN	1

/*
	Additional ssl alert value, indicating no error has ocurred.
*/
#define SSL_ALERT_NONE					255	/* No error */

#define SSL_HS_RANDOM_SIZE		32
#define SSL_HS_PREMASTER_SIZE	48

#define SSL2_MAJ_VER	2
#define SSL3_MAJ_VER	3
#define SSL3_MIN_VER	0
#define TLS_MIN_VER		1


/*
	SSL cipher suite values
*/
#define SSL_NULL_WITH_NULL_NULL			0x0000
#define SSL_RSA_WITH_NULL_MD5			0x0001
#define SSL_RSA_WITH_NULL_SHA			0x0002
#define SSL_RSA_WITH_RC4_128_MD5		0x0004
#define SSL_RSA_WITH_RC4_128_SHA		0x0005
#define SSL_RSA_WITH_3DES_EDE_CBC_SHA	0x000A

/*
	Maximum key block size for any defined cipher
	This must be validated if new ciphers are added
	Value is largest total among all cipher suites for
		2*macSize + 2*keySize + 2*ivSize
*/
#define SSL_MAX_KEY_BLOCK_SIZE			2*20 + 2*24 + 2*8

/*
	Master secret is 48 bytes, sessionId is 32 bytes max
*/
#define		SSL_HS_MASTER_SIZE		48
#define		SSL_MAX_SESSION_ID_SIZE	32


/*
	Return the length of padding bytes required for a record of 'LEN' bytes
	The name Pwr2 indicates that calculations will work with 'BLOCKSIZE'
	that are powers of 2.
	Because of the trailing pad length byte, a length that is a multiple
	of the pad bytes
*/
#define sslPadLenPwr2(LEN, BLOCKSIZE) \
	BLOCKSIZE <= 1 ? (unsigned char)0 : \
	(unsigned char)(BLOCKSIZE - ((LEN) & (BLOCKSIZE - 1)))

/*
	Round up the given length to the correct length with SSLv3 padding
*/
#define sslRoundup018(LEN, BLOCKSIZE) \
	BLOCKSIZE <= 1 ? BLOCKSIZE : (((LEN) + 8) & ~7)

#ifndef max
#define max(a,b)	(((a) > (b)) ? (a) : (b))
#endif

#ifndef min
#define min(a,b)	(((a) < (b)) ? (a) : (b))
#endif

/******************************************************************************/

/******************************************************************************/
/*
	Buffer structure
*/
#ifndef sslBuf_t
/*
	Empty buffer:
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
	|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|
	 ^
	 \end
	 \start
	 \buf
	 size = 16
	 len = (end - start) = 0

	Buffer with data:

     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
	|.|.|a|b|c|d|e|f|g|h|i|j|.|.|.|.|
	 ^   ^                   ^
	 |   |                   \end
	 |   \start
	 \buf
	size = 16
	len = (end - start) = 10

	Read from start pointer
	Write to end pointer
*/
typedef struct {
	unsigned char	*buf;	/* Pointer to the start of the buffer */
	unsigned char	*start;	/* Pointer to start of valid data */
	unsigned char	*end;	/* Pointer to first byte of invalid data */
	int32		size;			/* Size of buffer in bytes */
} sslBuf_t;
#endif

/******************************************************************************/
/*
	SSL record and session structures
*/
typedef struct {
	unsigned short	len;
	unsigned char	majVer;
	unsigned char	minVer;
	unsigned char	type;
	unsigned char	pad[3];		/* Padding for 64 bit compat */
} sslRec_t;

typedef struct {
	unsigned char	clientRandom[SSL_HS_RANDOM_SIZE];	/* From ClientHello */
	unsigned char	serverRandom[SSL_HS_RANDOM_SIZE];	/* From ServerHello */
	unsigned char	premaster[SSL_HS_PREMASTER_SIZE];	/* From ClientKeyExchange */
	unsigned char	masterSecret[SSL_HS_MASTER_SIZE];

	unsigned char	keyBlock[SSL_MAX_KEY_BLOCK_SIZE];	/* Storage for the next six items */
	unsigned char	*wMACptr;
	unsigned char	*rMACptr;
	unsigned char	*wKeyptr;
	unsigned char	*rKeyptr;
	unsigned char	*wIVptr;
	unsigned char	*rIVptr;

	/*	All maximum sizes for current cipher suites */
	unsigned char	writeMAC[SSL_MAX_MAC_SIZE];
	unsigned char	readMAC[SSL_MAX_MAC_SIZE];
	unsigned char	writeKey[SSL_MAX_SYM_KEY_SIZE];
	unsigned char	readKey[SSL_MAX_SYM_KEY_SIZE];
	unsigned char	writeIV[SSL_MAX_IV_SIZE];
	unsigned char	readIV[SSL_MAX_IV_SIZE];

	unsigned char	seq[8];
	unsigned char	remSeq[8];

#ifdef USE_CLIENT_SIDE_SSL
	sslRsaCert_t	*cert;
	int32 (*validateCert)(sslCertInfo_t *certInfo, void *arg);
	void			*validateCertArg;
	int32			certMatch;
#endif /* USE_CLIENT_SIDE_SSL */

	sslMd5Context_t		msgHashMd5;
	sslSha1Context_t	msgHashSha1;

	sslCipherContext_t	encryptCtx;
	sslCipherContext_t	decryptCtx;
} sslSec_t;

typedef struct {
	uint32	id;
	unsigned char	macSize;
	unsigned char	keySize;
	unsigned char	ivSize;
	unsigned char	blockSize;
	/* Init function */
	int32 (*init)(sslSec_t *sec, int32 type);
	/* Cipher functions */
	int32 (*encrypt)(sslCipherContext_t *ctx, unsigned char *in,
		unsigned char *out, int32 len);
	int32 (*decrypt)(sslCipherContext_t *ctx, unsigned char *in,
		unsigned char *out, int32 len);
	int32 (*encryptPub)(psPool_t *pool, sslRsaKey_t *key, 
		unsigned char *in, int32 inlen,
		unsigned char *out, int32 outlen);
	int32 (*decryptPriv)(psPool_t *pool, sslRsaKey_t *key, 
		unsigned char *in, int32 inlen,
		unsigned char *out, int32 outlen);
	int32 (*generateMac)(void *ssl, unsigned char type, unsigned char *data,
		int32 len, unsigned char *mac);
	int32 (*verifyMac)(void *ssl, unsigned char type, unsigned char *data,
		int32 len, unsigned char *mac);
} sslCipherSpec_t;

typedef struct sslLocalCert {
	sslRsaKey_t			*privKey;
	unsigned char		*certBin;
	uint32		certLen;
	struct sslLocalCert	*next;
} sslLocalCert_t;

typedef struct {
	sslLocalCert_t		cert;
#ifdef USE_CLIENT_SIDE_SSL
	sslRsaCert_t		*caCerts;
#endif /* USE_CLIENT_SIDE_SSL */
} sslKeys_t;

typedef struct ssl {
	sslRec_t		rec;			/* Current SSL record information*/
									
	sslSec_t		sec;			/* Security structure */

	sslKeys_t		*keys;			/* SSL public and private keys */

	psPool_t		*pool;			/* SSL session pool */
	psPool_t		*hsPool;		/* Full session handshake pool */

	unsigned char	sessionIdLen;
	char			sessionId[SSL_MAX_SESSION_ID_SIZE];

	/* Pointer to the negotiated cipher information */
	sslCipherSpec_t	*cipher;

	/* 	Symmetric cipher callbacks

		We duplicate these here from 'cipher' because we need to set the
		various callbacks at different times in the handshake protocol
		Also, there are 64 bit alignment issues in using the function pointers
		within 'cipher' directly
	*/
	int32 (*encrypt)(sslCipherContext_t *ctx, unsigned char *in,
		unsigned char *out, int32 len);
	int32 (*decrypt)(sslCipherContext_t *ctx, unsigned char *in,
		unsigned char *out, int32 len);
	/* Public key ciphers */
	int32 (*encryptPub)(psPool_t *pool, sslRsaKey_t *key, 
		unsigned char *in, int32 inlen,
		unsigned char *out, int32 outlen);
	int32 (*decryptPriv)(psPool_t *pool, sslRsaKey_t *key, 
		unsigned char *in, int32 inlen,
		unsigned char *out, int32 outlen);
	/* Message Authentication Codes */
	int32 (*generateMac)(void *ssl, unsigned char type, unsigned char *data,
		int32 len, unsigned char *mac);
	int32 (*verifyMac)(void *ssl, unsigned char type, unsigned char *data,
		int32 len, unsigned char *mac);

	/* Current encryption/decryption parameters */
	unsigned char	enMacSize;
	unsigned char	enIvSize;
	unsigned char	enBlockSize;
	unsigned char	deMacSize;
	unsigned char	deIvSize;
	unsigned char	deBlockSize;

	int32				flags;
	int32				hsState;		/* Next expected handshake message type */
	int32				err;			/* SSL errno of last api call */
	int32				ignoredMessageCount;

	unsigned char	reqMajVer;
	unsigned char	reqMinVer;
	unsigned char	majVer;
	unsigned char	minVer;
	int32				recordHeadLen;
	int32				hshakeHeadLen;
} ssl_t;

typedef struct {
	unsigned char	id[SSL_MAX_SESSION_ID_SIZE];
	unsigned char	masterSecret[SSL_HS_MASTER_SIZE];
	uint32	cipherId;
} sslSessionId_t;

typedef struct {
	unsigned char	id[SSL_MAX_SESSION_ID_SIZE];
	unsigned char	masterSecret[SSL_HS_MASTER_SIZE];
	sslCipherSpec_t	*cipher;
	unsigned char	majVer;
	unsigned char	minVer;
	sslTime_t		startTime;
	sslTime_t		accessTime;
	int32				inUse;
} sslSessionEntry_t;

/*
	Include the public header here to define the public api calls
	and public defines used internally.
	Some of the types in the public header are duplicately defined, but
	they are predicated on _h_MATRIXINTERNAL, which is defined by this file.
*/
#include "../matrixSsl.h"

/******************************************************************************/
/*
	No file system
*/
extern int32 matrixSslReadKeysMem(sslKeys_t **keys, char *certBuf, int32 certLen, 
								char *privBuf, int32 privLen, char *privPass,
								char *trustedCABuf, int32 trustedCALen);
/******************************************************************************/
/*
	sslEncode.c and sslDecode.c
*/
extern int32 psWriteRecordInfo(ssl_t *ssl, unsigned char type, int32 len,
							 unsigned char *c);
extern int32 psWriteHandshakeHeader(ssl_t *ssl, unsigned char type, int32 len, 
								int32 seq, int32 fragOffset, int32 fragLen,
								unsigned char *c);
extern int32 sslEncodeResponse(ssl_t *ssl, sslBuf_t *out);
extern int32 sslActivateReadCipher(ssl_t *ssl);
extern int32 sslActivateWriteCipher(ssl_t *ssl);
extern int32 sslActivatePublicCipher(ssl_t *ssl);
extern int32 sslUpdateHSHash(ssl_t *ssl, unsigned char *in, int32 len);
extern int32 sslInitHSHash(ssl_t *ssl);
extern int32 sslSnapshotHSHash(ssl_t *ssl, unsigned char *out, int32 senderFlag);

extern void sslResetContext(ssl_t *ssl);

#ifdef USE_SERVER_SIDE_SSL
extern int32 matrixRegisterSession(ssl_t *ssl);
extern int32 matrixResumeSession(ssl_t *ssl);
extern int32 matrixClearSession(ssl_t *ssl, int32 remove);
extern int32 matrixUpdateSession(ssl_t *ssl);
#endif /* USE_SERVER_SIDE_SSL */


/*
	cipherSuite.c
*/
extern sslCipherSpec_t *sslGetCipherSpec(int32 id);
extern int32 sslGetCipherSpecListLen();
extern int32 sslGetCipherSpecList(unsigned char *c, int32 len);

/******************************************************************************/
/*
	sslv3.c
*/
extern int32 sslGenerateFinishedHash(sslMd5Context_t *md5, sslSha1Context_t *sha1,
								unsigned char *masterSecret,
								unsigned char *out, int32 sender);

extern int32 sslDeriveKeys(ssl_t *ssl);

#ifdef USE_SHA1_MAC
extern int32 ssl3HMACSha1(unsigned char *key, unsigned char *seq, 
						unsigned char type, unsigned char *data, int32 len,
						unsigned char *mac);
#endif /* USE_SHA1_MAC */

#ifdef USE_MD5_MAC
extern int32 ssl3HMACMd5(unsigned char *key, unsigned char *seq, 
						unsigned char type, unsigned char *data, int32 len,
						unsigned char *mac);
#endif /* USE_MD5_MAC */


/******************************************************************************/

#ifdef __cplusplus
}
#endif

#endif /* _h_MATRIXINTERNAL */

/******************************************************************************/



