Remove Gost94 signature algorithm.
[openssl.git] / engines / ccgost / gost_ameth.c
index f5ac9c2d80155a6be4c024f189391b74e99f37d8..4f3bd90e81a2c98c0114609a0e5cf14fa8bc8715 100644 (file)
  *       for OpenSSL                                                  *
  *          Requires OpenSSL 0.9.9 for compilation                    *
  **********************************************************************/
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
 #include <openssl/engine.h>
 #include <openssl/evp.h>
 #include <openssl/asn1.h>
-#include <string.h>
-#include "gost_params.h"
+#ifndef OPENSSL_NO_CMS
+# include <openssl/cms.h>
+#endif
 #include "gost_lcl.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
+
+/* Convert little-endian byte array into bignum */
+BIGNUM *hashsum2bn(const unsigned char *dgst)
+{
+    unsigned char buf[32];
+
+    BUF_reverse(buf, (unsigned char*)dgst, 32);
+    return BN_bin2bn(buf, 32, NULL);
+}
+
+/*
+ * Pack bignum into byte buffer of given size, filling all leading bytes by
+ * zeros
  */
-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;
-        void *_pval;
-       ASN1_STRING *pval = NULL;
-       const unsigned char  *p;
-       GOST_KEY_PARAMS *gkp = NULL;
-
-       X509_ALGOR_get0(&palg_obj, &ptype, &_pval, palg);
-        pval = _pval;
-       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);
-               return 0;
-               }       
-       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);
-               }
-       }       
+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;
+}
+
+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;
+
+    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:
+        pkey_param_nid =
+            EC_GROUP_get_curve_name(EC_KEY_get0_group
+                                    (EVP_PKEY_get0((EVP_PKEY *)key)));
+        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;
+    void *_pval;
+    ASN1_STRING *pval = NULL;
+    const unsigned char *p;
+    GOST_KEY_PARAMS *gkp = NULL;
+
+    X509_ALGOR_get0(&palg_obj, &ptype, &_pval, palg);
+    pval = _pval;
+    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);
+        return 0;
+    }
+    param_nid = OBJ_obj2nid(gkp->key_params);
+    GOST_KEY_PARAMS_free(gkp);
+    if (!EVP_PKEY_set_type(pkey, pkey_nid)) {
+        GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    switch (pkey_nid) {
+    case NID_id_GostR3410_2001:
+        {
+            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_2001:
+        {
+            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_get0_priv_key(const EVP_PKEY *pkey)
+{
+    switch (EVP_PKEY_base_id(pkey)) {
+    case NID_id_GostR3410_2001:
+        {
+            EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pkey);
+            const BIGNUM *priv;
+            if (!ec) {
+                return NULL;
+            }
+            if ((priv = EC_KEY_get0_private_key(ec)) == NULL)
+                return NULL;
+            return (BIGNUM *)priv;
+        }
+    }
+    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;
+#ifndef OPENSSL_NO_CMS
+    case ASN1_PKEY_CTRL_CMS_SIGN:
+        if (arg1 == 0) {
+            X509_ALGOR *alg1 = NULL, *alg2 = NULL;
+            int nid = EVP_PKEY_base_id(pkey);
+            CMS_SignerInfo_get0_algs((CMS_SignerInfo *)arg2,
+                                     NULL, 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;
+#endif
+    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;
+#ifndef OPENSSL_NO_CMS
+    case ASN1_PKEY_CTRL_CMS_ENVELOPE:
+        if (arg1 == 0) {
+            X509_ALGOR *alg = NULL;
+            ASN1_STRING *params = encode_gost_algor_params(pkey);
+            if (!params) {
+                return -1;
+            }
+            CMS_RecipientInfo_ktri_get0_algs((CMS_RecipientInfo *)arg2, NULL,
+                                             NULL, &alg);
+            X509_ALGOR_set0(alg, OBJ_nid2obj(pkey->type), V_ASN1_SEQUENCE,
+                            params);
+        }
+        return 1;
+#endif
+    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+        *(int *)arg2 = NID_id_GostR3411_94;
+        return 2;
+    }
+
+    return -2;
+}
+
+/* --------------------- free functions * ------------------------------*/
+static void pkey_free_gost01(EVP_PKEY *key)
+{
+    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;
-               }
-       if (V_ASN1_OCTET_STRING == *p) 
-               {
-               /* New format - Little endian octet string */
-               unsigned char rev_buf[32];
-               int i;
-               ASN1_OCTET_STRING *s = d2i_ASN1_OCTET_STRING(NULL,&p,priv_len);
-               if (!s||s->length !=32) 
-                       {
-                       GOSTerr(GOST_F_PRIV_DECODE_GOST_94,
-                               EVP_R_DECODE_ERROR);
-                       return 0;       
-                       }
-               for (i=0;i<32;i++)
-                       {
-                       rev_buf[31-i]=s->data[i];
-                       }
-               ASN1_STRING_free(s);
-               pk_num = getbnfrombuf(rev_buf,32);
-               } 
-       else
-               {
-               priv_key=d2i_ASN1_INTEGER(NULL,&p,priv_len);
-               if (!priv_key || !(pk_num =  ASN1_INTEGER_to_BN(priv_key, NULL))) 
-                       {
-                       GOSTerr(GOST_F_PRIV_DECODE_GOST_94,
-                               EVP_R_DECODE_ERROR);
-                       return 0;       
-                       }
-               }
-
-       ret= gost_set_priv_key(pk,pk_num);
-       BN_free(pk_num);
-       return ret;
-       }
+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;
+    }
+    if (V_ASN1_OCTET_STRING == *p) {
+        /* New format - Little endian octet string */
+        unsigned char rev_buf[32];
+        int i;
+        ASN1_OCTET_STRING *s = d2i_ASN1_OCTET_STRING(NULL, &p, priv_len);
+        if (!s || s->length != 32) {
+            GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR);
+            return 0;
+        }
+        for (i = 0; i < 32; i++) {
+            rev_buf[31 - i] = s->data[i];
+        }
+        ASN1_STRING_free(s);
+        pk_num = getbnfrombuf(rev_buf, 32);
+    } else {
+        priv_key = d2i_ASN1_INTEGER(NULL, &p, priv_len);
+        if (!priv_key)
+            return 0;
+        ret = ((pk_num = ASN1_INTEGER_to_BN(priv_key, NULL)) != NULL);
+        ASN1_INTEGER_free(priv_key);
+        if (!ret) {
+            GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR);
+            return 0;
+        }
+    }
+
+    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;
-       }
+{
+    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;
+
+    ASN1_INTEGER *asn1key = NULL;
+    if (!params) {
+        return 0;
+    }
+    asn1key = BN_to_ASN1_INTEGER(gost_get0_priv_key(pk), NULL);
+    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);
+}
+
+/* --------- printing keys --------------------------------*/
+static int print_gost_01(BIO *out, const EVP_PKEY *pkey, int indent,
+                         ASN1_PCTX *pctx, int type)
+{
+    int param_nid = NID_undef;
+    if (type == 2) {
+        BIGNUM *key;
+
+        if (!BIO_indent(out, indent, 128))
+            return 0;
+        BIO_printf(out, "Private key: ");
+        key = gost_get0_priv_key(pkey);
+        if (!key)
+            BIO_printf(out, "<undefined)");
+        else
+            BN_print(out, key);
+        BIO_printf(out, "\n");
+    }
+    if (type >= 1) {
+        BN_CTX *ctx = BN_CTX_new();
+        BIGNUM *X, *Y;
+        const EC_POINT *pubkey;
+        const EC_GROUP *group;
+
+        if (!ctx) {
+            GOSTerr(GOST_F_PRINT_GOST_01, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        BN_CTX_start(ctx);
+        X = BN_CTX_get(ctx);
+        Y = BN_CTX_get(ctx);
+        pubkey =
+            EC_KEY_get0_public_key((EC_KEY *)EVP_PKEY_get0((EVP_PKEY *)pkey));
+        group = EC_KEY_get0_group((EC_KEY *)EVP_PKEY_get0((EVP_PKEY *)pkey));
+        if (!EC_POINT_get_affine_coordinates_GFp(group, pubkey, X, Y, ctx)) {
+            GOSTerr(GOST_F_PRINT_GOST_01, ERR_R_EC_LIB);
+            BN_CTX_free(ctx);
+            return 0;
+        }
+        if (!BIO_indent(out, indent, 128))
+            return 0;
+        BIO_printf(out, "Public key:\n");
+        if (!BIO_indent(out, indent + 3, 128))
+            return 0;
+        BIO_printf(out, "X:");
+        BN_print(out, X);
+        BIO_printf(out, "\n");
+        BIO_indent(out, indent + 3, 128);
+        BIO_printf(out, "Y:");
+        BN_print(out, Y);
+        BIO_printf(out, "\n");
+        BN_CTX_end(ctx);
+        BN_CTX_free(ctx);
+    }
+
+    param_nid =
+        EC_GROUP_get_curve_name(EC_KEY_get0_group
+                                (EVP_PKEY_get0((EVP_PKEY *)pkey)));
+    if (!BIO_indent(out, indent, 128))
+        return 0;
+    BIO_printf(out, "Parameter set: %s\n", OBJ_nid2ln(param_nid));
+    return 1;
+}
+
+static int param_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent,
+                              ASN1_PCTX *pctx)
+{
+    return print_gost_01(out, pkey, indent, pctx, 0);
+}
+
+static int pub_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent,
+                            ASN1_PCTX *pctx)
+{
+    return print_gost_01(out, pkey, indent, pctx, 1);
+}
+
+static int priv_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent,
+                             ASN1_PCTX *pctx)
+{
+    return print_gost_01(out, pkey, indent, pctx, 2);
+}
 
 /* ---------------------------------------------------------------------*/
