summaryrefslogtreecommitdiffstats
path: root/engines
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
parentbc7535bc7fe30fbba222c316a3957da7d906603b (diff)
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')
-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 */