openssl/engines/ccgost/gost_sign.c
Richard Levitte 0725acd071 Initialised 'ok' and redo the logic.
The logic with how 'ok' was calculated didn't quite convey what's "ok",
so the logic is slightly redone to make it less confusing.

Reviewed-by: Andy Polyakov <appro@openssl.org>
(cherry picked from commit 06affe3dac)
2015-04-21 01:45:58 +02:00

373 lines
9.6 KiB
C

/**********************************************************************
* gost_sign.c *
* Copyright (c) 2005-2006 Cryptocom LTD *
* This file is distributed under the same license as OpenSSL *
* *
* Implementation of GOST R 34.10-94 signature algorithm *
* for OpenSSL *
* Requires OpenSSL 0.9.9 for compilation *
**********************************************************************/
#include <string.h>
#include <openssl/rand.h>
#include <openssl/bn.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include "gost_params.h"
#include "gost_lcl.h"
#include "e_gost_err.h"
#ifdef DEBUG_SIGN
void dump_signature(const char *message, const unsigned char *buffer,
size_t len)
{
size_t i;
fprintf(stderr, "signature %s Length=%d", message, len);
for (i = 0; i < len; i++) {
if (i % 16 == 0)
fputc('\n', stderr);
fprintf(stderr, " %02x", buffer[i]);
}
fprintf(stderr, "\nEnd of signature\n");
}
void dump_dsa_sig(const char *message, DSA_SIG *sig)
{
fprintf(stderr, "%s\nR=", message);
BN_print_fp(stderr, sig->r);
fprintf(stderr, "\nS=");
BN_print_fp(stderr, sig->s);
fprintf(stderr, "\n");
}
#else
# define dump_signature(a,b,c)
# define dump_dsa_sig(a,b)
#endif
/*
* Computes signature and returns it as DSA_SIG structure
*/
DSA_SIG *gost_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
{
BIGNUM *k = NULL, *tmp = NULL, *tmp2 = NULL;
DSA_SIG *newsig, *ret = NULL;
BIGNUM *md = hashsum2bn(dgst);
/* check if H(M) mod q is zero */
BN_CTX *ctx = BN_CTX_new();
if(!ctx) {
GOSTerr(GOST_F_GOST_DO_SIGN, ERR_R_MALLOC_FAILURE);
goto err;
}
BN_CTX_start(ctx);
newsig = DSA_SIG_new();
if (!newsig) {
GOSTerr(GOST_F_GOST_DO_SIGN, GOST_R_NO_MEMORY);
goto err;
}
tmp = BN_CTX_get(ctx);
k = BN_CTX_get(ctx);
tmp2 = BN_CTX_get(ctx);
if(!tmp || !k || !tmp2) {
GOSTerr(GOST_F_GOST_DO_SIGN, ERR_R_MALLOC_FAILURE);
goto err;
}
BN_mod(tmp, md, dsa->q, ctx);
if (BN_is_zero(tmp)) {
BN_one(md);
}
do {
do {
/*
* Generate random number k less than q
*/
BN_rand_range(k, dsa->q);
/* generate r = (a^x mod p) mod q */
BN_mod_exp(tmp, dsa->g, k, dsa->p, ctx);
if (!(newsig->r)) {
newsig->r = BN_new();
if(!newsig->r) {
GOSTerr(GOST_F_GOST_DO_SIGN, ERR_R_MALLOC_FAILURE);
goto err;
}
}
BN_mod(newsig->r, tmp, dsa->q, ctx);
}
while (BN_is_zero(newsig->r));
/* generate s = (xr + k(Hm)) mod q */
BN_mod_mul(tmp, dsa->priv_key, newsig->r, dsa->q, ctx);
BN_mod_mul(tmp2, k, md, dsa->q, ctx);
if (!newsig->s) {
newsig->s = BN_new();
if(!newsig->s) {
GOSTerr(GOST_F_GOST_DO_SIGN, ERR_R_MALLOC_FAILURE);
goto err;
}
}
BN_mod_add(newsig->s, tmp, tmp2, dsa->q, ctx);
}
while (BN_is_zero(newsig->s));
ret = newsig;
err:
BN_free(md);
if(ctx) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
if(!ret && newsig) {
DSA_SIG_free(newsig);
}
return ret;
}
/*
* Packs signature according to Cryptocom rules
* and frees up DSA_SIG structure
*/
/*-
int pack_sign_cc(DSA_SIG *s,int order,unsigned char *sig, size_t *siglen)
{
*siglen = 2*order;
memset(sig,0,*siglen);
store_bignum(s->r, sig,order);
store_bignum(s->s, sig + order,order);
dump_signature("serialized",sig,*siglen);
DSA_SIG_free(s);
return 1;
}
*/
/*
* Packs signature according to Cryptopro rules
* and frees up DSA_SIG structure
*/
int pack_sign_cp(DSA_SIG *s, int order, unsigned char *sig, size_t *siglen)
{
*siglen = 2 * order;
memset(sig, 0, *siglen);
store_bignum(s->s, sig, order);
store_bignum(s->r, sig + order, order);
dump_signature("serialized", sig, *siglen);
DSA_SIG_free(s);
return 1;
}
/*
* Verifies signature passed as DSA_SIG structure
*
*/
int gost_do_verify(const unsigned char *dgst, int dgst_len,
DSA_SIG *sig, DSA *dsa)
{
BIGNUM *md = NULL, *tmp = NULL;
BIGNUM *q2 = NULL;
BIGNUM *u = NULL, *v = NULL, *z1 = NULL, *z2 = NULL;
BIGNUM *tmp2 = NULL, *tmp3 = NULL;
int ok = 0;
BN_CTX *ctx = BN_CTX_new();
if(!ctx) {
GOSTerr(GOST_F_GOST_DO_VERIFY, ERR_R_MALLOC_FAILURE);
goto err;
}
BN_CTX_start(ctx);
if (BN_cmp(sig->s, dsa->q) >= 1 || BN_cmp(sig->r, dsa->q) >= 1) {
GOSTerr(GOST_F_GOST_DO_VERIFY, GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q);
goto err;
}
md = hashsum2bn(dgst);
tmp = BN_CTX_get(ctx);
v = BN_CTX_get(ctx);
q2 = BN_CTX_get(ctx);
z1 = BN_CTX_get(ctx);
z2 = BN_CTX_get(ctx);
tmp2 = BN_CTX_get(ctx);
tmp3 = BN_CTX_get(ctx);
u = BN_CTX_get(ctx);
if(!tmp || !v || !q2 || !z1 || !z2 || !tmp2 || !tmp3 || !u) {
GOSTerr(GOST_F_GOST_DO_VERIFY, ERR_R_MALLOC_FAILURE);
goto err;
}
BN_mod(tmp, md, dsa->q, ctx);
if (BN_is_zero(tmp)) {
BN_one(md);
}
BN_copy(q2, dsa->q);
BN_sub_word(q2, 2);
BN_mod_exp(v, md, q2, dsa->q, ctx);
BN_mod_mul(z1, sig->s, v, dsa->q, ctx);
BN_sub(tmp, dsa->q, sig->r);
BN_mod_mul(z2, tmp, v, dsa->p, ctx);
BN_mod_exp(tmp, dsa->g, z1, dsa->p, ctx);
BN_mod_exp(tmp2, dsa->pub_key, z2, dsa->p, ctx);
BN_mod_mul(tmp3, tmp, tmp2, dsa->p, ctx);
BN_mod(u, tmp3, dsa->q, ctx);
ok = (BN_cmp(u, sig->r) == 0);
if (!ok) {
GOSTerr(GOST_F_GOST_DO_VERIFY, GOST_R_SIGNATURE_MISMATCH);
}
err:
if(md) BN_free(md);
if(ctx) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
return ok;
}
/*
* Computes public keys for GOST R 34.10-94 algorithm
*
*/
int gost94_compute_public(DSA *dsa)
{
/* Now fill algorithm parameters with correct values */
BN_CTX *ctx;
if (!dsa->g) {
GOSTerr(GOST_F_GOST94_COMPUTE_PUBLIC, GOST_R_KEY_IS_NOT_INITALIZED);
return 0;
}
ctx = BN_CTX_new();
if(!ctx) {
GOSTerr(GOST_F_GOST94_COMPUTE_PUBLIC, ERR_R_MALLOC_FAILURE);
return 0;
}
dsa->pub_key = BN_new();
if(!dsa->pub_key) {
GOSTerr(GOST_F_GOST94_COMPUTE_PUBLIC, ERR_R_MALLOC_FAILURE);
BN_CTX_free(ctx);
return 0;
}
/* Compute public key y = a^x mod p */
BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx);
BN_CTX_free(ctx);
return 1;
}
/*
* Fill GOST 94 params, searching them in R3410_paramset array
* by nid of paramset
*
*/
int fill_GOST94_params(DSA *dsa, int nid)
{
R3410_params *params = R3410_paramset;
while (params->nid != NID_undef && params->nid != nid)
params++;
if (params->nid == NID_undef) {
GOSTerr(GOST_F_FILL_GOST94_PARAMS, GOST_R_UNSUPPORTED_PARAMETER_SET);
return 0;
}
#define dump_signature(a,b,c)
if (dsa->p) {
BN_free(dsa->p);
}
dsa->p = NULL;
BN_dec2bn(&(dsa->p), params->p);
if (dsa->q) {
BN_free(dsa->q);
}
dsa->q = NULL;
BN_dec2bn(&(dsa->q), params->q);
if (dsa->g) {
BN_free(dsa->g);
}
dsa->g = NULL;
BN_dec2bn(&(dsa->g), params->a);
return 1;
}
/*
* Generate GOST R 34.10-94 keypair
*
*
*/
int gost_sign_keygen(DSA *dsa)
{
dsa->priv_key = BN_new();
if(!dsa->priv_key) {
GOSTerr(GOST_F_GOST_SIGN_KEYGEN, ERR_R_MALLOC_FAILURE);
return 0;
}
BN_rand_range(dsa->priv_key, dsa->q);
return gost94_compute_public(dsa);
}
/* Unpack signature according to cryptocom rules */
/*-
DSA_SIG *unpack_cc_signature(const unsigned char *sig,size_t siglen)
{
DSA_SIG *s;
s = DSA_SIG_new();
if (s == NULL)
{
GOSTerr(GOST_F_UNPACK_CC_SIGNATURE,GOST_R_NO_MEMORY);
return(NULL);
}
s->r = getbnfrombuf(sig, siglen/2);
s->s = getbnfrombuf(sig + siglen/2, siglen/2);
return s;
}
*/
/* Unpack signature according to cryptopro rules */
DSA_SIG *unpack_cp_signature(const unsigned char *sig, size_t siglen)
{
DSA_SIG *s;
s = DSA_SIG_new();
if (s == NULL) {
GOSTerr(GOST_F_UNPACK_CP_SIGNATURE, GOST_R_NO_MEMORY);
return NULL;
}
s->s = getbnfrombuf(sig, siglen / 2);
s->r = getbnfrombuf(sig + siglen / 2, siglen / 2);
return s;
}
/* Convert little-endian byte array into bignum */
BIGNUM *hashsum2bn(const unsigned char *dgst)
{
unsigned char buf[32];
int i;
for (i = 0; i < 32; i++) {
buf[31 - i] = dgst[i];
}
return getbnfrombuf(buf, 32);
}
/* Convert byte buffer to bignum, skipping leading zeros*/
BIGNUM *getbnfrombuf(const unsigned char *buf, size_t len)
{
while (*buf == 0 && len > 0) {
buf++;
len--;
}
if (len) {
return BN_bin2bn(buf, len, NULL);
} else {
BIGNUM *b = BN_new();
BN_zero(b);
return b;
}
}
/*
* Pack bignum into byte buffer of given size, filling all leading bytes by
* zeros
*/
int store_bignum(BIGNUM *bn, unsigned char *buf, int len)
{
int bytes = BN_num_bytes(bn);
if (bytes > len)
return 0;
memset(buf, 0, len);
BN_bn2bin(bn, buf + len - bytes);
return 1;
}