Update ssl library to support EVP_PKEY MAC API. Include generic MAC support.
diff --git a/ssl/d1_enc.c b/ssl/d1_enc.c
index cbff749..ef4d880 100644
--- a/ssl/d1_enc.c
+++ b/ssl/d1_enc.c
@@ -132,8 +132,8 @@
 
 	if (send)
 		{
-		if (s->write_hash != NULL)
-			n=EVP_MD_size(s->write_hash);
+		if (EVP_MD_CTX_md(s->write_hash))
+			n=EVP_MD_CTX_size(s->write_hash);
 		ds=s->enc_write_ctx;
 		rec= &(s->s3->wrec);
 		if (s->enc_write_ctx == NULL)
@@ -154,8 +154,8 @@
 		}
 	else
 		{
-		if (s->read_hash != NULL)
-			n=EVP_MD_size(s->read_hash);
+		if (EVP_MD_CTX_md(s->read_hash))
+			n=EVP_MD_CTX_size(s->read_hash);
 		ds=s->enc_read_ctx;
 		rec= &(s->s3->rrec);
 		if (s->enc_read_ctx == NULL)
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index 8a047ae..bf189f1 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -426,7 +426,7 @@
 
 	if (!clear)
 		{
-		mac_size=EVP_MD_size(s->read_hash);
+		mac_size=EVP_MD_CTX_size(s->read_hash);
 
 		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
 			{
@@ -1335,13 +1335,13 @@
 
 	if (	(sess == NULL) ||
 		(s->enc_write_ctx == NULL) ||
-		(s->write_hash == NULL))
+		(EVP_MD_CTX_md(s->write_hash) == NULL))
 		clear=1;
 
 	if (clear)
 		mac_size=0;
 	else
-		mac_size=EVP_MD_size(s->write_hash);
+		mac_size=EVP_MD_CTX_size(s->write_hash);
 
 	/* DTLS implements explicit IV, so no need for empty fragments */
 #if 0
diff --git a/ssl/s2_clnt.c b/ssl/s2_clnt.c
index 6d8883f..7b3b7d8 100644
--- a/ssl/s2_clnt.c
+++ b/ssl/s2_clnt.c
@@ -621,7 +621,7 @@
 	if (s->state == SSL2_ST_SEND_CLIENT_MASTER_KEY_A)
 		{
 
-		if (!ssl_cipher_get_evp(s->session,&c,&md,NULL))
+		if (!ssl_cipher_get_evp(s->session,&c,&md,NULL,NULL,NULL))
 			{
 			ssl2_return_error(s,SSL2_PE_NO_CIPHER);
 			SSLerr(SSL_F_CLIENT_MASTER_KEY,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS);
diff --git a/ssl/s2_enc.c b/ssl/s2_enc.c
index 1f62acd..ff3395f 100644
--- a/ssl/s2_enc.c
+++ b/ssl/s2_enc.c
@@ -68,15 +68,14 @@
 	const EVP_MD *md;
 	int num;
 
-	if (!ssl_cipher_get_evp(s->session,&c,&md,NULL))
+	if (!ssl_cipher_get_evp(s->session,&c,&md,NULL,NULL,NULL))
 		{
 		ssl2_return_error(s,SSL2_PE_NO_CIPHER);
 		SSLerr(SSL_F_SSL2_ENC_INIT,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS);
 		return(0);
 		}
-
-	s->read_hash=md;
-	s->write_hash=md;
+	ssl_replace_hash(&s->read_hash,md);
+	ssl_replace_hash(&s->write_hash,md);
 
 	if ((s->enc_read_ctx == NULL) &&
 		((s->enc_read_ctx=(EVP_CIPHER_CTX *)
@@ -176,7 +175,7 @@
 
 	/* There has to be a MAC algorithm. */
 	EVP_MD_CTX_init(&c);
-	EVP_DigestInit_ex(&c, s->read_hash, NULL);
+	EVP_MD_CTX_copy(&c, s->read_hash);
 	EVP_DigestUpdate(&c,sec,
 		EVP_CIPHER_CTX_key_length(s->enc_read_ctx));
 	EVP_DigestUpdate(&c,act,len); 
diff --git a/ssl/s2_pkt.c b/ssl/s2_pkt.c
index a10929a..e6d5d09 100644
--- a/ssl/s2_pkt.c
+++ b/ssl/s2_pkt.c
@@ -246,7 +246,7 @@
 			}
 		else
 			{
-			mac_size=EVP_MD_size(s->read_hash);
+			mac_size=EVP_MD_CTX_size(s->read_hash);
 			OPENSSL_assert(mac_size <= MAX_MAC_SIZE);
 			s->s2->mac_data=p;
 			s->s2->ract_data= &p[mac_size];
@@ -529,7 +529,7 @@
 	if (s->s2->clear_text)
 		mac_size=0;
 	else
-		mac_size=EVP_MD_size(s->write_hash);
+		mac_size=EVP_MD_CTX_size(s->write_hash);
 
 	/* lets set the pad p */
 	if (s->s2->clear_text)
diff --git a/ssl/s2_srvr.c b/ssl/s2_srvr.c
index 4594324..44c1ee3 100644
--- a/ssl/s2_srvr.c
+++ b/ssl/s2_srvr.c
@@ -451,7 +451,7 @@
 
 	is_export=SSL_C_IS_EXPORT(s->session->cipher);
 	
-	if (!ssl_cipher_get_evp(s->session,&c,&md,NULL))
+	if (!ssl_cipher_get_evp(s->session,&c,&md,NULL,NULL,NULL))
 		{
 		ssl2_return_error(s,SSL2_PE_NO_CIPHER);
 		SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS);
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index 8f3ba93..010069b 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -251,7 +251,8 @@
 			/* make sure it's intialized in case we exit later with an error */
 			EVP_CIPHER_CTX_init(s->enc_read_ctx);
 		dd= s->enc_read_ctx;
-		s->read_hash=m;
+
+		ssl_replace_hash(&s->read_hash,m);
 #ifndef OPENSSL_NO_COMP
 		/* COMPRESS */
 		if (s->expand != NULL)
@@ -287,7 +288,7 @@
 			/* make sure it's intialized in case we exit later with an error */
 			EVP_CIPHER_CTX_init(s->enc_write_ctx);
 		dd= s->enc_write_ctx;
-		s->write_hash=m;
+		ssl_replace_hash(&s->write_hash,m);
 #ifndef OPENSSL_NO_COMP
 		/* COMPRESS */
 		if (s->compress != NULL)
@@ -394,7 +395,7 @@
 	if (s->s3->tmp.key_block_length != 0)
 		return(1);
 
-	if (!ssl_cipher_get_evp(s->session,&c,&hash,&comp))
+	if (!ssl_cipher_get_evp(s->session,&c,&hash,NULL,NULL,&comp))
 		{
 		SSLerr(SSL_F_SSL3_SETUP_KEY_BLOCK,SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
 		return(0);
@@ -581,7 +582,6 @@
 
 	EVP_MD_CTX_init(&ctx);
 	EVP_MD_CTX_copy_ex(&ctx,in_ctx);
-
 	n=EVP_MD_CTX_size(&ctx);
 	npad=(48/n)*n;
 
@@ -609,7 +609,7 @@
 	SSL3_RECORD *rec;
 	unsigned char *mac_sec,*seq;
 	EVP_MD_CTX md_ctx;
-	const EVP_MD *hash;
+	const EVP_MD_CTX *hash;
 	unsigned char *p,rec_char;
 	unsigned int md_size;
 	int npad;
@@ -629,13 +629,13 @@
 		hash=ssl->read_hash;
 		}
 
-	md_size=EVP_MD_size(hash);
+	md_size=EVP_MD_CTX_size(hash);
 	npad=(48/md_size)*md_size;
 
 	/* Chop the digest off the end :-) */
 	EVP_MD_CTX_init(&md_ctx);
 
-	EVP_DigestInit_ex(  &md_ctx,hash, NULL);
+	EVP_MD_CTX_copy_ex( &md_ctx,hash);
 	EVP_DigestUpdate(&md_ctx,mac_sec,md_size);
 	EVP_DigestUpdate(&md_ctx,ssl3_pad_1,npad);
 	EVP_DigestUpdate(&md_ctx,seq,8);
@@ -647,7 +647,7 @@
 	EVP_DigestUpdate(&md_ctx,rec->input,rec->length);
 	EVP_DigestFinal_ex( &md_ctx,md,NULL);
 
-	EVP_DigestInit_ex(  &md_ctx,hash, NULL);
+	EVP_MD_CTX_copy_ex( &md_ctx,hash);
 	EVP_DigestUpdate(&md_ctx,mac_sec,md_size);
 	EVP_DigestUpdate(&md_ctx,ssl3_pad_2,npad);
 	EVP_DigestUpdate(&md_ctx,md,md_size);
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 4ac6961..bd0056b 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -1972,6 +1972,48 @@
 	256,
 	256,
 	},
+	{
+	1,
+	"GOST-GOST94",
+	0x0300ff01,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eGOST2814789CNT,
+	SSL_GOST94,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	0,
+	256,
+	256
+	},
+	{
+	1,
+	"GOST-GOST89MAC",
+	0x0300ff02,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eGOST2814789CNT,
+	SSL_GOST89MAC,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	0,
+	256,
+	256
+	},
+	{
+	1,
+	"GOST-GOST89STREAM",
+	0x0300ff03,
+	SSL_kRSA,
+	SSL_aRSA,
+	SSL_eGOST2814789CNT,
+	SSL_GOST89MAC,
+	SSL_TLSV1,
+	SSL_NOT_EXP|SSL_HIGH,
+	TLS1_STREAM_MAC,
+	256,
+	256
+	},
 #endif
 
 /* end of list */
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index 6754e99..58f2845 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -399,12 +399,12 @@
 	/* r->length is now the compressed data plus mac */
 	if (	(sess == NULL) ||
 		(s->enc_read_ctx == NULL) ||
-		(s->read_hash == NULL))
+		(EVP_MD_CTX_md(s->read_hash) == NULL))
 		clear=1;
 
 	if (!clear)
 		{
-		mac_size=EVP_MD_size(s->read_hash);
+		mac_size=EVP_MD_CTX_size(s->read_hash);
 
 		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
 			{
@@ -629,13 +629,13 @@
 
 	if (	(sess == NULL) ||
 		(s->enc_write_ctx == NULL) ||
-		(s->write_hash == NULL))
+		(EVP_MD_CTX_md(s->write_hash) == NULL))
 		clear=1;
 
 	if (clear)
 		mac_size=0;
 	else
-		mac_size=EVP_MD_size(s->write_hash);
+		mac_size=EVP_MD_CTX_size(s->write_hash);
 
 	/* 'create_empty_fragment' is true only when this function calls itself */
 	if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done)
diff --git a/ssl/ssl.h b/ssl/ssl.h
index abc3342..5702464 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -286,6 +286,8 @@
 #define SSL_TXT_MD5		"MD5"
 #define SSL_TXT_SHA1		"SHA1"
 #define SSL_TXT_SHA		"SHA" /* same as "SHA1" */
+#define SSL_TXT_GOST94		"GOST94" 
+#define SSL_TXT_GOST89MAC		"GOST89MAC" 
 
 #define SSL_TXT_SSLV2		"SSLv2"
 #define SSL_TXT_SSLV3		"SSLv3"
@@ -884,6 +886,9 @@
 #define SSL_want_write(s)	(SSL_want(s) == SSL_WRITING)
 #define SSL_want_x509_lookup(s)	(SSL_want(s) == SSL_X509_LOOKUP)
 
+#define SSL_MAC_FLAG_READ_MAC_STREAM 1
+#define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
+
 struct ssl_st
 	{
 	/* protocol version
@@ -975,9 +980,9 @@
 
 	/* These are the ones being used, the ones in SSL_SESSION are
 	 * the ones to be 'copied' into these ones */
-
+	int mac_flags; 
 	EVP_CIPHER_CTX *enc_read_ctx;		/* cryptographic state */
-	const EVP_MD *read_hash;		/* used for mac generation */
+	EVP_MD_CTX *read_hash;		/* used for mac generation */
 #ifndef OPENSSL_NO_COMP
 	COMP_CTX *expand;			/* uncompress */
 #else
@@ -985,7 +990,7 @@
 #endif
 
 	EVP_CIPHER_CTX *enc_write_ctx;		/* cryptographic state */
-	const EVP_MD *write_hash;		/* used for mac generation */
+	EVP_MD_CTX *write_hash;		/* used for mac generation */
 #ifndef OPENSSL_NO_COMP
 	COMP_CTX *compress;			/* compression */
 #else
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
index 5ddadb2..2d5db78 100644
--- a/ssl/ssl3.h
+++ b/ssl/ssl3.h
@@ -382,8 +382,10 @@
 	int delay_buf_pop_ret;
 
 	unsigned char read_sequence[8];
+	int read_mac_secret_size;
 	unsigned char read_mac_secret[EVP_MAX_MD_SIZE];
 	unsigned char write_sequence[8];
+	int write_mac_secret_size;
 	unsigned char write_mac_secret[EVP_MAX_MD_SIZE];
 
 	unsigned char server_random[SSL3_RANDOM_SIZE];
@@ -480,6 +482,8 @@
 
 		const EVP_CIPHER *new_sym_enc;
 		const EVP_MD *new_hash;
+		int new_mac_pkey_type;
+		int new_mac_secret_size;
 #ifndef OPENSSL_NO_COMP
 		const SSL_COMP *new_compression;
 #else
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index 0a56042..d2e648b 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -143,6 +143,7 @@
 #include <stdio.h>
 #include <openssl/objects.h>
 #include <openssl/comp.h>
+#include <openssl/engine.h>
 #include "ssl_locl.h"
 
 #define SSL_ENC_DES_IDX		0
@@ -172,9 +173,22 @@
 
 #define SSL_MD_MD5_IDX	0
 #define SSL_MD_SHA1_IDX	1
-#define SSL_MD_NUM_IDX	2
+#define SSL_MD_GOST94_IDX 2
+#define SSL_MD_GOST89MAC_IDX 3
+#define SSL_MD_NUM_IDX	4
 static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX]={
-	NULL,NULL,
+	NULL,NULL,NULL,NULL
+	};
+/* PKEY_TYPE for GOST89MAC is known in advance, but, because
+ * implementation is engine-provided, we'll fill it only if
+ * corresponding EVP_PKEY_METHOD is found 
+ */
+static int  ssl_mac_pkey_id[SSL_MD_NUM_IDX]={
+	EVP_PKEY_HMAC,EVP_PKEY_HMAC,EVP_PKEY_HMAC,NID_undef
+	};
+
+static int ssl_mac_secret_size[SSL_MD_NUM_IDX]={
+	0,0,0,0
 	};
 
 #define CIPHER_ADD	1
@@ -266,6 +280,8 @@
 	{0,SSL_TXT_MD5,0,     0,0,0,SSL_MD5,   0,0,0,0,0},
 	{0,SSL_TXT_SHA1,0,    0,0,0,SSL_SHA1,  0,0,0,0,0},
 	{0,SSL_TXT_SHA,0,     0,0,0,SSL_SHA1,  0,0,0,0,0},
+	{0,SSL_TXT_GOST94,0,     0,0,0,SSL_GOST94,  0,0,0,0,0},
+	{0,SSL_TXT_GOST89MAC,0,     0,0,0,SSL_GOST89MAC,  0,0,0,0,0},
 
 	/* protocol version aliases */
 	{0,SSL_TXT_SSLV2,0,   0,0,0,0,SSL_SSLV2, 0,0,0,0},
@@ -315,11 +331,36 @@
 
 	ssl_digest_methods[SSL_MD_MD5_IDX]=
 		EVP_get_digestbyname(SN_md5);
+	ssl_mac_secret_size[SSL_MD_MD5_IDX]=
+		EVP_MD_size(ssl_digest_methods[SSL_MD_MD5_IDX]);
 	ssl_digest_methods[SSL_MD_SHA1_IDX]=
 		EVP_get_digestbyname(SN_sha1);
+	ssl_mac_secret_size[SSL_MD_SHA1_IDX]=
+		EVP_MD_size(ssl_digest_methods[SSL_MD_SHA1_IDX]);
+	ssl_digest_methods[SSL_MD_GOST94_IDX]=
+		EVP_get_digestbyname(SN_id_GostR3411_94);
+	if (ssl_digest_methods[SSL_MD_GOST94_IDX])
+		{	
+		ssl_mac_secret_size[SSL_MD_GOST94_IDX]=
+			EVP_MD_size(ssl_digest_methods[SSL_MD_GOST94_IDX]);
+		}
+	ssl_digest_methods[SSL_MD_GOST89MAC_IDX]=
+		EVP_get_digestbyname(SN_id_Gost28147_89_MAC);
+		{
+		const EVP_PKEY_ASN1_METHOD *ameth;
+		ENGINE *tmpeng = NULL;
+		int pkey_id;
+		ameth = EVP_PKEY_asn1_find_str(&tmpeng,"gost-mac",-1);
+		if (ameth) 
+			{
+			EVP_PKEY_asn1_get0_info(&pkey_id, NULL,NULL,NULL,NULL,ameth);
+			ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX]= pkey_id;
+			ssl_mac_secret_size[SSL_MD_GOST89MAC_IDX]=32;
+			}		
+		if (tmpeng) ENGINE_finish(tmpeng);	
+		}
+
 	}
-
-
 #ifndef OPENSSL_NO_COMP
 
 static int sk_comp_cmp(const SSL_COMP * const *a,
@@ -374,7 +415,7 @@
 #endif
 
 int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
-	     const EVP_MD **md, SSL_COMP **comp)
+	     const EVP_MD **md, int *mac_pkey_type, int *mac_secret_size,SSL_COMP **comp)
 	{
 	int i;
 	SSL_CIPHER *c;
@@ -463,16 +504,31 @@
 	case SSL_SHA1:
 		i=SSL_MD_SHA1_IDX;
 		break;
+	case SSL_GOST94:
+		i = SSL_MD_GOST94_IDX;
+		break;
+	case SSL_GOST89MAC:
+		i = SSL_MD_GOST89MAC_IDX;
+		break;
 	default:
 		i= -1;
 		break;
 		}
 	if ((i < 0) || (i > SSL_MD_NUM_IDX))
-		*md=NULL;
-	else
-		*md=ssl_digest_methods[i];
+	{
+		*md=NULL; 
+		if (mac_pkey_type!=NULL) *mac_pkey_type = NID_undef;
+		if (mac_secret_size!=NULL) *mac_secret_size = 0;
 
-	if ((*enc != NULL) && (*md != NULL))
+	}
+	else
+	{
+		*md=ssl_digest_methods[i];
+		if (mac_pkey_type!=NULL) *mac_pkey_type = ssl_mac_pkey_id[i];
+		if (mac_secret_size!=NULL) *mac_secret_size = ssl_mac_secret_size[i];
+	}	
+
+	if ((*enc != NULL) && (*md != NULL) && (!mac_pkey_type||*mac_pkey_type != NID_undef))
 		return(1);
 	else
 		return(0);
@@ -567,6 +623,9 @@
 
 	*mac |= (ssl_digest_methods[SSL_MD_MD5_IDX ] == NULL) ? SSL_MD5 :0;
 	*mac |= (ssl_digest_methods[SSL_MD_SHA1_IDX] == NULL) ? SSL_SHA1:0;
+	*mac |= (ssl_digest_methods[SSL_MD_GOST94_IDX] == NULL) ? SSL_GOST94:0;
+	*mac |= (ssl_digest_methods[SSL_MD_GOST89MAC_IDX] == NULL || ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX]==NID_undef)? SSL_GOST89MAC:0;
+
 	}
 
 static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method,
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index d73c7ca..ab15575 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -225,6 +225,8 @@
 		}
 
 	ssl_clear_cipher_ctx(s);
