]> www.wagner.pp.ru Git - openssl-gost/engine.git/blobdiff - gost_ec_keyx.c
Delete .travis.yml
[openssl-gost/engine.git] / gost_ec_keyx.c
index eeb0122960594d01634123ebf7c51e7418f04187..7a6ebe7e12ea5e8f587ea1b0648a387377b96eac 100644 (file)
@@ -30,7 +30,7 @@ int VKO_compute_key(unsigned char *shared_key,
                     const int vko_dgst_nid)
 {
     unsigned char *databuf = NULL;
-    BIGNUM *scalar = NULL, *X = NULL, *Y = NULL;
+    BIGNUM *scalar = NULL, *X = NULL, *Y = NULL, *order = NULL;
     const EC_GROUP *grp = NULL;
     EC_POINT *pnt = NULL;
     BN_CTX *ctx = NULL;
@@ -51,9 +51,11 @@ int VKO_compute_key(unsigned char *shared_key,
         goto err;
     }
 
+    order = BN_CTX_get(ctx);
     grp = EC_KEY_get0_group(priv_key);
     scalar = BN_CTX_get(ctx);
     X = BN_CTX_get(ctx);
+    EC_GROUP_get_order(grp, order, ctx);
 
     if ((Y = BN_CTX_get(ctx)) == NULL
         || (pnt = EC_POINT_new(grp)) == NULL
@@ -80,7 +82,7 @@ int VKO_compute_key(unsigned char *shared_key,
         goto err;
     }
 
-    half_len = BN_num_bytes(EC_GROUP_get0_field(grp));
+    half_len = BN_num_bytes(order);
     buf_len = 2 * half_len;
     if ((databuf = OPENSSL_malloc(buf_len)) == NULL) {
         GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
@@ -172,6 +174,137 @@ static int gost_keg(const unsigned char *ukm_source, int pkey_nid,
     }
 }
 
+int pkey_gost_ec_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
+                             const EC_KEY *eckey)
+{
+    BN_CTX *ctx;
+    EC_POINT *tmp = NULL;
+    BIGNUM *x = NULL;
+    const BIGNUM *priv_key;
+    const EC_GROUP *group;
+    int ret = 0;
+    size_t buflen,len;
+    unsigned char *buf = NULL;
+    int nid;
+
+    if (outlen > INT_MAX) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, EC_R_INVALID_OUTPUT_LENGTH);
+        return 0;
+    }
+
+    if ((ctx = BN_CTX_new()) == NULL)
+        goto err;
+    BN_CTX_start(ctx);
+    x = BN_CTX_get(ctx);
+    if (x == NULL) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    priv_key = EC_KEY_get0_private_key(eckey);
+    if (priv_key == NULL) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, EC_R_MISSING_PRIVATE_KEY);
+        goto err;
+    }
+
+    group = EC_KEY_get0_group(eckey);
+
+    nid = EC_GROUP_get_curve_name(group);
+    if (nid == NID_id_tc26_gost_3410_2012_256_paramSetA 
+        || nid == NID_id_tc26_gost_3410_2012_512_paramSetC) {
+        if (!EC_GROUP_get_cofactor(group, x, NULL) ||
+            // or use BN_mul(...)
+            !BN_mod_mul(x, x, priv_key, EC_GROUP_get0_order(group), ctx)) {
+            GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        priv_key = x;
+    }
+
+    if ((tmp = EC_POINT_new(group)) == NULL) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (!gost_ec_point_mul(group, tmp, NULL, pub_key, priv_key, ctx)) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE);
+        goto err;
+    }
+
+    if (!EC_POINT_get_affine_coordinates(group, tmp, x, NULL, ctx)) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE);
+        goto err;
+    }
+
+    buflen = (EC_GROUP_get_degree(group) + 7) / 8;
+    len = BN_num_bytes(x);
+    if (len > buflen) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    if ((buf = OPENSSL_malloc(buflen)) == NULL) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    
+    if (buflen != BN_bn2lebinpad(x, buf, buflen)) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_BN_LIB);
+        goto err;
+    }
+
+    if (outlen > buflen)
+        outlen = buflen;
+    memcpy(out, buf, outlen);
+    OPENSSL_clear_free(buf, buflen);
+
+    ret = outlen;
+
+ err:
+    EC_POINT_clear_free(tmp);
+    BN_CTX_end(ctx);
+    BN_CTX_free(ctx);
+    return ret;
+}
+
+int pkey_gost_ec_2020_derive(EVP_PKEY_CTX *ctx, unsigned char *key, 
+                             size_t *keylen)
+{
+    int ret;
+    size_t outlen;
+    const EC_POINT *pubkey = NULL;
+    EC_KEY *eckey;
+    EVP_PKEY *my_key = EVP_PKEY_CTX_get0_pkey(ctx);
+    EVP_PKEY *peer_key = EVP_PKEY_CTX_get0_peerkey(ctx);
+
+    if (!my_key || !peer_key) {
+        GOSTerr(GOST_F_PKEY_GOST_EC_2020_DERIVE, EC_R_KEYS_NOT_SET);
+        return 0;
+    }
+
+    eckey = EVP_PKEY_get0(my_key);
+
+    if (!key) {
+        const EC_GROUP *group;
+        group = EC_KEY_get0_group(eckey);
+        *keylen = (EC_GROUP_get_degree(group) + 7) / 8;
+        return 1;
+    }
+    pubkey = EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key));
+
+    /*
+     * if *outlen is less than maximum size, the result is truncated. 
+     * (is it error or not?)
+     */
+    
+    outlen = *keylen;
+
+    ret = pkey_gost_ec_compute_key(key, outlen, pubkey, eckey);
+    if (ret <= 0)
+        return 0;
+    *keylen = ret;
+    return 1;
+}
+
 /*
  * EVP_PKEY_METHOD callback derive.
  * Implements VKO R 34.10-2001/2012 algorithms
@@ -193,8 +326,7 @@ int pkey_gost_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
     int dgst_nid = NID_undef;
 
     if (!data || data->shared_ukm_size == 0) {
-        GOSTerr(GOST_F_PKEY_GOST_EC_DERIVE, GOST_R_UKM_NOT_SET);
-        return 0;
+        return pkey_gost_ec_2020_derive(ctx, key, keylen);
     }
 
     /* VKO */
