Index: openssl-1.0.1i/crypto/objects/obj_dat.h
===================================================================
--- openssl-1.0.1i.orig/crypto/objects/obj_dat.h	2015-03-02 17:53:32.207243074 +0300
+++ openssl-1.0.1i/crypto/objects/obj_dat.h	2015-03-02 17:54:49.084742655 +0300
@@ -62,9 +62,9 @@
  * [including the GNU Public Licence.]
  */
 
-#define NUM_NID 935
-#define NUM_SN 928
-#define NUM_LN 928
+#define NUM_NID 936
+#define NUM_SN 929
+#define NUM_LN 929
 #define NUM_OBJ 872
 
 static const unsigned char lvalues[6095]={
@@ -2450,6 +2450,7 @@
 	NID_id_tc26_gost_3410_12_512_paramSetB,9,&(lvalues[6076]),0},
 {"id-tc26-gost-28147-param-A","id-tc26-gost-28147-param-A",
 	NID_id_tc26_gost_28147_param_A,9,&(lvalues[6085]),0},
+{"gost89-cbc","gost89-cbc",NID_gost89_cbc,0,NULL,0},
 };
 
 static const unsigned int sn_objs[NUM_SN]={
@@ -2764,6 +2765,7 @@
 923,	/* "gost2012_256" */
 924,	/* "gost2012_512" */
 813,	/* "gost89" */
+935,	/* "gost89-cbc" */
 814,	/* "gost89-cnt" */
 812,	/* "gost94" */
 850,	/* "gost94cc" */
@@ -3714,6 +3716,7 @@
 509,	/* "generationQualifier" */
 601,	/* "generic cryptogram" */
 99,	/* "givenName" */
+935,	/* "gost89-cbc" */
 814,	/* "gost89-cnt" */
 855,	/* "hmac" */
 780,	/* "hmac-md5" */
Index: openssl-1.0.1i/crypto/objects/obj_mac.h
===================================================================
--- openssl-1.0.1i.orig/crypto/objects/obj_mac.h	2015-03-02 17:53:32.207243074 +0300
+++ openssl-1.0.1i/crypto/objects/obj_mac.h	2015-03-02 17:54:07.425941191 +0300
@@ -3715,6 +3715,9 @@
 #define SN_gost89_cnt		"gost89-cnt"
 #define NID_gost89_cnt		814
 
+#define SN_gost89_cbc		"gost89-cbc"
+#define NID_gost89_cbc		935
+
 #define SN_id_Gost28147_89_MAC		"gost-mac"
 #define LN_id_Gost28147_89_MAC		"GOST 28147-89 MAC"
 #define NID_id_Gost28147_89_MAC		815
Index: openssl-1.0.1i/crypto/objects/obj_mac.num
===================================================================
--- openssl-1.0.1i.orig/crypto/objects/obj_mac.num	2015-03-02 17:53:32.207243074 +0300
+++ openssl-1.0.1i/crypto/objects/obj_mac.num	2015-03-02 17:54:07.425941191 +0300
@@ -932,3 +932,4 @@
 id_tc26_gost_3410_12_512_paramSetA		932
 id_tc26_gost_3410_12_512_paramSetB		933
 id_tc26_gost_28147_param_A		934
+gost89_cbc		935
Index: openssl-1.0.1i/crypto/objects/objects.txt
===================================================================
--- openssl-1.0.1i.orig/crypto/objects/objects.txt	2015-03-02 17:53:32.207243074 +0300
+++ openssl-1.0.1i/crypto/objects/objects.txt	2015-03-02 17:54:07.425941191 +0300
@@ -1169,6 +1169,7 @@
 !Cname id-Gost28147-89
 cryptopro 21		: gost89 		: GOST 28147-89
 			: gost89-cnt
+			: gost89-cbc
 !Cname id-Gost28147-89-MAC
 cryptopro 22		: gost-mac	: GOST 28147-89 MAC
 !Cname id-GostR3411-94-prf
Index: openssl-1.0.1i/engines/ccgost/gost89.c
===================================================================
--- openssl-1.0.1i.orig/engines/ccgost/gost89.c	2015-03-02 17:53:32.207243074 +0300
+++ openssl-1.0.1i/engines/ccgost/gost89.c	2015-03-02 17:54:07.425941191 +0300
@@ -6,15 +6,15 @@
  *          Implementation of GOST 28147-89 encryption algorithm      *
  *            No OpenSSL libraries required to compile and use        *
  *                              this code                             *
- **********************************************************************/ 
+ **********************************************************************/
 #include <string.h>
 #include "gost89.h"
-/* Substitution blocks from RFC 4357 
-   
-   Note: our implementation of gost 28147-89 algorithm 
-   uses S-box matrix rotated 90 degrees counterclockwise, relative to 
+/* Substitution blocks from RFC 4357
+
+   Note: our implementation of gost 28147-89 algorithm
+   uses S-box matrix rotated 90 degrees counterclockwise, relative to
    examples given in RFC.
-  
+
 
 */
 
@@ -28,7 +28,7 @@
 	{0X5,0X8,0X1,0XD,0XA,0X3,0X4,0X2,0XE,0XF,0XC,0X7,0X6,0X0,0X9,0XB},
 	{0XE,0XB,0X4,0XC,0X6,0XD,0XF,0XA,0X2,0X3,0X8,0X1,0X0,0X7,0X5,0X9},
 	{0X4,0XA,0X9,0X2,0XD,0X8,0X0,0XE,0X6,0XB,0X1,0XC,0X7,0XF,0X5,0X3}
-	};  
+	};
 /* Substitution blocks for hash function 1.2.643.2.9.1.6.1  */
 gost_subst_block GostR3411_94_CryptoProParamSet= {
 	{0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC},
@@ -69,7 +69,7 @@
 	{0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5}
 	};
 /* 1.2.643.2.2.31.2 */
-gost_subst_block Gost28147_CryptoProParamSetB= 
+gost_subst_block Gost28147_CryptoProParamSetB=
 	{
 	{0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC},
 	{0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE},
@@ -81,7 +81,7 @@
 	{0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF}
 	};
 /* 1.2.643.2.2.31.3 */