+	ssl_clear_hash_ctx(&s->read_hash);
+	ssl_clear_hash_ctx(&s->write_hash);
 
 	s->first_packet=0;
 
@@ -523,6 +525,8 @@
 		}
 
 	ssl_clear_cipher_ctx(s);
+	ssl_clear_hash_ctx(&s->read_hash);
+	ssl_clear_hash_ctx(&s->write_hash);
 
 	if (s->cert != NULL) ssl_cert_free(s->cert);
 	/* Free up if allocated */
@@ -2203,6 +2207,8 @@
 	s->handshake_func=s->method->ssl_accept;
 	/* clear the current cipher */
 	ssl_clear_cipher_ctx(s);
+	ssl_clear_hash_ctx(&s->read_hash);
+	ssl_clear_hash_ctx(&s->write_hash);
 	}
 
 void SSL_set_connect_state(SSL *s)
@@ -2213,6 +2219,8 @@
 	s->handshake_func=s->method->ssl_connect;
 	/* clear the current cipher */
 	ssl_clear_cipher_ctx(s);
+	ssl_clear_hash_ctx(&s->read_hash);
+	ssl_clear_hash_ctx(&s->write_hash);
 	}
 
 int ssl_undefined_function(SSL *s)
@@ -2836,7 +2844,25 @@
 	SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
 	}
 
