/**********************************************************************
* gost_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 <openssl/asn1.h>
#include <string.h>
#include "gost_params.h"
#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:
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, ¶ms->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);
EVP_PKEY_set_type(pkey,pkey_nid);
switch (pkey_nid)
{
case NID_id_GostR3410_94:
{
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:
{
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:
{
DSA *dsa = EVP_PKEY_get0(pkey);
if (!dsa)
{
dsa = DSA_new();
EVP_PKEY_assign(pkey,EVP_PKEY_base_id(pkey),dsa);
}
dsa->priv_key =<