-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;
-
-       }
+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_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_GOST01, GOST_R_KEY_PARAMETERS_MISSING);
+        return 0;
+    }
+    if (!eto) {
+        eto = EC_KEY_new();
+        if (!eto) {
+            GOSTerr(GOST_F_PARAM_COPY_GOST01, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        if (!EVP_PKEY_assign(to, EVP_PKEY_base_id(from), eto)) {
+            GOSTerr(GOST_F_PARAM_COPY_GOST01, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+    if (!EC_KEY_set_group(eto, EC_KEY_get0_group(efrom))) {
+        GOSTerr(GOST_F_PARAM_COPY_GOST01, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    if (EC_KEY_get0_private_key(eto)) {
+        gost2001_compute_public(eto);
+    }
+    return 1;
+}
+
+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 = V_ASN1_UNDEF;
-       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 = V_ASN1_UNDEF;
-
-       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 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;
+    int len;
+    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_GOST01, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    databuf = OPENSSL_malloc(octet->length);
+    if (databuf == NULL) {
+        GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_MALLOC_FAILURE);
+        ASN1_OCTET_STRING_free(octet);
+        return 0;
+    }
+    for (i = 0, j = octet->length - 1; i < octet->length; i++, j--) {
+        databuf[j] = octet->data[i];
+    }
+    len = octet->length / 2;
+    ASN1_OCTET_STRING_free(octet);
+
+    Y = getbnfrombuf(databuf, len);
+    X = getbnfrombuf(databuf + len, len);
+    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);
+        EC_POINT_free(pub_key);
+        BN_free(X);
+        BN_free(Y);
+        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);
+        EC_POINT_free(pub_key);
+        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 = V_ASN1_UNDEF;
+
+    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);
+        BN_free(order);
+        return 0;
+    }
+    X = BN_new();
+    Y = BN_new();
+    if (!X || !Y) {
+        GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_MALLOC_FAILURE);
+        BN_free(X);
+        BN_free(Y);
+        BN_free(order);
+        return 0;
+    }
+    if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec),
+                                        pub_key, X, Y, NULL)) {
+        GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_INTERNAL_ERROR);
+        BN_free(X);
+        BN_free(Y);
+        BN_free(order);
+        return 0;
+    }
+    data_len = 2 * BN_num_bytes(order);
+    BN_free(order);
+    databuf = OPENSSL_malloc(data_len);
+    if (databuf == NULL) {
+        GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_MALLOC_FAILURE);
+        BN_free(X);
+        BN_free(Y);
+        return 0;
+    }
+    memset(databuf, 0, data_len);
+
+    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();
+    if (octet == NULL) {
+        GOSTerr(GOST_F_PUB_ENCODE_GOST01, ERR_R_MALLOC_FAILURE);
+        OPENSSL_free(databuf);
+        return 0;
+    }
+    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_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 pkey_size_gost(const EVP_PKEY *pk)
-       {
-       return 64;
-       }
+{
+    return 64;
+}
 
 static int pkey_bits_gost(const EVP_PKEY *pk)
