Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for raw public key export and import #453

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions gost_ameth.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,135 @@ static ASN1_STRING *gost_encode_cms_params(int ka_nid)
return ret;
}

static int gost_set_raw_pub_key(EVP_PKEY *pk, const unsigned char *pub, size_t len)
{
int ret = 0;
BIGNUM *X = NULL;
BIGNUM *Y = NULL;
EC_POINT *pub_key = NULL;
EC_KEY *ec;
const EC_GROUP *group;
const BIGNUM *order;
int half;

if (pub == NULL || len == 0) {
return 0;
}

if ((ec = EVP_PKEY_get0(pk)) == NULL
|| (group = EC_KEY_get0_group(ec)) == NULL
|| (order = EC_GROUP_get0_order(group)) == NULL) {
return 0;
}

half = len / 2;
if ((X = BN_lebin2bn(pub, half, NULL)) == NULL
|| (Y = BN_lebin2bn(pub + half, half, NULL)) == NULL
|| (pub_key = EC_POINT_new(group)) == NULL) {
goto end;
}

if (EC_POINT_set_affine_coordinates(group, pub_key, X, Y, NULL) != 1) {
goto end;
}

if (EC_KEY_set_public_key(ec, pub_key) != 1) {
goto end;
}

ret = 1;
end:
EC_POINT_free(pub_key);
BN_free(Y);
BN_free(X);
return ret;
}

static int gost_get_raw_priv_key(const EVP_PKEY *pk, unsigned char *priv, size_t *len)
{
const EC_KEY *ec;
const EC_GROUP *group;
const BIGNUM *order;
const BIGNUM *priv_key;
int half;

if (len == NULL) {
return 0;
}

if ((ec = EVP_PKEY_get0(pk)) == NULL
|| (group = EC_KEY_get0_group(ec)) == NULL
|| (order = EC_GROUP_get0_order(group)) == NULL
|| (priv_key = EC_KEY_get0_private_key(ec)) == NULL) {
return 0;
}

half = BN_num_bytes(order);
if (priv == NULL) {
*len = half;
return 1;
}

if (BN_bn2lebinpad(priv_key, priv, half) != half) {
return 0;
}

return 1;
}

static int gost_get_raw_pub_key(const EVP_PKEY *pk, unsigned char *pub, size_t *len)
{
int ret = 0;
BIGNUM *X = NULL;
BIGNUM *Y = NULL;
const EC_KEY *ec;
const EC_GROUP *group;
const BIGNUM *order;
const EC_POINT *pub_key;
int half;

if (len == NULL) {
return 0;
}

if ((ec = EVP_PKEY_get0(pk)) == NULL
|| (group = EC_KEY_get0_group(ec)) == NULL
|| (order = EC_GROUP_get0_order(group)) == NULL
|| (pub_key = EC_KEY_get0_public_key(ec)) == NULL) {
return 0;
}

half = BN_num_bytes(order);
if (pub == NULL) {
*len = 2 * half;
return 1;
}

if (*len < 2 * half) {
return 0;
}

if ((X = BN_new()) == NULL
|| (Y = BN_new()) == NULL) {
goto end;
}

if (EC_POINT_get_affine_coordinates(group, pub_key, X, Y, NULL) != 1) {
goto end;
}

if (BN_bn2lebinpad(X, pub, half) != half
|| BN_bn2lebinpad(Y, pub + half, half) != half) {
goto end;
}

ret = 1;
end:
BN_free(Y);
BN_free(X);
return ret;
}

/*
* Control function
*/
Expand Down Expand Up @@ -531,6 +660,26 @@ static int pkey_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2)
case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
*(int *)arg2 = md_nid;
return 2;
case ASN1_PKEY_CTRL_GET1_TLS_ENCPT:
{
unsigned char **dup = (unsigned char **)arg2;
unsigned char *buf = NULL;
size_t len;

if (dup == NULL
|| gost_get_raw_pub_key(pkey, NULL, &len) != 1
|| (buf = OPENSSL_malloc(len)) == NULL
|| gost_get_raw_pub_key(pkey, buf, &len) != 1) {
if (buf)
OPENSSL_free(buf);
return 0;
}

*dup = buf;
return len;
}
case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
return gost_set_raw_pub_key(pkey, (const unsigned char *)arg2, arg1);
}

return -2;
Expand Down Expand Up @@ -1196,6 +1345,10 @@ int register_ameth_gost(int nid, EVP_PKEY_ASN1_METHOD **ameth,
pub_cmp_gost_ec, pub_print_gost_ec,
pkey_size_gost, pkey_bits_gost);

EVP_PKEY_asn1_set_set_pub_key(*ameth, gost_set_raw_pub_key);
EVP_PKEY_asn1_set_get_priv_key(*ameth, gost_get_raw_priv_key);
EVP_PKEY_asn1_set_get_pub_key(*ameth, gost_get_raw_pub_key);

EVP_PKEY_asn1_set_ctrl(*ameth, pkey_ctrl_gost);
EVP_PKEY_asn1_set_security_bits(*ameth, pkey_bits_gost);
break;
Expand Down
44 changes: 44 additions & 0 deletions test_sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,50 @@ static int test_sign(struct test_sign *t)
EVP_PKEY_CTX_free(ctx1);
EVP_PKEY_free(key1);

/* Extract public key in raw format.
* Should contain X||Y in little endian.
*/
size_t publen;
unsigned char *pub;
err = EVP_PKEY_get_raw_public_key(priv_key, NULL, &publen);
T(pub = OPENSSL_zalloc(publen));
err &= EVP_PKEY_get_raw_public_key(priv_key, pub, &publen);
printf("\tEVP_PKEY_get_raw_public_key:");
print_test_tf(err, err, "success", "failure");
ret |= err != 1;

unsigned char *pub2 = NULL;
int pub2len = EVP_PKEY_get1_encoded_public_key(priv_key, &pub2);
err = (publen == pub2len) && pub2 && !memcmp(pub, pub2, publen);
printf("\tEVP_PKEY_get1_encoded_public_key:\t");
print_test_tf(err, err, "success", "failure");
ret |= err != 1;
if (pub2)
OPENSSL_free(pub2);

EVP_PKEY *copy_key;
T(copy_key = EVP_PKEY_new());
T(EVP_PKEY_copy_parameters(copy_key, priv_key));
err = EVP_PKEY_set1_encoded_public_key(copy_key, pub, publen);
printf("\tEVP_PKEY_set1_encoded_public_key:\t");
print_test_tf(err, err, "success", "failure");
EVP_PKEY_free(copy_key);
OPENSSL_free(pub);
ret |= err != 1;

/* Extract private key in raw format.
* Should contain d on little endian form.
*/
size_t privlen;
unsigned char *priv;
err = EVP_PKEY_get_raw_private_key(priv_key, NULL, &privlen);
T(priv = OPENSSL_zalloc(privlen));
err &= EVP_PKEY_get_raw_private_key(priv_key, priv, &privlen);
printf("\tEVP_PKEY_get_raw_private_key:\t");
print_test_tf(err, err, "success", "failure");
OPENSSL_free(priv);
ret |= err != 1;

/*
* Prepare for sign testing.
*/
Expand Down
Loading