-gost_subst_block Gost28147_CryptoProParamSetC= 
+gost_subst_block Gost28147_CryptoProParamSetC=
 	{
 	{0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8},
 	{0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7},
@@ -93,7 +93,7 @@
 	{0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3}
 	};
 
-/* 1.2.643.2.2.31.4 */ 
+/* 1.2.643.2.2.31.4 */
 gost_subst_block Gost28147_CryptoProParamSetD=
 	{
 	{0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE},
@@ -112,12 +112,12 @@
     0x8D, 0x3A, 0xDB, 0x96,   0x46, 0xE9, 0x2A, 0xC4,
     0x18, 0xFE, 0xAC, 0x94,   0x00, 0xED, 0x07, 0x12,
     0xC0, 0x86, 0xDC, 0xC2,   0xEF, 0x4C, 0xA9, 0x2B
-	};	
+	};
 /* Initialization of gost_ctx subst blocks*/
 static void kboxinit(gost_ctx *c, const gost_subst_block *b)
-	{ 
-	int i; 
-	
+	{
+	int i;
+
 	for (i = 0; i < 256; i++)
 		{
 		c->k87[i] = (b->k8[i>>4] <<4 | b->k7 [i &15])<<24;
@@ -129,68 +129,68 @@
 	}
 
 /* Part of GOST 28147 algorithm moved into separate function */
-static word32 f(gost_ctx *c,word32 x) 
+static word32 f(gost_ctx *c,word32 x)
 	{
-	x = c->k87[x>>24 & 255] | c->k65[x>>16 & 255]| 
-		c->k43[x>> 8 & 255] | c->k21[x & 255]; 
-	/* Rotate left 11 bits */ 
+	x = c->k87[x>>24 & 255] | c->k65[x>>16 & 255]|
+		c->k43[x>> 8 & 255] | c->k21[x & 255];
+	/* Rotate left 11 bits */
 	return x<<11 | x>>(32-11);
 	}
 /* Low-level encryption routine - encrypts one 64 bit block*/
 void gostcrypt(gost_ctx *c, const byte *in, byte *out)
-	{ 
-	register word32 n1, n2; /* As named in the GOST */ 
-	n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24); 
-	n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24); 
-	/* Instead of swapping halves, swap names each round */ 
- 	 
-	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); 
-	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); 
-	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); 
-	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); 
-  
+	{
+	register word32 n1, n2; /* As named in the GOST */
+	n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24);
+	n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24);
+	/* Instead of swapping halves, swap names each round */
+
 	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
 	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
 	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
 	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
-                               
+
 	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
 	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
 	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
 	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
-                               
+
+	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
+	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
+	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
+	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
+
 	n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
 	n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
 	n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
 	n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
- 
+
 	out[0] = (byte)(n2&0xff);  out[1] = (byte)((n2>>8)&0xff);
-	out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24); 
+	out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24);
 	out[4] = (byte)(n1&0xff);  out[5] = (byte)((n1>>8)&0xff);
 	out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(n1>>24);
-	} 
+	}
 /* Low-level decryption routine. Decrypts one 64-bit block */
 void gostdecrypt(gost_ctx *c, const byte *in,byte *out)
-	{ 
-	register word32 n1, n2; /* As named in the GOST */ 
-	n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24); 
-	n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24); 
-	
-	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); 
-	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); 
+	{
+	register word32 n1, n2; /* As named in the GOST */
+	n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24);
+	n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24);
+
+	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
+	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
 	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
-	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); 
-	
+	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
+
 	n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
 	n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
 	n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
 	n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
-	
+
 	n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
 	n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
 	n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
 	n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]);
-	
+
 	n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]);
 	n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]);
 	n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]);
@@ -200,27 +200,27 @@
 	out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24);
 	out[4] = (byte)(n1&0xff);  out[5] = (byte)((n1>>8)&0xff);
 	out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(n1>>24);
-	} 
+	}
 
 /* Encrypts several blocks in ECB mode */
 void gost_enc(gost_ctx *c,const byte *clear,byte *cipher, int blocks)
-	{ 
-	int i; 
+	{
+	int i;
 	for(i=0;i<blocks;i++)
-		{ 
-		gostcrypt(c,clear,cipher); 
+		{
+		gostcrypt(c,clear,cipher);
 		clear+=8;
 		cipher+=8;
 		}
 	}
 /* Decrypts several blocks in ECB mode */
 void gost_dec(gost_ctx *c, const byte *cipher,byte *clear, int blocks)
-	{ 
-	int i; 
+	{
+	int i;
 	for(i=0;i<blocks;i++)
-		{ 
-		gostdecrypt(c,cipher,clear); 
-		clear+=8; 
+		{
+		gostdecrypt(c,cipher,clear);
+		clear+=8;
 		cipher+=8;
 		}
 	}
@@ -241,8 +241,26 @@
 			{
 			cur_iv[j]=out[j]=in[j]^gamma[j];
 			}
-		}	
-	}	
+		}
+	}
+/* Encrypts several full blocks in CBC mode using 8byte IV */
+void gost_enc_cbc(gost_ctx *ctx,const byte *iv,const byte *clear,byte *cipher, int blocks)
+	{
+	byte cur_iv[8],xor_buf[8];
+	int i,j;
+	const byte *in;
+	byte *out;
+	memcpy(cur_iv,iv,8);
+	for(i=0,in=clear,out=cipher;i<blocks;i++,in+=8,out+=8)
+		{
+		for (j=0;j<8;j++)
+			{
+				xor_buf[j]=in[j]^cur_iv[j];
+			}
+		gostcrypt(ctx,xor_buf,cur_iv);
+		memcpy(out,cur_iv,8);
+		}
+	}
 /* Decrypts several full blocks in CFB mode using 8byte IV */
 void gost_dec_cfb(gost_ctx *ctx,const byte *iv,const byte *cipher,byte *clear,  int blocks)
 	{
@@ -259,57 +277,77 @@
 			{
 			out[j]=(cur_iv[j]=in[j])^gamma[j];
 			}
-		}	
-	}	
+		}
+	}
+
+/* Decrypts several full blocks in CBC mode using 8byte IV */
+void gost_dec_cbc(gost_ctx *ctx,const byte *iv,const byte *cipher,byte *clear,  int blocks)
+	{
+	byte cur_iv[8];
+	byte xorbuf[8];
+	int i,j;
+	const byte *in;
+	byte *out;
+	memcpy(cur_iv,iv,8);
+	for(i=0,in=cipher,out=clear;i<blocks;i++,in+=8,out+=8)
+		{
+		gostdecrypt(ctx,in,xorbuf);
+		for (j=0;j<8;j++)
+			{
+			out[j]=(cur_iv[j]^xorbuf[j]);
+			}
+		memcpy(cur_iv,in,8);
+		}
+	}
 
 /* Encrypts one block using specified key */