@@ -286,6 +418,8 @@ static int pkey_GOST_ECcp_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out,
     int key_is_ephemeral = 1;
     gost_ctx cctx;
     EVP_PKEY *sec_key = EVP_PKEY_CTX_get0_peerkey(pctx);
+    int res_len = 0;
+
     if (data->shared_ukm_size) {
         memcpy(ukm, data->shared_ukm, 8);
     } else {
@@ -367,8 +501,26 @@ static int pkey_GOST_ECcp_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out,
             goto err;
         }
     }
-    if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt, out ? &out : NULL)) > 0)
+    res_len = i2d_GOST_KEY_TRANSPORT(gkt, NULL);
+    if (res_len <= 0) {
+        GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT, ERR_R_ASN1_LIB);
+        goto err;
+    }
+
+    if (out == NULL) {
+        *out_len = res_len;
         ret = 1;
+    } else {
+        if ((size_t)res_len > *out_len) {
+            GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT, GOST_R_INVALID_BUFFER_SIZE);
+            goto err;
+        }
+        if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt, &out)) > 0)
+            ret = 1;
+        else
+            GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT, ERR_R_ASN1_LIB);
+    }
+
     OPENSSL_cleanse(shared_key, sizeof(shared_key));
     GOST_KEY_TRANSPORT_free(gkt);
     return ret;
@@ -400,6 +552,7 @@ static int pkey_gost2018_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out,
     int exp_len = 0, iv_len = 0;
     unsigned char *exp_buf = NULL;
     int key_is_ephemeral = 0;
+    int res_len = 0;
 
     switch (data->cipher_nid) {
     case NID_magma_ctr:
@@ -493,8 +646,26 @@ static int pkey_gost2018_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out,
         goto err;
     }
 
-    if ((*out_len = i2d_PSKeyTransport_gost(pst, out ? &out : NULL)) > 0)
+    res_len = i2d_PSKeyTransport_gost(pst, NULL);
+    if (res_len <= 0) {
+        GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, ERR_R_ASN1_LIB);
+        goto err;
+    }
+
+    if (out == NULL) {
+        *out_len = res_len;
         ret = 1;
+    } else {
+        if ((size_t)res_len > *out_len) {
+            GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, GOST_R_INVALID_BUFFER_SIZE);
+            goto err;
+        }
+        if ((*out_len = i2d_PSKeyTransport_gost(pst, &out)) > 0)
+            ret = 1;
+        else
+            GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, ERR_R_ASN1_LIB);
+    }
+
  err:
     OPENSSL_cleanse(expkeys, sizeof(expkeys));
     if (key_is_ephemeral)
@@ -544,10 +715,6 @@ static int pkey_GOST_ECcp_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key,
     EVP_PKEY *eph_key = NULL, *peerkey = NULL;
     int dgst_nid = NID_undef;
 
-    if (!key) {
-        *key_len = 32;
-        return 1;
-    }
     gkt = d2i_GOST_KEY_TRANSPORT(NULL, (const unsigned char **)&p, in_len);
     if (!gkt) {
         GOSTerr(GOST_F_PKEY_GOST_ECCP_DECRYPT,
@@ -607,6 +774,7 @@ static int pkey_GOST_ECcp_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key,
         goto err;
     }
 
+    *key_len = 32;
     ret = 1;
  err:
     OPENSSL_cleanse(sharedKey, sizeof(sharedKey));
@@ -648,10 +816,6 @@ static int pkey_gost2018_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key,
         return -1;
         break;
     }
-    if (!key) {
-        *key_len = 32;
-        return 1;
-    }
 
     pst = d2i_PSKeyTransport_gost(NULL, (const unsigned char **)&p, in_len);
     if (!pst) {
@@ -672,6 +836,13 @@ static int pkey_gost2018_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key,
 
    o  q * Q_eph is not equal to zero point.
 */
+    if (eph_key == NULL || priv == NULL || data == NULL) {
+       GOSTerr(GOST_F_PKEY_GOST2018_DECRYPT,
+               GOST_R_ERROR_COMPUTING_EXPORT_KEYS);
+       ret = 0;
+       goto err;
+    }
+
     if (data->shared_ukm_size == 0 && pst->ukm != NULL) {
         if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_SET_IV,
         ASN1_STRING_length(pst->ukm), (void *)ASN1_STRING_get0_data(pst->ukm)) < 0) {
@@ -696,6 +867,7 @@ static int pkey_gost2018_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key,
         goto err;
     }
 
+    *key_len = 32;
     ret = 1;
  err:
     OPENSSL_cleanse(expkeys, sizeof(expkeys));
@@ -708,6 +880,17 @@ int pkey_gost_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key,
                       size_t *key_len, const unsigned char *in, size_t in_len)
 {
     struct gost_pmeth_data *gctx = EVP_PKEY_CTX_get_data(pctx);
+
+    if (key == NULL) {
+        *key_len = 32;
+        return 1;
+    }
+
+    if (key != NULL && *key_len < 32) {
+        GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, GOST_R_INVALID_BUFFER_SIZE);
+        return 0;
+    }
+
     switch (gctx->cipher_nid)
     {
         case NID_id_Gost28147_89: