0e1dba934f
of handshake failure 2. Changes to x509_certificate_type function (crypto/x509/x509type.c) to make it recognize GOST certificates as EVP_PKT_SIGN|EVP_PKT_EXCH (required for s3_srvr to accept GOST client certificates). 3. Changes to EVP - adding of function EVP_PKEY_CTX_get0_peerkey - Make function EVP_PKEY_derive_set_peerkey work for context with ENCRYPT operation, because we use peerkey field in the context to pass non-ephemeral secret key to GOST encrypt operation. - added EVP_PKEY_CTRL_SET_IV control command. It is really GOST-specific, but it is used in SSL code, so it has to go in some header file, available during libssl compilation 4. Fix to HMAC to avoid call of OPENSSL_cleanse on undefined data 5. Include des.h if KSSL_DEBUG is defined into some libssl files, to make debugging output which depends on constants defined there, work and other KSSL_DEBUG output fixes 6. Declaration of real GOST ciphersuites, two authentication methods SSL_aGOST94 and SSL_aGOST2001 and one key exchange method SSL_kGOST 7. Implementation of these methods. 8. Support for sending unsolicited serverhello extension if GOST ciphersuite is selected. It is require for interoperability with CryptoPro CSP 3.0 and 3.6 and controlled by SSL_OP_CRYPTOPRO_TLSEXT_BUG constant. This constant is added to SSL_OP_ALL, because it does nothing, if non-GOST ciphersuite is selected, and all implementation of GOST include compatibility with CryptoPro. 9. Support for CertificateVerify message without length field. It is another CryptoPro bug, but support is made unconditional, because it does no harm for draft-conforming implementation. 10. In tls1_mac extra copy of stream mac context is no more done. When I've written currently commited code I haven't read EVP_DigestSignFinal manual carefully enough and haven't noticed that it does an internal digest ctx copying. This implementation was tested against 1. CryptoPro CSP 3.6 client and server 2. Cryptopro CSP 3.0 server
752 lines
18 KiB
C
752 lines
18 KiB
C
/**********************************************************************
|
|
* 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 = BN_dup(priv);
|
|
if (!EVP_PKEY_missing_parameters(pkey))
|
|
gost94_compute_public(dsa);
|
|
break;
|
|
}
|
|
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_94:
|
|
{
|
|
DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pkey);
|
|
if (!dsa)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (!dsa->priv_key) return NULL;
|
|
return dsa->priv_key;
|
|
break;
|
|
}
|
|
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))) return NULL;
|
|
return (BIGNUM *)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;
|
|
}
|
|
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) 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_94,
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
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_get0_priv_key(pkey);
|
|
if (!key) return 0;
|
|
BN_print(out,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_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 = 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;
|
|
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_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];
|
|
}
|
|
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);
|
|
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);
|
|
|
|
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;
|
|
}
|
|
/*------------------------ ASN1 METHOD for GOST MAC -------------------*/
|
|
static void mackey_free_gost(EVP_PKEY *pk)
|
|
{
|
|
if (pk->pkey.ptr) {
|
|
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_undef;
|
|
return 2;
|
|
}
|
|
return -2;
|
|
}
|
|
/* ----------------------------------------------------------------------*/
|
|
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:
|
|
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:
|
|
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_ctrl(*ameth,mac_ctrl_gost);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|