-void gost_enc_with_key(gost_ctx *c,byte *key,byte *inblock,byte *outblock) 
+void gost_enc_with_key(gost_ctx *c,byte *key,byte *inblock,byte *outblock)
 	{
 	gost_key(c,key);
 	gostcrypt(c,inblock,outblock);
 	}
 
 /* Set 256 bit  key into context */
-void gost_key(gost_ctx *c, const byte *k) 
-	{ 
-	int i,j; 
+void gost_key(gost_ctx *c, const byte *k)
+	{
+	int i,j;
 	for(i=0,j=0;i<8;i++,j+=4)
 		{
 		c->k[i]=k[j]|(k[j+1]<<8)|(k[j+2]<<16)|(k[j+3]<<24);
-		}		
-	} 
+		}
+	}
 
 /* Retrieve 256-bit key from context */
-void gost_get_key(gost_ctx *c, byte *k) 
+void gost_get_key(gost_ctx *c, byte *k)
 	{
-	int i,j; 
+	int i,j;
 	for(i=0,j=0;i<8;i++,j+=4)
 		{
 		k[j]=(byte)(c->k[i]& 0xFF);
 		k[j+1]=(byte)((c->k[i]>>8 )&0xFF);
 		k[j+2]=(byte)((c->k[i]>>16) &0xFF);
 		k[j+3]=(byte)((c->k[i]>>24) &0xFF);
-		}		
+		}
 	}
 
 /* Initalize context. Provides default value for subst_block */
 void gost_init(gost_ctx *c, const gost_subst_block *b)
-	{ 	
+	{
 	if(!b)
 		{
 		b=&GostR3411_94_TestParamSet;
-		}	
-	kboxinit(c,b); 
+		}
+	kboxinit(c,b);
 	}
 
 /* Cleans up key from context */
 void gost_destroy(gost_ctx *c)
-	{ 
-	int i; for(i=0;i<8;i++) c->k[i]=0; 
-	} 
+	{
+	int i; for(i=0;i<8;i++) c->k[i]=0;
+	}
 
-/* Compute GOST 28147 mac block 
- * 
+/* Compute GOST 28147 mac block
+ *
  * Parameters
  *   gost_ctx *c - context initalized with substitution blocks and key
  *   buffer - 8-byte mac state buffer
@@ -317,21 +355,21 @@
  * */
 void mac_block(gost_ctx *c,byte *buffer,const  byte *block)
 	{
-	register word32 n1, n2; /* As named in the GOST */ 
+	register word32 n1, n2; /* As named in the GOST */
 	int i;
 	for (i=0; i<8; i++)
 		{
 		buffer[i]^=block[i];
-		}	  
-	n1 = buffer[0]|(buffer[1]<<8)|(buffer[2]<<16)|(buffer[3]<<24); 
-	n2 = buffer[4]|(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24); 
-	/* Instead of swapping halves, swap names each round */ 
- 	 
-	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); 
-	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); 
-	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); 
-	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); 
-  
+		}
+	n1 = buffer[0]|(buffer[1]<<8)|(buffer[2]<<16)|(buffer[3]<<24);
+	n2 = buffer[4]|(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24);
+	/* Instead of swapping halves, swap names each round */
+
+	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
+	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
+	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
+	n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]);
+
 	n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]);
 	n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]);
 	n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]);
@@ -352,17 +390,17 @@
 	int i;
 	for (i=0;i<nbytes;i++) out[i]=buffer[i];
 	if (rembits) out[i]=buffer[i]&mask;
-	}	
+	}
 
-/* Compute mac of specified length (in bits) from data. 
+/* Compute mac of specified length (in bits) from data.
  * Context should be initialized with key and subst blocks */
 int gost_mac(gost_ctx *ctx,int mac_len,const unsigned char *data,
-	unsigned int data_len,unsigned char *mac) 
+	unsigned int data_len,unsigned char *mac)
 	{
 	byte buffer[8]={0,0,0,0,0,0,0,0};
 	byte buf2[8];
 	unsigned int i;
-	for (i=0;i+8<=data_len;i+=8) 
+	for (i=0;i+8<=data_len;i+=8)
 		mac_block(ctx,buffer,data+i);
 	if (i<data_len)
 		{
@@ -382,13 +420,13 @@
 
 /* Compute MAC with non-zero IV. Used in some RFC 4357 algorithms */
 int gost_mac_iv(gost_ctx *ctx,int mac_len,const unsigned char *iv,const unsigned char *data,
-	unsigned int data_len,unsigned char *mac) 
+	unsigned int data_len,unsigned char *mac)
 	{
 	byte buffer[8];
 	byte buf2[8];
 	unsigned int i;
 	memcpy (buffer,iv,8);
-	for (i=0;i+8<=data_len;i+=8) 
+	for (i=0;i+8<=data_len;i+=8)
 		mac_block(ctx,buffer,data+i);
 	if (i<data_len)
 		{
@@ -396,7 +434,7 @@
 		memcpy(buf2,data+i,data_len-i);
 		mac_block(ctx,buffer,buf2);
 		i+=8;
-		}	
+		}
 	if (i==8)
 		{
 		memset(buf2,0,8);
Index: openssl-1.0.1i/engines/ccgost/gost89.h
===================================================================
--- openssl-1.0.1i.orig/engines/ccgost/gost89.h	2015-03-02 17:53:32.207243074 +0300
+++ openssl-1.0.1i/engines/ccgost/gost89.h	2015-03-02 17:54:07.425941191 +0300
@@ -51,6 +51,10 @@
 /* Decrypts several full blocks in CFB mode using 8byte IV */
 void gost_dec_cfb(gost_ctx *ctx,const byte *iv,const byte *cipher,byte *clear,int  blocks);
 
+/* Encrypts several full blocks in CBC mode using 8byte IV */
+void gost_enc_cbc(gost_ctx *ctx,const byte *iv,const byte *clear,byte *cipher,int  blocks);
+/* Decrypts several full blocks in CBC mode using 8byte IV */
+void gost_dec_cbc(gost_ctx *ctx,const byte *iv,const byte *cipher,byte *clear,int  blocks);
 /* Encrypt one  block */
 void gostcrypt(gost_ctx *c, const byte *in, byte *out);
 /* Decrypt one  block */
Index: openssl-1.0.1i/engines/ccgost/gost_crypt.c
===================================================================
--- openssl-1.0.1i.orig/engines/ccgost/gost_crypt.c	2015-03-02 17:53:32.207243074 +0300
+++ openssl-1.0.1i/engines/ccgost/gost_crypt.c	2015-03-02 18:01:46.586327605 +0300
@@ -19,17 +19,22 @@
 #endif
 #include <assert.h>
 
-static int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, 
+static int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+	const unsigned char *iv, int enc);
+static int gost_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 	const unsigned char *iv, int enc);
 static int	gost_cipher_init_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 	const unsigned char *iv, int enc);