+/* Allocates new EVP_MD_CTX and sets pointer to it into given pointer
+ * vairable, freeing  EVP_MD_CTX previously stored in that variable, if
+ * any. If EVP_MD pointer is passed, initializes ctx with this md
+ * Returns newly allocated ctx;
+ */ 
 
+EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) 
+{
+	ssl_clear_hash_ctx(hash);
+	*hash = EVP_MD_CTX_create();
+	if (md) EVP_DigestInit_ex(*hash,md,NULL);
+	return *hash;
+}
+void ssl_clear_hash_ctx(EVP_MD_CTX **hash) 
+{
+
+	if (*hash) EVP_MD_CTX_destroy(*hash);
+	*hash=NULL;
+}
 
 #if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16)
 #include "../crypto/bio/bss_file.c"
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 8488a61..004e21d 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -320,7 +320,8 @@
 /* Bits for algorithm_mac (symmetric authentication) */
 #define SSL_MD5			0x00000001L
 #define SSL_SHA1		0x00000002L
-
+#define SSL_GOST94      0x00000004L
+#define SSL_GOST89MAC   0x00000008L
 
 /* Bits for algorithm_ssl (protocol version) */
 #define SSL_SSLV2		0x00000001L
@@ -753,7 +754,7 @@
 					     const char *rule_str);
 void ssl_update_cache(SSL *s, int mode);
 int ssl_cipher_get_evp(const SSL_SESSION *s,const EVP_CIPHER **enc,
-		       const EVP_MD **md,SSL_COMP **comp);
+		       const EVP_MD **md,int *mac_pkey_type,int *mac_secret_size, SSL_COMP **comp);
 int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk);
 int ssl_undefined_function(SSL *s);
 int ssl_undefined_void_function(void);
