aboutsummaryrefslogtreecommitdiffstats
path: root/engines/ccgost
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2006-09-17 13:00:18 +0000
committerDr. Stephen Henson <steve@openssl.org>2006-09-17 13:00:18 +0000
commita04549cc755408ff2dcab209fd87d3e46f7d662a (patch)
treee4778866a61dddb7fb9ef4465490ad48de919645 /engines/ccgost
parentbc7535bc7fe30fbba222c316a3957da7d906603b (diff)
downloadopenssl-a04549cc755408ff2dcab209fd87d3e46f7d662a.tar.gz
GOST public key algorithm ENGINE donated to the OpenSSL by Cryptocom.
Very early version, doesn't do much yet, not even added to the build system.
Diffstat (limited to 'engines/ccgost')
-rw-r--r--engines/ccgost/Makefile122
-rw-r--r--engines/ccgost/ameth.c671
-rw-r--r--engines/ccgost/crypt.h62
-rw-r--r--engines/ccgost/e_gost_err.c210
-rw-r--r--engines/ccgost/e_gost_err.h150
-rw-r--r--engines/ccgost/e_gost_err.proto61
-rw-r--r--engines/ccgost/engine.c230
-rw-r--r--engines/ccgost/gost.ec5
-rw-r--r--engines/ccgost/gost2001.c324
-rw-r--r--engines/ccgost/gost2001_keyx.c385
-rw-r--r--engines/ccgost/gost89.c383
-rw-r--r--engines/ccgost/gost89.h96
-rw-r--r--engines/ccgost/gost94_keyx.c420
-rw-r--r--engines/ccgost/gost_asn1.c55
-rw-r--r--engines/ccgost/gost_asn1.h57
-rw-r--r--engines/ccgost/gost_crypt.c579
-rw-r--r--engines/ccgost/gost_sign.c302
-rw-r--r--engines/ccgost/gosthash.c256
-rw-r--r--engines/ccgost/gosthash.h39
-rw-r--r--engines/ccgost/gostkeyx.h42
-rw-r--r--engines/ccgost/gostsum.178
-rw-r--r--engines/ccgost/gostsum.c184
-rw-r--r--engines/ccgost/keywrap.c97
-rw-r--r--engines/ccgost/keywrap.h56
-rw-r--r--engines/ccgost/md.h41
-rw-r--r--engines/ccgost/md_gost.c69
-rw-r--r--engines/ccgost/meth.h22
-rw-r--r--engines/ccgost/params.c198
-rw-r--r--engines/ccgost/paramset.h34
-rw-r--r--engines/ccgost/pmeth.c514
-rw-r--r--engines/ccgost/pmeth.h26
-rw-r--r--engines/ccgost/sign.h30
-rw-r--r--engines/ccgost/tools.h38
33 files changed, 5836 insertions, 0 deletions
diff --git a/engines/ccgost/Makefile b/engines/ccgost/Makefile
new file mode 100644
index 0000000000..b4caacdb7e
--- /dev/null
+++ b/engines/ccgost/Makefile
@@ -0,0 +1,122 @@
+# OPENSSL_DIR is a root directory of openssl sources
+THISDIR?=$(shell perl -MCwd -e 'print getcwd')
+OPENSSL_DIR?=$(THISDIR)/../openssl
+ENGINE_ID?=gost
+TESTSUITE_DIR?=$(THISDIR)/test-suite
+FOR?=$(HOST)
+CC=gcc
+CFLAGS=-fPIC -g -Wall -I$(OPENSSL_DIR)/include
+LDFLAGS=-g -L $(OPENSSL_DIR) -static-libgcc
+ifeq "$(FOR)" "s64"
+CFLAGS+=-m64
+LDFLAGS+=-m64
+endif
+OS:=$(shell uname -s)
+ifeq "$(OS)" "FreeBSD"
+LIBDIR:=$(shell LD_LIBRARY_PATH=$(OPENSSL_DIR) $(OPENSSL_DIR)/apps/openssl version -d|sed -e 's/^[^"]*"//' -e 's/".*$$//')/lib
+LDFLAGS+=-rpath $(LIBDIR)
+endif
+
+
+ifeq "$(FOR)" "w32"
+ENGINE_LIB?=$(ENGINE_ID)$(DLLSUFFIX)
+DLLSUFFIX=.dll
+EXESUFFIX=.exe
+CFLAGS+=-mno-cygwin
+LDFLAGS+=-mno-cygwin
+ifeq "$(OS)" "Linux"
+CC=i586-mingw32msvc-gcc
+endif
+LIBS=-lcrypto.dll
+else
+ENGINE_LIB?=lib$(ENGINE_ID)$(DLLSUFFIX)
+LIBS=-lcrypto
+DLLSUFFIX=.so
+endif
+export DLLSUFFIX
+export EXESUFFIX
+ifneq "$(FOR)" ""
+export FOR
+endif
+CFLAGS+=$(DEBUG_FLAGS)
+export ENGINE_LIB
+ENG_SOURCES=md_gost.c gost_crypt.c gost_asn1.c ameth.c pmeth.c\
+ gost_crypt.c gost_sign.c gost2001.c md_gost.c gost_crypt.c\
+ engine.c gost94_keyx.c keywrap.c gost2001_keyx.c
+all: $(ENGINE_LIB) openssl.cnf
+buildtests:
+$(ENGINE_LIB): e_gost_err.o engine.o ameth.o pmeth.o params.o md_gost.o gosthash.o gost89.o gost_sign.o gost_crypt.o keywrap.o gost2001.o gost94_keyx.o gost2001_keyx.o gost_asn1.o
+ $(CC) $(LDFLAGS) -shared -o $@ $+ $(LIBS) $(LDFLAGS)
+openssl.cnf: openssl.cnf.1 openssl.cnf.2
+ cat $+ > $@
+openssl.cnf.1:
+ echo "openssl_conf = openssl_def" > $@
+openssl.cnf.2:
+ echo "[openssl_def]" > $@
+ echo "engines = engine_section" >> $@
+ echo "[engine_section]" >> $@
+ echo "$(ENGINE_ID) = $(ENGINE_ID)_section" >> $@
+ echo "[$(ENGINE_ID)_section]" >> $@
+ echo "dynamic_path = $(THISDIR)/$(ENGINE_LIB)" >> $@
+ echo "engine_id = $(ENGINE_ID)" >> $@
+ echo "default_algorithms = ALL" >> $@
+gosthash1.o: gosthash.c
+ $(CC) -c $(CFLAGS) -o $@ -DOPENSSL_BUILD $+
+gostsum: gostsum.o gosthash.o gost89.o
+inttests: gosttest$(EXESUFFIX) etalon wraptest$(EXESUFFIX) etalon.wrap ectest$(EXESUFFIX) etalon.ec
+ ./gosttest${EXESUFFIX} > gost_test
+ diff -uw gost_test etalon
+ ./wraptest$(EXESUFFIX) > wrap_test
+ diff -uw wrap_test etalon.wrap
+ ./ectest$(EXESUFFIX) > ec_test 2>&1
+ diff -uw ec_test etalon.ec
+ectest$(EXESUFFIX): ectest.o gost2001_dbg.o gost_sign_dbg.o params.o e_gost_err.o
+ $(CC) -o $@ $(LDFLAGS) $+ -lcrypto
+%_dbg.o: %.c
+ $(CC) -c $(CFLAGS) -DDEBUG_SIGN -DDEBUG_KEYS -o $@ $+
+gosttest$(EXESUFFIX): gosttest.o gosthash.o gost89.o
+ $(CC) $(LDFLAGS) -o $@ $+
+wraptest$(EXESUFFIX): wraptest.c keywrap.c gost89.c
+ $(CC) -DDEBUG_DH $(LDFLAGS) -o $@ $+
+sign_ex: LOADLIBES=-lcrypto
+sign_ex: sign_ex.o
+clean:
+ rm -f core gosttest gostsum *.o gost_test openssl.cnf* $(ENGINE_LIB)
+ if [ -f t/Makefile ]; then $(MAKE) -C t clean; fi
+ if [ -f $(TESTSUITE_DIR)/Makefile ]; then $(MAKE) -C $(TESTSUITE_DIR) clean; fi
+e_gost_err.c e_gost_err.h: $(ENG_SOURCES) gost.ec e_gost_err.proto
+ perl $(OPENSSL_DIR)/util/mkerr.pl -conf gost.ec -nostatic -debug -write $(ENG_SOURCES)
+
+tests: openssl.cnf.2
+ OPENSSL_DIR=$(OPENSSL_DIR) $(MAKE) -C $(TESTSUITE_DIR) CONFADD=$(THISDIR)/openssl.cnf.2
+
+# depedencies
+#
+#
+gost_sign.o: gost_sign.c sign.h paramset.h tools.h e_gost_err.h
+
+pmeth.o: pmeth.c meth.h pmeth.h sign.h paramset.h e_gost_err.h
+
+ameth.o: ameth.c tools.h meth.h pmeth.h gost_asn1.h crypt.h e_gost_err.h paramset.h
+
+keywrap.o: keywrap.c gost89.h keywrap.h
+
+gost2001.o: gost2001.c tools.h sign.h paramset.h e_gost_err.h
+
+engine.o: engine.c md.h crypt.h meth.h e_gost_err.h
+
+gost89.o: gost89.c gost89.h
+
+gost_asn1.o: gost_asn1.c gost_asn1.h
+
+gost_crypt.o: gost_crypt.c crypt.h gost89.h e_gost_err.h gost_asn1.h
+
+gosthash.o: gosthash.c gost89.h gosthash.h
+
+md_gost.o: md_gost.c md.h gosthash.h e_gost_err.h
+
+params.o: params.c paramset.h
+
+gost94_keyx.o: gost94_keyx.c gost_asn1.h gost89.h gosthash.h crypt.h pmeth.h keywrap.h e_gost_err.h gostkeyx.h
+
+gost2001_keyx.o: gost2001_keyx.c gost89.h gost_asn1.h e_gost_err.h keywrap.h crypt.h sign.h gostkeyx.h pmeth.h gosthash.h tools.h
diff --git a/engines/ccgost/ameth.c b/engines/ccgost/ameth.c
new file mode 100644
index 0000000000..c64cd2d298
--- /dev/null
+++ b/engines/ccgost/ameth.c
@@ -0,0 +1,671 @@
+/**********************************************************************
+ * ameth.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Implementation of RFC 4490/4491 ASN1 method *
+ * for OpenSSL *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+#include <string.h>
+#include "meth.h"
+#include "pmeth.h"
+#include "paramset.h"
+#include "gost_asn1.h"
+#include "crypt.h"
+#include "sign.h"
+#include "tools.h"
+#include "e_gost_err.h"
+
+int gost94_nid_by_params(DSA *p)
+{
+ R3410_params *gost_params;
+ BIGNUM *q=BN_new();
+ for (gost_params = R3410_paramset;gost_params->q!=NULL; gost_params++) {
+ BN_dec2bn(&q,gost_params->q);
+ if (!BN_cmp(q,p->q))
+ {
+ BN_free(q);
+ return gost_params->nid;
+ }
+ }
+ BN_free(q);
+ return NID_undef;
+}
+
+static ASN1_STRING *encode_gost_algor_params(const EVP_PKEY *key)
+{
+ ASN1_STRING *params = ASN1_STRING_new();
+ GOST_KEY_PARAMS *gkp = GOST_KEY_PARAMS_new();
+ int pkey_param_nid = NID_undef;
+ int cipher_param_nid = NID_undef;
+ if (!params || !gkp) {
+ GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS,
+ ERR_R_MALLOC_FAILURE);
+ ASN1_STRING_free(params);
+ params = NULL;
+ goto err;
+ }
+ switch (EVP_PKEY_base_id(key)) {
+ case NID_id_GostR3410_2001_cc:
+ pkey_param_nid = NID_id_GostR3410_2001_ParamSet_cc;
+ cipher_param_nid = NID_id_Gost28147_89_cc;
+ break;
+ case NID_id_GostR3410_94_cc:
+ pkey_param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet;
+ cipher_param_nid = NID_id_Gost28147_89_cc;
+ break;
+ case NID_id_GostR3410_2001:
+ pkey_param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)key)));
+ cipher_param_nid = get_encryption_params(NULL)->nid;
+ break;
+ case NID_id_GostR3410_94:
+ pkey_param_nid = (int) gost94_nid_by_params(EVP_PKEY_get0((EVP_PKEY *)key));
+ if (pkey_param_nid == NID_undef) {
+ GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS,
+ GOST_R_INVALID_GOST94_PARMSET);
+ ASN1_STRING_free(params);
+ params=NULL;
+ goto err;
+ }
+ cipher_param_nid = get_encryption_params(NULL)->nid;
+ break;
+ }
+ gkp->key_params = OBJ_nid2obj(pkey_param_nid);
+ gkp->hash_params = OBJ_nid2obj(NID_id_GostR3411_94_CryptoProParamSet);
+ /*gkp->cipher_params = OBJ_nid2obj(cipher_param_nid);*/
+ params->length = i2d_GOST_KEY_PARAMS(gkp, &params->data);
+ if (params->length <=0 )
+ {
+ GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS,
+ ERR_R_MALLOC_FAILURE);
+ ASN1_STRING_free(params);
+ params = NULL;
+ goto err;
+ }
+ params ->type = V_ASN1_SEQUENCE;
+err:
+ GOST_KEY_PARAMS_free(gkp);
+ return params;
+}
+/* Parses GOST algorithm parameters from X509_ALGOR and
+ * modifies pkey setting NID and parameters
+ */
+static int decode_gost_algor_params(EVP_PKEY *pkey, X509_ALGOR *palg)
+{
+ ASN1_OBJECT *palg_obj =NULL;
+ int ptype = V_ASN1_UNDEF;
+ int pkey_nid = NID_undef,param_nid = NID_undef;
+ ASN1_STRING *pval = NULL;
+ const unsigned char *p;
+ GOST_KEY_PARAMS *gkp = NULL;
+
+ X509_ALGOR_get0(&palg_obj, &ptype, (void **) (&pval), palg);
+ if (ptype != V_ASN1_SEQUENCE) {
+ GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS,
+ GOST_R_BAD_KEY_PARAMETERS_FORMAT);
+ return 0;
+ }
+ p=pval->data;
+ pkey_nid = OBJ_obj2nid(palg_obj);
+
+ gkp = d2i_GOST_KEY_PARAMS(NULL,&p,pval->length);
+ if (!gkp) {
+ GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS,
+ GOST_R_BAD_PKEY_PARAMETERS_FORMAT);
+ }
+ param_nid = OBJ_obj2nid(gkp->key_params);
+ GOST_KEY_PARAMS_free(gkp);
+ EVP_PKEY_set_type(pkey,pkey_nid);
+ switch (pkey_nid) {
+ case NID_id_GostR3410_94:
+ case NID_id_GostR3410_94_cc:
+ { DSA *dsa= EVP_PKEY_get0(pkey);
+ if (!dsa) {
+ dsa = DSA_new();
+ if (!EVP_PKEY_assign(pkey,pkey_nid,dsa)) return 0;
+ }
+ if (!fill_GOST94_params(dsa,param_nid)) return 0;
+ break;
+ }
+ case NID_id_GostR3410_2001:
+ case NID_id_GostR3410_2001_cc:
+ { EC_KEY *ec = EVP_PKEY_get0(pkey);
+ if (!ec) {
+ ec = EC_KEY_new();
+ if (!EVP_PKEY_assign(pkey,pkey_nid,ec)) return 0;
+ }
+ if (!fill_GOST2001_params(ec,param_nid)) return 0;
+
+ }
+
+ }
+
+ return 1;
+}
+
+static int gost_set_priv_key(EVP_PKEY *pkey,BIGNUM *priv)
+{
+ switch (EVP_PKEY_base_id(pkey)) {
+ case NID_id_GostR3410_94:
+ case NID_id_GostR3410_94_cc:
+ { DSA *dsa = EVP_PKEY_get0(pkey);
+ if (!dsa) {
+ dsa = DSA_new();
+ EVP_PKEY_assign(pkey,EVP_PKEY_base_id(pkey),dsa);
+ }
+ dsa->priv_key = BN_dup(priv);
+ if (!EVP_PKEY_missing_parameters(pkey))
+ gost94_compute_public(dsa);
+ break;
+ }
+ case NID_id_GostR3410_2001:
+ case NID_id_GostR3410_2001_cc:
+ { EC_KEY *ec = EVP_PKEY_get0(pkey);
+ if (!ec) {
+ ec = EC_KEY_new();
+ EVP_PKEY_assign(pkey,EVP_PKEY_base_id(pkey),ec);
+ }
+ if (!EC_KEY_set_private_key(ec,priv)) return 0;
+ if (!EVP_PKEY_missing_parameters(pkey))
+ gost2001_compute_public(ec);
+ break;
+ }
+
+ }
+ return 1;
+}
+BIGNUM* gost_get_priv_key(const EVP_PKEY *pkey)
+{
+ switch (EVP_PKEY_base_id(pkey)) {
+ case NID_id_GostR3410_94:
+ case NID_id_GostR3410_94_cc:
+ { DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pkey);
+ if (!dsa) {
+ return NULL;
+ }
+ if (!dsa->priv_key) return NULL;
+ return BN_dup(dsa->priv_key);
+ break;
+ }
+ case NID_id_GostR3410_2001:
+ case NID_id_GostR3410_2001_cc:
+ { EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pkey);
+ const BIGNUM* priv;
+ if (!ec) {
+ return NULL;
+ }
+ if (!(priv=EC_KEY_get0_private_key(ec))) return NULL;
+ return BN_dup(priv);
+ break;
+ }
+
+ }
+ return NULL;
+}
+static int pkey_ctrl_gost(EVP_PKEY *pkey, int op,
+ long arg1, void *arg2)
+{
+ switch (op)
+ {
+ case ASN1_PKEY_CTRL_PKCS7_SIGN:
+ if (arg1 == 0) {
+ X509_ALGOR *alg1 = NULL, *alg2 = NULL;
+ int nid = EVP_PKEY_base_id(pkey);
+ PKCS7_SIGNER_INFO_get0_algs((PKCS7_SIGNER_INFO*)arg2,
+ NULL, &alg1, &alg2);
+ X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_id_GostR3411_94),
+ V_ASN1_NULL, 0);
+ if (nid == NID_undef) {
+ return (-1);
+ }
+ X509_ALGOR_set0(alg2, OBJ_nid2obj(nid), V_ASN1_NULL, 0);
+ }
+ return 1;
+ case ASN1_PKEY_CTRL_PKCS7_ENCRYPT:
+ if (arg1 == 0)
+ {
+ X509_ALGOR *alg;
+ ASN1_STRING * params = encode_gost_algor_params(pkey);
+ if (!params) {
+ return -1;
+ }
+ PKCS7_RECIP_INFO_get0_alg((PKCS7_RECIP_INFO*)arg2, &alg);
+ X509_ALGOR_set0(alg, OBJ_nid2obj(pkey->type),
+ V_ASN1_SEQUENCE, params);
+ }
+ return 1;
+ case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+ *(int *)arg2 = NID_id_GostR3411_94;
+ return 2;
+ }
+
+ return -2;
+}
+/*----------------------- free functions * ------------------------------*/
+static void pkey_free_gost94(EVP_PKEY *key) {
+ if (key->pkey.dsa) {
+ DSA_free(key->pkey.dsa);
+ }
+}
+static void pkey_free_gost01(EVP_PKEY *key) {
+ if (key->pkey.ec) {
+ EC_KEY_free(key->pkey.ec);
+ }
+}
+/* ------------------ private key functions -----------------------------*/
+static int priv_decode_gost( EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf)
+{
+ const unsigned char *pkey_buf = NULL,*p=NULL;
+ int priv_len = 0;
+ BIGNUM *pk_num=NULL;
+ int ret =0;
+ X509_ALGOR *palg =NULL;
+ ASN1_OBJECT *palg_obj = NULL;
+ ASN1_INTEGER *priv_key=NULL;
+
+ if (!PKCS8_pkey_get0(&palg_obj,&pkey_buf,&priv_len,&palg,p8inf))
+ return 0;
+ p = pkey_buf;
+ if (!decode_gost_algor_params(pk,palg)) {
+ return 0;
+ }
+ priv_key=d2i_ASN1_INTEGER(NULL,&p,priv_len);
+ if (!priv_key) {
+ }
+
+ if (!(pk_num = ASN1_INTEGER_to_BN(priv_key, NULL))) {
+ GOSTerr(GOST_F_PRIV_DECODE_GOST_94,
+ EVP_R_DECODE_ERROR);
+ }
+
+ ret= gost_set_priv_key(pk,pk_num);
+ BN_free(pk_num);
+ return ret;
+}
+/* ----------------------------------------------------------------------*/
+static int priv_encode_gost(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk)
+{
+ ASN1_OBJECT *algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk));
+ ASN1_STRING *params = encode_gost_algor_params(pk);
+ unsigned char *priv_buf = NULL;
+ int priv_len;
+ BIGNUM *key;
+
+ ASN1_INTEGER *asn1key=NULL;
+ if (!params) {
+ return 0;
+ }
+ key = gost_get_priv_key(pk);
+ asn1key = BN_to_ASN1_INTEGER(key,NULL);
+ BN_free(key);
+ priv_len = i2d_ASN1_INTEGER(asn1key,&priv_buf);
+ ASN1_INTEGER_free(asn1key);
+ return PKCS8_pkey_set0(p8,algobj,0,V_ASN1_SEQUENCE,params,
+ priv_buf,priv_len);
+}
+
+static int priv_print_gost (BIO *out,const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx)
+{
+ BIGNUM *key;
+ if (!BIO_indent(out,indent,128)) return 0;
+ key = gost_get_priv_key(pkey);
+ if (!key) return 0;
+ BN_print(out,key);
+ BN_free(key);
+ return 1;
+}
+/* ---------------------------------------------------------------------*/
+static int param_missing_gost94(const EVP_PKEY *pk)
+{
+ const DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pk);
+ if (!dsa) return 1;
+ if (!dsa->q) return 1;
+ return 0;
+}
+static int param_missing_gost01(const EVP_PKEY *pk)
+{
+ const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk);
+ if (!ec) return 1;
+ if (!EC_KEY_get0_group(ec)) return 1;
+ return 0;
+}
+
+static int param_copy_gost94(EVP_PKEY *to, const EVP_PKEY *from)
+{
+ const DSA *dfrom = EVP_PKEY_get0((EVP_PKEY *)from);
+ DSA *dto = EVP_PKEY_get0(to);
+ if (EVP_PKEY_base_id(from) != EVP_PKEY_base_id(to))
+ {
+ GOSTerr(GOST_F_PARAM_COPY_GOST94,
+ GOST_R_INCOMPATIBLE_ALGORITHMS);
+ return 0;
+ }
+ if (!dfrom)
+ {
+ GOSTerr(GOST_F_PARAM_COPY_GOST94,
+ GOST_R_KEY_PARAMETERS_MISSING);
+ return 0;
+ }
+ if (!dto)
+ {
+ dto = DSA_new();
+ EVP_PKEY_assign(to,EVP_PKEY_base_id(from),dto);
+ }
+#define COPYBIGNUM(a,b,x) if (a->x) BN_free(a->x); a->x=BN_dup(b->x);
+ COPYBIGNUM(dto,dfrom,p)
+ COPYBIGNUM(dto,dfrom,q)
+ COPYBIGNUM(dto,dfrom,g)
+
+ if (dto->priv_key)
+ gost94_compute_public(dto);
+ return 1;
+}
+static int param_copy_gost01(EVP_PKEY *to, const EVP_PKEY *from) {
+ EC_KEY *eto = EVP_PKEY_get0(to);
+ const EC_KEY *efrom = EVP_PKEY_get0((EVP_PKEY *)from);
+ if (EVP_PKEY_base_id(from) != EVP_PKEY_base_id(to)) {
+ GOSTerr(GOST_F_PARAM_COPY_GOST01,
+ GOST_R_INCOMPATIBLE_ALGORITHMS);
+ return 0;
+ }
+ if (!efrom) {
+ GOSTerr(GOST_F_PARAM_COPY_GOST94,
+ GOST_R_KEY_PARAMETERS_MISSING);
+ return 0;
+ }
+ if (!eto) {
+ eto = EC_KEY_new();
+ EVP_PKEY_assign(to,EVP_PKEY_base_id(from),eto);
+ }
+ EC_KEY_set_group(eto,EC_GROUP_dup(EC_KEY_get0_group(efrom)));
+ if (EC_KEY_get0_private_key(eto)) {
+ gost2001_compute_public(eto);
+ }
+ return 1;
+
+
+
+}
+static int param_cmp_gost94(const EVP_PKEY *a, const EVP_PKEY *b) {
+ const DSA *da = EVP_PKEY_get0((EVP_PKEY *)a);
+ const DSA *db = EVP_PKEY_get0((EVP_PKEY *)b);
+ if (!BN_cmp(da->q,db->q)) return 1;
+ return 0;
+}
+static int param_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b) {
+ if (EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)a)))==
+ EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)b)))) {
+ return 1;
+ }
+ return 0;
+
+}
+/* ---------- Public key functions * --------------------------------------*/
+static int pub_decode_gost94(EVP_PKEY *pk, X509_PUBKEY *pub)
+{
+ X509_ALGOR *palg = NULL;
+ const unsigned char *pubkey_buf = NULL;
+ unsigned char *databuf;
+ ASN1_OBJECT *palgobj = NULL;
+ int pub_len,i,j;
+ DSA *dsa;
+ ASN1_OCTET_STRING *octet= NULL;
+
+ if (!X509_PUBKEY_get0_param(&palgobj,&pubkey_buf,&pub_len,
+ &palg, pub)) return 0;
+ EVP_PKEY_assign(pk,OBJ_obj2nid(palgobj),NULL);
+ if (!decode_gost_algor_params(pk,palg)) return 0;
+ octet = d2i_ASN1_OCTET_STRING(NULL,&pubkey_buf,pub_len);
+ if (!octet)
+ {
+ GOSTerr(GOST_F_PUB_DECODE_GOST94,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ databuf = OPENSSL_malloc(octet->length);
+ for (i=0,j=octet->length-1;i<octet->length;i++,j--)
+ {
+ databuf[j]=octet->data[i];
+ }
+ dsa = EVP_PKEY_get0(pk);
+ dsa->pub_key=BN_bin2bn(databuf,octet->length,NULL);
+ ASN1_OCTET_STRING_free(octet);
+ OPENSSL_free(databuf);
+ return 1;
+
+}
+static int pub_encode_gost94(X509_PUBKEY *pub,const EVP_PKEY *pk)
+{
+ ASN1_OBJECT *algobj = NULL;
+ ASN1_OCTET_STRING *octet = NULL;
+ void *pval = NULL;
+ unsigned char *buf=NULL,*databuf,*sptr;
+ int i,j,data_len,ret=0;
+
+ int ptype;
+ DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pk);
+ algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk));
+ if (pk->save_parameters) {
+ ASN1_STRING *params = encode_gost_algor_params(pk);
+ pval = params;
+ ptype = V_ASN1_SEQUENCE;
+ }
+ data_len = BN_num_bytes(dsa->pub_key);
+ databuf = OPENSSL_malloc(data_len);
+ BN_bn2bin(dsa->pub_key,databuf);
+ octet = ASN1_OCTET_STRING_new();
+ ASN1_STRING_set(octet,NULL,data_len);
+ sptr = ASN1_STRING_data(octet);
+ for (i=0,j=data_len-1; i< data_len;i++,j--)
+ {
+ sptr[i]=databuf[j];
+ }
+ OPENSSL_free(databuf);
+ ret = i2d_ASN1_OCTET_STRING(octet,&buf);
+ ASN1_BIT_STRING_free(octet);
+ if (ret <0) return 0;
+ return X509_PUBKEY_set0_param(pub,algobj,ptype,pval,buf,ret);
+}
+static int pub_decode_gost01(EVP_PKEY *pk,X509_PUBKEY *pub)
+{
+ X509_ALGOR *palg = NULL;
+ const unsigned char *pubkey_buf = NULL;
+ unsigned char *databuf;
+ ASN1_OBJECT *palgobj = NULL;
+ int pub_len,i,j;
+ EC_POINT *pub_key;
+ BIGNUM *X,*Y;
+ ASN1_OCTET_STRING *octet= NULL;
+ const EC_GROUP *group;
+
+ if (!X509_PUBKEY_get0_param(&palgobj,&pubkey_buf,&pub_len,
+ &palg, pub)) return 0;
+ EVP_PKEY_assign(pk,OBJ_obj2nid(palgobj),NULL);
+ if (!decode_gost_algor_params(pk,palg)) return 0;
+ group = EC_KEY_get0_group(EVP_PKEY_get0(pk));
+ octet = d2i_ASN1_OCTET_STRING(NULL,&pubkey_buf,pub_len);
+ if (!octet)
+ {
+ GOSTerr(GOST_F_PUB_DECODE_GOST94,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ databuf = OPENSSL_malloc(octet->length);
+ for (i=0,j=octet->length-1;i<octet->length;i++,j--)
+ {
+ databuf[j]=octet->data[i];
+ }
+ if (EVP_PKEY_base_id(pk) == NID_id_GostR3410_2001_cc) {
+ X= getbnfrombuf(databuf,octet->length/2);
+ Y= getbnfrombuf(databuf+(octet->length/2),octet->length/2);
+ } else {
+ Y= getbnfrombuf(databuf,octet->length/2);
+ X= getbnfrombuf(databuf+(octet->length/2),octet->length/2);
+ }
+ OPENSSL_free(databuf);
+ pub_key = EC_POINT_new(group);
+ if (!EC_POINT_set_affine_coordinates_GFp(group
+ ,pub_key,X,Y,NULL))
+ {
+ GOSTerr(GOST_F_PUB_DECODE_GOST01,
+ ERR_R_EC_LIB);
+ return 0;
+ }
+ BN_free(X);
+ BN_free(Y);
+ if (!EC_KEY_set_public_key(EVP_PKEY_get0(pk),pub_key))
+ {
+ GOSTerr(GOST_F_PUB_DECODE_GOST01,
+ ERR_R_EC_LIB);
+ return 0;
+ }
+ /*EC_POINT_free(pub_key);*/
+ return 1;
+
+}
+static int pub_encode_gost01(X509_PUBKEY *pub,const EVP_PKEY *pk)
+{
+ ASN1_OBJECT *algobj = NULL;
+ ASN1_OCTET_STRING *octet = NULL;
+ void *pval = NULL;
+ unsigned char *buf=NULL,*databuf,*sptr;
+ int i,j,data_len,ret=0;
+ const EC_POINT *pub_key;
+ BIGNUM *X,*Y,*order;
+ const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk);
+ int ptype;
+
+ algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk));
+ if (pk->save_parameters) {
+ ASN1_STRING *params = encode_gost_algor_params(pk);
+ pval = params;
+ ptype = V_ASN1_SEQUENCE;
+ }
+ order = BN_new();
+ EC_GROUP_get_order(EC_KEY_get0_group(ec),order,NULL);
+ pub_key=EC_KEY_get0_public_key(ec);
+ if (!pub_key) {
+ GOSTerr(GOST_F_PUB_ENCODE_GOST01,
+ GOST_R_PUBLIC_KEY_UNDEFINED);
+ return 0;
+ }
+ X=BN_new();
+ Y=BN_new();
+ EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec),
+ pub_key,X,Y,NULL);
+ data_len = 2*BN_num_bytes(order);
+ BN_free(order);
+ databuf = OPENSSL_malloc(data_len);
+ memset(databuf,0,data_len);
+ if (EVP_PKEY_base_id(pk) == NID_id_GostR3410_2001_cc) {
+ store_bignum(X,databuf,data_len/2);
+ store_bignum(Y,databuf+data_len/2,data_len/2);
+ } else {
+ store_bignum(X,databuf+data_len/2,data_len/2);
+ store_bignum(Y,databuf,data_len/2);
+ }
+ BN_free(X);
+ BN_free(Y);
+ octet = ASN1_OCTET_STRING_new();
+ ASN1_STRING_set(octet,NULL,data_len);
+ sptr=ASN1_STRING_data(octet);
+ for (i=0,j=data_len-1;i<data_len;i++,j--) {
+ sptr[i]=databuf[j];
+ }
+ OPENSSL_free(databuf);
+ ret = i2d_ASN1_OCTET_STRING(octet,&buf);
+ ASN1_BIT_STRING_free(octet);
+ if (ret <0) return 0;
+ return X509_PUBKEY_set0_param(pub,algobj,ptype,pval,buf,ret);
+}
+static int pub_cmp_gost94(const EVP_PKEY *a, const EVP_PKEY *b)
+{
+ const DSA *da = EVP_PKEY_get0((EVP_PKEY *)a);
+ const DSA *db = EVP_PKEY_get0((EVP_PKEY *)b);
+ if (da && db && da->pub_key && db->pub_key
+ && !BN_cmp(da->pub_key,db->pub_key)) {
+ return 1;
+ }
+ return 0;
+}
+static int pub_cmp_gost01(const EVP_PKEY *a,const EVP_PKEY *b)
+{
+ const EC_KEY *ea = EVP_PKEY_get0((EVP_PKEY *)a);
+ const EC_KEY *eb = EVP_PKEY_get0((EVP_PKEY *)b);
+ const EC_POINT *ka,*kb;
+ int ret=0;
+ if (!ea || !eb) return 0;
+ ka = EC_KEY_get0_public_key(ea);
+ kb = EC_KEY_get0_public_key(eb);
+ if (!ka || !kb) return 0;
+ ret = (0==EC_POINT_cmp(EC_KEY_get0_group(ea),ka,kb,NULL)) ;
+ return ret;
+}
+static int pub_print_gost94(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx)
+{
+ const BIGNUM *key;
+ if (!BIO_indent(out,indent,128)) return 0;
+ key = ((DSA *)EVP_PKEY_get0((EVP_PKEY *)pkey))->pub_key;
+ if (!key) return 0;
+ BN_print(out,key);
+ return 1;
+}
+static int pub_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx)
+{
+ return 0;
+}
+static int pkey_size_gost(const EVP_PKEY *pk)
+{
+ return 64;
+}
+static int pkey_bits_gost(const EVP_PKEY *pk)
+{
+ return 256;
+}
+/* ----------------------------------------------------------------------*/
+int register_ameth_gost (int nid, EVP_PKEY_ASN1_METHOD **ameth, const char* pemstr, const char* info) {
+ *ameth = EVP_PKEY_asn1_new(nid,
+ ASN1_PKEY_SIGPARAM_NULL, pemstr, info);
+ if (!*ameth) return 0;
+ switch (nid) {
+ case NID_id_GostR3410_94_cc:
+ case NID_id_GostR3410_94:
+ EVP_PKEY_asn1_set_free (*ameth, pkey_free_gost94);
+ EVP_PKEY_asn1_set_private (*ameth,
+ priv_decode_gost, priv_encode_gost,
+ priv_print_gost);
+
+ EVP_PKEY_asn1_set_param (*ameth, 0, 0,
+ param_missing_gost94, param_copy_gost94,
+ param_cmp_gost94,0 );
+ EVP_PKEY_asn1_set_public (*ameth,
+ pub_decode_gost94, pub_encode_gost94,
+ pub_cmp_gost94, pub_print_gost94,
+ pkey_size_gost, pkey_bits_gost);
+
+ EVP_PKEY_asn1_set_ctrl (*ameth, pkey_ctrl_gost);
+ break;
+ case NID_id_GostR3410_2001_cc:
+ case NID_id_GostR3410_2001:
+ EVP_PKEY_asn1_set_free (*ameth, pkey_free_gost01);
+ EVP_PKEY_asn1_set_private (*ameth,
+ priv_decode_gost, priv_encode_gost,
+ priv_print_gost);
+
+ EVP_PKEY_asn1_set_param (*ameth, 0, 0,
+ param_missing_gost01, param_copy_gost01,
+ param_cmp_gost01, 0);
+ EVP_PKEY_asn1_set_public (*ameth,
+ pub_decode_gost01, pub_encode_gost01,
+ pub_cmp_gost01, pub_print_gost01,
+ pkey_size_gost, pkey_bits_gost);
+
+ EVP_PKEY_asn1_set_ctrl (*ameth, pkey_ctrl_gost);
+ break;
+ }
+ return 1;
+}
diff --git a/engines/ccgost/crypt.h b/engines/ccgost/crypt.h
new file mode 100644
index 0000000000..bdd3dc08a8
--- /dev/null
+++ b/engines/ccgost/crypt.h
@@ -0,0 +1,62 @@
+/**********************************************************************
+ * gost_crypt.h *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Declarations for GOST 28147-89 encryption algorithm *
+ * OpenSSL 0.9.9 libraries required *
+ **********************************************************************/
+#ifndef GOST_CRYPT_H
+#define GOST_CRYPT_H
+#include <unistd.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include "gost89.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+/* Cipher context used for EVP_CIPHER operation */
+struct ossl_gost_cipher_ctx {
+ int paramNID;
+ off_t count;
+ int key_meshing;
+ gost_ctx cctx;
+};
+/* Structure to map parameter NID to S-block */
+struct gost_cipher_info {
+ int nid;
+ gost_subst_block *sblock;
+ int key_meshing;
+};
+#ifdef USE_SSL
+/* Context for MAC */
+struct ossl_gost_imit_ctx {
+ gost_ctx cctx;
+ unsigned char buffer[8];
+ unsigned char partial_block[8];
+ off_t count;
+ int key_meshing;
+ int bytes_left;
+ int key_set;
+};
+#endif
+/* Table which maps parameter NID to S-blocks */
+extern struct gost_cipher_info gost_cipher_list[];
+/* Find encryption params from ASN1_OBJECT */
+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;
+#ifdef USE_SSL
+#define EVP_MD_FLAG_NEEDS_KEY 0x20
+#define EVP_MD_CTRL_GET_TLS_MAC_KEY_LENGTH (EVP_MD_CTRL_ALG_CTRL+1)
+#define EVP_MD_CTRL_SET_KEY (EVP_MD_CTRL_ALG_CTRL+2)
+/* Ciphers and MACs specific for GOST TLS draft */
+extern EVP_CIPHER cipher_gost_vizircfb;
+extern EVP_CIPHER cipher_gost_cpacnt;
+extern EVP_MD imit_gost_vizir;
+extern EVP_MD imit_gost_cpa;
+#endif
+#ifdef __cplusplus
+ };
+#endif
+#endif
diff --git a/engines/ccgost/e_gost_err.c b/engines/ccgost/e_gost_err.c
new file mode 100644
index 0000000000..5ba09e885a
--- /dev/null
+++ b/engines/ccgost/e_gost_err.c
@@ -0,0 +1,210 @@
+/* e_gost_err.c */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/* NOTE: this file was auto generated by the mkerr.pl script: any changes
+ * made to it will be overwritten when the script next updates this file,
+ * only reason strings will be preserved.
+ */
+
+#include <stdio.h>
+#include <openssl/err.h>
+#include "e_gost_err.h"
+
+/* BEGIN ERROR CODES */
+#ifndef OPENSSL_NO_ERR
+
+#define ERR_FUNC(func) ERR_PACK(0,func,0)
+#define ERR_REASON(reason) ERR_PACK(0,0,reason)
+
+static ERR_STRING_DATA GOST_str_functs[]=
+ {
+{ERR_FUNC(GOST_F_DECODE_GOST_ALGOR_PARAMS), "DECODE_GOST_ALGOR_PARAMS"},
+{ERR_FUNC(GOST_F_DECRYPT_CRYPTOCOM_KEY), "decrypt_cryptocom_key"},
+{ERR_FUNC(GOST_F_ENCODE_GOST_ALGOR_PARAMS), "ENCODE_GOST_ALGOR_PARAMS"},
+{ERR_FUNC(GOST_F_FILL_GOST2001_PARAMS), "FILL_GOST2001_PARAMS"},
+{ERR_FUNC(GOST_F_FILL_GOST94_PARAMS), "FILL_GOST94_PARAMS"},
+{ERR_FUNC(GOST_F_GET_ENCRYPTION_PARAMS), "get_encryption_params"},
+{ERR_FUNC(GOST_F_GOST2001_COMPUTE_PUBLIC), "GOST2001_COMPUTE_PUBLIC"},
+{ERR_FUNC(GOST_F_GOST2001_DO_SIGN), "GOST2001_DO_SIGN"},
+{ERR_FUNC(GOST_F_GOST2001_DO_VERIFY), "GOST2001_DO_VERIFY"},
+{ERR_FUNC(GOST_F_GOST89_GET_ASN1_PARAMETERS), "gost89_get_asn1_parameters"},
+{ERR_FUNC(GOST_F_GOST89_SET_ASN1_PARAMETERS), "gost89_set_asn1_parameters"},
+{ERR_FUNC(GOST_F_GOST94_COPY_PARAMETERS), "GOST94_COPY_PARAMETERS"},
+{ERR_FUNC(GOST_F_GOST_CIPHER_CTL), "gost_cipher_ctl"},
+{ERR_FUNC(GOST_F_GOST_COMPUTE_PUBLIC), "GOST_COMPUTE_PUBLIC"},
+{ERR_FUNC(GOST_F_GOST_DO_SIGN), "GOST_DO_SIGN"},
+{ERR_FUNC(GOST_F_GOST_DO_VERIFY), "GOST_DO_VERIFY"},
+{ERR_FUNC(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001), "MAKE_RFC4490_KEYTRANSPORT_2001"},
+{ERR_FUNC(GOST_F_PARAM_COPY_GOST01), "PARAM_COPY_GOST01"},
+{ERR_FUNC(GOST_F_PARAM_COPY_GOST94), "PARAM_COPY_GOST94"},
+{ERR_FUNC(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT), "PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT"},
+{ERR_FUNC(GOST_F_PKCS7_GOST94_KEY_TRANSPORT_DECRYPT), "PKCS7_GOST94_KEY_TRANSPORT_DECRYPT"},
+{ERR_FUNC(GOST_F_PKEY_GOST01CC_DECRYPT), "pkey_GOST01cc_decrypt"},
+{ERR_FUNC(GOST_F_PKEY_GOST01CC_ENCRYPT), "pkey_GOST01cc_encrypt"},
+{ERR_FUNC(GOST_F_PKEY_GOST01CP_ENCRYPT), "pkey_GOST01cp_encrypt"},
+{ERR_FUNC(GOST_F_PKEY_GOST01_KEYGEN), "PKEY_GOST01_KEYGEN"},
+{ERR_FUNC(GOST_F_PKEY_GOST94CC_DECRYPT), "pkey_GOST94cc_decrypt"},
+{ERR_FUNC(GOST_F_PKEY_GOST94CC_ENCRYPT), "pkey_GOST94cc_encrypt"},
+{ERR_FUNC(GOST_F_PKEY_GOST94CP_DECRYPT), "pkey_GOST94cp_decrypt"},
+{ERR_FUNC(GOST_F_PKEY_GOST94CP_ENCRYPT), "pkey_GOST94cp_encrypt"},
+{ERR_FUNC(GOST_F_PKEY_GOST94_KEYGEN), "PKEY_GOST94_KEYGEN"},
+{ERR_FUNC(GOST_F_PKEY_GOST_CTRL), "PKEY_GOST_CTRL"},
+{ERR_FUNC(GOST_F_PKEY_GOST_CTRL01_STR), "PKEY_GOST_CTRL01_STR"},
+{ERR_FUNC(GOST_F_PKEY_GOST_CTRL94_STR), "PKEY_GOST_CTRL94_STR"},
+{ERR_FUNC(GOST_F_PRIV_DECODE_GOST_94), "PRIV_DECODE_GOST_94"},
+{ERR_FUNC(GOST_F_PUB_DECODE_GOST01), "PUB_DECODE_GOST01"},
+{ERR_FUNC(GOST_F_PUB_DECODE_GOST94), "PUB_DECODE_GOST94"},
+{ERR_FUNC(GOST_F_PUB_ENCODE_GOST01), "PUB_ENCODE_GOST01"},
+{ERR_FUNC(GOST_F_UNPACK_CC_SIGNATURE), "UNPACK_CC_SIGNATURE"},
+{ERR_FUNC(GOST_F_UNPACK_CP_SIGNATURE), "UNPACK_CP_SIGNATURE"},
+{0,NULL}
+ };
+
+static ERR_STRING_DATA GOST_str_reasons[]=
+ {
+{ERR_REASON(GOST_R_BAD_KEY_PARAMETERS_FORMAT),"bad key parameters format"},
+{ERR_REASON(GOST_R_BAD_PKEY_PARAMETERS_FORMAT),"bad pkey parameters format"},
+{ERR_REASON(GOST_R_CANNOT_PACK_EPHEMERAL_KEY),"cannot pack ephemeral key"},
+{ERR_REASON(GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT),"ctx not initialized for encrypt"},
+{ERR_REASON(GOST_R_ERROR_COMPUTING_MAC) ,"error computing mac"},
+{ERR_REASON(GOST_R_ERROR_COMPUTING_SHARED_KEY),"error computing shared key"},
+{ERR_REASON(GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO),"error packing key transport info"},
+{ERR_REASON(GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO),"error parsing key transport info"},
+{ERR_REASON(GOST_R_ERROR_STORING_ENCRYPTED_KEY),"error storing encrypted key"},
+{ERR_REASON(GOST_R_ERROR_STORING_IV) ,"error storing iv"},
+{ERR_REASON(GOST_R_ERROR_STORING_MAC) ,"error storing mac"},
+{ERR_REASON(GOST_R_INCOMPATIBLE_ALGORITHMS),"incompatible algorithms"},
+{ERR_REASON(GOST_R_INVALID_CIPHER_PARAMS),"invalid cipher params"},
+{ERR_REASON(GOST_R_INVALID_CIPHER_PARAM_OID),"invalid cipher param oid"},
+{ERR_REASON(GOST_R_INVALID_DIGEST_TYPE) ,"invalid digest type"},
+{ERR_REASON(GOST_R_INVALID_ENCRYPTED_KEY_SIZE),"invalid encrypted key size"},
+{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_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"},
+{ERR_REASON(GOST_R_KEY_PARAMETERS_MISSING),"key parameters missing"},
+{ERR_REASON(GOST_R_MALLOC_FAILURE) ,"malloc failure"},
+{ERR_REASON(GOST_R_NOT_ENOUGH_SPACE_FOR_KEY),"not enough space for key"},
+{ERR_REASON(GOST_R_NO_MEMORY) ,"no memory"},
+{ERR_REASON(GOST_R_NO_PARAMETERS_SET) ,"no parameters set"},
+{ERR_REASON(GOST_R_PUBLIC_KEY_UNDEFINED) ,"public key undefined"},
+{ERR_REASON(GOST_R_RANDOM_GENERATOR_ERROR),"random generator error"},
+{ERR_REASON(GOST_R_RANDOM_GENERATOR_FAILURE),"random generator failure"},
+{ERR_REASON(GOST_R_RANDOM_NUMBER_GENERATOR_FAILED),"random number generator failed"},
+{ERR_REASON(GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH),"session key mac does not match"},
+{ERR_REASON(GOST_R_SIGNATURE_MISMATCH) ,"signature mismatch"},
+{ERR_REASON(GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q),"signature parts greater than q"},
+{ERR_REASON(GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND),"unsupported cipher ctl command"},
+{ERR_REASON(GOST_R_UNSUPPORTED_PARAMETER_SET),"unsupported parameter set"},
+{0,NULL}
+ };
+
+#endif
+
+#ifdef GOST_LIB_NAME
+static ERR_STRING_DATA GOST_lib_name[]=
+ {
+{0 ,GOST_LIB_NAME},
+{0,NULL}
+ };
+#endif
+
+
+static int GOST_lib_error_code=0;
+static int GOST_error_init=1;
+
+void ERR_load_GOST_strings(void)
+ {
+ if (GOST_lib_error_code == 0)
+ GOST_lib_error_code=ERR_get_next_error_library();
+
+ if (GOST_error_init)
+ {
+ GOST_error_init=0;
+#ifndef OPENSSL_NO_ERR
+ ERR_load_strings(GOST_lib_error_code,GOST_str_functs);
+ ERR_load_strings(GOST_lib_error_code,GOST_str_reasons);
+#endif
+
+#ifdef GOST_LIB_NAME
+ GOST_lib_name->error = ERR_PACK(GOST_lib_error_code,0,0);
+ ERR_load_strings(0,GOST_lib_name);
+#endif
+ }
+ }
+
+void ERR_unload_GOST_strings(void)
+ {
+ if (GOST_error_init == 0)
+ {
+#ifndef OPENSSL_NO_ERR
+ ERR_unload_strings(GOST_lib_error_code,GOST_str_functs);
+ ERR_unload_strings(GOST_lib_error_code,GOST_str_reasons);
+#endif
+
+#ifdef GOST_LIB_NAME
+ ERR_unload_strings(0,GOST_lib_name);
+#endif
+ GOST_error_init=1;
+ }
+ }
+
+void ERR_GOST_error(int function, int reason, char *file, int line)
+ {
+ if (GOST_lib_error_code == 0)
+ GOST_lib_error_code=ERR_get_next_error_library();
+ ERR_PUT_error(GOST_lib_error_code,function,reason,file,line);
+ }
diff --git a/engines/ccgost/e_gost_err.h b/engines/ccgost/e_gost_err.h
new file mode 100644
index 0000000000..49f4cd5766
--- /dev/null
+++ b/engines/ccgost/e_gost_err.h
@@ -0,0 +1,150 @@
+/* ====================================================================
+ * Copyright (c) 2001-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_GOST_ERR_H
+#define HEADER_GOST_ERR_H
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_GOST_strings(void);
+void ERR_unload_GOST_strings(void);
+void ERR_GOST_error(int function, int reason, char *file, int line);
+#define GOSTerr(f,r) ERR_GOST_error((f),(r),__FILE__,__LINE__)
+
+/* Error codes for the GOST functions. */
+
+/* Function codes. */
+#define GOST_F_DECODE_GOST_ALGOR_PARAMS 131
+#define GOST_F_DECRYPT_CRYPTOCOM_KEY 120
+#define GOST_F_ENCODE_GOST_ALGOR_PARAMS 130
+#define GOST_F_FILL_GOST2001_PARAMS 99
+#define GOST_F_FILL_GOST94_PARAMS 100
+#define GOST_F_GET_ENCRYPTION_PARAMS 101
+#define GOST_F_GOST2001_COMPUTE_PUBLIC 102
+#define GOST_F_GOST2001_DO_SIGN 103
+#define GOST_F_GOST2001_DO_VERIFY 104
+#define GOST_F_GOST89_GET_ASN1_PARAMETERS 105
+#define GOST_F_GOST89_SET_ASN1_PARAMETERS 106
+#define GOST_F_GOST94_COPY_PARAMETERS 107
+#define GOST_F_GOST_CIPHER_CTL 108
+#define GOST_F_GOST_COMPUTE_PUBLIC 109
+#define GOST_F_GOST_DO_SIGN 110
+#define GOST_F_GOST_DO_VERIFY 111
+#define GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001 127
+#define GOST_F_PARAM_COPY_GOST01 132
+#define GOST_F_PARAM_COPY_GOST94 133
+#define GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT 121
+#define GOST_F_PKCS7_GOST94_KEY_TRANSPORT_DECRYPT 122
+#define GOST_F_PKEY_GOST01CC_DECRYPT 128
+#define GOST_F_PKEY_GOST01CC_ENCRYPT 129
+#define GOST_F_PKEY_GOST01CP_ENCRYPT 137
+#define GOST_F_PKEY_GOST01_KEYGEN 112
+#define GOST_F_PKEY_GOST94CC_DECRYPT 125
+#define GOST_F_PKEY_GOST94CC_ENCRYPT 123
+#define GOST_F_PKEY_GOST94CP_DECRYPT 126
+#define GOST_F_PKEY_GOST94CP_ENCRYPT 124
+#define GOST_F_PKEY_GOST94_KEYGEN 113
+#define GOST_F_PKEY_GOST_CTRL 114
+#define GOST_F_PKEY_GOST_CTRL01_STR 115
+#define GOST_F_PKEY_GOST_CTRL94_STR 116
+#define GOST_F_PRIV_DECODE_GOST_94 117
+#define GOST_F_PUB_DECODE_GOST01 136
+#define GOST_F_PUB_DECODE_GOST94 134
+#define GOST_F_PUB_ENCODE_GOST01 135
+#define GOST_F_UNPACK_CC_SIGNATURE 118
+#define GOST_F_UNPACK_CP_SIGNATURE 119
+
+/* Reason codes. */
+#define GOST_R_BAD_KEY_PARAMETERS_FORMAT 128
+#define GOST_R_BAD_PKEY_PARAMETERS_FORMAT 129
+#define GOST_R_CANNOT_PACK_EPHEMERAL_KEY 114
+#define GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT 115
+#define GOST_R_ERROR_COMPUTING_MAC 116
+#define GOST_R_ERROR_COMPUTING_SHARED_KEY 117
+#define GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO 118
+#define GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO 119
+#define GOST_R_ERROR_STORING_ENCRYPTED_KEY 120
+#define GOST_R_ERROR_STORING_IV 121
+#define GOST_R_ERROR_STORING_MAC 122
+#define GOST_R_INCOMPATIBLE_ALGORITHMS 130
+#define GOST_R_INVALID_CIPHER_PARAMS 99
+#define GOST_R_INVALID_CIPHER_PARAM_OID 100
+#define GOST_R_INVALID_DIGEST_TYPE 101
+#define GOST_R_INVALID_ENCRYPTED_KEY_SIZE 123
+#define GOST_R_INVALID_GOST94_PARMSET 127
+#define GOST_R_INVALID_IV_LENGTH 102
+#define GOST_R_INVALID_PARAMSET 103
+#define GOST_R_KEY_IS_NOT_INITALIZED 104
+#define GOST_R_KEY_IS_NOT_INITIALIZED 105
+#define GOST_R_KEY_PARAMETERS_MISSING 131
+#define GOST_R_MALLOC_FAILURE 124
+#define GOST_R_NOT_ENOUGH_SPACE_FOR_KEY 125
+#define GOST_R_NO_MEMORY 106
+#define GOST_R_NO_PARAMETERS_SET 107
+#define GOST_R_PUBLIC_KEY_UNDEFINED 132
+#define GOST_R_RANDOM_GENERATOR_ERROR 108
+#define GOST_R_RANDOM_GENERATOR_FAILURE 133
+#define GOST_R_RANDOM_NUMBER_GENERATOR_FAILED 109
+#define GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH 126
+#define GOST_R_SIGNATURE_MISMATCH 110
+#define GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q 111
+#define GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND 112
+#define GOST_R_UNSUPPORTED_PARAMETER_SET 113
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/engines/ccgost/e_gost_err.proto b/engines/ccgost/e_gost_err.proto
new file mode 100644
index 0000000000..c57bd1bd8f
--- /dev/null
+++ b/engines/ccgost/e_gost_err.proto
@@ -0,0 +1,61 @@
+/* ====================================================================
+ * Copyright (c) 2001-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_GOST_ERR_H
+#define HEADER_GOST_ERR_H
+
+#define GOST_LIB_NAME "GOST engine"
+#ifdef __cplusplus
+ extern "C" {
+#endif
diff --git a/engines/ccgost/engine.c b/engines/ccgost/engine.c
new file mode 100644
index 0000000000..757793b396
--- /dev/null
+++ b/engines/ccgost/engine.c
@@ -0,0 +1,230 @@
+/**********************************************************************
+ * engine.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Main file of GOST engine *
+ * for OpenSSL *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+#include <openssl/obj_mac.h>
+#include "e_gost_err.h"
+#include "md.h"
+#include "crypt.h"
+#include "meth.h"
+
+static const char *engine_gost_id = "gost";
+static const char *engine_gost_name = "Reference implementation of GOST engine";
+
+/* Symmetric cipher and digest function registrar */
+
+static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+ const int **nids, int nid);
+
+static int gost_digests(ENGINE *e, const EVP_MD **digest,
+ const int **nids, int ind);
+
+static int gost_pkey_meths (ENGINE *e, EVP_PKEY_METHOD **pmeth,
+ const int **nids, int nid);
+
+static int gost_pkey_asn1_meths (ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
+ const int **nids, int nid);
+
+static int gost_cipher_nids[] =
+ {NID_id_Gost28147_89, 0};
+
+static int gost_digest_nids[] =
+ {NID_id_GostR3411_94, 0};
+
+static int gost_pkey_meth_nids[] =
+ {NID_id_GostR3410_94_cc, NID_id_GostR3410_94, NID_id_GostR3410_2001_cc,
+ NID_id_GostR3410_2001, 0};
+
+static EVP_PKEY_METHOD *pmeth_GostR3410_94_cc = NULL, *pmeth_GostR3410_94 = NULL,
+ *pmeth_GostR3410_2001_cc = NULL, *pmeth_GostR3410_2001 = NULL;
+
+static EVP_PKEY_ASN1_METHOD *ameth_GostR3410_94_cc = NULL, *ameth_GostR3410_94 = NULL,
+ *ameth_GostR3410_2001_cc = NULL, *ameth_GostR3410_2001 = NULL;
+
+
+static int gost_engine_init(ENGINE *e) {
+ return 1;
+}
+static int gost_engine_finish(ENGINE *e) {
+ return 1;
+}
+
+static int gost_engine_destroy(ENGINE *e) {
+ return 1;
+}
+
+static int bind_gost (ENGINE *e,const char *id) {
+ int ret = 0;
+ if (id && strcmp(id, engine_gost_id)) return 0;
+
+ if (!ENGINE_set_id(e, engine_gost_id)) {
+ 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;
+ }
+ 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)) goto end;
+
+
+
+ if (!register_ameth_gost(NID_id_GostR3410_94_cc, &ameth_GostR3410_94_cc, "GOST94CC", "GOST R 34.10-94, Cryptocom LTD implementation")) goto end;
+ if (!register_ameth_gost(NID_id_GostR3410_94, &ameth_GostR3410_94, "GOST94", "GOST R 34.10-94")) goto end;
+ if (!register_ameth_gost(NID_id_GostR3410_2001_cc, &ameth_GostR3410_2001_cc, "GOST2001CC", "GOST R 34.10-2001, Cryptocom LTD implementation")) goto end;
+ if (!register_ameth_gost(NID_id_GostR3410_2001, &ameth_GostR3410_2001, "GOST2001", "GOST R 34.10-2001")) goto end;
+
+ if (!register_pmeth_gost(NID_id_GostR3410_94_cc, &pmeth_GostR3410_94_cc, 0)) goto end;
+ if (!register_pmeth_gost(NID_id_GostR3410_94, &pmeth_GostR3410_94, 0)) goto end;
+ if (!register_pmeth_gost(NID_id_GostR3410_2001_cc, &pmeth_GostR3410_2001_cc, 0)) goto end;
+ if (!register_pmeth_gost(NID_id_GostR3410_2001, &pmeth_GostR3410_2001, 0)) goto end;
+ if ( ! ENGINE_register_ciphers(e)
+ || ! ENGINE_register_digests(e)
+ || ! ENGINE_register_pkey_meths(e)
+ /* These two actually should go in LIST_ADD command */
+ || ! EVP_add_cipher(&cipher_gost)
+ || ! EVP_add_digest(&digest_gost)
+ ) goto end;
+
+ ERR_load_GOST_strings();
+ ret = 1;
+end:
+ return ret;
+}
+
+#ifdef _WIN32
+extern __declspec( dllexport )
+#endif
+
+//#ifndef OPENSSL_NO_DYNAMIC_ENGINE
+IMPLEMENT_DYNAMIC_BIND_FN(bind_gost);
+
+#ifdef _WIN32
+extern __declspec( dllexport )
+#endif
+
+IMPLEMENT_DYNAMIC_CHECK_FN();
+//#else
+static ENGINE *engine_gost(void)
+ {
+ ENGINE *ret = ENGINE_new();
+ if(!ret)
+ return NULL;
+ if(!bind_gost(ret, engine_gost_id))
+ {
+ ENGINE_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+void ENGINE_load_gost(void)
+ {
+ /* Copied from eng_[openssl|dyn].c */
+ ENGINE *toadd = engine_gost();
+ if(!toadd) return;
+ ENGINE_add(toadd);
+ ENGINE_free(toadd);
+ ERR_clear_error();
+ }
+//#endif /* OPENSSL_NO_DYNAMIC_ENGINE */
+
+static int gost_digests(ENGINE *e, const EVP_MD **digest,
+ const int **nids, int nid)
+{
+ int ok =1 ;
+ if (!digest) {
+ *nids = gost_digest_nids;
+ return 1;
+ }
+ //printf("Digest no %d requested\n",nid);
+ if(nid == NID_id_GostR3411_94) {
+ *digest = &digest_gost;
+ } else {
+ ok =0;
+ *digest = NULL;
+ }
+ return ok;
+}
+
+static int gost_ciphers (ENGINE *e,const EVP_CIPHER **cipher,
+ const int **nids, int nid) {
+ int ok = 1;
+ if (!cipher) {
+ *nids = gost_cipher_nids;
+ return 1; /* Only one cipher supported */
+ }
+
+ if(nid == NID_id_Gost28147_89) {
+ *cipher = &cipher_gost;
+ } else {
+ ok = 0;
+ *cipher = NULL;
+ }
+ return ok;
+}
+
+static int gost_pkey_meths (ENGINE *e, EVP_PKEY_METHOD **pmeth,
+ const int **nids, int nid)
+{
+ if (!pmeth) {
+ *nids = gost_pkey_meth_nids;
+ return 4;
+ }
+
+ switch (nid) {
+ case NID_id_GostR3410_94_cc: *pmeth = pmeth_GostR3410_94_cc; return 1;
+ case NID_id_GostR3410_94: *pmeth = pmeth_GostR3410_94; return 1;
+ case NID_id_GostR3410_2001_cc: *pmeth = pmeth_GostR3410_2001_cc; return 1;
+ case NID_id_GostR3410_2001: *pmeth = pmeth_GostR3410_2001; return 1;
+ default:;
+ }
+
+ *pmeth = NULL;
+ return 0;
+}
+
+static int gost_pkey_asn1_meths (ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
+ const int **nids, int nid)
+{
+ if (!ameth) {
+ *nids = gost_pkey_meth_nids;
+ return 4;
+ }
+ switch (nid) {
+ case NID_id_GostR3410_94_cc: *ameth = ameth_GostR3410_94_cc; return 1;
+ case NID_id_GostR3410_94: *ameth = ameth_GostR3410_94; return 1;
+ case NID_id_GostR3410_2001_cc: *ameth = ameth_GostR3410_2001_cc; return 1;
+ case NID_id_GostR3410_2001: *ameth = ameth_GostR3410_2001; return 1;
+ default:;
+ }
+
+ *ameth = NULL;
+ return 0;
+}
diff --git a/engines/ccgost/gost.ec b/engines/ccgost/gost.ec
new file mode 100644
index 0000000000..6c2c85e57c
--- /dev/null
+++ b/engines/ccgost/gost.ec
@@ -0,0 +1,5 @@
+L GOST e_gost_err.h e_gost_err.c
+L NONE asymm.h NONE
+L NONE md.h NONE
+L NONE crypt.h NONE
+L NONE gostkeyx.h NONE
diff --git a/engines/ccgost/gost2001.c b/engines/ccgost/gost2001.c
new file mode 100644
index 0000000000..c53bd6c7c5
--- /dev/null
+++ b/engines/ccgost/gost2001.c
@@ -0,0 +1,324 @@
+/**********************************************************************
+ * gost2001.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Implementation of GOST R 34.10-2001 *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include "tools.h"
+#include "sign.h"
+#include "paramset.h"
+#include <string.h>
+#include <openssl/rand.h>
+#include <openssl/ecdsa.h>
+#include <openssl/err.h>
+#include "e_gost_err.h"
+#ifdef DEBUG_SIGN
+extern
+void dump_signature(const char *message,const unsigned char *buffer,size_t len);
+void dump_dsa_sig(const char *message, DSA_SIG *sig);
+#else
+
+#define dump_signature(a,b,c)
+#define dump_dsa_sig(a,b)
+#endif
+
+/*
+ * Fills EC_KEY structure hidden in the app_data field of DSA structure
+ * with parameter information, extracted from parameter array in
+ * params.c file.
+ *
+ * Also fils DSA->q field with copy of EC_GROUP order field to make
+ * DSA_size function work
+ */
+int fill_GOST2001_params(EC_KEY *eckey, int nid) {
+ R3410_2001_params *params = R3410_2001_paramset;
+ EC_GROUP *grp;
+ BIGNUM *p=NULL,*q=NULL,*a=NULL,*b=NULL,*x=NULL,*y=NULL;
+ EC_POINT *P=NULL;
+ BN_CTX *ctx=BN_CTX_new();
+ int ok=0;
+
+ BN_CTX_start(ctx);
+ p=BN_CTX_get(ctx);
+ a=BN_CTX_get(ctx);
+ b=BN_CTX_get(ctx);
+ x=BN_CTX_get(ctx);
+ y=BN_CTX_get(ctx);
+ q=BN_CTX_get(ctx);
+ while (params->nid!=NID_undef && params->nid != nid) params++;
+ if (params->nid == NID_undef) {
+ GOSTerr(GOST_F_FILL_GOST2001_PARAMS,GOST_R_UNSUPPORTED_PARAMETER_SET);
+ goto err;
+ }
+ BN_hex2bn(&p,params->p);
+ BN_hex2bn(&a,params->a);
+ BN_hex2bn(&b,params->b);
+
+ grp = EC_GROUP_new_curve_GFp(p,a,b,ctx);
+
+ P = EC_POINT_new(grp);
+
+ BN_hex2bn(&x,params->x);
+ BN_hex2bn(&y,params->y);
+ EC_POINT_set_affine_coordinates_GFp(grp,P,x,y,ctx);
+ BN_hex2bn(&q,params->q);
+#ifdef DEBUG_KEYS
+ fprintf(stderr,"Set params index %d oid %s\nq=",
+ (params-R3410_2001_paramset),OBJ_nid2sn(params->nid));
+ BN_print_fp(stderr,q);
+ fprintf(stderr,"\n");
+#endif
+
+ EC_GROUP_set_generator(grp,P,q,NULL);
+ EC_GROUP_set_curve_name(grp,params->nid);
+
+ EC_KEY_set_group(eckey,grp);
+ ok=1;
+err:
+ EC_POINT_free(P);
+ EC_GROUP_free(grp);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ok;
+
+}
+
+
+/*
+ * Computes gost2001 signature as DSA_SIG structure
+ *
+ *
+ */
+DSA_SIG *gost2001_do_sign(const unsigned char *dgst,int dlen, EC_KEY *eckey) {
+ DSA_SIG *newsig = NULL;
+ BIGNUM *md = hashsum2bn(dgst);
+ BIGNUM *order = NULL;
+ const EC_GROUP *group;
+ const BIGNUM *priv_key;
+ BIGNUM *r=NULL,*s=NULL,*X=NULL,*tmp=NULL,*tmp2=NULL, *k=NULL,*e=NULL;
+ EC_POINT *C=NULL;
+ BN_CTX *ctx = BN_CTX_new();
+ BN_CTX_start(ctx);
+ OPENSSL_assert(dlen==32);
+ newsig=DSA_SIG_new();
+ if (!newsig)
+ {
+ GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_NO_MEMORY);
+ goto err;
+ }
+ group = EC_KEY_get0_group(eckey);
+ order=BN_CTX_get(ctx);
+ EC_GROUP_get_order(group,order,ctx);
+ priv_key = EC_KEY_get0_private_key(eckey);
+ e = BN_CTX_get(ctx);
+ BN_mod(e,md,order,ctx);
+#ifdef DEBUG_SIGN
+ fprintf(stderr,"digest as bignum=");
+ BN_print_fp(stderr,md);
+ fprintf(stderr,"\ndigest mod q=");
+ BN_print_fp(stderr,e);
+ fprintf(stderr,"\n");
+#endif
+ if (BN_is_zero(e))
+ {
+ BN_one(e);
+ }
+ k =BN_CTX_get(ctx);
+ C=EC_POINT_new(group);
+ do {
+ do {
+ if (!BN_rand_range(k,order))
+ {
+ GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_RANDOM_NUMBER_GENERATOR_FAILED);
+ DSA_SIG_free(newsig);
+ goto err;
+ }
+ if (!EC_POINT_mul(group,C,k,NULL,NULL,ctx)) {
+ GOSTerr(GOST_F_GOST2001_DO_SIGN,ERR_R_EC_LIB);
+ DSA_SIG_free(newsig);
+ goto err;
+ }
+ if (!X) X=BN_CTX_get(ctx);
+ if (!EC_POINT_get_affine_coordinates_GFp(group,C,X,NULL,ctx)) {
+ GOSTerr(GOST_F_GOST2001_DO_SIGN,ERR_R_EC_LIB);
+ DSA_SIG_free(newsig);
+ goto err;
+ }
+ if (!r) r=BN_CTX_get(ctx);
+ BN_nnmod(r,X,order,ctx);
+ } while (BN_is_zero(r));
+ /* s = (r*priv_key+k*e) mod order */
+ if (!tmp) tmp = BN_CTX_get(ctx);
+ BN_mod_mul(tmp,priv_key,r,order,ctx);
+ if (!tmp2) tmp2 = BN_CTX_get(ctx);
+ BN_mod_mul(tmp2,k,e,order,ctx);
+ if (!s) s=BN_CTX_get(ctx);
+ BN_mod_add(s,tmp,tmp2,order,ctx);
+ } while (BN_is_zero(s));
+
+ newsig->s=BN_dup(s);
+ newsig->r=BN_dup(r);
+err:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ EC_POINT_free(C);
+ BN_free(md);
+ return newsig;
+}
+/*
+ * Verifies gost 2001 signature
+ *
+ */
+int gost2001_do_verify(const unsigned char *dgst,int dgst_len,
+ DSA_SIG *sig, EC_KEY *ec) {
+ BN_CTX *ctx=BN_CTX_new();
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
+ BIGNUM *order;
+ BIGNUM *md = NULL,*e=NULL,*R=NULL,*v=NULL,*z1=NULL,*z2=NULL;
+ BIGNUM *X=NULL,*tmp=NULL;
+ EC_POINT *C = NULL;
+ const EC_POINT *pub_key=NULL;
+ int ok=0;
+
+ BN_CTX_start(ctx);
+ order = BN_CTX_get(ctx);
+ e = BN_CTX_get(ctx);
+ z1 = BN_CTX_get(ctx);
+ z2 = BN_CTX_get(ctx);
+ tmp = BN_CTX_get(ctx);
+ X= BN_CTX_get(ctx);
+ R=BN_CTX_get(ctx);
+ v=BN_CTX_get(ctx);
+
+ EC_GROUP_get_order(group,order,ctx);
+ pub_key = EC_KEY_get0_public_key(ec);
+ if (BN_is_zero(sig->s) || BN_is_zero(sig->r) ||
+ (BN_cmp(sig->s,order)>=1) || (BN_cmp(sig->r,order)>=1))
+ {
+ GOSTerr(GOST_F_GOST_DO_VERIFY,GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q);
+ goto err;
+
+ }
+ md = hashsum2bn(dgst);
+
+ BN_mod(e,md,order,ctx);
+#ifdef DEBUG_SIGN
+ fprintf(stderr,"digest as bignum: ");
+ BN_print_fp(stderr,md);
+ fprintf(stderr,"\ndigest mod q: ");
+ BN_print_fp(stderr,e);
+#endif
+ if (BN_is_zero(e)) BN_one(e);
+ v=BN_mod_inverse(v,e,order,ctx);
+ BN_mod_mul(z1,sig->s,v,order,ctx);
+ BN_sub(tmp,order,sig->r);
+ BN_mod_mul(z2,tmp,v,order,ctx);
+#ifdef DEBUG_SIGN
+ fprintf(stderr,"\nInverted digest value: ");
+ BN_print_fp(stderr,v);
+ fprintf(stderr,"\nz1: ");
+ BN_print_fp(stderr,z1);
+ fprintf(stderr,"\nz2: ");
+ BN_print_fp(stderr,z2);
+#endif
+ C = EC_POINT_new(group);
+ if (!EC_POINT_mul(group,C,z1,pub_key,z2,ctx))
+ {
+ GOSTerr(GOST_F_GOST2001_DO_VERIFY,ERR_R_EC_LIB);
+ goto err;
+ }
+ if (!EC_POINT_get_affine_coordinates_GFp(group,C,X,NULL,ctx))
+ {
+ GOSTerr(GOST_F_GOST2001_DO_VERIFY,ERR_R_EC_LIB);
+ goto err;
+ }
+ BN_mod(R,X,order,ctx);
+#ifdef DEBUG_SIGN
+ fprintf(stderr,"\nX=");
+ BN_print_fp(stderr,X);
+ fprintf(stderr,"\nX mod q=");
+ BN_print_fp(stderr,R);
+ fprintf(stderr,"\n");
+#endif
+ if (BN_cmp(R,sig->r)!=0) {
+ GOSTerr(GOST_F_GOST2001_DO_VERIFY,GOST_R_SIGNATURE_MISMATCH);
+ } else {
+ ok = 1;
+ }
+err:
+ EC_POINT_free(C);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ BN_free(md);
+ return ok;
+}
+/*
+ * Computes GOST R 34.10-2001 public key
+ *
+ *
+ */
+int gost2001_compute_public(EC_KEY *ec)
+{
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
+ EC_POINT *pub_key=NULL;
+ const BIGNUM *priv_key=NULL;
+ BN_CTX *ctx=NULL;
+ int ok=0;
+
+ if (!group) {
+ GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,GOST_R_KEY_IS_NOT_INITIALIZED);
+ return 0;
+ }
+ ctx=BN_CTX_new();
+ BN_CTX_start(ctx);
+ if (!(priv_key=EC_KEY_get0_private_key(ec)))
+ {
+ GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB);
+ goto err;
+ }
+
+ pub_key = EC_POINT_new(group);
+ if (!EC_POINT_mul(group,pub_key,priv_key,NULL,NULL,ctx))
+ {
+ GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB);
+ goto err;
+ }
+ if (!EC_KEY_set_public_key(ec,pub_key)) {
+ GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB);
+ goto err;
+ }
+ ok = 256;
+err:
+ BN_CTX_end(ctx);
+ EC_POINT_free(pub_key);
+ BN_CTX_free(ctx);
+ return ok;
+}
+/*
+ *
+ * Generates GOST R 34.10-2001 keypair
+ *
+ *
+ */
+int gost2001_keygen(EC_KEY *ec) {
+ BIGNUM *order = BN_new(),*d=BN_new();
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
+ EC_GROUP_get_order(group,order,NULL);
+
+ do {
+ if (!BN_rand_range(d,order))
+ {
+ GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_RANDOM_NUMBER_GENERATOR_FAILED);
+ BN_free(d);
+ BN_free(order);
+ return 0;
+ }
+ } while (BN_is_zero(d));
+ EC_KEY_set_private_key(ec,d);
+ BN_free(d);
+ BN_free(order);
+ return gost2001_compute_public(ec);
+}
+
diff --git a/engines/ccgost/gost2001_keyx.c b/engines/ccgost/gost2001_keyx.c
new file mode 100644
index 0000000000..120ec69d3c
--- /dev/null
+++ b/engines/ccgost/gost2001_keyx.c
@@ -0,0 +1,385 @@
+/**********************************************************************
+ * gost_keyx.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * VK0 34.10-2001 key exchange and GOST R 34.10-2001 *
+ * based PKCS7/SMIME support *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <string.h>
+#include <openssl/objects.h>
+#include "gost89.h"
+#include "gosthash.h"
+#include "gost_asn1.h"
+#include "e_gost_err.h"
+#include "keywrap.h"
+#include "crypt.h"
+#include "sign.h"
+#include "pmeth.h"
+#include "tools.h"
+#include "gostkeyx.h"
+
+/* Transform ECDH shared key into little endian as required by Cryptocom
+ * key exchange */
+static void *make_key_le(const void *in, size_t inlen, void *out, size_t *outlen) {
+ const char* inbuf= in;
+ char* outbuf= out;
+ int i;
+ if (*outlen < inlen) {
+ return NULL;
+ }
+ for (i=0;i<inlen;i++) {
+ outbuf[inlen-1-i]=inbuf[i];
+ }
+ *outlen = inlen;
+ return out;
+}
+
+/* Create gost 2001 ephemeral key with same parameters as peer key */
+static EC_KEY *make_ec_ephemeral_key(EC_KEY *peer_key,BIGNUM *seckey) {
+ EC_KEY *out = EC_KEY_new();
+ EC_KEY_copy(out,peer_key);
+ EC_KEY_set_private_key(out,seckey);
+ gost2001_compute_public(out);
+ return out;
+}
+/* Packs GOST elliptic curve key into EVP_PKEY setting same parameters
+ * as in passed pubkey
+ */
+static EVP_PKEY *ec_ephemeral_key_to_EVP(EVP_PKEY *pubk,int type,EC_KEY *ephemeral)
+{
+ EVP_PKEY *newkey;
+ newkey = EVP_PKEY_new();
+ EVP_PKEY_assign(newkey,type,ephemeral);
+ return newkey;
+}
+
+/*
+ * EVP_PKEY_METHOD callback encrypt
+ * Implementation of GOST2001 key transport, cryptocom variation
+ */
+
+int pkey_GOST01cc_encrypt (EVP_PKEY_CTX *pctx,unsigned char *out,
+ size_t *out_len, const unsigned char *key,size_t key_len)
+{
+ EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx);
+ struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx);
+ GOST_KEY_TRANSPORT *gkt = NULL;
+ int ret=0;
+ gost_ctx ctx;
+ EC_KEY *ephemeral=NULL;
+ const EC_POINT *pub_key_point=NULL;
+ unsigned char shared_key[32],encrypted_key[32],hmac[4],
+ iv[8]={0,0,0,0,0,0,0,0};
+ ephemeral = make_ec_ephemeral_key(EVP_PKEY_get0(pubk), gost_get_priv_key(data->eph_seckey));
+ if (!ephemeral) goto err;
+ /* compute shared key */
+ pub_key_point=EC_KEY_get0_public_key(EVP_PKEY_get0(pubk));
+ if (!ECDH_compute_key(shared_key,32,pub_key_point,ephemeral,make_key_le))
+ {
+ GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY);
+ goto err;
+ }
+ /* encrypt session key */
+ gost_init(&ctx, &GostR3411_94_CryptoProParamSet);
+ gost_key(&ctx,shared_key);
+ encrypt_cryptocom_key(key,key_len,encrypted_key,&ctx);
+ /* compute hmac of session key */
+ if (!gost_mac(&ctx,32,key,32,hmac))
+ {
+ GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_COMPUTING_MAC);
+ return -1;
+ }
+ gkt = GOST_KEY_TRANSPORT_new();
+ if (!gkt)
+ {
+ GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_NO_MEMORY);
+ return -1;
+ }
+ /* Store IV which is always zero in our case */
+ if (!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,iv,8))
+ {
+ GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_IV);
+ goto err;
+ }
+ if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,hmac,4))
+ {
+ GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_MAC);
+ goto err;
+ }
+ if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,encrypted_key,32))
+ {
+ GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_ENCRYPTED_KEY);
+ goto err;
+ }
+
+ if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) {
+ GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
+ goto err;
+ }
+ ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
+ gkt->key_agreement_info->cipher = OBJ_nid2obj(NID_id_Gost28147_89_cc);
+ if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,&out))>0) ret = 1;
+ ;
+err:
+ if (gkt) GOST_KEY_TRANSPORT_free(gkt);
+ return ret;
+}
+/*
+ * EVP_PKEY_METHOD callback decrypt
+ * Implementation of GOST2001 key transport, cryptocom variation
+ */
+int pkey_GOST01cc_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len, const unsigned char *in, size_t in_len) {
+ /* Form DH params from compute shared key */
+ EVP_PKEY *priv=EVP_PKEY_CTX_get0_pkey(pctx);
+ GOST_KEY_TRANSPORT *gkt = NULL;
+ const unsigned char *p=in;
+ unsigned char shared_key[32];
+ unsigned char hmac[4],hmac_comp[4];
+ unsigned char iv[8];
+ int i;
+ gost_ctx ctx;
+ const EC_POINT *pub_key_point;
+ EVP_PKEY *eph_key;
+
+ if (!key) {
+ *key_len = 32;
+ return 1;
+ }
+ /* Parse passed octet string and find out public key, iv and HMAC*/
+ gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p,
+ in_len);
+ if (!gkt) {
+ GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
+ return 0;
+ }
+ eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
+ /* Initialization vector is really ignored here */
+ OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8);
+ memcpy(iv,gkt->key_agreement_info->eph_iv->data,8);
+ /* HMAC should be computed and checked */
+ OPENSSL_assert(gkt->key_info->imit->length==4);
+ memcpy(hmac,gkt->key_info->imit->data,4);
+ /* Compute shared key */
+ pub_key_point=EC_KEY_get0_public_key(EVP_PKEY_get0(eph_key));
+ i=ECDH_compute_key(shared_key,32,pub_key_point,EVP_PKEY_get0(priv),make_key_le);
+ EVP_PKEY_free(eph_key);
+ if (!i)
+ {
+ GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY);
+ GOST_KEY_TRANSPORT_free(gkt);
+ return 0;
+ }
+ /* Decrypt session key */
+ gost_init(&ctx, &GostR3411_94_CryptoProParamSet);
+ gost_key(&ctx,shared_key);
+
+ if (!decrypt_cryptocom_key(key,*key_len,gkt->key_info->encrypted_key->data,
+ gkt->key_info->encrypted_key->length, &ctx))
+ {
+ GOST_KEY_TRANSPORT_free(gkt);
+ return 0;
+ }
+ GOST_KEY_TRANSPORT_free(gkt);
+ /* check HMAC of session key*/
+ if (!gost_mac(&ctx,32,key,32,hmac_comp)) {
+ GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_ERROR_COMPUTING_MAC);
+ return 0;
+ }
+ /* HMAC of session key is not correct */
+ if (memcmp(hmac,hmac_comp,4)!=0) {
+ GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH);
+ return 0;
+ }
+ return 1;
+}
+
+/* Implementation of CryptoPro VKO 34.10-2001 algorithm */
+static int VKO_compute_key(unsigned char *shared_key,size_t shared_key_size,const EC_POINT *pub_key,EC_KEY *priv_key,const unsigned char *ukm) {
+ unsigned char ukm_be[8],databuf[64],hashbuf[64];
+ BIGNUM *UKM=NULL,*p=NULL,*order=NULL,*X=NULL,*Y=NULL;
+ const BIGNUM* key=EC_KEY_get0_private_key(priv_key);
+ EC_POINT *pnt=EC_POINT_new(EC_KEY_get0_group(priv_key));
+ int i;
+ gost_hash_ctx hash_ctx;
+ BN_CTX *ctx = BN_CTX_new();
+
+ for (i=0;i<8;i++) {
+ ukm_be[7-i]=ukm[i];
+ }
+ BN_CTX_start(ctx);
+ UKM=getbnfrombuf(ukm_be,8);
+ p=BN_CTX_get(ctx);
+ order = BN_CTX_get(ctx);
+ X=BN_CTX_get(ctx);
+ Y=BN_CTX_get(ctx);
+ EC_GROUP_get_order(EC_KEY_get0_group(priv_key),order,ctx);
+ BN_mod_mul(p,key,UKM,order,ctx);
+ EC_POINT_mul(EC_KEY_get0_group(priv_key),pnt,NULL,pub_key,p,ctx);
+ EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(priv_key),
+ pnt,X,Y,ctx);
+ /*Serialize elliptic curve point same way as we do it when saving
+ * key */
+ store_bignum(Y,databuf,32);
+ store_bignum(X,databuf+32,32);
+ /* And reverse byte order of whole buffer */
+ for (i=0;i<64;i++) {
+ hashbuf[63-i]=databuf[i];
+ }
+ init_gost_hash_ctx(&hash_ctx,&GostR3411_94_CryptoProParamSet);
+ start_hash(&hash_ctx);
+ hash_block(&hash_ctx,hashbuf,64);
+ finish_hash(&hash_ctx,shared_key);
+ done_gost_hash_ctx(&hash_ctx);
+ BN_free(UKM);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ EC_POINT_free(pnt);
+ return 32;
+}
+
+/* Generates ephemeral key based on pubk algorithm
+ * computes shared key using VKO and returns filled up
+ * GOST_KEY_TRANSPORT structure
+ */
+/* Public, because it would be needed in SSL implementation */
+GOST_KEY_TRANSPORT *make_rfc4490_keytransport_2001(EVP_PKEY *pubk,BIGNUM *eph_key,
+ const unsigned char *key,size_t keylen, unsigned char *ukm,
+ size_t ukm_len)
+{
+
+ const struct gost_cipher_info *param=get_encryption_params(NULL);
+ EC_KEY *ephemeral = NULL;
+ GOST_KEY_TRANSPORT *gkt=NULL;
+ const EC_POINT *pub_key_point = EC_KEY_get0_public_key(EVP_PKEY_get0(pubk));
+ unsigned char shared_key[32],crypted_key[44];
+ gost_ctx ctx;
+ EVP_PKEY *newkey=NULL;
+
+ /* Do not use vizir cipher parameters with cryptopro */
+ if (!getenv("CRYPT_PARAMS") && param == gost_cipher_list) {
+ param= gost_cipher_list+1;
+ }
+ ephemeral = make_ec_ephemeral_key(EVP_PKEY_get0(pubk),eph_key);
+ VKO_compute_key(shared_key,32,pub_key_point,ephemeral,ukm);
+ gost_init(&ctx,param->sblock);
+ keyWrapCryptoPro(&ctx,shared_key,ukm,key,crypted_key);
+ gkt = GOST_KEY_TRANSPORT_new();
+ if (!gkt) {
+ goto memerr;
+ }
+ if(!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,
+ ukm,8)) {
+ goto memerr;
+ }
+ if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,crypted_key+40,4)) {
+ goto memerr;
+ }
+ if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,crypted_key+8,32)) {
+ goto memerr;
+ }
+ newkey = ec_ephemeral_key_to_EVP(pubk,NID_id_GostR3410_2001,ephemeral);
+ if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,newkey)) {
+ GOSTerr(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001,GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
+ goto err;
+ }
+ ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
+ gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid);
+ EVP_PKEY_free(newkey);
+ return gkt;
+memerr:
+ GOSTerr(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001,
+ GOST_R_MALLOC_FAILURE);
+err:
+ GOST_KEY_TRANSPORT_free(gkt);
+ return NULL;
+}
+
+/*
+ * EVP_PKEY_METHOD callback encrypt
+ * Implementation of GOST2001 key transport, cryptopo variation
+ */
+
+int pkey_GOST01cp_encrypt (EVP_PKEY_CTX *pctx, unsigned char *out, size_t *out_len, const unsigned char *key,size_t key_len)
+{
+ GOST_KEY_TRANSPORT *gkt=NULL;
+ EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx);
+ struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx);
+ unsigned char ukm[8];
+ int ret=0;
+ if (RAND_bytes(ukm,8)<=0) {
+ GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT,
+ GOST_R_RANDOM_GENERATOR_FAILURE);
+ return 0;
+ }
+
+ if (!(gkt=make_rfc4490_keytransport_2001(pubk,gost_get_priv_key(data->eph_seckey),key, key_len,ukm,8))) {
+ goto err;
+ }
+ if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,&out))>0) ret =1;
+ GOST_KEY_TRANSPORT_free(gkt);
+ return ret;
+err:
+ GOST_KEY_TRANSPORT_free(gkt);
+ return -1;
+}
+/* Public, because it would be needed in SSL implementation */
+int decrypt_rfc4490_shared_key_2001(EVP_PKEY *priv,GOST_KEY_TRANSPORT *gkt,
+ unsigned char *key_buf,int key_buf_len)
+{
+ unsigned char wrappedKey[44];
+ unsigned char sharedKey[32];
+ gost_ctx ctx;
+ const struct gost_cipher_info *param=NULL;
+ EVP_PKEY *eph_key=NULL;
+
+ eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
+ param = get_encryption_params(gkt->key_agreement_info->cipher);
+ gost_init(&ctx,param->sblock);
+ OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8);
+ memcpy(wrappedKey,gkt->key_agreement_info->eph_iv->data,8);
+ OPENSSL_assert(gkt->key_info->encrypted_key->length==32);
+ memcpy(wrappedKey+8,gkt->key_info->encrypted_key->data,32);
+ OPENSSL_assert(gkt->key_info->imit->length==4);
+ memcpy(wrappedKey+40,gkt->key_info->imit->data,4);
+ VKO_compute_key(sharedKey,32,EC_KEY_get0_public_key(EVP_PKEY_get0(eph_key)),
+ EVP_PKEY_get0(priv),wrappedKey);
+ if (!keyUnwrapCryptoPro(&ctx,sharedKey,wrappedKey,key_buf)) {
+ GOSTerr(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT,
+ GOST_R_ERROR_COMPUTING_SHARED_KEY);
+ goto err;
+ }
+
+ EVP_PKEY_free(eph_key);
+ return 32;
+err:
+ EVP_PKEY_free(eph_key);
+ return -1;
+}
+/*
+ * EVP_PKEY_METHOD callback decrypt
+ * Implementation of GOST2001 key transport, cryptopo variation
+ */
+int pkey_GOST01cp_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t * key_len, const unsigned char *in, size_t in_len) {
+ const unsigned char *p = in;
+ EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx);
+ GOST_KEY_TRANSPORT *gkt = NULL;
+ int ret=0;
+
+ if (!key) {
+ *key_len = 32;
+ return 1;
+ }
+ gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p,
+ in_len);
+ if (!gkt) {
+ GOSTerr(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
+ return -1;
+ }
+ ret = decrypt_rfc4490_shared_key_2001(priv,gkt,key,*key_len);
+ GOST_KEY_TRANSPORT_free(gkt);
+ return ret;
+}
diff --git a/engines/ccgost/gost89.c b/engines/ccgost/gost89.c
new file mode 100644
index 0000000000..03675724cc
--- /dev/null
+++ b/engines/ccgost/gost89.c
@@ -0,0 +1,383 @@
+/**********************************************************************
+ * gost89.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * 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
+ examples given in RFC.
+
+
+*/
+
+/* Substitution blocks from test examples for GOST R 34.11-94*/
+gost_subst_block GostR3411_94_TestParamSet = {
+ {0X1,0XF,0XD,0X0,0X5,0X7,0XA,0X4,0X9,0X2,0X3,0XE,0X6,0XB,0X8,0XC},
+ {0XD,0XB,0X4,0X1,0X3,0XF,0X5,0X9,0X0,0XA,0XE,0X7,0X6,0X8,0X2,0XC},
+ {0X4,0XB,0XA,0X0,0X7,0X2,0X1,0XD,0X3,0X6,0X8,0X5,0X9,0XC,0XF,0XE},
+ {0X6,0XC,0X7,0X1,0X5,0XF,0XD,0X8,0X4,0XA,0X9,0XE,0X0,0X3,0XB,0X2},
+ {0X7,0XD,0XA,0X1,0X0,0X8,0X9,0XF,0XE,0X4,0X6,0XC,0XB,0X2,0X5,0X3},
+ {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},
+ {0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB},
+ {0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3},
+ {0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5},
+ {0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3},
+ {0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD},
+ {0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8},
+ {0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF}
+} ;
+
+/* Test paramset from GOST 28147 */
+gost_subst_block Gost28147_TestParamSet =
+{
+ {0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8},
+ {0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD},
+ {0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4},
+ {0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4},
+ {0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8},
+ {0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB},
+ {0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5},
+ {0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6}
+};
+
+
+
+
+/* 1.2.643.2.2.31.1 */
+gost_subst_block Gost28147_CryptoProParamSetA= {
+ {0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4},
+ {0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE},
+ {0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6},
+ {0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6},
+ {0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6},
+ {0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9},
+ {0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1},
+ {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=
+{
+ {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},
+ {0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5},
+ {0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3},
+ {0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8},
+ {0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4},
+ {0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE},
+ {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=
+{
+ {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},
+ {0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD},
+ {0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7},
+ {0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4},
+ {0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB},
+ {0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3},
+ {0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3}
+};
+
+/* 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},
+ {0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7},
+ {0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6},
+ {0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1},
+ {0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8},
+ {0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2},
+ {0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1},
+ {0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3}
+};
+
+
+const byte CryptoProKeyMeshingKey[]={
+ 0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23,
+ 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*/
+void kboxinit(gost_ctx *c, const gost_subst_block *b) {
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ c->k87[i] = (b->k8[i>>4] <<4 | b->k7 [i &15])<<24;
+ c->k65[i] = (b->k6[i>>4] << 4 | b->k5 [i &15])<<16;
+ c->k43[i] = (b->k4[i>>4] <<4 | b->k3 [i &15])<<8;
+ c->k21[i] = b->k2[i>>4] <<4 | b->k1 [i &15];
+
+ }
+}
+
+/* Part of GOST 28147 algorithm moved into separate function */
+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 */
+ 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]);
+
+ 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] = (n2&0xff); out[1] = (n2>>8)&0xff; out[2]=(n2>>16)&0xff; out[3]=n2>>24;
+ out[4] = (n1&0xff); out[5] = (n1>>8)&0xff; out[6]=(n1>>16)&0xff; out[7]=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]);
+ 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]);
+
+ 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]);
+ out[0] = (n2&0xff); out[1] = (n2>>8)&0xff; out[2]=(n2>>16)&0xff; out[3]=n2>>24;
+ out[4] = (n1&0xff); out[5] = (n1>>8)&0xff; out[6]=(n1>>16)&0xff; out[7]=n1>>24;
+}
+
+/* Encrypts several blocks in ECB mode */
+void gost_enc(gost_ctx *c,const byte *clear,byte *cipher, int blocks)
+{
+ int i;
+ for(i=0;i<blocks;i++){
+ 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;
+ for(i=0;i<blocks;i++) {
+ gostdecrypt(c,cipher,clear);
+ clear+=8;
+ cipher+=8;
+ }
+
+}
+
+/* Encrypts several full blocks in CFB mode using 8byte IV */
+void gost_enc_cfb(gost_ctx *ctx,const byte *iv,const byte *clear,byte *cipher, int blocks) {
+ byte cur_iv[8];
+ byte gamma[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) {
+ gostcrypt(ctx,cur_iv,gamma);
+ for (j=0;j<8;j++) {
+ cur_iv[j]=out[j]=in[j]^gamma[j];
+ }
+ }
+
+}
+/* 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) {
+ byte cur_iv[8];
+ byte gamma[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) {
+ gostcrypt(ctx,cur_iv,gamma);
+ for (j=0;j<8;j++) {
+ out[j]=(cur_iv[j]=in[j])^gamma[j];
+ }
+ }
+}
+
+/* Encrypts one block using specified key */
+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;
+ 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)
+{
+ int i,j;
+ for(i=0,j=0;i<8;i++,j+=4) {
+ k[j]=c->k[i]& 0xFF;
+ k[j+1]=(c->k[i]>>8 )&0xFF;
+ k[j+2]=(c->k[i]>>16) &0xFF;
+ k[j+3]=(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);
+}
+/* Cleans up key from context */
+void gost_destroy(gost_ctx *c)
+{
+ int i; for(i=0;i<8;i++) c->k[i]=0;
+}
+
+/* Compute GOST 28147 mac block
+ *
+ * Parameters
+ * gost_ctx *c - context initalized with substitution blocks and key
+ * buffer - 8-byte mac state buffer
+ * block 8-byte block to process.
+ * */
+void mac_block(gost_ctx *c,byte *buffer,const byte *block) {
+
+ 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]);
+
+ 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]);
+
+ buffer[0] = (n1&0xff); buffer[1] = (n1>>8)&0xff; buffer[2]=(n1>>16)&0xff; buffer[3]=n1>>24;
+ buffer[4] = (n2&0xff); buffer[5] = (n2>>8)&0xff; buffer[6]=(n2>>16)&0xff; buffer[7]=n2>>24;
+}
+
+/* Get mac with specified number of bits from MAC state buffer */
+void get_mac(byte *buffer,int nbits,byte *out) {
+ int nbytes= nbits >> 3;
+ int rembits = nbits & 7;
+ int mask =rembits?((1<rembits)-1):0;
+ 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.
+ * 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)
+{
+ byte buffer[8]={0,0,0,0,0,0,0,0};
+ byte buf2[8];
+ int i;
+ for (i=0;i+8<=data_len;i+=8)
+ mac_block(ctx,buffer,data+i);
+ if (i<data_len) {
+ memset(buf2,0,8);
+ memcpy(buf2,data+i,data_len-i);
+ mac_block(ctx,buffer,buf2);
+ }
+ get_mac(buffer,mac_len,mac);
+ return 1;
+}
+/* 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)
+{
+ byte buffer[8];
+ byte buf2[8];
+ int i;
+ memcpy (buffer,iv,8);
+ for (i=0;i+8<=data_len;i+=8)
+ mac_block(ctx,buffer,data+i);
+ if (i<data_len) {
+ memset(buf2,0,8);
+ memcpy(buf2,data+i,data_len-i);
+ mac_block(ctx,buffer,buf2);
+ }
+ get_mac(buffer,mac_len,mac);
+ return 1;
+}
+
+/* Implements key meshing algorithm by modifing ctx and IV in place */
+void cryptopro_key_meshing(gost_ctx *ctx, unsigned char *iv) {
+ unsigned char newkey[32],newiv[8];
+ /* Set static keymeshing key */
+ /* "Decrypt" key with keymeshing key */
+ gost_dec(ctx,CryptoProKeyMeshingKey,newkey,4);
+ /* set new key */
+ gost_key(ctx,newkey);
+ /* Encrypt iv with new key */
+ gostcrypt(ctx,iv,newiv);
+ memcpy(iv,newiv,8);
+}
diff --git a/engines/ccgost/gost89.h b/engines/ccgost/gost89.h
new file mode 100644
index 0000000000..2157852519
--- /dev/null
+++ b/engines/ccgost/gost89.h
@@ -0,0 +1,96 @@
+/**********************************************************************
+ * gost89.h *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Declarations for GOST 28147-89 encryption algorithm *
+ * No OpenSSL libraries required to compile and use *
+ * this code *
+ **********************************************************************/
+#ifndef GOST89_H
+#define GOST89_H
+
+/* Typedef for unsigned 32-bit integer */
+#if __LONG_MAX__ > 2147483647L
+typedef unsigned int u4;
+#else
+typedef unsigned long u4;
+#endif
+/* Typedef for unsigned 8-bit integer */
+typedef unsigned char byte;
+
+/* Internal representation of GOST substitution blocks */
+typedef struct {
+ byte k8[16];
+ byte k7[16];
+ byte k6[16];
+ byte k5[16];
+ byte k4[16];
+ byte k3[16];
+ byte k2[16];
+ byte k1[16];
+} gost_subst_block;
+
+
+/* Cipher context includes key and preprocessed substitution block */
+typedef struct {
+ u4 k[8];
+ /* Constant s-boxes -- set up in gost_init(). */
+ u4 k87[256],k65[256],k43[256],k21[256];
+} gost_ctx;
+/* Note: encrypt and decrypt expect full blocks--padding blocks is
+ caller's responsibility. All bulk encryption is done in
+ ECB mode by these calls. Other modes may be added easily
+ enough. */
+/* Encrypt several full blocks in ECB mode */
+void gost_enc(gost_ctx *ctx, const byte *clear,byte *cipher, int blocks);
+/* Decrypt several full blocks in ECB mode */
+void gost_dec(gost_ctx *ctx, const byte *cipher,byte *clear, int blocks);
+/* Encrypts several full blocks in CFB mode using 8byte IV */
+void gost_enc_cfb(gost_ctx *ctx,const byte *iv,const byte *clear,byte *cipher,int blocks);
+/* 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);
+
+/* Encrypt one block */
+void gostcrypt(gost_ctx *c, const byte *in, byte *out);
+/* Decrypt one block */
+void gostdecrypt(gost_ctx *c, const byte *in,byte *out);
+/* Set key into context */
+void gost_key(gost_ctx *ctx, const byte *key);
+/* Get key from context */
+void gost_get_key(gost_ctx *ctx, byte *key);
+/* Set S-blocks into context */
+void gost_init(gost_ctx *ctx, const gost_subst_block *subst_block);
+/* Clean up context */
+void gost_destroy(gost_ctx *ctx);
+/* Intermediate function used for calculate hash */
+void gost_enc_with_key(gost_ctx *,byte *key,byte *inblock,byte *outblock);
+/* Compute MAC of given length in bits from data */
+int gost_mac(gost_ctx *ctx,int hmac_len,const unsigned char *data,
+ unsigned int data_len,unsigned char *hmac) ;
+/* Compute MAC of given length in bits from data, using non-zero 8-byte
+ * IV (non-standard, for use in CryptoPro key transport only */
+int gost_mac_iv(gost_ctx *ctx,int hmac_len,const unsigned char *iv,const unsigned char *data,
+ unsigned int data_len,unsigned char *hmac) ;
+/* Perform one step of MAC calculation like gostcrypt */
+void mac_block(gost_ctx *c,byte *buffer,const byte *block);
+/* Extracts MAC value from mac state buffer */
+void get_mac(byte *buffer,int nbits,byte *out);
+/* Implements cryptopro key meshing algorithm. Expect IV to be 8-byte size*/
+void cryptopro_key_meshing(gost_ctx *ctx, unsigned char *iv);
+/* Parameter sets specified in RFC 4357 */
+extern gost_subst_block GostR3411_94_TestParamSet;
+extern gost_subst_block GostR3411_94_CryptoProParamSet;
+extern gost_subst_block Gost28147_TestParamSet;
+extern gost_subst_block Gost28147_CryptoProParamSetA;
+extern gost_subst_block Gost28147_CryptoProParamSetB;
+extern gost_subst_block Gost28147_CryptoProParamSetC;
+extern gost_subst_block Gost28147_CryptoProParamSetD;
+extern const byte CryptoProKeyMeshingKey[];
+#if __LONG_MAX__ > 2147483647L
+typedef unsigned int word32;
+#else
+typedef unsigned long word32;
+#endif
+
+#endif
diff --git a/engines/ccgost/gost94_keyx.c b/engines/ccgost/gost94_keyx.c
new file mode 100644
index 0000000000..4cf8a0ba80
--- /dev/null
+++ b/engines/ccgost/gost94_keyx.c
@@ -0,0 +1,420 @@
+/**********************************************************************
+ * gost94_keyx.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Implements generation and parsing of GOST_KEY_TRANSPORT for *
+ * GOST R 34.10-94 algorithms *
+ * *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <string.h>
+#include <openssl/dh.h>
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+
+#include "gostkeyx.h"
+#include "gost_asn1.h"
+#include "gost89.h"
+#include "gosthash.h"
+#include "crypt.h"
+#include "e_gost_err.h"
+#include "pmeth.h"
+#include "keywrap.h"
+#include "tools.h"
+/* Common functions for both 94 and 2001 key exchange schemes */
+int decrypt_cryptocom_key(unsigned char *sess_key,int max_key_len,
+ const unsigned char *crypted_key,int crypted_key_len, gost_ctx *ctx)
+{
+ int i;
+ int j;
+ int blocks = crypted_key_len >>3;
+ unsigned char gamma[8];
+ if (max_key_len <crypted_key_len) {
+ GOSTerr(GOST_F_DECRYPT_CRYPTOCOM_KEY,GOST_R_NOT_ENOUGH_SPACE_FOR_KEY);
+ return 0;
+ }
+ if ((crypted_key_len & 7) !=0)
+ {
+ GOSTerr(GOST_F_DECRYPT_CRYPTOCOM_KEY,GOST_R_INVALID_ENCRYPTED_KEY_SIZE);
+ return 0;
+ }
+ for (i=blocks-1;i>0;i--)
+ {
+ gostcrypt(ctx,crypted_key+(i-1)*8,gamma);
+ for(j=0;j<8;j++)
+ {
+ sess_key[i*8+j]=gamma[j]^crypted_key[i*8+j];
+ }
+ }
+ gostcrypt(ctx,sess_key+crypted_key_len-8,gamma);
+ for(j=0;j<8;j++)
+ {
+ sess_key[j]=gamma[j]^crypted_key[j];
+ }
+ return 1;
+}
+int encrypt_cryptocom_key(const unsigned char *sess_key,int key_len,
+ unsigned char *crypted_key, gost_ctx *ctx)
+{
+ int i;
+ int j;
+ unsigned char gamma[8];
+ memcpy(gamma,sess_key+key_len-8,8);
+ for (i=0;i<key_len;i+=8)
+ {
+ gostcrypt(ctx,gamma,gamma);
+ for (j=0;j<8;j++)
+ gamma[j]=crypted_key[i+j]=sess_key[i+j]^gamma[j];
+ }
+ return 1;
+}
+/* Implementation of the Diffi-Hellman key agreement scheme based on
+ * GOST-94 keys */
+
+/* Computes Diffie-Hellman key and stores it into buffer in
+ * little-endian byte order as expected by both versions of GOST 94
+ * algorigthm
+ */
+static int compute_pair_key_le(unsigned char *pair_key,BIGNUM *pub_key,DH *dh)
+{
+ unsigned char be_key[128];
+ int i,key_size;
+ key_size=DH_compute_key(be_key,pub_key,dh);
+ if (!key_size) return 0;
+ memset(pair_key,0,128);
+ for (i=0;i<key_size;i++) {
+ pair_key[i]=be_key[key_size-1-i];
+ }
+ return key_size;
+}
+/*
+ * Computes 256 bit key exchange key for CryptoCom variation of GOST 94
+ * algorithm
+ */
+static int make_gost_shared_key(DH *dh,EVP_PKEY *pubk,unsigned char *shared_key)
+{
+ unsigned char dh_key [128];
+ int i;
+ /* Compute key */
+ memset(dh_key,0,128);
+ if (!compute_pair_key_le(dh_key,((DSA *)EVP_PKEY_get0(pubk))->pub_key,dh)) return 0;
+ /* Fold it down to 256 bit */
+ /* According to GOST either 2^1020<p<2^1024 or
+ * 2^509<p<2^512, so DH_size can be exactly 128 or exactly 64 only
+ */
+
+ if (DH_size(dh)==128)
+ for (i=0;i<64;i++) {
+ dh_key[i]^=dh_key[64+i];
+ }
+ for (i=0;i<32;i++) {
+ shared_key[i]=dh_key[i]^dh_key[32+i];
+ }
+ return 1;
+}
+
+static DH *make_ephemeral_key(EVP_PKEY *pubk,BIGNUM *ephemeral_key)
+{
+ DH *dh = DH_new();
+ dh->g = BN_dup(pubk->pkey.dsa->g);
+ dh->p = BN_dup(pubk->pkey.dsa->p);
+ dh->priv_key = BN_dup(ephemeral_key);
+ /* Generate ephemeral key pair */
+ if (!DH_generate_key(dh)) {
+ DH_free(dh);
+ return NULL;
+ }
+ return dh;
+}
+/*
+ * Computes 256 bit Key exchange key as specified in RFC 4357
+ */
+static int make_cp_exchange_key(DH *dh,EVP_PKEY *pubk, unsigned char *shared_key)
+{
+ unsigned char dh_key [128];
+ gost_hash_ctx hash_ctx;
+ memset(dh_key,0,128);
+ if (!compute_pair_key_le(dh_key,((DSA *)(EVP_PKEY_get0(pubk)))->pub_key,dh)) return 0;
+ init_gost_hash_ctx(&hash_ctx,&GostR3411_94_CryptoProParamSet);
+ start_hash(&hash_ctx);
+ hash_block(&hash_ctx,dh_key,128);
+ finish_hash(&hash_ctx,shared_key);
+ done_gost_hash_ctx(&hash_ctx);
+ return 1;
+}
+/* EVP_PKEY_METHOD callback encrypt for
+ * GOST R 34.10-94 cryptopro modification
+ */
+
+int pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* key, size_t key_len )
+{
+ GOST_KEY_TRANSPORT *gkt=NULL;
+ DH *dh = NULL;
+ unsigned char shared_key[32], ukm[8],crypted_key[44];
+ const struct gost_cipher_info *param=get_encryption_params(NULL);
+ EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(ctx);
+ struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
+ int size=-1;
+ gost_ctx cctx;
+
+
+ if (!(data->eph_seckey)) {
+ GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,
+ GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT);
+ return -1;
+ }
+
+ dh = make_ephemeral_key(pubk,gost_get_priv_key(data->eph_seckey));
+ gost_init(&cctx,param->sblock);
+ make_cp_exchange_key(dh,pubk,shared_key);
+ if (RAND_bytes(ukm,8)<=0) {
+ GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,
+ GOST_R_RANDOM_GENERATOR_FAILURE);
+ return -1;
+ }
+ keyWrapCryptoPro(&cctx,shared_key,ukm,key,crypted_key);
+ gkt = GOST_KEY_TRANSPORT_new();
+ if (!gkt) {
+ goto memerr;
+ }
+ if(!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,
+ ukm,8)) {
+ goto memerr;
+ }
+ if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,crypted_key+40,4)) {
+ goto memerr;
+ }
+ if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,crypted_key+8,32)) {
+ goto memerr;
+ }
+ if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) {
+ GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
+ goto err;
+ }
+ ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
+ gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid);
+ *outlen = i2d_GOST_KEY_TRANSPORT(gkt,&out);
+ if (!size) {
+ GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO);
+ size=-1;
+ }
+ GOST_KEY_TRANSPORT_free(gkt);
+ DH_free(dh);
+ return 1;
+memerr:
+ GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,
+ GOST_R_MALLOC_FAILURE);
+err:
+ GOST_KEY_TRANSPORT_free(gkt);
+ DH_free(dh);
+ return -1;
+}
+/* EVP_PKEY_METHOD callback encrypt for
+ * GOST R 34.10-94 cryptocom modification
+ */
+
+int pkey_GOST94cc_encrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * key,size_t key_len)
+{
+ EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(ctx);
+ struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
+ /* create DH structure filling parameters from passed pub_key */
+ DH *dh = NULL;
+ GOST_KEY_TRANSPORT *gkt = NULL;
+ gost_ctx cctx;
+ EVP_PKEY *newkey=NULL;
+ unsigned char shared_key[32],encrypted_key[32],hmac[4],
+ iv[8]={0,0,0,0,0,0,0,0};
+
+ if (! data->eph_seckey) {
+ GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,
+ GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT);
+ return -1;
+ }
+ dh = make_ephemeral_key(pubk,gost_get_priv_key(data->eph_seckey));
+ if (!dh) goto err;
+ /* compute shared key */
+ if (!make_gost_shared_key(dh,pubk,shared_key))
+ {
+ GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY);
+ goto err;
+ }
+ /* encrypt session key */
+ gost_init(&cctx, &GostR3411_94_CryptoProParamSet);
+ gost_key(&cctx,shared_key);
+ encrypt_cryptocom_key(key,key_len,encrypted_key,&cctx);
+ /* compute hmac of session key */
+ if (!gost_mac(&cctx,32,key,32,hmac))
+ {
+ DH_free(dh);
+ GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_COMPUTING_MAC);
+ return -1;
+ }
+ gkt = GOST_KEY_TRANSPORT_new();
+ if (!gkt)
+ {
+ DH_free(dh);
+ GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_NO_MEMORY);
+ return -1;
+ }
+ /* Store IV which is always zero in our case */
+ if (!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,iv,8))
+ {
+ GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_IV);
+ goto err;
+ }
+ if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,hmac,4))
+ {
+ GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_MAC);
+ goto err;
+ }
+ if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,encrypted_key,32))
+ {
+ GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_ENCRYPTED_KEY);
+ goto err;
+ }
+ if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) {
+ GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
+ goto err;
+ }
+ ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
+ gkt->key_agreement_info->cipher = OBJ_nid2obj(NID_id_Gost28147_89_cc);
+ *outlen = i2d_GOST_KEY_TRANSPORT(gkt,&out);
+err:
+ if (gkt) GOST_KEY_TRANSPORT_free(gkt);
+ if (dh) DH_free(dh);
+ if (newkey) EVP_PKEY_free(newkey);
+ return 1;
+}
+
+/* EVP_PLEY_METHOD callback decrypt for
+ * GOST R 34.10-94 cryptopro modification
+ */
+int pkey_GOST94cp_decrypt (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_len,const unsigned char *in, size_t in_len) {
+ DH *dh = DH_new();
+ const unsigned char *p = in;
+ GOST_KEY_TRANSPORT *gkt = NULL;
+ unsigned char wrappedKey[44];
+ unsigned char sharedKey[32];
+ gost_ctx cctx;
+ const struct gost_cipher_info *param=NULL;
+ EVP_PKEY *eph_key=NULL;
+ EVP_PKEY *priv= EVP_PKEY_CTX_get0_pkey(ctx);
+
+ if (!key) {
+ *key_len = 32;
+ return 1;
+ }
+
+ dh->g = BN_dup(priv->pkey.dsa->g);
+ dh->p = BN_dup(priv->pkey.dsa->p);
+ dh->priv_key = BN_dup(priv->pkey.dsa->priv_key);
+ gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p,
+ in_len);
+ if (!gkt) {
+ GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
+ DH_free(dh);
+ return 0;
+ }
+ eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
+ param = get_encryption_params(gkt->key_agreement_info->cipher);
+ gost_init(&cctx,param->sblock);
+ OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8);
+ memcpy(wrappedKey,gkt->key_agreement_info->eph_iv->data,8);
+ OPENSSL_assert(gkt->key_info->encrypted_key->length==32);
+ memcpy(wrappedKey+8,gkt->key_info->encrypted_key->data,32);
+ OPENSSL_assert(gkt->key_info->imit->length==4);
+ memcpy(wrappedKey+40,gkt->key_info->imit->data,4);
+ make_cp_exchange_key(dh,eph_key,sharedKey);
+ if (!keyUnwrapCryptoPro(&cctx,sharedKey,wrappedKey,key)) {
+ GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,
+ GOST_R_ERROR_COMPUTING_SHARED_KEY);
+ goto err;
+ }
+
+ EVP_PKEY_free(eph_key);
+ GOST_KEY_TRANSPORT_free(gkt);
+ DH_free(dh);
+ return 1;
+err:
+ EVP_PKEY_free(eph_key);
+ GOST_KEY_TRANSPORT_free(gkt);
+ DH_free(dh);
+ return -1;
+
+}
+/* EVP_PKEY_METHOD callback decrypt for
+ * GOST R 34.10-94 cryptocom modification
+ */
+
+int pkey_GOST94cc_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len, const unsigned char *in, size_t in_len)
+{
+ /* Form DH params from compute shared key */
+ GOST_KEY_TRANSPORT *gkt = NULL;
+ const unsigned char *p=in;
+ unsigned char shared_key[32];
+ unsigned char hmac[4],hmac_comp[4];
+ unsigned char iv[8];
+ int i;
+ gost_ctx ctx;
+ DH *dh = DH_new();
+ EVP_PKEY *eph_key;
+ EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx);
+
+ if (!key) {
+ *key_len = 32;
+ return 1;
+ }
+ /* Construct DH structure from the our GOST private key */
+ dh->g = BN_dup(priv->pkey.dsa->g);
+ dh->p = BN_dup(priv->pkey.dsa->p);
+ dh->priv_key = BN_dup(priv->pkey.dsa->priv_key);
+ /* Parse passed octet string and find out public key, iv and HMAC*/
+ gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p,
+ in_len);
+ if (!gkt) {
+ GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
+ DH_free(dh);
+ return 0;
+ }
+ eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
+ /* Initialization vector is really ignored here */
+ OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8);
+ memcpy(iv,gkt->key_agreement_info->eph_iv->data,8);
+ /* HMAC should be computed and checked */
+ OPENSSL_assert(gkt->key_info->imit->length==4);
+ memcpy(hmac,gkt->key_info->imit->data,4);
+ /* Compute shared key */
+ i=make_gost_shared_key(dh,eph_key,shared_key);
+ EVP_PKEY_free(eph_key);
+ DH_free(dh);
+ if (!i)
+ {
+ GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY);
+ GOST_KEY_TRANSPORT_free(gkt);
+ return 0;
+ }
+ /* Decrypt session key */
+ gost_init(&ctx, &GostR3411_94_CryptoProParamSet);
+ gost_key(&ctx,shared_key);
+
+ if (!decrypt_cryptocom_key(key,*key_len,gkt->key_info->encrypted_key->data,
+ gkt->key_info->encrypted_key->length, &ctx))
+ {
+ GOST_KEY_TRANSPORT_free(gkt);
+ return 0;
+ }
+ GOST_KEY_TRANSPORT_free(gkt);
+ /* check HMAC of session key*/
+ if (!gost_mac(&ctx,32,key,32,hmac_comp)) {
+ GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_ERROR_COMPUTING_MAC);
+ return 0;
+ }
+ /* HMAC of session key is not correct */
+ if (memcmp(hmac,hmac_comp,4)!=0) {
+ GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH);
+ return 0;
+ }
+ return 1;
+}
diff --git a/engines/ccgost/gost_asn1.c b/engines/ccgost/gost_asn1.c
new file mode 100644
index 0000000000..e7303b7f92
--- /dev/null
+++ b/engines/ccgost/gost_asn1.c
@@ -0,0 +1,55 @@
+/**********************************************************************
+ * gost_keytrans.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * ASN1 structure definition for GOST key transport *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <stdio.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include "gost_asn1.h"
+
+ASN1_NDEF_SEQUENCE(GOST_KEY_TRANSPORT) = {
+ ASN1_SIMPLE(GOST_KEY_TRANSPORT, key_info, GOST_KEY_INFO),
+ ASN1_IMP(GOST_KEY_TRANSPORT, key_agreement_info, GOST_KEY_AGREEMENT_INFO, 0)
+} ASN1_NDEF_SEQUENCE_END(GOST_KEY_TRANSPORT)
+
+IMPLEMENT_ASN1_FUNCTIONS(GOST_KEY_TRANSPORT)
+
+ASN1_NDEF_SEQUENCE(GOST_KEY_INFO) = {
+ ASN1_SIMPLE(GOST_KEY_INFO, encrypted_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(GOST_KEY_INFO, imit, ASN1_OCTET_STRING)
+} ASN1_NDEF_SEQUENCE_END(GOST_KEY_INFO)
+
+IMPLEMENT_ASN1_FUNCTIONS(GOST_KEY_INFO)
+
+ASN1_NDEF_SEQUENCE(GOST_KEY_AGREEMENT_INFO) = {
+ ASN1_SIMPLE(GOST_KEY_AGREEMENT_INFO, cipher, ASN1_OBJECT),
+ ASN1_IMP(GOST_KEY_AGREEMENT_INFO, ephem_key, X509_PUBKEY, 0),
+ ASN1_SIMPLE(GOST_KEY_AGREEMENT_INFO, eph_iv, ASN1_OCTET_STRING)
+} ASN1_NDEF_SEQUENCE_END(GOST_KEY_AGREEMENT_INFO)
+
+IMPLEMENT_ASN1_FUNCTIONS(GOST_KEY_AGREEMENT_INFO)
+
+ASN1_NDEF_SEQUENCE(GOST_KEY_PARAMS) = {
+ ASN1_SIMPLE(GOST_KEY_PARAMS, key_params, ASN1_OBJECT),
+ ASN1_SIMPLE(GOST_KEY_PARAMS, hash_params, ASN1_OBJECT),
+ ASN1_OPT(GOST_KEY_PARAMS, cipher_params, ASN1_OBJECT),
+} ASN1_NDEF_SEQUENCE_END(GOST_KEY_PARAMS);
+
+IMPLEMENT_ASN1_FUNCTIONS(GOST_KEY_PARAMS)
+
+ASN1_NDEF_SEQUENCE(GOST_CIPHER_PARAMS) = {
+ ASN1_SIMPLE(GOST_CIPHER_PARAMS, iv, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(GOST_CIPHER_PARAMS, enc_param_set, ASN1_OBJECT),
+} ASN1_NDEF_SEQUENCE_END(GOST_CIPHER_PARAMS);
+
+IMPLEMENT_ASN1_FUNCTIONS(GOST_CIPHER_PARAMS);
+
+ASN1_NDEF_SEQUENCE(GOST_CLIENT_KEY_EXCHANGE_PARAMS) = { //FIXME incomplete
+ ASN1_SIMPLE(GOST_CLIENT_KEY_EXCHANGE_PARAMS, gkt, GOST_KEY_TRANSPORT)
+} ASN1_NDEF_SEQUENCE_END(GOST_CLIENT_KEY_EXCHANGE_PARAMS);
+
+IMPLEMENT_ASN1_FUNCTIONS(GOST_CLIENT_KEY_EXCHANGE_PARAMS);
diff --git a/engines/ccgost/gost_asn1.h b/engines/ccgost/gost_asn1.h
new file mode 100644
index 0000000000..81075e47d3
--- /dev/null
+++ b/engines/ccgost/gost_asn1.h
@@ -0,0 +1,57 @@
+/**********************************************************************
+ * gost_keytrans.h *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * ASN1 structure declaration for GOST key transport *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#ifndef GOST_KEY_TRANS_H
+#define GOST_KEY_TRANS_H
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+
+
+typedef struct {
+ ASN1_OCTET_STRING *encrypted_key;
+ ASN1_OCTET_STRING *imit;
+} GOST_KEY_INFO;
+
+DECLARE_ASN1_FUNCTIONS(GOST_KEY_INFO)
+
+typedef struct {
+ ASN1_OBJECT *cipher;
+ X509_PUBKEY *ephem_key;
+ ASN1_OCTET_STRING *eph_iv;
+} GOST_KEY_AGREEMENT_INFO;
+
+DECLARE_ASN1_FUNCTIONS(GOST_KEY_AGREEMENT_INFO)
+
+typedef struct {
+ GOST_KEY_INFO *key_info;
+ GOST_KEY_AGREEMENT_INFO *key_agreement_info;
+} GOST_KEY_TRANSPORT;
+
+DECLARE_ASN1_FUNCTIONS(GOST_KEY_TRANSPORT)
+
+typedef struct { //FIXME incomplete
+ GOST_KEY_TRANSPORT *gkt;
+} GOST_CLIENT_KEY_EXCHANGE_PARAMS;
+
+DECLARE_ASN1_FUNCTIONS(GOST_CLIENT_KEY_EXCHANGE_PARAMS)
+typedef struct {
+ ASN1_OBJECT *key_params;
+ ASN1_OBJECT *hash_params;
+ ASN1_OBJECT *cipher_params;
+} GOST_KEY_PARAMS;
+
+DECLARE_ASN1_FUNCTIONS(GOST_KEY_PARAMS)
+
+typedef struct {
+ ASN1_OCTET_STRING *iv;
+ ASN1_OBJECT *enc_param_set;
+} GOST_CIPHER_PARAMS;
+
+DECLARE_ASN1_FUNCTIONS(GOST_CIPHER_PARAMS)
+
+#endif
diff --git a/engines/ccgost/gost_crypt.c b/engines/ccgost/gost_crypt.c
new file mode 100644
index 0000000000..9b3803d8fd
--- /dev/null
+++ b/engines/ccgost/gost_crypt.c
@@ -0,0 +1,579 @@
+/**********************************************************************
+* gost_crypt.c *
+* Copyright (c) 2005-2006 Cryptocom LTD *
+* This file is distributed under the same license as OpenSSL *
+* *
+* OpenSSL interface to GOST 28147-89 cipher functions *
+* Requires OpenSSL 0.9.9 for compilation *
+**********************************************************************/
+#include <string.h>
+#include "crypt.h"
+#include "gost89.h"
+#include <openssl/rand.h>
+#include "e_gost_err.h"
+#include "gost_asn1.h"
+static int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc);
+#ifdef USE_SSL
+/* Specialized init functions which set specific parameters */
+static int gost_cipher_init_vizir(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);
+#endif
+/* Handles block of data in CFB mode */
+static int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, unsigned int 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, unsigned int inl);
+/* 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);
+static int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx,ASN1_TYPE *params);
+/* Control function */
+static int gost_cipher_ctl(EVP_CIPHER_CTX *ctx,int type,int arg,void *ptr);
+
+EVP_CIPHER cipher_gost =
+ {
+ NID_id_Gost28147_89,
+ 1,/*block_size*/
+ 32,/*key_size*/
+ 8,/*iv_len - ñèíõðîïîñûëêà*/
+ EVP_CIPH_CFB_MODE| EVP_CIPH_NO_PADDING |
+ EVP_CIPH_CUSTOM_IV| EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT,
+ gost_cipher_init,
+ gost_cipher_do_cfb,
+ gost_cipher_cleanup,
+ sizeof(struct ossl_gost_cipher_ctx),/* ctx_size */
+ gost89_set_asn1_parameters,
+ gost89_get_asn1_parameters,
+ gost_cipher_ctl,
+ NULL,
+ };
+
+#ifdef USE_SSL
+static EVP_CIPHER cipher_gost_vizircfb =
+ {
+ NID_undef,
+ 1,/*block_size*/
+ 32,/*key_size*/
+ 8,/*iv_len - ñèíõðîïîñûëêà*/
+ EVP_CIPH_CFB_MODE| EVP_CIPH_NO_PADDING |
+ EVP_CIPH_CUSTOM_IV| EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT,
+ gost_cipher_init_vizir,
+ gost_cipher_do_cfb,
+ gost_cipher_cleanup,
+ sizeof(struct ossl_gost_cipher_ctx), /* ctx_size */
+ gost89_set_asn1_parameters,
+ gost89_get_asn1_parameters,
+ gost_cipher_ctl,
+ NULL,
+ };
+
+static EVP_CIPHER cipher_gost_cpacnt =
+ {
+ NID_undef,
+ 1,/*block_size*/
+ 32,/*key_size*/
+ 8,/*iv_len - ñèíõðîïîñûëêà*/
+ EVP_CIPH_OFB_MODE| EVP_CIPH_NO_PADDING |
+ EVP_CIPH_CUSTOM_IV| EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT,
+ gost_cipher_init_cpa,
+ gost_cipher_do_cnt,
+ gost_cipher_cleanup,
+ sizeof(struct ossl_gost_cipher_ctx), /* ctx_size */
+ gost89_set_asn1_parameters,
+ gost89_get_asn1_parameters,
+ gost_cipher_ctl,
+ NULL,
+ };
+/* Implementation of GOST 28147-89 in MAC (imitovstavka) mode */
+/* Init functions which set specific parameters */
+static int gost_imit_init_vizir(EVP_MD_CTX *ctx);
+static int gost_imit_init_cpa(EVP_MD_CTX *ctx);
+/* process block of data */
+static int gost_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count);
+/* Return computed value */
+static int gost_imit_final(EVP_MD_CTX *ctx,unsigned char *md);
+/* Copies context */
+static int gost_imit_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from);
+static int gost_imit_cleanup(EVP_MD_CTX *ctx);
+/* Control function, knows how to set MAC key.*/
+static int gost_imit_ctrl(EVP_MD_CTX *ctx,int type, int arg, void *ptr);
+
+EVP_MD imit_gost_vizir =
+ {
+ NID_undef,
+ NID_undef,
+ 4,
+ EVP_MD_FLAG_NEEDS_KEY,
+ gost_imit_init_vizir,
+ gost_imit_update,
+ gost_imit_final,
+ gost_imit_copy,
+ gost_imit_cleanup,
+ gost_imit_ctrl,
+ NULL,
+ NULL,
+ {0,0,0,0,0},
+ 8,
+ sizeof(struct ossl_gost_imit_ctx)
+ };
+
+EVP_MD imit_gost_cpa =
+ {
+ NID_undef,
+ NID_undef,
+ 4,
+ EVP_MD_FLAG_NEEDS_KEY,
+ gost_imit_init_cpa,
+ gost_imit_update,
+ gost_imit_final,
+ gost_imit_copy,
+ gost_imit_cleanup,
+ gost_imit_ctrl,
+ NULL,
+ NULL,
+ {0,0,0,0,0},
+ 8,
+ sizeof(struct ossl_gost_imit_ctx)
+ };
+
+#endif
+/*
+* Correspondence between gost parameter OIDs and substitution blocks
+* NID field is filed by register_gost_NID function in engine.c
+* upon engine initialization
+*/
+
+struct gost_cipher_info gost_cipher_list[]={
+/* NID */ /* Subst block */ /* Key meshing*/
+/*{NID_id_GostR3411_94_CryptoProParamSet,&GostR3411_94_CryptoProParamSet,0},*/
+{NID_id_Gost28147_89_cc,&GostR3411_94_CryptoProParamSet,0},
+{NID_id_Gost28147_89_CryptoPro_A_ParamSet,&Gost28147_CryptoProParamSetA,1},
+{NID_id_Gost28147_89_CryptoPro_B_ParamSet,&Gost28147_CryptoProParamSetB,1},
+{NID_id_Gost28147_89_CryptoPro_C_ParamSet,&Gost28147_CryptoProParamSetC,1},
+{NID_id_Gost28147_89_CryptoPro_D_ParamSet,&Gost28147_CryptoProParamSetD,1},
+{NID_undef,NULL,0}
+};
+
+/* get encryption parameters from crypto network settings
+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) {
+int nid;
+struct gost_cipher_info *param;
+if (!obj) {
+ const char * params = getenv("CRYPT_PARAMS");
+ if (!params || !strlen(params))
+ return &gost_cipher_list[0];
+
+ nid = OBJ_txt2nid(params);
+ if (nid == NID_undef) {
+ 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;
+ param++);
+if (!param->sblock) {
+ GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS,GOST_R_INVALID_CIPHER_PARAMS);
+ return NULL;
+
+}
+return param;
+
+}
+/* Sets cipher param from paramset NID. */
+int gost_cipher_set_param(struct ossl_gost_cipher_ctx *c,int nid) {
+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;
+gost_init(&(c->cctx), param->sblock);
+return 1;
+}
+/* Initializes EVP_CIPHER_CTX by paramset NID */
+static int gost_cipher_init_param(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc, int paramNID,int mode) {
+struct ossl_gost_cipher_ctx *c=ctx->cipher_data;
+if (!gost_cipher_set_param(c,paramNID)) return 0;
+if (key) gost_key(&(c->cctx),key);
+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;
+}
+
+/* Initializes EVP_CIPHER_CTX with fixed cryptopro A paramset */
+int gost_cipher_init_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc) {
+struct ossl_gost_cipher_ctx *c=ctx->cipher_data;
+gost_init(&(c->cctx),&Gost28147_CryptoProParamSetA);
+c->key_meshing=1;
+c->count=0;
+gost_key(&(c->cctx),key);
+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;
+}
+/* Initializes EVP_CIPHER_CTX with fixed vizir paramset */
+int gost_cipher_init_vizir(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc) {
+struct ossl_gost_cipher_ctx *c=ctx->cipher_data;
+gost_init(&(c->cctx),&GostR3411_94_CryptoProParamSet);
+c->key_meshing=0;
+c->count=0;
+gost_key(&(c->cctx),key);
+
+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;
+}
+
+/* Initializes EVP_CIPHER_CTX with default values */
+int gost_cipher_init(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_CFB_MODE);
+}
+/* Wrapper around gostcrypt function from gost89.c which perform
+* key meshing when nesseccary
+*/
+static void gost_crypt_mesh (void *ctx,unsigned char *iv,unsigned char *buf) {
+ struct ossl_gost_cipher_ctx *c = ctx;
+ if (c->count&&c->key_meshing && c->count%1024==0) {
+ cryptopro_key_meshing(&(c->cctx),iv);
+ }
+ gostcrypt(&(c->cctx),iv,buf);
+ c->count+=8;
+}
+
+static void gost_cnt_next (void *ctx, unsigned char *iv, unsigned char *buf) {
+struct ossl_gost_cipher_ctx *c = ctx;
+word32 g,go;
+unsigned char buf1[8];
+if (c->count && c->key_meshing && c->count %1024 ==0) {
+ cryptopro_key_meshing(&(c->cctx),iv);
+}
+if (c->count==0) {
+gostcrypt(&(c->cctx),iv,buf1);
+} else {
+ memcpy(buf1,iv,8);
+}
+ g = buf1[0]|(buf1[1]<<8)|(buf1[2]<<16)|(buf1[3]<<24);
+ g += 0x01010101;
+ buf1[0]=g&0xff; buf1[1]=(g>>8)&0xff; buf1[2]=(g>>16)&0xff; buf1[3]=(g>>24)&0xff;
+ g = buf1[4]|(buf1[5]<<8)|(buf1[6]<<16)|(buf1[7]<<24);
+ go = g;
+ g += 0x01010104;
+ if (go > g) /* overflow*/
+ g++;
+ buf1[4]=g&0xff; buf1[5]=(g>>8)&0xff; buf1[6]=(g>>16)&0xff; buf1[7]=(g>>24)&0xff;
+ memcpy(iv,buf1,8);
+ gostcrypt(&(c->cctx),buf1,buf);
+c->count +=8;
+}
+
+/* GOST encryption in CFB mode */
+int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, unsigned int inl) {
+const unsigned char *in_ptr=in;
+unsigned char *out_ptr=out;
+int i=0;
+int j;
+/* process partial block if any */
+if (ctx->num)
+{
+ 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);
+ ctx->num=0;
+ } else {
+ ctx->num=j;
+ return 1;
+ }
+}
+
+for (;i+8<inl;i+=8,in_ptr+=8,out_ptr+=8) {
+ /*block cipher current iv */
+ gost_crypt_mesh(ctx->cipher_data,ctx->iv,ctx->buf);
+ /*xor next block of input text with it and output it*/
+ /*output this block */
+ if (!ctx->encrypt) memcpy(ctx->iv,in_ptr,8);
+ 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);
+}
+/* Process rest of buffer */
+if (i<inl) {
+ gost_crypt_mesh(ctx->cipher_data,ctx->iv,ctx->buf);
+ if (!ctx->encrypt) memcpy(ctx->buf+8,in_ptr,j);
+ 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;
+}
+int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, unsigned int inl) {
+const unsigned char *in_ptr=in;
+unsigned char *out_ptr=out;
+int i=0;
+int j;
+/* process partial block if any */
+if (ctx->num)
+{
+ 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;
+ } else {
+ ctx->num=j;
+ return 1;
+ }
+}
+
+for (;i+8<inl;i+=8,in_ptr+=8,out_ptr+=8) {
+ /*block cipher current iv */
+ /* Encrypt */
+ gost_cnt_next(ctx->cipher_data,ctx->iv,ctx->buf);
+ /*xor next block of input text with it and output it*/
+ /*output this block */
+ for (j=0;j<8;j++) {
+ out_ptr[j]=ctx->buf[j]^in_ptr[j];
+ }
+}
+/* Process rest of buffer */
+if (i<inl) {
+ gost_cnt_next(ctx->cipher_data,ctx->iv,ctx->buf);
+ 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)
+{
+gost_destroy((gost_ctx *)ctx->cipher_data);
+return 1;
+
+}
+/* Control function for gost cipher */
+int gost_cipher_ctl(EVP_CIPHER_CTX *ctx,int type,int arg,void *ptr)
+{
+switch (type)
+{
+ case EVP_CTRL_RAND_KEY:
+ {
+ if (RAND_bytes((unsigned char *)ptr,ctx->key_len)<=0)
+ {
+ GOSTerr(GOST_F_GOST_CIPHER_CTL,GOST_R_RANDOM_GENERATOR_ERROR);
+ return -1;
+ }
+ break;
+ }
+ default:
+ GOSTerr(GOST_F_GOST_CIPHER_CTL,GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND);
+ return -1;
+}
+return 1;
+}
+
+/* Set cipher parameters from ASN1 structure */
+int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx,ASN1_TYPE *params)
+{
+int len=0;
+unsigned char *buf=NULL;
+unsigned char *p=NULL;
+struct ossl_gost_cipher_ctx *c = ctx->cipher_data;
+GOST_CIPHER_PARAMS *gcp = GOST_CIPHER_PARAMS_new();
+ASN1_OCTET_STRING *os = NULL;
+if (!gcp) {
+ GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, GOST_R_NO_MEMORY);
+ return 0;
+}
+if (!ASN1_OCTET_STRING_set(gcp->iv, ctx->iv, ctx->cipher->iv_len)) {
+ GOST_CIPHER_PARAMS_free(gcp);
+ GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, GOST_R_NO_MEMORY);
+ return 0;
+}
+ASN1_OBJECT_free(gcp->enc_param_set);
+gcp->enc_param_set = OBJ_nid2obj(c->paramNID);
+
+len = i2d_GOST_CIPHER_PARAMS(gcp, NULL);
+p = buf = (unsigned char*)OPENSSL_malloc(len);
+if (!buf) {
+ GOST_CIPHER_PARAMS_free(gcp);
+ GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, GOST_R_NO_MEMORY);
+ return 0;
+}
+i2d_GOST_CIPHER_PARAMS(gcp, &p);
+GOST_CIPHER_PARAMS_free(gcp);
+
+os = ASN1_OCTET_STRING_new();
+
+if(!os || !ASN1_OCTET_STRING_set(os, buf, len)) {
+ OPENSSL_free(buf);
+ GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, GOST_R_NO_MEMORY);
+ return 0;
+}
+OPENSSL_free(buf);
+
+ASN1_TYPE_set(params, V_ASN1_SEQUENCE, os);
+return 1;
+}
+/* Store parameters into ASN1 structure */
+int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx,ASN1_TYPE *params)
+{
+int ret = -1;
+int len;
+GOST_CIPHER_PARAMS *gcp = NULL;
+unsigned char *p = params->value.sequence->data;
+struct ossl_gost_cipher_ctx *c=ctx->cipher_data;
+if (ASN1_TYPE_get(params) != V_ASN1_SEQUENCE) {
+ return ret;
+}
+
+gcp = d2i_GOST_CIPHER_PARAMS(NULL, (const unsigned char **)&p,
+ params->value.sequence->length);
+
+len = gcp->iv->length;
+if (len != ctx->cipher->iv_len) {
+ GOST_CIPHER_PARAMS_free(gcp);
+ GOSTerr(GOST_F_GOST89_GET_ASN1_PARAMETERS,
+ GOST_R_INVALID_IV_LENGTH);
+ return -1;
+}
+if (!gost_cipher_set_param(c,OBJ_obj2nid(gcp->enc_param_set))) {
+ GOST_CIPHER_PARAMS_free(gcp);
+ return -1;
+}
+memcpy(ctx->oiv, gcp->iv->data, len);
+
+GOST_CIPHER_PARAMS_free(gcp);
+
+return 1;
+
+}
+
+#ifdef USE_SSL
+
+int gost_imit_init_vizir(EVP_MD_CTX *ctx) {
+struct ossl_gost_imit_ctx *c = ctx->md_data;
+memset(c,0,sizeof(struct ossl_gost_imit_ctx));
+gost_init(&(c->cctx),&GostR3411_94_CryptoProParamSet);
+return 1;
+}
+int gost_imit_init_cpa(EVP_MD_CTX *ctx) {
+struct ossl_gost_imit_ctx *c = ctx->md_data;
+memset(c,0,sizeof(struct ossl_gost_imit_ctx));
+c->key_meshing=1;
+gost_init(&(c->cctx),&Gost28147_CryptoProParamSetA);
+return 1;
+}
+
+static void mac_block_mesh(struct ossl_gost_imit_ctx *c,unsigned char *data)
+{
+ char buffer[8];
+ /* 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
+ */
+ if (c->key_meshing&& c->count && c->count %1024 ==0) {
+ cryptopro_key_meshing(&(c->cctx),buffer);
+ }
+ mac_block(&(c->cctx),c->buffer,data);
+ c->count +=8;
+}
+
+int gost_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+ struct ossl_gost_imit_ctx *c = ctx->md_data;
+ const unsigned char *p = data;
+ size_t bytes = count,i;
+ if (!(c->key_set)) return 0;
+ if (c->bytes_left) {
+ for (i=c->bytes_left;i<8&&bytes>0;bytes--,i++,p++) {
+ c->partial_block[i]=*p;
+ }
+ if (i==8) {
+ mac_block_mesh(c,c->partial_block);
+ } else {
+ c->bytes_left = i;
+ return 1;
+ }
+ }
+ while (bytes>8) {
+ mac_block_mesh(c,p);
+ p+=8;
+ bytes-=8;
+ }
+ if (bytes>0) {
+ memcpy(c->partial_block,p,bytes);
+ c->bytes_left=bytes;
+ }
+ return 1;
+}
+
+int gost_imit_final(EVP_MD_CTX *ctx,unsigned char *md) {
+ struct ossl_gost_imit_ctx *c = ctx->md_data;
+ if (c->bytes_left) {
+ int i;
+ for (i=c->bytes_left;i<8;i++) {
+ c->partial_block[i]=0;
+ }
+ mac_block_mesh(c,c->partial_block);
+ }
+ get_mac(c->buffer,32,md);
+ return 1;
+}
+int gost_imit_ctrl(EVP_MD_CTX *ctx,int type, int arg, void *ptr) {
+ switch (type) {
+ case EVP_MD_CTRL_GET_TLS_MAC_KEY_LENGTH:
+ *((unsigned int*)(ptr)) = 32;
+ return 1;
+ case EVP_MD_CTRL_SET_KEY:
+ {
+ gost_key(&(((struct ossl_gost_imit_ctx*)(ctx->md_data))->cctx),ptr) ;
+ ((struct ossl_gost_imit_ctx*)(ctx->md_data))->key_set = 1;
+
+ }
+ default:
+ return 0;
+ }
+}
+int gost_imit_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from) {
+ memcpy(to->md_data,from->md_data,sizeof(struct ossl_gost_imit_ctx));
+ return 1;
+}
+/* Clean up imit ctx */
+int gost_imit_cleanup(EVP_MD_CTX *ctx) {
+ memset(ctx->md_data,0,sizeof(struct ossl_gost_imit_ctx));
+ return 1;
+
+}
+#endif
diff --git a/engines/ccgost/gost_sign.c b/engines/ccgost/gost_sign.c
new file mode 100644
index 0000000000..d4c9e5d3ff
--- /dev/null
+++ b/engines/ccgost/gost_sign.c
@@ -0,0 +1,302 @@
+/**********************************************************************
+ * gost_sign.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Implementation of GOST R 34.10-94 signature algoritgthm *
+ * for OpenSSL *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <string.h>
+#include <openssl/rand.h>
+#include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/evp.h>
+
+#include "sign.h"
+#include "paramset.h"
+#include "tools.h"
+#include "e_gost_err.h"
+
+#ifdef DEBUG_SIGN
+void dump_signature(const char *message,const unsigned char *buffer,size_t len) {
+ size_t i;
+ fprintf(stderr,"signature %s Length=%d",message,len);
+ for (i=0; i<len; i++) {
+ if (i% 16 ==0) fputc('\n',stderr);
+ fprintf (stderr," %02x",buffer[i]);
+ }
+ fprintf(stderr,"\nEnd of signature\n");
+}
+
+void dump_dsa_sig(const char *message, DSA_SIG *sig) {
+ fprintf(stderr,"%s\nR=",message);
+ BN_print_fp(stderr,sig->r);
+ fprintf(stderr,"\nS=");
+ BN_print_fp(stderr,sig->s);
+ fprintf(stderr,"\n");
+}
+
+#else
+
+#define dump_signature(a,b,c)
+#define dump_dsa_sig(a,b)
+#endif
+
+/*
+ * Computes signature and returns it as DSA_SIG structure
+ */
+DSA_SIG *gost_do_sign(const unsigned char *dgst,int dlen, DSA *dsa)
+{
+ BIGNUM *k=NULL,*tmp=NULL,*tmp2=NULL;
+ DSA_SIG *newsig = DSA_SIG_new();
+ BIGNUM *md = hashsum2bn(dgst);
+ /* check if H(M) mod q is zero */
+ BN_CTX *ctx=BN_CTX_new();
+ BN_CTX_start(ctx);
+ if (!newsig)
+ {
+ GOSTerr(GOST_F_GOST_DO_SIGN,GOST_R_NO_MEMORY);
+ goto err;
+ }
+ tmp=BN_CTX_get(ctx);
+ k = BN_CTX_get(ctx);
+ tmp2 = BN_CTX_get(ctx);
+ BN_mod(tmp,md,dsa->q,ctx);
+ if (BN_is_zero(tmp))
+ {
+ BN_one(md);
+ }
+ do {
+ do {
+ /*Generate random number k less than q*/
+ BN_rand_range(k,dsa->q);
+ /* generate r = (a^x mod p) mod q */
+ BN_mod_exp(tmp,dsa->g, k, dsa->p,ctx);
+ if (!(newsig->r)) newsig->r=BN_new();
+ BN_mod(newsig->r,tmp,dsa->q,ctx);
+ } while (BN_is_zero(newsig->r));
+ /* generate s = (xr + k(Hm)) mod q */
+ BN_mod_mul(tmp,dsa->priv_key,newsig->r,dsa->q,ctx);
+ BN_mod_mul(tmp2,k,md,dsa->q,ctx);
+ if (!newsig->s) newsig->s=BN_new();
+ BN_mod_add(newsig->s,tmp,tmp2,dsa->q,ctx);
+ } while (BN_is_zero(newsig->s));
+err:
+ BN_free(md);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return newsig;
+}
+
+
+/*
+ * Packs signature according to Cryptocom rules
+ * and frees up DSA_SIG structure
+ */
+
+int pack_sign_cc(DSA_SIG *s,int order,unsigned char *sig, unsigned int *siglen)
+{
+
+ *siglen = 2*order;
+ memset(sig,0,*siglen);
+ store_bignum(s->r, sig,order);
+ store_bignum(s->s, sig + order,order);
+ dump_signature("serialized",sig,*siglen);
+ DSA_SIG_free(s);
+ return 1;
+}
+/*
+ * Packs signature according to Cryptopro rules
+ * and frees up DSA_SIG structure
+ */
+int pack_sign_cp(DSA_SIG *s,int order,unsigned char *sig, unsigned int *siglen)
+{
+
+ *siglen = 2*order;
+ memset(sig,0,*siglen);
+ store_bignum(s->s, sig, order);
+ store_bignum(s->r, sig+order,order);
+ dump_signature("serialized",sig,*siglen);
+ DSA_SIG_free(s);
+ return 1;
+}
+
+
+
+
+/*
+ * Verifies signature passed as DSA_SIG structure
+ *
+ */
+
+int gost_do_verify(const unsigned char *dgst, int dgst_len,
+ DSA_SIG *sig, DSA *dsa)
+{
+ BIGNUM *md, *tmp=NULL;
+ BIGNUM *q2=NULL;
+ BIGNUM *u=NULL,*v=NULL,*z1=NULL,*z2=NULL;
+ BIGNUM *tmp2=NULL,*tmp3=NULL;
+ int ok;
+ BN_CTX *ctx = BN_CTX_new();
+
+ BN_CTX_start(ctx);
+ if (BN_cmp(sig->s,dsa->q)>=1||
+ BN_cmp(sig->r,dsa->q)>=1)
+ {
+ GOSTerr(GOST_F_GOST_DO_VERIFY,GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q);
+ return 0;
+ }
+ md=hashsum2bn(dgst);
+
+ tmp=BN_CTX_get(ctx);
+ v=BN_CTX_get(ctx);
+ q2=BN_CTX_get(ctx);
+ z1=BN_CTX_get(ctx);
+ z2=BN_CTX_get(ctx);
+ tmp2=BN_CTX_get(ctx);
+ tmp3=BN_CTX_get(ctx);
+ u = BN_CTX_get(ctx);
+
+ BN_mod(tmp,md,dsa->q,ctx);
+ if (BN_is_zero(tmp)) {
+ BN_one(md);
+ }
+ BN_copy(q2,dsa->q);
+ BN_sub_word(q2,2);
+ BN_mod_exp(v,md,q2,dsa->q,ctx);
+ BN_mod_mul(z1,sig->s,v,dsa->q,ctx);
+ BN_sub(tmp,dsa->q,sig->r);
+ BN_mod_mul(z2,tmp,v,dsa->p,ctx);
+ BN_mod_exp(tmp,dsa->g,z1,dsa->p,ctx);
+ BN_mod_exp(tmp2,dsa->pub_key,z2,dsa->p,ctx);
+ BN_mod_mul(tmp3,tmp,tmp2,dsa->p,ctx);
+ BN_mod(u,tmp3,dsa->q,ctx);
+ ok= BN_cmp(u,sig->r);
+
+ BN_free(md);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ if (ok!=0) {
+ GOSTerr(GOST_F_GOST_DO_VERIFY,GOST_R_SIGNATURE_MISMATCH);
+ }
+ return (ok==0);
+}
+
+/*
+ * Computes public keys for GOST R 34.10-94 algorithm
+ *
+ */
+int gost94_compute_public(DSA *dsa)
+{
+ /* Now fill algorithm parameters with correct values */
+ BN_CTX *ctx = BN_CTX_new();
+ if (!dsa->g) {
+ GOSTerr(GOST_F_GOST_COMPUTE_PUBLIC,GOST_R_KEY_IS_NOT_INITALIZED);
+ return 0;
+ }
+ /* Compute public key y = a^x mod p */
+ dsa->pub_key=BN_new();
+ BN_mod_exp(dsa->pub_key, dsa->g,dsa->priv_key,dsa->p,ctx);
+ BN_CTX_free(ctx);
+ return 1;
+}
+
+/*
+ * Fill GOST 94 params, searching them in R3410_paramset array
+ * by nid of paramset
+ *
+ */
+int fill_GOST94_params(DSA *dsa,int nid) {
+ R3410_params *params=R3410_paramset;
+ while (params->nid!=NID_undef && params->nid !=nid) params++;
+ if (params->nid == NID_undef)
+ {
+ GOSTerr(GOST_F_FILL_GOST94_PARAMS,GOST_R_UNSUPPORTED_PARAMETER_SET);
+ return 0;
+ }
+#define dump_signature(a,b,c)
+ if (dsa->p) { BN_free(dsa->p); }
+ dsa->p=NULL;
+ BN_dec2bn(&(dsa->p),params->p);
+ if (dsa->q) { BN_free(dsa->q); }
+ dsa->q=NULL;
+ BN_dec2bn(&(dsa->q),params->q);
+ if (dsa->g) { BN_free(dsa->g); }
+ dsa->g=NULL;
+ BN_dec2bn(&(dsa->g),params->a);
+ return 1;
+}
+
+/*
+ * Generate GOST R 34.10-94 keypair
+ *
+ *
+ */
+int gost_sign_keygen(DSA *dsa)
+{
+ dsa->priv_key = BN_new();
+ BN_rand_range(dsa->priv_key,dsa->q);
+ return gost94_compute_public( dsa);
+}
+/* Unpack signature according to cryptocom rules */
+
+DSA_SIG *unpack_cc_signature(const unsigned char *sig,size_t siglen)
+{
+ DSA_SIG *s;
+ s = DSA_SIG_new();
+ if (s == NULL) {
+ GOSTerr(GOST_F_UNPACK_CC_SIGNATURE,GOST_R_NO_MEMORY);
+ return(NULL);
+ }
+ s->r = getbnfrombuf(sig, siglen/2);
+ s->s = getbnfrombuf(sig + siglen/2, siglen/2);
+ return s;
+}
+/* Unpack signature according to cryptopro rules */
+DSA_SIG *unpack_cp_signature(const unsigned char *sig,size_t siglen)
+{
+ DSA_SIG *s;
+
+ s = DSA_SIG_new();
+ if (s == NULL) {
+ GOSTerr(GOST_F_UNPACK_CP_SIGNATURE,GOST_R_NO_MEMORY);
+ return NULL;
+ }
+ s->s = getbnfrombuf(sig , siglen/2);
+ s->r = getbnfrombuf(sig + siglen/2, siglen/2);
+ return s;
+}
+/* Convert little-endian byte array into bignum */
+BIGNUM *hashsum2bn(const unsigned char *dgst)
+{ unsigned char buf[32];
+ int i;
+ for (i=0;i<32;i++) {
+ buf[31-i]=dgst[i];
+ }
+ return getbnfrombuf(buf,32);
+}
+
+/* Convert byte buffer to bignum, skipping leading zeros*/
+BIGNUM *getbnfrombuf(const unsigned char *buf,size_t len) {
+ while (*buf==0&&len>0) {
+ buf++; len--;
+ }
+ if (len) {
+ return BN_bin2bn(buf,len,NULL);
+ } else {
+ BIGNUM *b=BN_new();
+ BN_zero(b);
+ return b;
+ }
+}
+/* Pack bignum into byte buffer of given size, filling all leading bytes
+ * by zeros */
+int store_bignum(BIGNUM *bn, unsigned char *buf,int len) {
+ int bytes = BN_num_bytes(bn);
+ if (bytes>len) return 0;
+ memset(buf,0,len);
+ BN_bn2bin(bn,buf+len-bytes);
+ return 1;
+}
+
diff --git a/engines/ccgost/gosthash.c b/engines/ccgost/gosthash.c
new file mode 100644
index 0000000000..5978dbabaa
--- /dev/null
+++ b/engines/ccgost/gosthash.c
@@ -0,0 +1,256 @@
+/**********************************************************************
+ * gosthash.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Implementation of GOST R 34.11-94 hash function *
+ * uses on gost89.c and gost89.h Doesn't need OpenSSL *
+ **********************************************************************/
+#include <string.h>
+
+#include "gost89.h"
+#include "gosthash.h"
+
+
+/* Use OPENSSL_malloc for memory allocation if compiled with
+ * -DOPENSSL_BUILD, and libc malloc otherwise
+ */
+#ifndef MYALLOC
+# ifdef OPENSSL_BUILD
+# include <openssl/crypto.h>
+# define MYALLOC(size) OPENSSL_malloc(size)
+# define MYFREE(ptr) OPENSSL_free(ptr)
+# else
+# define MYALLOC(size) malloc(size)
+# define MYFREE(ptr) free(ptr)
+# endif
+#endif
+/* Following functions are various bit meshing routines used in
+ * GOST R 34.11-94 algorithms */
+static void swap_bytes (byte *w, byte *k)
+{
+ int i,j;
+ for (i=0;i<4;i++)
+ for (j=0;j<8;j++)
+ k[i+4*j]=w[8*i+j];
+
+}
+/* was A_A */
+static void circle_xor8 (const byte *w, byte *k)
+{
+ byte buf[8];
+ int i;
+ memcpy(buf,w,8);
+ memcpy(k,w+8,24);
+ for(i=0;i<8;i++)
+ k[i+24]=buf[i]^k[i];
+}
+/* was R_R */
+static void transform_3 (byte *data)
+{
+ unsigned short int acc;
+ acc=(data[0]^data[2]^data[4]^data[6]^data[24]^data[30])|
+ ((data[1]^data[3]^data[5]^data[7]^data[25]^data[31])<<8);
+ memmove(data,data+2,30);
+ data[30]=acc&0xff;
+ data[31]=acc>>8;
+}
+
+/* Adds blocks of N bytes modulo 2**(8*n). Returns carry*/
+static int add_blocks(int n,byte *left, const byte *right)
+{
+ int i;
+ int carry=0;
+ int sum;
+ for (i=0;i<n;i++)
+ {
+ sum=(int)left[i]+(int)right[i]+carry;
+ left[i]=sum & 0xff;
+ carry=sum>>8;
+ }
+ return carry;
+}
+/* Xor two sequences of bytes */
+static void xor_blocks (byte *result,const byte *a,const byte *b,size_t len) {
+ size_t i;
+ for (i=0;i<len;i++) result[i]=a[i]^b[i];
+}
+
+/*
+ * Calculate H(i+1) = Hash(Hi,Mi)
+ * Where H and M are 32 bytes long
+ */
+static int hash_step(gost_ctx *c,byte *H,const byte *M)
+{
+ static byte U[32],W[32],V[32],S[32],Key[32];
+ int i;
+ /* Compute first key */
+ xor_blocks(W,H,M,32);
+ swap_bytes(W,Key);
+ /* Encrypt first 8 bytes of H with first key*/
+ gost_enc_with_key(c,Key,H,S);
+ /* Compute second key*/
+ circle_xor8(H,U);
+ circle_xor8(M,V);
+ circle_xor8(V,V);
+ xor_blocks(W,U,V,32);
+ swap_bytes(W,Key);
+ /* encrypt second 8 bytes of H with second key*/
+ gost_enc_with_key(c,Key,H+8,S+8);
+ /* compute third key */
+ circle_xor8(U,U);
+ U[31]=~U[31]; U[29]=~U[29]; U[28]=~U[28]; U[24]=~U[24];
+ U[23]=~U[23]; U[20]=~U[20]; U[18]=~U[18]; U[17]=~U[17];
+ U[14]=~U[14]; U[12]=~U[12]; U[10]=~U[10]; U[ 8]=~U[ 8];
+ U[ 7]=~U[ 7]; U[ 5]=~U[ 5]; U[ 3]=~U[ 3]; U[ 1]=~U[ 1];
+ circle_xor8(V,V);
+ circle_xor8(V,V);
+ xor_blocks(W,U,V,32);
+ swap_bytes(W,Key);
+ /* encrypt third 8 bytes of H with third key*/
+ gost_enc_with_key(c,Key,H+16,S+16);
+ /* Compute fourth key */
+ circle_xor8(U,U);
+ circle_xor8(V,V);
+ circle_xor8(V,V);
+ xor_blocks(W,U,V,32);
+ swap_bytes(W,Key);
+ /* Encrypt last 8 bytes with fourth key */
+ gost_enc_with_key(c,Key,H+24,S+24);
+ for (i=0;i<12;i++)
+ transform_3(S);
+ xor_blocks(S,S,M,32);
+ transform_3(S);
+ xor_blocks(S,S,H,32);
+ for (i=0;i<61;i++)
+ transform_3(S);
+ memcpy(H,S,32);
+ return 1;
+}
+
+/* Initialize gost_hash ctx - cleans up temporary structures and
+ * set up substitution blocks
+ */
+int init_gost_hash_ctx(gost_hash_ctx *ctx, const gost_subst_block *subst_block) {
+ memset(ctx,0,sizeof(gost_hash_ctx));
+ ctx->cipher_ctx = (gost_ctx *)MYALLOC(sizeof(gost_ctx));
+ if (!ctx->cipher_ctx) {
+ return 0;
+ }
+ gost_init(ctx->cipher_ctx,subst_block);
+ return 1;
+}
+/*
+ * Free cipher CTX if it is dynamically allocated. Do not use
+ * if cipher ctx is statically allocated as in OpenSSL implementation of
+ * GOST hash algroritm
+ *
+ */
+void done_gost_hash_ctx(gost_hash_ctx *ctx)
+{
+ /* No need to use gost_destroy, because cipher keys are not really
+ * secret when hashing */
+ MYFREE(ctx->cipher_ctx);
+}
+/*
+ * reset state of hash context to begin hashing new message
+ */
+int start_hash(gost_hash_ctx *ctx) {
+ if (!ctx->cipher_ctx) return 0;
+ memset(&(ctx->H),0,32);
+ memset(&(ctx->S),0,32);
+ ctx->len = 0L;
+ ctx->left=0;
+ return 1;
+}
+/*
+ * Hash block of arbitrary length
+ *
+ *
+ */
+int hash_block(gost_hash_ctx *ctx,const byte *block, size_t length) {
+ const byte *curptr=block;
+ const byte *barrier=block+(length-32);/* Last byte we can safely hash*/
+ gost_ctx *save_c = ctx->cipher_ctx;
+ if (ctx->left) {
+ /*There are some bytes from previous step*/
+ int add_bytes = 32-ctx->left;
+ if (add_bytes>length) {
+ add_bytes = length;
+ }
+ memcpy(&(ctx->remainder[ctx->left]),block,add_bytes);
+ ctx->left+=add_bytes;
+ if (ctx->left<32) {
+ return 1;
+ }
+ if (ctx->left>32) {
+ abort();
+ }
+ curptr=block+add_bytes;
+ hash_step(ctx->cipher_ctx,ctx->H,ctx->remainder);
+ if (save_c!=ctx->cipher_ctx) {
+ abort();
+ }
+ add_blocks(32,ctx->S,ctx->remainder);
+ if (save_c!=ctx->cipher_ctx) {
+ abort();
+ }
+ ctx->len+=32;
+ ctx->left=0;
+ }
+ while (curptr<=barrier)
+ {
+ hash_step(ctx->cipher_ctx,ctx->H,curptr);
+ if (save_c!=ctx->cipher_ctx) {
+ abort();
+ }
+
+ add_blocks(32,ctx->S,curptr);
+ if (save_c!=ctx->cipher_ctx) {
+ abort();
+ }
+ ctx->len+=32;
+ curptr+=32;
+ }
+ if (curptr!=block+length) {
+ ctx->left=block+length-curptr;
+ if (ctx->left>32) {
+ abort();
+ }
+ memcpy(ctx->remainder,curptr,ctx->left);
+ }
+ return 1;
+}
+/*
+ * Compute hash value from current state of ctx
+ * state of hash ctx becomes invalid and cannot be used for further
+ * hashing.
+ */
+int finish_hash(gost_hash_ctx *ctx,byte *hashval) {
+ byte buf[32];
+ byte H[32];
+ byte S[32];
+ long long fin_len=ctx->len;
+ byte *bptr;
+ memcpy(H,ctx->H,32);
+ memcpy(S,ctx->S,32);
+ if (ctx->left) {
+ memset(buf,0,32);
+ memcpy(buf,ctx->remainder,ctx->left);
+ hash_step(ctx->cipher_ctx,H,buf);
+ add_blocks(32,S,buf);
+ fin_len+=ctx->left;
+ }
+ memset(buf,0,32);
+ bptr=buf;
+ fin_len<<=3; /* Hash length in BITS!!*/
+ while(fin_len>0) {
+ *(bptr++)=fin_len&0xFF;
+ fin_len>>=8;
+ };
+ hash_step(ctx->cipher_ctx,H,buf);
+ hash_step(ctx->cipher_ctx,H,S);
+ memcpy(hashval,H,32);
+ return 1;
+}
+
diff --git a/engines/ccgost/gosthash.h b/engines/ccgost/gosthash.h
new file mode 100644
index 0000000000..d9889cae2d
--- /dev/null
+++ b/engines/ccgost/gosthash.h
@@ -0,0 +1,39 @@
+/**********************************************************************
+ * gosthash.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Declaration of GOST R 34.11-94 hash functions *
+ * uses and gost89.h Doesn't need OpenSSL *
+ **********************************************************************/
+#ifndef GOSTHASH_H
+#define GOSTHASH_H
+#include "gost89.h"
+#include <stdlib.h>
+typedef struct gost_hash_ctx {
+ long long len;
+ gost_ctx *cipher_ctx;
+ int left;
+ byte H[32];
+ byte S[32];
+ byte remainder[32];
+} gost_hash_ctx;
+
+
+/* Initalizes gost hash ctx, including creation of gost cipher ctx */
+
+int init_gost_hash_ctx(gost_hash_ctx *ctx, const gost_subst_block *subst_block);
+void done_gost_hash_ctx(gost_hash_ctx *ctx);
+
+/* Cleans up all fields, except cipher ctx preparing ctx for computing
+ * of new hash value */
+int start_hash(gost_hash_ctx *ctx);
+
+/* Hashes block of data */
+int hash_block(gost_hash_ctx *ctx, const byte *block, size_t length);
+
+/* Finalizes computation of hash and fills buffer (which should be at
+ * least 32 bytes long) with value of computed hash. */
+int finish_hash(gost_hash_ctx *ctx, byte *hashval);
+
+#endif
diff --git a/engines/ccgost/gostkeyx.h b/engines/ccgost/gostkeyx.h
new file mode 100644
index 0000000000..56fc6a2372
--- /dev/null
+++ b/engines/ccgost/gostkeyx.h
@@ -0,0 +1,42 @@
+#ifndef GOSTKEYX_H
+#define GOSTKEYX_H
+/**********************************************************************
+ * gostkeyx.h *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Declaration of the key transport functions for GOST pkey methods *
+ * *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <openssl/evp.h>
+#include "gost89.h"
+/* EVP_PKEY_METHOD 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 );
+int pkey_GOST94cc_encrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * key,size_t key_len);
+
+int pkey_GOST94cp_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* in, size_t in_len );
+int pkey_GOST94cc_decrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * in,size_t in_len);
+/* From gost2001_keyx.c */
+int pkey_GOST01cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* key, size_t key_len );
+int pkey_GOST01cc_encrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * key,size_t key_len);
+
+int pkey_GOST01cp_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* in, size_t in_len );
+int pkey_GOST01cc_decrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * in,size_t in_len);
+
+/* Internal functions to make error processing happy */
+int decrypt_cryptocom_key(unsigned char *sess_key,int max_key_len,
+ const unsigned char *crypted_key,int crypted_key_len, gost_ctx *ctx);
+int encrypt_cryptocom_key(const unsigned char *sess_key,int key_len,
+ unsigned char *crypted_key, gost_ctx *ctx);
+/*int compute_pair_key_le(unsigned char *pair_key,BIGNUM *pub_key,DH *dh) ;*/
+/*
+ * Computes 256 bit key exchange key for CryptoCom variation of GOST 94
+ * algorithm
+ *//*
+int make_gost_shared_key(DH *dh,EVP_PKEY *pubk,unsigned char *shared_key) ;
+DH *make_ephemeral_key(EVP_PKEY *pubk,BIGNUM *ephemeral_key);
+int make_cp_exchange_key(DH *dh,EVP_PKEY *pubk, unsigned char *shared_key);
+*/
+#endif
diff --git a/engines/ccgost/gostsum.1 b/engines/ccgost/gostsum.1
new file mode 100644
index 0000000000..3dfd7e40d0
--- /dev/null
+++ b/engines/ccgost/gostsum.1
@@ -0,0 +1,78 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.TH MD5SUM 1 "29th November 1995" "Lankester et al." "Debian GNU/Linux"
+.SH NAME
+gostsum \- generates or checks GOST R34.11-94 message digests
+
+.SH SYNOPSIS
+.B gostsum
+[\-bv] [\-c [file]] | [file...]
+
+.SH DESCRIPTION
+.B gostsum
+generates or checks GOST hash sums. The algorithm to generate the
+is reasonably fast and strong enough for most cases. Exact
+specification of the algorithm is in
+.I GOST R34.11-94.
+
+Normally
+.B gostsum
+generates checksums of all files given to it as a parameter and prints
+the checksums followed by the filenames. If, however,
+.B \-c
+is specified, only one filename parameter is allowed. This file should
+contain checksums and filenames to which these checksums refer to, and
+the files listed in that file are checked against the checksums listed
+there. See option
+.B \-c
+for more information.
+
+.SS OPTIONS
+.TP
+.B \-b
+Use binary mode. In unix environment, only difference between this and
+the normal mode is an asterisk preceding the filename in the output.
+.TP
+.B \-c
+Check md5sum of all files listed in
+.I file
+against the checksum listed in the same file. The actual format of that
+file is the same as output of
+.B md5sum.
+That is, each line in the file describes a file. A line looks like:
+
+.B <hashsum> <filename>
+
+So, for example, if a file was created and its message digest calculated
+like so:
+
+.B echo foo > hash\-test\-file; gost5sum hash\-test\-file
+
+.B gost5sum
+would report:
+
+.B d3b07384d113edec49eaa6238ad5ff00\ md5\-test\-file
+
+.TP
+.B \-v
+Be more verbose. Print filenames when checking (with \-c).
+
+.TP
+.B -t
+Use test parameter set.
+.B gostsum supports two sets of parameters (which are really parameters
+of GOST 28147-89 block cipher) specified in the IETF draft
+.B draft-popov-cryptopro-cpalgs-02.txt
+By default, cryptopro paramset is used. This option enables use of test
+paramset as specified in appendices to the GOST.
+
+.SH BUGS
+
+This manpage is not quite accurate and has formatting inconsistent
+with other manpages.
+
+.B gostsum
+does not accept standard options like
+.BR \-\-help .
+
+.SH AUTHOR
+
diff --git a/engines/ccgost/gostsum.c b/engines/ccgost/gostsum.c
new file mode 100644
index 0000000000..92bd5f9419
--- /dev/null
+++ b/engines/ccgost/gostsum.c
@@ -0,0 +1,184 @@
+/**********************************************************************
+ * gostsum.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Almost drop-in replacement for md5sum and sha1sum *
+ * which computes GOST R 34.11-94 hashsum instead *
+ * *
+ **********************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <string.h>
+#include "gosthash.h"
+#define BUF_SIZE 262144
+int hash_file(gost_hash_ctx *ctx,char *filename,char *sum,int mode);
+int hash_stream(gost_hash_ctx *ctx,int fd, char *sum);
+int get_line(FILE *f,char *hash,char *filename);
+void help()
+{
+ fprintf(stderr,"gostsum [-bvt] [-c [file]]| [files]\n"
+ "\t-c check message digests (default is generate)\n"
+ "\t-v verbose, print file names when checking\n"
+ "\t-b read files in binary mode\n"
+ "\t-t use test GOST paramset (default is CryptoPro paramset)\n"
+"The input for -c should be the list of message digests and file names\n"
+"that is printed on stdout by this program when it generates digests.\n");
+exit(3);
+}
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+int main(int argc,char **argv)
+{
+ int c,i;
+ int verbose=0;
+ int errors=0;
+ int open_mode = O_RDONLY;
+ gost_subst_block *b= &GostR3411_94_CryptoProParamSet;
+ FILE *check_file = NULL;
+ gost_hash_ctx ctx;
+
+ while( (c=getopt(argc,argv,"bc::tv"))!=-1)
+ {
+ switch (c)
+ {
+ case 'v': verbose=1; break;
+ case 't': b= &GostR3411_94_TestParamSet; break;
+ case 'b': open_mode |= O_BINARY; break;
+ case 'c': if (optarg) {
+ check_file = fopen(optarg,"r");
+ if (!check_file) {
+ perror(optarg);
+ exit(2);
+ }
+ } else {
+ check_file= stdin;
+ }
+ break;
+ default:
+ fprintf(stderr,"invalid option %c",optopt);
+ help();
+ }
+ }
+ init_gost_hash_ctx(&ctx,b);
+ if (check_file)
+ {
+ char inhash[65],calcsum[65],filename[PATH_MAX];
+ int failcount=0,count=0;;
+ if (check_file==stdin && optind<argc)
+ {
+ check_file=fopen(argv[optind],"r");
+ if (!check_file)
+ {
+ perror(argv[optind]);
+ exit(2);
+ }
+ }
+ while (get_line(check_file,inhash,filename))
+ {
+ if (!hash_file(&ctx,filename,calcsum,open_mode)) {
+ exit (2);
+ }
+ count++;
+ if (!strncmp(calcsum,inhash,65))
+ {
+ if (verbose) {
+ fprintf(stderr,"%s\tOK\n",filename);
+ }
+ } else {
+ if (verbose) {
+ fprintf(stderr,"%s\tFAILED\n",filename);
+ } else {
+ fprintf(stderr,"%s: GOST hash sum check failed for '%s'\n",
+ argv[0],filename);
+ }
+ failcount++;
+ }
+ }
+ if (verbose && failcount) {
+ fprintf(stderr,"%s: %d of %d file(f) failed GOST hash sum check\n",
+ argv[0],failcount,count);
+ }
+ exit (failcount?1:0);
+ }
+ if (optind==argc) {
+ char sum[65];
+ if (!hash_stream(&ctx,fileno(stdin),sum)) {
+ perror("stdin");
+ exit(1);
+ }
+ printf("%s -\n",sum);
+ exit(0);
+ }
+ for (i=optind;i<argc;i++) {
+ char sum[65];
+ if (!hash_file(&ctx,argv[i],sum,open_mode)) {
+ errors++;
+ } else {
+ printf("%s %s\n",sum,argv[i]);
+ }
+ }
+ exit(errors?1:0);
+}
+
+int hash_file(gost_hash_ctx *ctx,char *filename,char *sum,int mode)
+{
+ int fd;
+ if ((fd=open(filename,mode))<0) {
+ perror(filename);
+ return 0;
+ }
+ if (!hash_stream(ctx,fd,sum)) {
+ perror(filename);
+ return 0;
+ }
+ close(fd);
+ return 1;
+}
+
+int hash_stream(gost_hash_ctx *ctx,int fd, char *sum)
+{
+ unsigned char buffer[BUF_SIZE];
+ ssize_t bytes;
+ int i;
+ start_hash(ctx);
+ while ((bytes=read(fd,buffer,BUF_SIZE))>0) {
+ hash_block(ctx,buffer,bytes);
+ }
+ if (bytes<0) {
+ return 0;
+ }
+ finish_hash(ctx,buffer);
+ for (i=0;i<32;i++) {
+ sprintf(sum+2*i,"%02x",buffer[31-i]);
+ }
+ return 1;
+}
+
+int get_line(FILE *f,char *hash,char *filename) {
+ int i;
+ if (fread(hash,1,64,f)<64) return 0;
+ hash[64]=0;
+ for (i=0;i<64;i++)
+ {
+ if (hash[i]<'0' || (hash[i]>'9' && hash[i]<'A') || (hash[i]>'F'
+ && hash[i]<'a')||hash[i]>'f')
+ {
+ fprintf(stderr,"Not a hash value '%s'\n",hash);
+ return 0;
+ }
+ }
+ if (fgetc(f)!=' ') {
+ fprintf(stderr,"Malformed input line\n");
+ return 0;
+ }
+ i=strlen(fgets(filename,PATH_MAX,f));
+ while (filename[--i]=='\n'||filename[i]=='\r') filename[i]=0;
+ return 1;
+}
diff --git a/engines/ccgost/keywrap.c b/engines/ccgost/keywrap.c
new file mode 100644
index 0000000000..4e7d675a73
--- /dev/null
+++ b/engines/ccgost/keywrap.c
@@ -0,0 +1,97 @@
+/**********************************************************************
+ * keywrap.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Implementation of CryptoPro key wrap algorithm, as defined in *
+ * RFC 4357 p 6.3 and 6.4 *
+ * Doesn't need OpenSSL *
+ **********************************************************************/
+#include <string.h>
+#include "gost89.h"
+#include "keywrap.h"
+
+/* Diversifies key using random UserKey Material
+ * Implements RFC 4357 p 6.5 key diversification algorithm
+ *
+ * inputKey - 32byte key to be diversified
+ * ukm - 8byte user key material
+ * outputKey - 32byte buffer to store diversified key
+ *
+ */
+void keyDiversifyCryptoPro(gost_ctx *ctx,const unsigned char *inputKey, const unsigned char *ukm, unsigned char *outputKey)
+{
+
+ u4 k,s1,s2;
+ int i,j,mask;
+ unsigned char S[8];
+ memcpy(outputKey,inputKey,32);
+ for (i=0;i<8;i++) {
+ /* Make array of integers from key */
+ /* Compute IV S*/
+ s1=0,s2=0;
+ for (j=0,mask=1;j<8;j++,mask<<=1) {
+ k=((u4)outputKey[4*j])|(outputKey[4*j+1]<<8)|
+ (outputKey[4*j+2]<<16)|(outputKey[4*j+3]<<24);
+ if (mask & ukm[i]) {
+ s1+=k;
+ } else {
+ s2+=k;
+ }
+ }
+ S[0]=s1&0xff; S[1]=(s1>>8)&0xff; S[2]=(s1>>16)&0xff; S[3]=(s1>>24)&0xff;
+ S[4]=s2&0xff; S[5]=(s2>>8)&0xff; S[6]=(s2>>16)&0xff; S[7]=(s2>>24)&0xff;
+ gost_key(ctx,outputKey);
+ gost_enc_cfb(ctx,S,outputKey,outputKey,4);
+ }
+}
+
+
+/*
+ * Wraps key using RFC 4357 6.3
+ * ctx - gost encryption context, initialized with some S-boxes
+ * keyExchangeKey (KEK) 32-byte (256-bit) shared key
+ * ukm - 8 byte (64 bit) user key material,
+ * sessionKey - 32-byte (256-bit) key to be wrapped
+ * wrappedKey - 44-byte buffer to store wrapped key
+ */
+
+int keyWrapCryptoPro(gost_ctx *ctx,const unsigned char *keyExchangeKey, const unsigned char *ukm,
+ const unsigned char *sessionKey, unsigned char *wrappedKey)
+{
+ unsigned char kek_ukm[32];
+ keyDiversifyCryptoPro(ctx,keyExchangeKey,ukm,kek_ukm);
+ gost_key(ctx,kek_ukm);
+ memcpy(wrappedKey,ukm,8);
+ gost_enc(ctx,sessionKey,wrappedKey+8,4);
+ gost_mac_iv(ctx,32,ukm,sessionKey,32,wrappedKey+40);
+ return 1;
+}
+/*
+ * Unwraps key using RFC 4357 6.4
+ * ctx - gost encryption context, initialized with some S-boxes
+ * keyExchangeKey 32-byte shared key
+ * wrappedKey 44 byte key to be unwrapped (concatenation of 8-byte UKM,
+ * 32 byte encrypted key and 4 byte MAC
+ *
+ * sessionKEy - 32byte buffer to store sessionKey in
+ * Returns 1 if key is decrypted successfully, and 0 if MAC doesn't match
+ */
+
+int keyUnwrapCryptoPro(gost_ctx *ctx,const unsigned char *keyExchangeKey,
+ const unsigned char *wrappedKey, unsigned char *sessionKey)
+{
+ unsigned char kek_ukm[32],cek_mac[4];
+ keyDiversifyCryptoPro(ctx,keyExchangeKey,wrappedKey
+ /* First 8 bytes of wrapped Key is ukm */
+ ,kek_ukm);
+ gost_key(ctx,kek_ukm);
+ gost_dec(ctx,wrappedKey+8,sessionKey,4);
+ gost_mac_iv(ctx,32,wrappedKey,sessionKey,32,cek_mac);
+ if (memcmp(cek_mac,wrappedKey+40,4)) {
+ return 0;
+ }
+ return 1;
+}
+
+
diff --git a/engines/ccgost/keywrap.h b/engines/ccgost/keywrap.h
new file mode 100644
index 0000000000..5553c92ff6
--- /dev/null
+++ b/engines/ccgost/keywrap.h
@@ -0,0 +1,56 @@
+/**********************************************************************
+ * keywrap.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Implementation of CryptoPro key wrap algorithm, as defined in *
+ * RFC 4357 p 6.3 and 6.4 *
+ * Doesn't need OpenSSL *
+ **********************************************************************/
+#ifndef GOST_KEYWRAP_H
+#define GOST_KEYWRAP_H
+#include <string.h>
+#include "gost89.h"
+/* Diversifies key using random UserKey Material
+ * Implements RFC 4357 p 6.5 key diversification algorithm
+ *
+ * inputKey - 32byte key to be diversified
+ * ukm - 8byte user key material
+ * outputKey - 32byte buffer to store diversified key
+ *
+ */
+void keyDiversifyCryptoPro(gost_ctx *ctx,
+ const unsigned char *inputKey,
+ const unsigned char *ukm,
+ unsigned char *outputKey);
+/*
+ * Wraps key using RFC 4357 6.3
+ * ctx - gost encryption context, initialized with some S-boxes
+ * keyExchangeKey (KEK) 32-byte (256-bit) shared key
+ * ukm - 8 byte (64 bit) user key material,
+ * sessionKey - 32-byte (256-bit) key to be wrapped
+ * wrappedKey - 44-byte buffer to store wrapped key
+ */
+
+int keyWrapCryptoPro(gost_ctx *ctx,
+ const unsigned char *keyExchangeKey,
+ const unsigned char *ukm,
+ const unsigned char *sessionKey,
+ unsigned char *wrappedKey) ;
+/*
+ * Unwraps key using RFC 4357 6.4
+ * ctx - gost encryption context, initialized with some S-boxes
+ * keyExchangeKey 32-byte shared key
+ * wrappedKey 44 byte key to be unwrapped (concatenation of 8-byte UKM,
+ * 32 byte encrypted key and 4 byte MAC
+ *
+ * sessionKEy - 32byte buffer to store sessionKey in
+ * Returns 1 if key is decrypted successfully, and 0 if MAC doesn't match
+ */
+
+
+int keyUnwrapCryptoPro(gost_ctx *ctx,
+ const unsigned char *keyExchangeKey,
+ const unsigned char *wrappedKey,
+ unsigned char *sessionKey) ;
+#endif
diff --git a/engines/ccgost/md.h b/engines/ccgost/md.h
new file mode 100644
index 0000000000..7cf0af2a6b
--- /dev/null
+++ b/engines/ccgost/md.h
@@ -0,0 +1,41 @@
+#ifndef GOST_MD_H
+#define GOST_MD_H
+/**********************************************************************
+ * md.h *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Declaration of GOST R 34.11 bindings to OpenSSL *
+ * *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <unistd.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include "gost89.h"
+#include "gosthash.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ /* Structure used as EVP_MD_CTX-md_data.
+ * It allows to avoid storing in the md-data pointers to
+ * dynamically allocated memory.
+ *
+ * I cannot invent better way to avoid memory leaks, because
+ * openssl insist on invoking Init on Final-ed digests, and there
+ * is no reliable way to find out whether pointer in the passed
+ * md_data is valid or not.
+ * */
+struct ossl_gost_digest_ctx {
+ gost_hash_ctx dctx;
+ gost_ctx cctx;
+};
+
+extern EVP_MD digest_gost;
+
+
+#ifdef __cplusplus
+ };
+#endif
+#endif
diff --git a/engines/ccgost/md_gost.c b/engines/ccgost/md_gost.c
new file mode 100644
index 0000000000..b0fede6d34
--- /dev/null
+++ b/engines/ccgost/md_gost.c
@@ -0,0 +1,69 @@
+/**********************************************************************
+ * md_gost.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * OpenSSL interface to GOST R 34.11-94 hash functions *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <string.h>
+#include "md.h"
+#include "gosthash.h"
+#include "e_gost_err.h"
+
+/* implementation of GOST 34.11 hash function See gost_md.c*/
+static int gost_digest_init(EVP_MD_CTX *ctx);
+static int gost_digest_update(EVP_MD_CTX *ctx, const void *data, size_t count);
+static int gost_digest_final(EVP_MD_CTX *ctx,unsigned char *md);
+static int gost_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from);
+static int gost_digest_cleanup(EVP_MD_CTX *ctx);
+
+EVP_MD digest_gost=
+{
+ NID_id_GostR3411_94,
+ NID_undef,
+ 32,
+ EVP_MD_FLAG_PKEY_METHOD_SIGNATURE,
+ gost_digest_init,
+ gost_digest_update,
+ gost_digest_final,
+ gost_digest_copy,
+ gost_digest_cleanup,
+ NULL,
+ NULL,
+ {NID_undef,NID_undef,0,0,0},
+ 32,
+ sizeof(struct ossl_gost_digest_ctx ),
+ NULL
+};
+
+int gost_digest_init(EVP_MD_CTX *ctx)
+{
+ struct ossl_gost_digest_ctx *c = ctx->md_data;
+ memset(&(c->dctx),0,sizeof(gost_hash_ctx));
+ gost_init(&(c->cctx),&GostR3411_94_CryptoProParamSet);
+ c->dctx.cipher_ctx= &(c->cctx);
+ return 1;
+}
+
+int gost_digest_update(EVP_MD_CTX *ctx,const void *data,size_t count)
+{
+ return hash_block((gost_hash_ctx *)ctx->md_data,data,count);
+}
+
+int gost_digest_final(EVP_MD_CTX *ctx,unsigned char *md)
+{
+ return finish_hash((gost_hash_ctx *)ctx->md_data,md);
+
+}
+
+int gost_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from)
+{
+ memcpy(to->md_data,from->md_data,sizeof(struct ossl_gost_digest_ctx));
+ return 1;
+}
+
+int gost_digest_cleanup(EVP_MD_CTX *ctx) {
+ memset(ctx->md_data,0,sizeof(struct ossl_gost_digest_ctx));
+ return 1;
+}
diff --git a/engines/ccgost/meth.h b/engines/ccgost/meth.h
new file mode 100644
index 0000000000..863046648c
--- /dev/null
+++ b/engines/ccgost/meth.h
@@ -0,0 +1,22 @@
+#ifndef CCE_METH_H
+#define CCE_METH_H
+/**********************************************************************
+ * meth.h *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Declaration of method registration functions *
+ * *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ int register_ameth_gost (int nid, EVP_PKEY_ASN1_METHOD **ameth, const char* pemstr, const char* info);
+ int register_pmeth_gost (int id, EVP_PKEY_METHOD **pmeth, int flags);
+#ifdef __cplusplus
+ };
+#endif
+
+#endif
diff --git a/engines/ccgost/params.c b/engines/ccgost/params.c
new file mode 100644
index 0000000000..37aa23d653
--- /dev/null
+++ b/engines/ccgost/params.c
@@ -0,0 +1,198 @@
+/**********************************************************************
+ * params.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Definitions of GOST R 34.10 parameter sets, defined in RFC 4357 *
+ * OpenSSL 0.9.9 libraries required to compile and use *
+ * this code *
+ **********************************************************************/
+#include "paramset.h"
+#include <openssl/objects.h>
+/* Parameters of GOST 34.10 */
+
+R3410_params R3410_paramset[]={
+/* Paramset A */
+{NID_id_GostR3410_94_CryptoPro_A_ParamSet,
+"100997906755055304772081815535925224869"
+"8410825720534578748235158755771479905292727772441528526992987964833"
+"5669968284202797289605274717317548059048560713474685214192868091256"
+"1502802222185647539190902656116367847270145019066794290930185446216"
+"3997308722217328898303231940973554032134009725883228768509467406639"
+"62",
+"127021248288932417465907042777176443525"
+"7876535089165358128175072657050312609850984974231883334834011809259"
+"9999512098893413065920561499672425412104927434935707492031276956145"
+"1689224110579311248812610229678534638401693520013288995000362260684"
+"2227508135323070045173416336850045410625869714168836867788425378203"
+"83",
+"683631961449557007844441656118272528951"
+"02170888761442055095051287550314083023"},
+{NID_id_GostR3410_94_CryptoPro_B_ParamSet,
+"429418261486158041438734477379555023926"
+"7234596860714306679811299408947123142002706038521669956384871995765"
+"7284814898909770759462613437669456364882730370838934791080835932647"
+"9767786019153434744009610342313166725786869204821949328786333602033"
+"8479709268434224762105576023501613261478065276102850944540333865234"
+"1",
+"139454871199115825601409655107690713107"
+"0417070599280317977580014543757653577229840941243685222882398330391"
+"1468164807668823692122073732267216074074777170091113455043205380464"
+"7694904686120113087816240740184800477047157336662926249423571248823"
+"9685422217536601433914856808405203368594584948031873412885804895251"
+"63",
+"79885141663410976897627118935756323747307951916507639758300472692338873533959"
+},
+{NID_id_GostR3410_94_CryptoPro_C_ParamSet,
+"816552717970881016017893191415300348226"
+"2544051353358162468249467681876621283478212884286545844013955142622"
+"2087723485023722868022275009502224827866201744494021697716482008353"
+"6398202298024892620480898699335508064332313529725332208819456895108"
+"5155178100221003459370588291073071186553005962149936840737128710832"
+"3",
+"110624679233511963040518952417017040248"
+"5862954819831383774196396298584395948970608956170224210628525560327"
+"8638246716655439297654402921844747893079518669992827880792192992701"
+"1428546551433875806377110443534293554066712653034996277099320715774"
+"3542287621283671843703709141350171945045805050291770503634517804938"
+"01",
+"113468861199819350564868233378875198043"
+"267947776488510997961231672532899549103"
+},
+{NID_id_GostR3410_94_CryptoPro_D_ParamSet,
+"756976611021707301782128757801610628085"
+"5283803109571158829574281419208532589041660017017859858216341400371"
+"4687551412794400562878935266630754392677014598582103365983119173924"
+"4732511225464712252386803315902707727668715343476086350472025298282"
+"7271461690125050616858238384366331089777463541013033926723743254833"
+"7",
+"905457649621929965904290958774625315611"
+"3056083907389766971404812524422262512556054474620855996091570786713"
+"5849550236741915584185990627801066465809510095784713989819413820871"
+"5964648914493053407920737078890520482730623038837767710173664838239"
+"8574828787891286471201460474326612697849693665518073864436497893214"
+"9",
+"108988435796353506912374591498972192620"
+"190487557619582334771735390599299211593"
+},
+
+{NID_id_GostR3410_94_CryptoPro_XchA_ParamSet,
+"1335318132727206734338595199483190012179423759678474868994823595993"
+"6964252873471246159040332773182141032801252925387191478859899310331"
+"0567744136196364803064721377826656898686468463277710150809401182608"
+"7702016153249904683329312949209127762411378780302243557466062839716"
+"59376426832674269780880061631528163475887",
+"14201174159756348119636828602231808974327613839524373876287257344192"
+"74593935127189736311660784676003608489466235676257952827747192122419"
+"29071046134208380636394084512691828894000571524625445295769349356752"
+"72895683154177544176313938445719175509684710784659566254794231229333"
+"8483924514339614727760681880609734239",
+"91771529896554605945588149018382750217296858393520724172743325725474"
+"374979801"
+},
+{NID_id_GostR3410_94_CryptoPro_XchB_ParamSet,
+"8890864727828423151699995801875757891031463338652579140051973659"
+"3048131440685857067369829407947744496306656291505503608252399443"
+"7900272386749145996230867832228661977543992816745254823298629859"
+"8753575466286051738837854736167685769017780335804511440773337196"
+"2538423532919394477873664752824509986617878992443177",
+"1028946126624994859676552074360530315217970499989304888248413244"
+"8474923022758470167998871003604670704877377286176171227694098633"
+"1539089568784129110109512690503345393869871295783467257264868341"
+"7200196629860561193666752429682367397084815179752036423595736533"
+"68957392061769855284593965042530895046088067160269433",
+"9109671391802626916582318050603555673628769498182593088388796888"
+"5281641595199"
+},
+{NID_id_GostR3410_94_CryptoPro_XchC_ParamSet,
+"4430618464297584182473135030809859326863990650118941756995270074"
+"8609973181426950235239623239110557450826919295792878938752101867"
+"7047181623251027516953100431855964837602657827828194249605561893"
+"6965865325513137194483136247773653468410118796740709840825496997"
+"9375560722345106704721086025979309968763193072908334",
+"1246996366993477513607147265794064436203408861395055989217248455"
+"7299870737698999651480662364723992859320868822848751165438350943"
+"3276647222625940615560580450040947211826027729977563540237169063"
+"0448079715771649447778447000597419032457722226253269698374446528"
+"35352729304393746106576383349151001715930924115499549",
+"6787876137336591234380295020065682527118129468050147943114675429"
+"4748422492761"
+},
+
+
+{NID_undef,NULL, NULL, NULL}
+};
+
+R3410_2001_params R3410_2001_paramset[]={
+ /* default_cc_sign01_param 1.2.643.2.9.1.8.1 */
+ {NID_id_GostR3410_2001_ParamSet_cc,
+ /* A */
+ "C0000000000000000000000000000000000000000000000000000000000003c4",
+ /* B */
+ "2d06B4265ebc749ff7d0f1f1f88232e81632e9088fd44b7787d5e407e955080c",
+ /* P */
+ "C0000000000000000000000000000000000000000000000000000000000003C7",
+ /* Q */
+ "5fffffffffffffffffffffffffffffff606117a2f4bde428b7458a54b6e87b85",
+ /* X */
+ "2",
+ /* Y */
+ "a20e034bf8813ef5c18d01105e726a17eb248b264ae9706f440bedc8ccb6b22c"
+ },
+ /* 1.2.643.2.2.35.0 */
+ {NID_id_GostR3410_2001_TestParamSet,
+ "7",
+ "5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E",
+ "8000000000000000000000000000000000000000000000000000000000000431",
+ "8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3",
+ "2",
+ "08E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8"
+ },
+ /*1.2.643.2.2.35.1*/
+ {NID_id_GostR3410_2001_CryptoPro_A_ParamSet,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
+ "a6",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893",
+ "1",
+ "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14"
+ },
+ /*1.2.643.2.2.35.2*/
+ {NID_id_GostR3410_2001_CryptoPro_B_ParamSet,
+ "8000000000000000000000000000000000000000000000000000000000000C96",
+ "3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B",
+ "8000000000000000000000000000000000000000000000000000000000000C99",
+ "800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F",
+ "1",
+ "3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC"
+ },
+ /*1.2.643.2.2.35.3*/
+ {NID_id_GostR3410_2001_CryptoPro_C_ParamSet,
+ "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598",
+ "805a",
+ "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B",
+ "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9",
+ "0",
+ "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67"
+ },
+ /*1.2.643.2.2.36.0*/
+ {NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
+ "a6",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893",
+ "1",
+ "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14"
+ },
+ /*1.2.643.2.2.36.1*/
+ {NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet,
+ "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598",
+ "805a",
+ "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B",
+ "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9",
+ "0",
+ "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67"
+ },
+ { 0,NULL,NULL,NULL,NULL,NULL,NULL
+ }
+};
diff --git a/engines/ccgost/paramset.h b/engines/ccgost/paramset.h
new file mode 100644
index 0000000000..002ac7857b
--- /dev/null
+++ b/engines/ccgost/paramset.h
@@ -0,0 +1,34 @@
+/**********************************************************************
+ * paramset.h *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Declaration of structures used to represent GOST R 34.10 *
+ * parameter sets, defined in RFC 4357 *
+ * OpenSSL 0.9.9 libraries required to compile and use *
+ * this code *
+ **********************************************************************/
+#ifndef GOST_PARAMSET_H
+#define GOST_PARAMSET_H
+typedef struct R3410 {
+ int nid;
+ char *a;
+ char *p;
+ char *q;
+} R3410_params;
+
+extern R3410_params R3410_paramset[];
+
+typedef struct R3410_2001 {
+ int nid;
+ char *a;
+ char *b;
+ char *p;
+ char *q;
+ char *x;
+ char *y;
+} R3410_2001_params;
+
+extern R3410_2001_params R3410_2001_paramset[];
+
+#endif
diff --git a/engines/ccgost/pmeth.c b/engines/ccgost/pmeth.c
new file mode 100644
index 0000000000..2698e4f937
--- /dev/null
+++ b/engines/ccgost/pmeth.c
@@ -0,0 +1,514 @@
+/**********************************************************************
+ * pmeth.c *
+ * Copyright (c) 2005-2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Implementation of RFC 4357 (GOST R 34.10) Publick key method *
+ * for OpenSSL *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/ec.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "meth.h"
+#include "pmeth.h"
+#include "sign.h"
+#include "gostkeyx.h"
+#include "paramset.h"
+#include "tools.h"
+#include "e_gost_err.h"
+/*-------init, cleanup, copy - uniform for all algs ---------------*/
+/* Allocates new gost_pmeth_data structure and assigns it as data */
+static int pkey_gost_init(EVP_PKEY_CTX *ctx) {
+ struct gost_pmeth_data *data;
+ data = OPENSSL_malloc(sizeof(struct gost_pmeth_data));
+ if (!data) return 0;
+ memset(data,0,sizeof(struct gost_pmeth_data));
+ EVP_PKEY_CTX_set_data(ctx,data);
+ return 1;
+}
+/* Copies contents of gost_pmeth_data structure */
+static int pkey_gost_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
+{
+ struct gost_pmeth_data *dst_data,*src_data;
+ if (!pkey_gost_init(dst)) {
+ return 0;
+ }
+ src_data = EVP_PKEY_CTX_get_data(src);
+ dst_data = EVP_PKEY_CTX_get_data(dst);
+ *dst_data = *src_data;
+ if (src_data -> eph_seckey) {
+ dst_data ->eph_seckey = NULL;
+ }
+ return 1;
+}
+/* Frees up gost_pmeth_data structure */
+static void pkey_gost_cleanup (EVP_PKEY_CTX *ctx) {
+ struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
+ if (data->eph_seckey) EVP_PKEY_free(data->eph_seckey);
+ OPENSSL_free(data);
+}
+/* --------------------- control functions ------------------------------*/
+static int pkey_gost_ctrl (EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
+{
+ struct gost_pmeth_data *pctx = (struct gost_pmeth_data*)EVP_PKEY_CTX_get_data(ctx);
+ switch (type)
+ {
+ case EVP_PKEY_CTRL_MD:
+ {
+ if (EVP_MD_type((const EVP_MD *)p2) != NID_id_GostR3411_94) {
+ GOSTerr(GOST_F_PKEY_GOST_CTRL, GOST_R_INVALID_DIGEST_TYPE);
+ return 0;
+ }
+ pctx->md = (EVP_MD *)p2;
+ return 1;
+ }
+ break;
+
+ case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
+ case EVP_PKEY_CTRL_PKCS7_DECRYPT:
+ case EVP_PKEY_CTRL_PKCS7_SIGN:
+ return 1;
+
+ case EVP_PKEY_CTRL_GOST_PARAMSET:
+ pctx->sign_param_nid = (int)p1;
+ pctx->crypt_param_nid= (int)p2;
+ return 1;
+
+ }
+ return -2;
+}
+
+static int pkey_gost_ctrl94cc_str(EVP_PKEY_CTX *ctx,
+ const char *type, const char *value)
+{
+ if(!strcmp(type, param_ctrl_string)) {
+ return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
+ NID_id_GostR3410_94_CryptoPro_A_ParamSet,
+ (void *)NID_id_Gost28147_89_cc);
+ }
+ return -2;
+}
+
+static int pkey_gost_ctrl01cc_str(EVP_PKEY_CTX *ctx,
+ const char *type, const char *value)
+{
+ if(!strcmp(type, param_ctrl_string)) {
+ return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
+ NID_id_GostR3410_2001_ParamSet_cc,
+ (void *)
+ NID_id_Gost28147_89_cc);
+ }
+ return -2;
+}
+static int pkey_gost_ctrl94_str(EVP_PKEY_CTX *ctx,
+ const char *type, const char *value)
+{
+ int param_nid=0;
+ if(!strcmp(type, param_ctrl_string)) {
+ if (!value) {
+ return 0;
+ }
+ if (strlen(value) == 1) {
+ switch(toupper(value[0])) {
+ case 'A':
+ param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet;
+ break;
+ case 'B':
+ param_nid = NID_id_GostR3410_94_CryptoPro_B_ParamSet;
+ break;
+ case 'C':
+ param_nid = NID_id_GostR3410_94_CryptoPro_C_ParamSet;
+ break;
+ case 'D':
+ param_nid = NID_id_GostR3410_94_CryptoPro_D_ParamSet;
+ break;
+ default:
+ return 0;
+ break;
+ }
+ } else if ((strlen(value) == 2) && (toupper(value[0]) == 'X')) {
+ switch (toupper(value[1])) {
+ case 'A':
+ param_nid = NID_id_GostR3410_94_CryptoPro_XchA_ParamSet;
+ break;
+ case 'B':
+ param_nid = NID_id_GostR3410_94_CryptoPro_XchB_ParamSet;
+ break;
+ case 'C':
+ param_nid = NID_id_GostR3410_94_CryptoPro_XchC_ParamSet;
+ break;
+ default:
+ return 0;
+ break;
+ }
+ } else {
+ R3410_params *p = R3410_paramset;
+ param_nid = OBJ_txt2nid(value);
+ if (param_nid == NID_undef) {
+ return 0;
+ }
+ for (;p->nid != NID_undef;p++) {
+ if (p->nid == param_nid) break;
+ }
+ if (p->nid == NID_undef) {
+ GOSTerr(GOST_F_PKEY_GOST_CTRL94_STR,
+ GOST_R_INVALID_PARAMSET);
+ return 0;
+ }
+ }
+
+ return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
+ param_nid, (void *)NID_id_Gost28147_89_CryptoPro_A_ParamSet);
+ }
+ return -2;
+}
+
+static int pkey_gost_ctrl01_str(EVP_PKEY_CTX *ctx,
+ const char *type, const char *value)
+{
+ int param_nid=0;
+ if(!strcmp(type, param_ctrl_string)) {
+ if (!value) {
+ return 0;
+ }
+ if (strlen(value) == 1) {
+ switch(toupper(value[0])) {
+ case 'A':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_A_ParamSet;
+ break;
+ case 'B':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_B_ParamSet;
+ break;
+ case 'C':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_C_ParamSet;
+ break;
+ case '0':
+ param_nid = NID_id_GostR3410_2001_TestParamSet;
+ break;
+ default:
+ return 0;
+ break;
+ }
+ } else if ((strlen(value) == 2) && (toupper(value[0]) == 'X')) {
+ switch (toupper(value[1])) {
+ case 'A':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet;
+ break;
+ case 'B':
+ param_nid = NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet;
+ break;
+ default:
+ return 0;
+ break;
+ }
+ } else {
+ R3410_2001_params *p = R3410_2001_paramset;
+ param_nid = OBJ_txt2nid(value);
+ if (param_nid == NID_undef) {
+ return 0;
+ }
+ for (;p->nid != NID_undef;p++) {
+ if (p->nid == param_nid) break;
+ }
+ if (p->nid == NID_undef) {
+ GOSTerr(GOST_F_PKEY_GOST_CTRL01_STR,
+ GOST_R_INVALID_PARAMSET);
+ return 0;
+ }
+ }
+
+ return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
+ param_nid, (void *)NID_id_Gost28147_89_CryptoPro_A_ParamSet);
+ }
+ return -2;
+}
+/* --------------------- key generation --------------------------------*/
+/* Generates GOST 94 key and assigns it setting specified type */
+static int pkey_gost94_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey,int type)
+{
+ struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
+ DSA *dsa=NULL;
+ if (data->sign_param_nid == NID_undef) {
+ if (type== NID_id_GostR3410_94_cc) {
+ data->sign_param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet;
+ } else {
+ GOSTerr(GOST_F_PKEY_GOST94_KEYGEN,
+ GOST_R_NO_PARAMETERS_SET);
+ return 0;
+ }
+ }
+ dsa = DSA_new();
+ if (!fill_GOST94_params(dsa,data->sign_param_nid)) {
+ DSA_free(dsa);
+ return 0;
+ }
+ gost_sign_keygen(dsa);
+ EVP_PKEY_assign(pkey,type,dsa);
+ return 1;
+}
+/* Generates Gost_R3410_94_cc key */
+static int pkey_gost94cc_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+ return pkey_gost94_keygen(ctx,pkey,NID_id_GostR3410_94_cc);
+}
+
+/* Generates Gost_R3410_94_cp key */
+static int pkey_gost94cp_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+ return pkey_gost94_keygen(ctx,pkey,NID_id_GostR3410_94);
+}
+/* Generates GOST_R3410 2001 key and assigns it using specified type */
+static int pkey_gost01_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey,int type)
+{
+ struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
+ EC_KEY *ec=NULL;
+ if (data->sign_param_nid == NID_undef) {
+ if (type == NID_id_GostR3410_2001_cc) {
+ data->sign_param_nid = NID_id_GostR3410_2001_ParamSet_cc;
+ } else {
+ GOSTerr(GOST_F_PKEY_GOST01_KEYGEN,
+ GOST_R_NO_PARAMETERS_SET);
+ return 0;
+ }
+ }
+ ec = EC_KEY_new();
+ if (!fill_GOST2001_params(ec,data->sign_param_nid)) {
+ EC_KEY_free(ec);
+ return 0;
+ }
+ gost2001_keygen(ec);
+
+ EVP_PKEY_assign(pkey,type,ec);
+ return 1;
+}
+/* Generates GOST R3410 2001_cc key */
+static int pkey_gost01cc_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+ return pkey_gost01_keygen(ctx,pkey,NID_id_GostR3410_2001_cc);
+}
+
+/* Generates GOST R3410 2001_cp key */
+static int pkey_gost01cp_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+ return pkey_gost01_keygen(ctx,pkey,NID_id_GostR3410_2001);
+}
+/* ----------- sign callbacks --------------------------------------*/
+static int pkey_gost94_cc_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+ const unsigned char *tbs, size_t tbs_len)
+{
+ DSA_SIG *unpacked_sig=NULL;
+ EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
+ if (!siglen) return 0;
+ if (!sig)
+ {
+ *siglen= 64; /* better to check size of pkey->pkey.dsa-q */
+ return 1;
+ }
+ unpacked_sig = gost_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
+ if (!unpacked_sig) {
+ return 0;
+ }
+
+ return pack_sign_cc(unpacked_sig,32,sig,siglen);
+
+
+}
+static int pkey_gost94_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+ const unsigned char *tbs, size_t tbs_len)
+{
+ DSA_SIG *unpacked_sig=NULL;
+ EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
+ if (!siglen) return 0;
+ if (!sig)
+ {
+ *siglen= 64; /* better to check size of pkey->pkey.dsa-q */
+ return 1;
+ }
+ unpacked_sig = gost_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
+ if (!unpacked_sig) {
+ return 0;
+ }
+ return pack_sign_cp(unpacked_sig,32,sig,siglen);
+
+
+}
+static int pkey_gost01_cc_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+ const unsigned char *tbs, size_t tbs_len)
+{
+ DSA_SIG *unpacked_sig=NULL;
+ EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
+ if (!siglen) return 0;
+ if (!sig)
+ {
+ *siglen= 64; /* better to check size of curve order*/
+ return 1;
+ }
+ unpacked_sig = gost2001_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
+ if (!unpacked_sig) {
+ return 0;
+ }
+ return pack_sign_cc(unpacked_sig,32,sig,siglen);
+}
+static int pkey_gost01_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+ const unsigned char *tbs, size_t tbs_len)
+{
+ DSA_SIG *unpacked_sig=NULL;
+ EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
+ if (!siglen) return 0;
+ if (!sig)
+ {
+ *siglen= 64; /* better to check size of curve order*/
+ return 1;
+ }
+ unpacked_sig = gost2001_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
+ if (!unpacked_sig) {
+ return 0;
+ }
+ return pack_sign_cp(unpacked_sig,32,sig,siglen);
+}
+/* ------------------- verify callbacks ---------------------------*/
+static int pkey_gost94_cc_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
+ size_t siglen, const unsigned char *tbs, size_t tbs_len)
+{
+ int ok = 0;
+ EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
+ DSA_SIG *s=unpack_cc_signature(sig,siglen);
+ if (!s) return 0;
+ if (pub_key) ok = gost_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
+ DSA_SIG_free(s);
+ return ok;
+}
+
+static int pkey_gost94_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
+ size_t siglen, const unsigned char *tbs, size_t tbs_len)
+{
+ int ok = 0;
+ EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
+ DSA_SIG *s=unpack_cp_signature(sig,siglen);
+ if (!s) return 0;
+ if (pub_key) ok = gost_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
+ DSA_SIG_free(s);
+ return ok;
+}
+static int pkey_gost01_cc_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
+ size_t siglen, const unsigned char *tbs, size_t tbs_len)
+{
+ int ok = 0;
+ EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
+ DSA_SIG *s=unpack_cc_signature(sig,siglen);
+ fprintf(stderr,"R=");
+ BN_print_fp(stderr,s->r);
+ fprintf(stderr,"\nS=");
+ BN_print_fp(stderr,s->s);
+ fprintf(stderr,"\n");
+ if (!s) return 0;
+ if (pub_key) ok = gost2001_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
+ DSA_SIG_free(s);
+ return ok;
+}
+
+static int pkey_gost01_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
+ size_t siglen, const unsigned char *tbs, size_t tbs_len)
+{
+ int ok = 0;
+ EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
+ DSA_SIG *s=unpack_cp_signature(sig,siglen);
+ if (!s) return 0;
+ fprintf(stderr,"R=");
+ BN_print_fp(stderr,s->r);
+ fprintf(stderr,"\nS=");
+ BN_print_fp(stderr,s->s);
+ fprintf(stderr,"\n");
+ if (pub_key) ok = gost2001_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
+ DSA_SIG_free(s);
+ return ok;
+}
+/* ------------- encrypt init -------------------------------------*/
+/* Generates ephermeral key */
+static int pkey_gost_encrypt_init(EVP_PKEY_CTX *ctx)
+{
+ struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
+ EVP_PKEY *eph_key = EVP_PKEY_new();
+ EVP_PKEY *old_key =EVP_PKEY_CTX_get0_pkey(ctx);
+
+ if (data->eph_seckey) EVP_PKEY_free(data->eph_seckey);
+ EVP_PKEY_assign(eph_key,EVP_PKEY_base_id(old_key),NULL);
+ if (!EVP_PKEY_copy_parameters(eph_key,old_key)) return 0;
+ switch (EVP_PKEY_base_id(old_key)) {
+ case NID_id_GostR3410_2001:
+ case NID_id_GostR3410_2001_cc:
+ gost2001_keygen(EVP_PKEY_get0(eph_key));
+ break;
+ case NID_id_GostR3410_94:
+ case NID_id_GostR3410_94_cc:
+ gost_sign_keygen(EVP_PKEY_get0(eph_key));
+ break;
+
+
+ }
+
+
+ data->eph_seckey=eph_key;
+ return 1;
+}
+/* ----------------------------------------------------------------*/
+int register_pmeth_gost(int id, EVP_PKEY_METHOD **pmeth,int flags) {
+ *pmeth = EVP_PKEY_meth_new(id, flags);
+ if (!*pmeth) return 0;
+
+ switch (id) {
+ case NID_id_GostR3410_94_cc:
+ EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl94cc_str);
+ EVP_PKEY_meth_set_keygen(*pmeth,NULL,pkey_gost94cc_keygen);
+ EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost94_cc_sign);
+ EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost94_cc_verify);
+ EVP_PKEY_meth_set_encrypt(*pmeth,
+ pkey_gost_encrypt_init, pkey_GOST94cc_encrypt);
+ EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST94cc_decrypt);
+ break;
+ case NID_id_GostR3410_94:
+ EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl94_str);
+ EVP_PKEY_meth_set_keygen(*pmeth,NULL,pkey_gost94cp_keygen);
+ EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost94_cp_sign);
+ EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost94_cp_verify);
+ EVP_PKEY_meth_set_encrypt(*pmeth,
+ pkey_gost_encrypt_init, pkey_GOST94cp_encrypt);
+ EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST94cp_decrypt);
+
+
+ break;
+ case NID_id_GostR3410_2001_cc:
+ EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl01cc_str);
+ EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost01_cc_sign);
+ EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost01_cc_verify);
+
+ EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost01cc_keygen);
+
+ EVP_PKEY_meth_set_encrypt(*pmeth,
+ pkey_gost_encrypt_init, pkey_GOST01cc_encrypt);
+ EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST01cc_decrypt);
+ break;
+ /* There is intentionally no break here */
+ case NID_id_GostR3410_2001:
+ EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl01_str);
+ EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost01_cp_sign);
+ EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost01_cp_verify);
+
+ EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost01cp_keygen);
+
+ EVP_PKEY_meth_set_encrypt(*pmeth,
+ pkey_gost_encrypt_init, pkey_GOST01cp_encrypt);
+ EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST01cp_decrypt);
+ break;
+ default: //Unsupported method
+ return 0;
+ }
+ EVP_PKEY_meth_set_init(*pmeth, pkey_gost_init);
+ EVP_PKEY_meth_set_cleanup(*pmeth, pkey_gost_cleanup);
+
+ EVP_PKEY_meth_set_copy(*pmeth, pkey_gost_copy);
+ //FIXME derive etc...
+
+ return 1;
+}
+
diff --git a/engines/ccgost/pmeth.h b/engines/ccgost/pmeth.h
new file mode 100644
index 0000000000..a94f778f09
--- /dev/null
+++ b/engines/ccgost/pmeth.h
@@ -0,0 +1,26 @@
+#ifndef GOST_PMETH_H
+#define GOST_PMETH_H
+/**********************************************************************
+ * pmeth.h *
+ * Copyright (c) 2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Declaration of GOST PKEY context internal data *
+ * *
+ * Requires OpenSSL 0.9.9 for compilation *
+ **********************************************************************/
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+
+/* Gost-specific control-function parameters */
+#define param_ctrl_string "paramset"
+#define EVP_PKEY_CTRL_GOST_PARAMSET (EVP_PKEY_ALG_CTRL+1)
+
+ struct gost_pmeth_data {
+ int sign_param_nid; /* Should be set whenever parameters are filled */
+ int crypt_param_nid;
+ EVP_PKEY *eph_seckey;
+ EVP_MD *md;
+ };
+
+#endif
diff --git a/engines/ccgost/sign.h b/engines/ccgost/sign.h
new file mode 100644
index 0000000000..c697c4fedb
--- /dev/null
+++ b/engines/ccgost/sign.h
@@ -0,0 +1,30 @@
+#ifndef GOST_SIGN_H
+#define GOST_SIGN_H
+/**********************************************************************
+ * sign.h *
+ * Copyright (c) 2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Declaration of internal funtions implementing GOST R 34.10 *
+ * signature and key generation *
+ * OpenSSL 0.9.9 libraries required to compile and use *
+ * this code *
+ **********************************************************************/
+#include <openssl/evp.h>
+#include <openssl/dsa.h>
+#include <openssl/ec.h>
+int fill_GOST94_params(DSA *dsa,int nid);
+int fill_GOST2001_params(EC_KEY *eckey, int nid);
+int gost_sign_keygen(DSA *dsa) ;
+int gost2001_keygen(EC_KEY *ec) ;
+
+DSA_SIG *gost_do_sign(const unsigned char *dgst,int dlen, DSA *dsa) ;
+DSA_SIG *gost2001_do_sign(const unsigned char *dgst,int dlen, EC_KEY *eckey);
+
+int gost_do_verify(const unsigned char *dgst, int dgst_len,
+ DSA_SIG *sig, DSA *dsa) ;
+int gost2001_do_verify(const unsigned char *dgst,int dgst_len,
+ DSA_SIG *sig, EC_KEY *ec);
+int gost2001_compute_public(EC_KEY *ec) ;
+int gost94_compute_public(DSA *dsa) ;
+#endif
diff --git a/engines/ccgost/tools.h b/engines/ccgost/tools.h
new file mode 100644
index 0000000000..db3d6089f3
--- /dev/null
+++ b/engines/ccgost/tools.h
@@ -0,0 +1,38 @@
+#ifndef GOST_TOOLS_H
+#define GOST_TOOLS_H
+/**********************************************************************
+ * sign.h *
+ * Copyright (c) 2006 Cryptocom LTD *
+ * This file is distributed under the same license as OpenSSL *
+ * *
+ * Miscellaneous functions used in GOST engine *
+ * OpenSSL 0.9.9 libraries required to compile and use *
+ * this code *
+ **********************************************************************/
+#include <openssl/evp.h>
+#include <openssl/dsa.h>
+
+/* from gost_sign.c */
+/* Convert GOST R 34.11 hash sum to bignum according to standard */
+BIGNUM *hashsum2bn(const unsigned char *dgst) ;
+/* Store bignum in byte array of given length, prepending by zeros
+ * if nesseccary */
+int store_bignum(BIGNUM *bn, unsigned char *buf,int len);
+/* Read bignum, which can have few MSB all-zeros from buffer*/
+BIGNUM *getbnfrombuf(const unsigned char *buf,size_t len);
+/* Pack GOST R 34.10 signature according to CryptoCom rules */
+int pack_sign_cc(DSA_SIG *s,int order,unsigned char *sig, unsigned int *siglen);
+/* Pack GOST R 34.10 signature according to CryptoPro rules */
+int pack_sign_cp(DSA_SIG *s,int order,unsigned char *sig, unsigned int *siglen);
+/* Unpack GOST R 34.10 signature according to CryptoCom rules */
+DSA_SIG *unpack_cc_signature(const unsigned char *sig,size_t siglen) ;
+/* Unpack GOST R 34.10 signature according to CryptoPro rules */
+DSA_SIG *unpack_cp_signature(const unsigned char *sig,size_t siglen) ;
+/* from ameth.c */
+/* Get private key as BIGNUM from both R 34.10-94 and R 34.10-2001 keys*/
+BIGNUM* gost_get_priv_key(const EVP_PKEY *pkey) ;
+/* Find NID by GOST 94 parameters */
+int gost94_nid_by_params(DSA *p) ;
+
+
+#endif