-/* Handles block of data in CFB mode */			
+/* Handles block of data in CFB mode */
 static int	gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out,
 	const unsigned char *in, size_t inl);
-/* Handles block of data in CNT mode */			
+/* Handles block of data in CBC mode */
+static int	gost_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out,
+	const unsigned char *in, size_t inl);
+/* Handles block of data in CNT mode */
 static int	gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out,
 	const unsigned char *in, size_t inl);
-/* Cleanup function */			
+/* Cleanup function */
 static int gost_cipher_cleanup(EVP_CIPHER_CTX *);
 /* set/get cipher parameters */
 static int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx,ASN1_TYPE *params);
@@ -37,7 +42,7 @@
 /* Control function */
 static int gost_cipher_ctl(EVP_CIPHER_CTX *ctx,int type,int arg,void *ptr);
 
-EVP_CIPHER cipher_gost = 
+EVP_CIPHER cipher_gost =
 	{
 	NID_id_Gost28147_89,
 	1,/*block_size*/
@@ -55,7 +60,24 @@
 	NULL,
 	};
 
-EVP_CIPHER cipher_gost_cpacnt = 
+EVP_CIPHER cipher_gost_cbc =
+	{
+	NID_gost89_cbc,
+	8,/*block_size*/
+	32,/*key_size*/
+	8,/*iv_len */
+	EVP_CIPH_CBC_MODE|
+	EVP_CIPH_CUSTOM_IV| EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT,
+	gost_cipher_init_cbc,
+	gost_cipher_do_cbc,
+	gost_cipher_cleanup,
+	sizeof(struct ossl_gost_cipher_ctx),/* ctx_size */
+	gost89_set_asn1_parameters,
+	gost89_get_asn1_parameters,
+	gost_cipher_ctl,
+	NULL,
+	};
+EVP_CIPHER cipher_gost_cpacnt =
 	{
 	NID_gost89_cnt,
 	1,/*block_size*/
@@ -101,11 +123,11 @@
 	NULL,
 	{0,0,0,0,0},
 	8,
-	sizeof(struct ossl_gost_imit_ctx), 
+	sizeof(struct ossl_gost_imit_ctx),
 	gost_imit_ctrl
 	};
 
-/* 
+/*
  * Correspondence between gost parameter OIDs and substitution blocks
  * NID field is filed by register_gost_NID function in engine.c
  * upon engine initialization
@@ -122,10 +144,10 @@
 	{NID_id_Gost28147_89_CryptoPro_D_ParamSet,&Gost28147_CryptoProParamSetD,1},
 	{NID_id_Gost28147_89_TestParamSet,&Gost28147_TestParamSet,1},
 	{NID_undef,NULL,0}
-	};	
+	};
 
 /*  get encryption parameters from crypto network settings
-	FIXME For now we use environment var CRYPT_PARAMS as place to 
+	FIXME For now we use environment var CRYPT_PARAMS as place to
 	store these settings. Actually, it is better to use engine control   command, read from configuration file to set them */
 const struct gost_cipher_info *get_encryption_params(ASN1_OBJECT *obj)
 	{
@@ -134,7 +156,7 @@
 	if (!obj)
 		{
 		const char * params = get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS);
-		if (!params || !strlen(params)) 
+		if (!params || !strlen(params))
 			return &gost_cipher_list[1];
 
 		nid = OBJ_txt2nid(params);
@@ -143,19 +165,19 @@
 			GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS,
 				GOST_R_INVALID_CIPHER_PARAM_OID);
 			return NULL;
-			}	
+			}
 		}
 	else
 		{
 		nid= OBJ_obj2nid(obj);
 		}
-	for (param=gost_cipher_list;param->sblock!=NULL && param->nid!=nid; 
+	for (param=gost_cipher_list;param->sblock!=NULL && param->nid!=nid;
 		 param++);
 	if (!param->sblock)
 		{
 		GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS,GOST_R_INVALID_CIPHER_PARAMS);
 		return NULL;
-		}	
+		}
 	return param;
 	}
 
@@ -165,7 +187,7 @@
 	const struct gost_cipher_info *param;
 	param=get_encryption_params((nid==NID_undef?NULL:OBJ_nid2obj(nid)));
 	if (!param) return 0;
-	
+
 	c->paramNID = param->nid;
 	c->key_meshing=param->key_meshing;
 	c->count=0;
@@ -187,7 +209,7 @@
 	if(iv) memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx));
 	memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx));
 	return 1;