-       {
-       return 256;
-       }
-/*------------------------ ASN1 METHOD for GOST MAC  -------------------*/
-static void  mackey_free_gost(EVP_PKEY *pk)
-       {
-               if (pk->pkey.ptr) {
-                       OPENSSL_free(pk->pkey.ptr);
-               }       
-       }
-static int     priv_decode_mac(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf)
-       {       
-               X509_ALGOR *palg = NULL;
-               int priv_len = 0;
-               ASN1_OBJECT *palg_obj = NULL;
-               ASN1_OCTET_STRING *s=NULL;
-               const unsigned char *pkey_buf = NULL, *p = NULL;
-               unsigned char *keybuf=NULL;
-               if (!PKCS8_pkey_get0(&palg_obj,&pkey_buf,&priv_len,&palg,p8inf)) 
-                       {
-                       return 0;
-                       }
-               p = pkey_buf;
-               if (V_ASN1_OCTET_STRING != *p) 
-                       {
-                       GOSTerr(GOST_F_PRIV_DECODE_MAC,
-                               GOST_R_DECODE_ERROR);
-                       return 0;       
-                       }       
-               s = d2i_ASN1_OCTET_STRING(NULL,&p,priv_len);
-               if (!s || s->length!=32) 
-                       {
-                       GOSTerr(GOST_F_PRIV_DECODE_MAC,
-                               GOST_R_DECODE_ERROR);
-                       return 0;       
-                       }       
-               keybuf = OPENSSL_malloc(32);
-               memcpy(keybuf,s->data,32);
-               EVP_PKEY_assign(pk,EVP_PKEY_base_id(pk),keybuf);
-               ASN1_STRING_free(s);
-               return 1;
-       }
-       
-static int     priv_encode_mac(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk)
-       {
-       ASN1_OBJECT *algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk));
-       ASN1_STRING *key = ASN1_STRING_new();
-       unsigned char *priv_buf=NULL, *data = EVP_PKEY_get0((EVP_PKEY *)pk);
-       int priv_len;
-       
-       ASN1_STRING_set(key, data, 32);
-       priv_len = i2d_ASN1_OCTET_STRING(key,&priv_buf);
-       ASN1_STRING_free(key);
-       return PKCS8_pkey_set0(p8,algobj,0,V_ASN1_NULL,NULL,priv_buf,priv_len);
-       }
-
-static int     priv_print_mac(BIO *out,const EVP_PKEY *pkey, int indent,
-       ASN1_PCTX *pctx)
-       {
-               unsigned char *data = EVP_PKEY_get0((EVP_PKEY *)pkey);
-               int i;
-               if (!BIO_indent(out, indent,128)) return 0;
-               for (i=0; i<32;i++) {
-                       BIO_printf(out,"%02x",data[i]);
-               }
-               return 1;
-       }       
+{
+    return 256;
+}
+
+/* ---------------------- ASN1 METHOD for GOST MAC  -------------------*/
+static void mackey_free_gost(EVP_PKEY *pk)
+{
+    OPENSSL_free(pk->pkey.ptr);
+}
+
 static int mac_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2)
 {
-       switch (op)
-               {
-               case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
-                       *(int *)arg2 = NID_id_Gost28147_89_MAC;
-                       return 2;
-               }
-       return -2;
-}      
+    switch (op) {
+    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+        *(int *)arg2 = NID_id_Gost28147_89_MAC;
+        return 2;
+    }
+    return -2;
+}
+
+static int gost2001_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
+{
+    int nid =
+        EC_GROUP_get_curve_name(EC_KEY_get0_group
+                                (EVP_PKEY_get0((EVP_PKEY *)pkey)));
+    return i2d_ASN1_OBJECT(OBJ_nid2obj(nid), pder);
+}
+
+static int gost2001_param_decode(EVP_PKEY *pkey, const unsigned char **pder,
+                                 int derlen)
+{
+    ASN1_OBJECT *obj = NULL;
+    int nid;
+    EC_KEY *ec = EVP_PKEY_get0(pkey);
+    if (d2i_ASN1_OBJECT(&obj, pder, derlen) == NULL) {
+        return 0;
+    }
+    nid = OBJ_obj2nid(obj);
+    ASN1_OBJECT_free(obj);
+    if (!ec) {
+        ec = EC_KEY_new();
+        if (!EVP_PKEY_assign(pkey, NID_id_GostR3410_2001, ec))
+            return 0;
+    }
+    if (!fill_GOST2001_params(ec, nid))
+        return 0;
+    return 1;
+}
+
 /* ----------------------------------------------------------------------*/
-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;
-               case NID_id_Gost28147_89_MAC:
-                       EVP_PKEY_asn1_set_free(*ameth, mackey_free_gost);
-                       EVP_PKEY_asn1_set_private(*ameth, priv_decode_mac,
-                               priv_encode_mac, priv_print_mac);
-                       EVP_PKEY_asn1_set_ctrl(*ameth,mac_ctrl_gost);   
-                       break;
-               }               
-       return 1;
-       }
+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_2001:
+        EVP_PKEY_asn1_set_free(*ameth, pkey_free_gost01);
+        EVP_PKEY_asn1_set_private(*ameth,
+                                  priv_decode_gost, priv_encode_gost,
+                                  priv_print_gost01);
+
+        EVP_PKEY_asn1_set_param(*ameth,
+                                gost2001_param_decode, gost2001_param_encode,
+                                param_missing_gost01, param_copy_gost01,
+                                param_cmp_gost01, param_print_gost01);
+        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;
+    case NID_id_Gost28147_89_MAC:
+        EVP_PKEY_asn1_set_free(*ameth, mackey_free_gost);
+        EVP_PKEY_asn1_set_ctrl(*ameth, mac_ctrl_gost);
+        break;
+    }
+    return 1;
+}