@@ -984,5 +985,7 @@
 int ssl_prepare_serverhello_tlsext(SSL *s);
 int ssl_check_clienthello_tlsext(SSL *s);
 int ssl_check_serverhello_tlsext(SSL *s);
+EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
+void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
 #endif
 #endif
diff --git a/ssl/ssl_txt.c b/ssl/ssl_txt.c
index f51e48b..22f9a40 100644
--- a/ssl/ssl_txt.c
+++ b/ssl/ssl_txt.c
@@ -188,7 +188,7 @@
 		{
 		SSL_COMP *comp = NULL;
 
-		ssl_cipher_get_evp(x,NULL,NULL,&comp);
+		ssl_cipher_get_evp(x,NULL,NULL,NULL,NULL,&comp);
 		if (comp == NULL)
 			{
 			if (BIO_printf(bp,"\n   Compression: %d",x->compress_meth) <= 0) goto err;
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 8398d27..7a4e2ce 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -261,12 +261,17 @@
 	const SSL_COMP *comp;
 #endif
 	const EVP_MD *m;
+	int mac_type;
+	int *mac_secret_size;
+	EVP_MD_CTX *mac_ctx;
+	EVP_PKEY *mac_key;
 	int is_export,n,i,j,k,exp_label_len,cl;
 	int reuse_dd = 0;
 
 	is_export=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher);
 	c=s->s3->tmp.new_sym_enc;
 	m=s->s3->tmp.new_hash;
+	mac_type = s->s3->tmp.new_mac_pkey_type;
 #ifndef OPENSSL_NO_COMP
 	comp=s->s3->tmp.new_compression;
 #endif
@@ -291,6 +296,11 @@
 
 	if (which & SSL3_CC_READ)
 		{
+		if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
+			s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM;
+			else
+			s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM;
+
 		if (s->enc_read_ctx != NULL)
 			reuse_dd = 1;
 		else if ((s->enc_read_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
@@ -299,7 +309,7 @@
 			/* make sure it's intialized in case we exit later with an error */
 			EVP_CIPHER_CTX_init(s->enc_read_ctx);
 		dd= s->enc_read_ctx;
-		s->read_hash=m;
+		mac_ctx=ssl_replace_hash(&s->read_hash,NULL);
 #ifndef OPENSSL_NO_COMP
 		if (s->expand != NULL)
 			{
@@ -325,9 +335,14 @@
  		if (s->version != DTLS1_VERSION)
 			memset(&(s->s3->read_sequence[0]),0,8);
 		mac_secret= &(s->s3->read_mac_secret[0]);
+		mac_secret_size=&(s->s3->read_mac_secret_size);
 		}
 	else
 		{
+		if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
+			s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM;
+			else
+			s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_STREAM;
 		if (s->enc_write_ctx != NULL)
 			reuse_dd = 1;
 		else if ((s->enc_write_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL)
@@ -336,7 +351,7 @@
 			/* make sure it's intialized in case we exit later with an error */
 			EVP_CIPHER_CTX_init(s->enc_write_ctx);
 		dd= s->enc_write_ctx;
-		s->write_hash=m;
+		mac_ctx = ssl_replace_hash(&s->write_hash,NULL);
 #ifndef OPENSSL_NO_COMP
 		if (s->compress != NULL)
 			{
@@ -357,13 +372,15 @@
  		if (s->version != DTLS1_VERSION)
 			memset(&(s->s3->write_sequence[0]),0,8);
 		mac_secret= &(s->s3->write_mac_secret[0]);
+		mac_secret_size = &(s->s3->write_mac_secret_size);
 		}
 
 	if (reuse_dd)
 		EVP_CIPHER_CTX_cleanup(dd);
 
 	p=s->s3->tmp.key_block;
-	i=EVP_MD_size(m);
+	i=*mac_secret_size=s->s3->tmp.new_mac_secret_size;
+
 	cl=EVP_CIPHER_key_length(c);
 	j=is_export ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ?
 	               cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
@@ -399,6 +416,10 @@
 		}
 
 	memcpy(mac_secret,ms,i);
+	mac_key = EVP_PKEY_new_mac_key(mac_type, NULL,
+			mac_secret,*mac_secret_size);
+	EVP_DigestSignInit(mac_ctx,NULL,m,NULL,mac_key);
+	EVP_PKEY_free(mac_key);
 #ifdef TLS_DEBUG
 printf("which = %04X\nmac key=",which);
 { int z; for (z=0; z<i; z++) printf("%02X%c",ms[z],((z+1)%16)?' ':'\n'); }
@@ -477,6 +498,7 @@
 	const EVP_MD *hash;
 	int num;
 	SSL_COMP *comp;
+	int mac_type= NID_undef,mac_secret_size=0;
 
 #ifdef KSSL_DEBUG
 	printf ("tls1_setup_key_block()\n");
@@ -485,7 +507,7 @@
 	if (s->s3->tmp.key_block_length != 0)
 		return(1);
 
-	if (!ssl_cipher_get_evp(s->session,&c,&hash,&comp))
+	if (!ssl_cipher_get_evp(s->session,&c,&hash,&mac_type,&mac_secret_size,&comp))
 		{
 		SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK,SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
 		return(0);
@@ -493,8 +515,9 @@
 
 	s->s3->tmp.new_sym_enc=c;
 	s->s3->tmp.new_hash=hash;
-
-	num=EVP_CIPHER_key_length(c)+EVP_MD_size(hash)+EVP_CIPHER_iv_length(c);
+	s->s3->tmp.new_mac_pkey_type = mac_type;
+	s->s3->tmp.new_mac_secret_size = mac_secret_size;
+	num=EVP_CIPHER_key_length(c)+mac_secret_size+EVP_CIPHER_iv_length(c);
 	num*=2;
 
 	ssl3_cleanup_key_block(s);
@@ -559,8 +582,8 @@
 
 	if (send)
 		{
-		if (s->write_hash != NULL)
-			n=EVP_MD_size(s->write_hash);
+		if (EVP_MD_CTX_md(s->write_hash))
+			n=EVP_MD_CTX_size(s->write_hash);
 		ds=s->enc_write_ctx;
 		rec= &(s->s3->wrec);
 		if (s->enc_write_ctx == NULL)
@@ -570,8 +593,8 @@
 		}
 	else
 		{
-		if (s->read_hash != NULL)
-			n=EVP_MD_size(s->read_hash);
+		if (EVP_MD_CTX_md(s->read_hash))
+			n=EVP_MD_CTX_size(s->read_hash);
 		ds=s->enc_read_ctx;
 		rec= &(s->s3->rrec);
 		if (s->enc_read_ctx == NULL)
@@ -742,12 +765,12 @@
 	{
 	SSL3_RECORD *rec;
 	unsigned char *mac_sec,*seq;
-	const EVP_MD *hash;
-	unsigned int md_size;
+	EVP_MD_CTX *hash;
+	size_t md_size;
 	int i;
-	HMAC_CTX hmac;
+	EVP_MD_CTX hmac, *mac_ctx;
 	unsigned char buf[5]; 
-
+	int stream_mac = (send?(ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM):(ssl->mac_flags&SSL_MAC_FLAG_READ_MAC_STREAM));
 	if (send)
 		{
 		rec= &(ssl->s3->wrec);
@@ -763,7 +786,7 @@
 		hash=ssl->read_hash;
 		}
 
-	md_size=EVP_MD_size(hash);
+	md_size=EVP_MD_CTX_size(hash);
 
 	buf[0]=rec->type;
 	buf[1]=TLS1_VERSION_MAJOR;
@@ -772,14 +795,21 @@
 	buf[4]=rec->length&0xff;
 
 	/* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
-	HMAC_CTX_init(&hmac);
-	HMAC_Init_ex(&hmac,mac_sec,EVP_MD_size(hash),hash,NULL);
-	HMAC_Update(&hmac,seq,8);
-	HMAC_Update(&hmac,buf,5);
-	HMAC_Update(&hmac,rec->input,rec->length);
-	HMAC_Final(&hmac,md,&md_size);
-	HMAC_CTX_cleanup(&hmac);
-
+	if (stream_mac) 
+		{
+			mac_ctx = hash;
+		}
+		else
+		{
+			EVP_MD_CTX_copy(&hmac,hash);
+			mac_ctx = &hmac;
+		}	
+	EVP_DigestSignUpdate(mac_ctx,seq,8);
+	EVP_DigestSignUpdate(mac_ctx,buf,5);
+	EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length);
+	if (stream_mac) EVP_MD_CTX_copy(&hmac,hash);
+	EVP_DigestSignFinal(&hmac,md,&md_size);
+	EVP_MD_CTX_cleanup(&hmac);
 #ifdef TLS_DEBUG
 printf("sec=");
 {unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",mac_sec[z]); printf("\n"); }
diff --git a/ssl/tls1.h b/ssl/tls1.h
index 05d74f5..84ab246 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -404,6 +404,10 @@
 #define TLS1_TXT_DHE_RSA_WITH_SEED_SHA                  "DHE-RSA-SEED-SHA"
 #define TLS1_TXT_ADH_WITH_SEED_SHA                      "ADH-SEED-SHA"
 
+/* Flags for SSL_CIPHER.algorithm2 field */
+/* Stream MAC for GOST ciphersuites from cryptopro draft */
+#define TLS1_STREAM_MAC 0x04
+
 #define TLS_CT_RSA_SIGN			1
 #define TLS_CT_DSS_SIGN			2
 #define TLS_CT_RSA_FIXED_DH		3