-	}	
+	}
 
 static int gost_cipher_init_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key,
 	const unsigned char *iv, int enc)
@@ -207,9 +229,15 @@
 	const unsigned char *iv, int enc)
 	{
 	return gost_cipher_init_param(ctx,key,iv,enc,NID_undef,EVP_CIPH_CFB_MODE);
-	}	
+	}
+/* Initializes EVP_CIPHER_CTX with default values */
+int gost_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+	const unsigned char *iv, int enc)
+	{
+	return gost_cipher_init_param(ctx,key,iv,enc,NID_undef,EVP_CIPH_CBC_MODE);
+	}
 /* Wrapper around gostcrypt function from gost89.c which perform
- * key meshing when nesseccary 
+ * key meshing when nesseccary
  */
 static void gost_crypt_mesh (void *ctx,unsigned char *iv,unsigned char *buf)
 	{
@@ -218,7 +246,7 @@
 	if (c->key_meshing && c->count==1024)
 		{
 		cryptopro_key_meshing(&(c->cctx),iv);
-		}	
+		}
 	gostcrypt(&(c->cctx),iv,buf);
 	c->count = c->count%1024 + 8;
 	}
@@ -240,7 +268,7 @@
 	else
 		{
 		memcpy(buf1,iv,8);
-		}	
+		}
 	g = buf1[0]|(buf1[1]<<8)|(buf1[2]<<16)|(buf1[3]<<24);
 	g += 0x01010101;
 	buf1[0]=(unsigned char)(g&0xff);
@@ -261,6 +289,47 @@
 	c->count = c->count%1024 + 8;
 	}
 
+/* GOST encryptoon in CBC mode */
+int gost_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out,
+	const unsigned char *in, size_t inl)
+	{
+	OPENSSL_assert(inl % 8 ==0);
+	unsigned char b[8];
+	const unsigned char *in_ptr=in;
+	unsigned char *out_ptr=out;
+	int i;
+	struct ossl_gost_cipher_ctx *c = ctx->cipher_data;
+	if (ctx->encrypt)
+		{
+		while(inl>0)
+		    {
+			for (i=0;i<8;i++)
+			   {
+				b[i]=ctx->iv[i]^in_ptr[i];
+		     	}
+			gostcrypt(&(c->cctx),b,out_ptr);
+			memcpy(ctx->iv,out_ptr,8);
+			out_ptr+=8;
+			in_ptr+=8;
+			inl-=8;
+		    }
+		}
+	else
+		{
+		while (inl>0) {
+			gostdecrypt(&(c->cctx),in_ptr,b);
+			for (i=0;i<8;i++)
+			    {
+				out_ptr[i]=ctx->iv[i]^b[i];
+			    }
+			memcpy(ctx->iv,in_ptr,8);
+			out_ptr+=8;
+			in_ptr+=8;
+			inl-=8;
+		    }
+	    }
+	return 1;
+	}
 /* GOST encryption in CFB mode */
 int	gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out,
 	const unsigned char *in, size_t inl)
@@ -270,14 +339,14 @@
 	size_t i=0;
 	size_t j=0;
 /* process partial block if any */
-	if (ctx->num) 
+	if (ctx->num)
 		{
-		for (j=ctx->num,i=0;j<8 && i<inl;j++,i++,in_ptr++,out_ptr++) 
+		for (j=ctx->num,i=0;j<8 && i<inl;j++,i++,in_ptr++,out_ptr++)
 			{
 			if (!ctx->encrypt) ctx->buf[j+8]=*in_ptr;
 			*out_ptr=ctx->buf[j]^(*in_ptr);
 			if (ctx->encrypt) ctx->buf[j+8]=*out_ptr;
-			}	
+			}
 		if (j==8)
 			{
 			memcpy(ctx->iv,ctx->buf+8,8);
@@ -287,8 +356,8 @@
 			{
 			ctx->num=j;
 			return 1;
-			}	
-		}	
+			}
+		}
 
 	for (;i+8<inl;i+=8,in_ptr+=8,out_ptr+=8)
 		{
@@ -300,7 +369,7 @@
 		for (j=0;j<8;j++)
 			{
 			out_ptr[j]=ctx->buf[j]^in_ptr[j];
-			}	
+			}
 		/* Encrypt */
 		/* Next iv is next block of cipher text*/
 		if (ctx->encrypt) memcpy(ctx->iv,out_ptr,8);
@@ -313,14 +382,14 @@
 		for (j=0;i<inl;j++,i++)
 			{
 			out_ptr[j]=ctx->buf[j]^in_ptr[j];
-			}			
+			}
 		ctx->num = j;
 		if (ctx->encrypt) memcpy(ctx->buf+8,out_ptr,j);
 		}
 	else
 		{
 		ctx->num = 0;
-		}	
+		}
 	return 1;
 	}
 
@@ -332,12 +401,12 @@
 	size_t i=0;
 	size_t j;
 /* process partial block if any */
-	if (ctx->num) 
+	if (ctx->num)
 		{
-		for (j=ctx->num,i=0;j<8 && i<inl;j++,i++,in_ptr++,out_ptr++) 
+		for (j=ctx->num,i=0;j<8 && i<inl;j++,i++,in_ptr++,out_ptr++)
 			{
 			*out_ptr=ctx->buf[j]^(*in_ptr);
-			}	
+			}
 		if (j==8)
 			{
 			ctx->num=0;
@@ -346,8 +415,8 @@
 			{
 			ctx->num=j;
 			return 1;
-			}	
-		}	
+			}
+		}
 
 	for (;i+8<inl;i+=8,in_ptr+=8,out_ptr+=8)
 		{
@@ -359,7 +428,7 @@
 		for (j=0;j<8;j++)
 			{
 			out_ptr[j]=ctx->buf[j]^in_ptr[j];
-			}	
+			}
 		}
 /* Process rest of buffer */
 	if (i<inl)
@@ -368,23 +437,23 @@
 		for (j=0;i<inl;j++,i++)
 			{
 			out_ptr[j]=ctx->buf[j]^in_ptr[j];
-			}			
+			}
 		ctx->num = j;
 		}
 	else
 		{
 		ctx->num = 0;
-		}	
+		}
 	return 1;
 	}
 
 /* Cleaning up of EVP_CIPHER_CTX */
-int gost_cipher_cleanup(EVP_CIPHER_CTX *ctx) 
+int gost_cipher_cleanup(EVP_CIPHER_CTX *ctx)
 	{
 	gost_destroy(&((struct ossl_gost_cipher_ctx *)ctx->cipher_data)->cctx);
 	ctx->app_data = NULL;
 	return 1;
-	}	
+	}
 
 /* Control function for gost cipher */
 int gost_cipher_ctl(EVP_CIPHER_CTX *ctx,int type,int arg,void *ptr)
@@ -406,8 +475,8 @@
 				return 1;
 			} else {
 				return 0;
-			}	
-				
+			}
+
 		default:
 			GOSTerr(GOST_F_GOST_CIPHER_CTL,GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND);
 			return -1;
@@ -467,7 +536,7 @@
 int  gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx,ASN1_TYPE *params)
 	{
 	int ret = -1;
-	int len; 
+	int len;
 	GOST_CIPHER_PARAMS *gcp = NULL;
 	unsigned char *p;
 	struct ossl_gost_cipher_ctx *c=ctx->cipher_data;
@@ -510,6 +579,7 @@
 	c->count = 0;
 	c->bytes_left=0;
 	c->key_meshing=1;
+	c->dgst_size=4;
 	gost_init(&(c->cctx),&Gost28147_CryptoProParamSetA);
 	return 1;
 	}
@@ -517,7 +587,7 @@
 static void mac_block_mesh(struct ossl_gost_imit_ctx *c,const unsigned char *data)
 	{
 	unsigned char buffer[8];
-	/* We are using local buffer for iv because CryptoPro doesn't 
+	/* We are using local buffer for iv because CryptoPro doesn't
 	 * interpret internal state of MAC algorithm as iv during keymeshing
 	 * (but does initialize internal state from iv in key transport
 	 */
@@ -553,8 +623,8 @@
 			{
 			c->bytes_left = i;
 			return 1;
-			}		
-		}	
+			}
+		}
 	while (bytes>8)
 		{
 		mac_block_mesh(c,p);
@@ -564,7 +634,7 @@
 	if (bytes>0)
 		{
 		memcpy(c->partial_block,p,bytes);
-		}	
+		}
 	c->bytes_left=bytes;
 	return 1;
 	}
@@ -591,7 +661,7 @@
 			}
 		mac_block_mesh(c,c->partial_block);
 		}
-	get_mac(c->buffer,32,md);
+	get_mac(c->buffer,8*c->dgst_size,md);
 	return 1;
 	}
 
@@ -605,7 +675,7 @@
 		case EVP_MD_CTRL_SET_KEY:
 		{
 		if (arg!=32) {
-			GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_LENGTH);
+			GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE);
 			return 0;
 		}
 
@@ -614,9 +684,20 @@
 		return 1;
 
 		}
+		case EVP_MD_CTRL_MAC_LEN:
+		{
+			if (arg<1 || arg>8) {
+				GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE);
+				return 0;
+			}
+			struct ossl_gost_imit_ctx *c = ctx->md_data;
+			c->dgst_size=arg;
+			return 1;
+		}
+
 		default:
 			return 0;
-		}		
+		}
 	}
 
 int gost_imit_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from)
Index: openssl-1.0.1i/engines/ccgost/gost_eng.c
===================================================================
--- openssl-1.0.1i.orig/engines/ccgost/gost_eng.c	2015-03-02 17:53:32.207243074 +0300
+++ openssl-1.0.1i/engines/ccgost/gost_eng.c	2015-03-02 17:54:07.425941191 +0300
@@ -33,7 +33,7 @@
 	const int **nids, int nid);
 
 static int gost_cipher_nids[] =
-    {NID_id_Gost28147_89, NID_gost89_cnt,0};
+    {NID_id_Gost28147_89, NID_gost89_cnt,NID_gost89_cbc,0};
 
 static int gost_digest_nids[] =
 	{NID_id_GostR3411_94,NID_id_Gost28147_89_MAC,
@@ -98,43 +98,43 @@
 		{
 		printf("ENGINE_set_id failed\n");
 		goto end;
-		}	
+		}
 	if (!ENGINE_set_name(e, engine_gost_name))
 		{
 		printf("ENGINE_set_name failed\n");
 		goto end;
-		}	
+		}
 	if (!ENGINE_set_digests(e, gost_digests))
 		{
 		printf("ENGINE_set_digests failed\n");
 		goto end;
-		}	
+		}
 	if (! ENGINE_set_ciphers(e, gost_ciphers))
 		{
 		printf("ENGINE_set_ciphers failed\n");
 		goto end;
-		}	
+		}
 	if (! ENGINE_set_pkey_meths(e, gost_pkey_meths))
 		{
 		printf("ENGINE_set_pkey_meths failed\n");
 		goto end;
-		}	
+		}
 	if (! ENGINE_set_pkey_asn1_meths(e, gost_pkey_asn1_meths))
 		{
 		printf("ENGINE_set_pkey_asn1_meths failed\n");
 		goto end;
-		}	
+		}
 	/* Control function and commands */
 	if (!ENGINE_set_cmd_defns(e,gost_cmds))
 		{
 		fprintf(stderr,"ENGINE_set_cmd_defns failed\n");
 		goto end;
-		}	
+		}
 	if (!ENGINE_set_ctrl_function(e,gost_control_func))
 		{
 		fprintf(stderr,"ENGINE_set_ctrl_func failed\n");
 		goto end;
-		}	
+		}
 	if ( ! ENGINE_set_destroy_function(e, gost_engine_destroy)
 		|| ! ENGINE_set_init_function(e,gost_engine_init)
 		|| ! ENGINE_set_finish_function(e,gost_engine_finish))
@@ -160,6 +160,7 @@
 		|| ! ENGINE_register_pkey_meths(e)
 		/* These two actually should go in LIST_ADD command */
 		|| ! EVP_add_cipher(&cipher_gost)
+		|| ! EVP_add_cipher(&cipher_gost_cbc)
 		|| ! EVP_add_cipher(&cipher_gost_cpacnt)
 		|| ! EVP_add_digest(&digest_gost)
 		|| ! EVP_add_digest(&digest_gost12_256)
@@ -174,7 +175,7 @@
 	ret = 1;
 	end:
 	return ret;
-	}	
+	}
 
 #ifndef OPENSSL_NO_DYNAMIC_ENGINE
 IMPLEMENT_DYNAMIC_BIND_FN(bind_gost)
@@ -214,7 +215,7 @@
 		}
 	return ok;
 	}
-	
+
 static int gost_ciphers (ENGINE *e,const EVP_CIPHER **cipher,
 	const int **nids, int nid)
 	{
@@ -222,7 +223,7 @@
 	if (!cipher)
 		{
 		*nids = gost_cipher_nids;
-		return 2; /* two ciphers are supported */
+		return 3; /* three ciphers are supported */
 		}
 
 	if(nid == NID_id_Gost28147_89)
@@ -233,13 +234,17 @@
 		{
 		*cipher = &cipher_gost_cpacnt;
 		}
-	else	
+	else if  (nid == NID_gost89_cbc)
+		{
+		*cipher = &cipher_gost_cbc;
+		}
+	else
 		{
 		ok = 0;
 		*cipher = NULL;
 		}
 	return ok;
-	}	
+	}
 
 static int gost_pkey_meths (ENGINE *e, EVP_PKEY_METHOD **pmeth,
 	const int **nids, int nid)
@@ -259,7 +264,7 @@
 		case NID_id_tc26_gost3410_12_512: *pmeth = pmeth_GostR3410_2012_512; return 1;
 		default:;
 		}
-	
+
 	*pmeth = NULL;
 	return 0;
 	}
@@ -281,14 +286,14 @@
 		case NID_id_tc26_gost3410_12_512: *ameth = ameth_GostR3410_2012_512; return 1;
 		default:;
 		}
-	
+
 	*ameth = NULL;
 	return 0;
 	}
 
 #ifdef OPENSSL_NO_DYNAMIC_ENGINE
 static ENGINE *engine_gost(void)
-	{	
+	{
 	ENGINE *ret = ENGINE_new();
 	if (!ret)
 		return NULL;
@@ -299,7 +304,7 @@
 		}
 	return ret;
 	}
-	
+
 void ENGINE_load_gost(void)
 	{
 	ENGINE *toadd;
@@ -311,5 +316,5 @@
 	ENGINE_free(toadd);
 	ERR_clear_error();
 	}
-#endif	
+#endif
 
Index: openssl-1.0.1i/engines/ccgost/gost_lcl.h
===================================================================
--- openssl-1.0.1i.orig/engines/ccgost/gost_lcl.h	2015-03-02 17:53:32.207243074 +0300
+++ openssl-1.0.1i/engines/ccgost/gost_lcl.h	2015-03-02 17:54:07.425941191 +0300
@@ -41,7 +41,9 @@
 /* For GOST 28147 MAC */
 #define key_ctrl_string "key"
 #define hexkey_ctrl_string "hexkey"
+#define maclen_ctrl_string "size"
 #define EVP_PKEY_CTRL_GOST_MAC_HEXKEY (EVP_PKEY_ALG_CTRL+3)
+#define EVP_PKEY_CTRL_MAC_LEN (EVP_PKEY_ALG_CTRL+5)
 /* Pmeth internal representation */
 	struct gost_pmeth_data {
    	    int sign_param_nid; /* Should be set whenever parameters are filled */
@@ -51,7 +53,8 @@
 	};
 
 	struct gost_mac_pmeth_data {
-		int key_set;
+		short int key_set;
+		short int mac_size;
 		EVP_MD *md;
 		unsigned char key[32];
 	}	;
@@ -158,6 +161,7 @@
 	int key_meshing;
 	int bytes_left;
 	int key_set;
+	int dgst_size;
 };	
 /* Table which maps parameter NID to S-blocks */
 extern struct gost_cipher_info gost_cipher_list[];
@@ -165,9 +169,11 @@
 const struct gost_cipher_info *get_encryption_params(ASN1_OBJECT *obj);
 /* Implementation of GOST 28147-89 cipher in CFB and CNT modes */
 extern EVP_CIPHER cipher_gost;
+extern EVP_CIPHER cipher_gost_cbc;
 extern EVP_CIPHER cipher_gost_cpacnt;
 #define EVP_MD_CTRL_KEY_LEN (EVP_MD_CTRL_ALG_CTRL+3)
 #define EVP_MD_CTRL_SET_KEY (EVP_MD_CTRL_ALG_CTRL+4)
+#define EVP_MD_CTRL_MAC_LEN (EVP_MD_CTRL_ALG_CTRL+5)
 /* EVP_PKEY_METHOD key encryption callbacks */
 /* From gost94_keyx.c */
 int pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* key, size_t key_len );
Index: openssl-1.0.1i/engines/ccgost/e_gost_err.c
===================================================================
--- openssl-1.0.1i.orig/engines/ccgost/e_gost_err.c	2015-03-02 17:53:07.000000000 +0300
+++ openssl-1.0.1i/engines/ccgost/e_gost_err.c	2015-03-02 17:54:07.425941191 +0300
@@ -135,6 +135,8 @@
 {ERR_REASON(GOST_R_INVALID_GOST94_PARMSET),"invalid gost94 parmset"},
 {ERR_REASON(GOST_R_INVALID_IV_LENGTH)    ,"invalid iv length"},
 {ERR_REASON(GOST_R_INVALID_MAC_KEY_LENGTH),"invalid mac key length"},
+{ERR_REASON(GOST_R_INVALID_MAC_KEY_SIZE) ,"invalid mac key size"},
+{ERR_REASON(GOST_R_INVALID_MAC_SIZE)     ,"invalid mac size"},
 {ERR_REASON(GOST_R_INVALID_PARAMSET)     ,"invalid paramset"},
 {ERR_REASON(GOST_R_KEY_IS_NOT_INITALIZED),"key is not initalized"},
 {ERR_REASON(GOST_R_KEY_IS_NOT_INITIALIZED),"key is not initialized"},
Index: openssl-1.0.1i/engines/ccgost/e_gost_err.h
===================================================================
--- openssl-1.0.1i.orig/engines/ccgost/e_gost_err.h	2015-03-02 17:53:07.000000000 +0300
+++ openssl-1.0.1i/engines/ccgost/e_gost_err.h	2015-03-02 17:54:07.425941191 +0300
@@ -133,6 +133,8 @@
 #define GOST_R_INVALID_GOST94_PARMSET			 109
 #define GOST_R_INVALID_IV_LENGTH			 110
 #define GOST_R_INVALID_MAC_KEY_LENGTH			 111
+#define GOST_R_INVALID_MAC_KEY_SIZE			 134
+#define GOST_R_INVALID_MAC_SIZE				 136
 #define GOST_R_INVALID_PARAMSET				 112
 #define GOST_R_KEY_IS_NOT_INITALIZED			 113
 #define GOST_R_KEY_IS_NOT_INITIALIZED			 114
Index: openssl-1.0.1i/engines/ccgost/README.gost
===================================================================
--- openssl-1.0.1i.orig/engines/ccgost/README.gost	2015-03-02 17:53:07.000000000 +0300
+++ openssl-1.0.1i/engines/ccgost/README.gost	2015-03-02 17:54:07.425941191 +0300
@@ -36,6 +36,8 @@
 	It has 256-bit symmetric key and only 32 bits of MAC value
 	(while HMAC has same key size and value size). 
 
+	Really, this algorithm supports from 8 to 64 bits of the MAC value
+
 	It is implemented as combination of EVP_PKEY type and EVP_MD type.
 
 USAGE OF THESE ALGORITHMS
@@ -218,11 +220,30 @@
  implementation of this mac) and OpenSSL is clever enough to find out
  this.
 
+ Following mac options are supported:
+
+ key:(32 bytes of key)
+
+ hexkey:(64 hexadecimal digits of key)
+
+ Engine support calculation of mac with size different from default 32
+ bits. You can set mac size to any value from 1 to 8 bytes using
+
+ -sigopt size:(number from 1 to 8 - mac size in bytes)
+
+ (dgst command uses different EVP_PKEY_CTX for initialization and for
+  finalization of MAC. Option of first are set via -macopt, and for
+  second via -sigopt. Key should be set during initialization and size
+  during finalization. If you use API functions
+  EVP_DigestSignInit/EVP_DigestSignFinal, you can set both options at
+  the same time).
+
  Encryption with GOST 28147 CFB mode
  openssl enc -gost89 -out encrypted-file -in plain-text-file -k <passphrase>  
  Encryption with GOST 28147 CNT mode
  openssl enc -gost89-cnt -out encrypted-file -in plain-text-file -k <passphrase>
-
+ Encryption with GOST 28147 CBC mode
+ openssl enc -gost89-cbc -out encrypted-file -in plain-text-file -k <passphrase>
 
 6. Encrypting private keys and PKCS12
 
@@ -241,6 +262,7 @@
 
  openssl speed -evp gost89
  openssl speed -evp gost89-cnt
+ openssl speed -evp gost89-cbc
 
 
 PROGRAMMING INTERFACES DETAILS
Index: openssl-1.0.1i/engines/ccgost/gost_pmeth.c
===================================================================
--- openssl-1.0.1i.orig/engines/ccgost/gost_pmeth.c	2015-03-02 17:53:07.000000000 +0300
+++ openssl-1.0.1i/engines/ccgost/gost_pmeth.c	2015-03-02 17:54:07.425941191 +0300
@@ -566,6 +566,7 @@
 	data = OPENSSL_malloc(sizeof(struct gost_mac_pmeth_data));
 	if (!data) return 0;
 	memset(data,0,sizeof(struct gost_mac_pmeth_data));
+	data->mac_size=4;
 	EVP_PKEY_CTX_set_data(ctx,data);
 	return 1;
 	}	
@@ -644,7 +645,18 @@
 				}
 			return mctx->digest->md_ctrl(mctx,EVP_MD_CTRL_SET_KEY,32,key);
 			}
-		}	
+		case EVP_PKEY_CTRL_MAC_LEN:
+			{
+			if (p1<1 || p1>8)
+				{
+					
+					GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,GOST_R_INVALID_MAC_SIZE);
+					return 0;
+				}
+				data->mac_size=p1;
+				return 1;
+				}
+		}
 	return -2;
 	}
 static int pkey_gost_mac_ctrl_str(EVP_PKEY_CTX *ctx,
@@ -678,6 +690,17 @@
 			return ret;
 	
 		}
+	else if (!strcmp(type,maclen_ctrl_string)) {
+			char *endptr;
+			long size=strtol(value,&endptr,10);
+			if (*endptr!='\0') {
+				GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL_STR,
+					GOST_R_INVALID_MAC_SIZE);
+				return 0;
+			}
+			return pkey_gost_mac_ctrl(ctx, EVP_PKEY_CTRL_MAC_LEN,size,NULL);
+
+	}
 	return -2;
 	}	
 
@@ -703,15 +726,16 @@
 
 static int pkey_gost_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, EVP_MD_CTX *mctx)
 	{
-		unsigned int tmpsiglen=*siglen; /* for platforms where sizeof(int)!=sizeof(size_t)*/
 		int ret;
+		struct gost_mac_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
 		if (!sig)
 			{
-			*siglen = 4;
+			*siglen = data->mac_size;
 			return 1;
 			}
-		ret=EVP_DigestFinal_ex(mctx,sig,&tmpsiglen);
-		*siglen = tmpsiglen;
+		mctx->digest->md_ctrl(mctx,EVP_MD_CTRL_MAC_LEN,data->mac_size,NULL);
+		ret=EVP_DigestFinal_ex(mctx,sig,NULL);
+		*siglen = data->mac_size;
 		return ret;
 	}
 /* ----------------------------------------------------------------*/
