]> www.wagner.pp.ru Git - openssl-gost/engine.git/commitdiff
Added support for raw public key export and import 453/head
authorarx11 <>
Sat, 23 Mar 2024 10:13:59 +0000 (06:13 -0400)
committerarx11 <>
Sat, 23 Mar 2024 10:13:59 +0000 (06:13 -0400)
In total there are 3 new functions to export/import raw values of public and private keys.
Public key functions are used to handle ASN1_PKEY_CTRL_GET1_TLS_ENCPT and ASN1_PKEY_CTRL_SET1_TLS_ENCPT control codes used by SSL stack during key exchange.
Private key export function is just a convenient way to get the key value (EVP_PKEY_new_raw_private_key does not provide paramset to use for key import).

gost_ameth.c
test_sign.c

index 8e02a15c27b3c663274b8a81853164716e586a54..d7e7d6394aa363a0fa04772f01a0a260e31ab619 100644 (file)
@@ -410,6 +410,135 @@ end:
        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
  */
@@ -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;
@@ -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;
index 63ae3b56877d5ffdabcf88f52d2f737c672c7793..fee6d6e147346954ef111952996da28c5c83959b 100644 (file)
@@ -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.
      */