Enable export_to functions to have access to the libctx
[openssl.git] / crypto / ec / ecx_meth.c
index 2eedba3d84a567fbfdace4057f18a1cb1134d634..750a51c3f248215909095b4120ad075fda6c3c03 100644 (file)
@@ -7,34 +7,25 @@
  * https://www.openssl.org/source/license.html
  */
 
+/*
+ * ECDSA low level APIs are deprecated for public use, but still ok for
+ * internal use.
+ */
+#include "internal/deprecated.h"
+
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/x509.h>
 #include <openssl/ec.h>
 #include <openssl/rand.h>
+#include <openssl/core_names.h>
+#include "openssl/param_build.h"
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
-#include "ec_lcl.h"
-#include "curve448/curve448_lcl.h"
-
-#define X25519_BITS          253
-#define X25519_SECURITY_BITS 128
-
-#define ED25519_SIGSIZE      64
-
-#define X448_BITS            448
-#define ED448_BITS           456
-#define X448_SECURITY_BITS   224
-
-#define ED448_SIGSIZE        114
-
-#define ISX448(id)      ((id) == EVP_PKEY_X448)
-#define IS25519(id)     ((id) == EVP_PKEY_X25519 || (id) == EVP_PKEY_ED25519)
-#define KEYLENID(id)    (IS25519(id) ? X25519_KEYLEN \
-                                     : ((id) == EVP_PKEY_X448 ? X448_KEYLEN \
-                                                              : ED448_KEYLEN))
-#define KEYLEN(p)       KEYLENID((p)->ameth->pkey_id)
-
+#include "crypto/ecx.h"
+#include "ec_local.h"
+#include "curve448/curve448_local.h"
+#include "ecx_backend.h"
 
 typedef enum {
     KEY_OP_PUBLIC,
@@ -67,7 +58,7 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
         }
     }
 
-    key = OPENSSL_zalloc(sizeof(*key));
+    key = ecx_key_new(KEYNID2TYPE(id), 1);
     if (key == NULL) {
         ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
         return 0;
@@ -77,17 +68,14 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
     if (op == KEY_OP_PUBLIC) {
         memcpy(pubkey, p, plen);
     } else {
-        privkey = key->privkey = OPENSSL_secure_malloc(KEYLENID(id));
+        privkey = ecx_key_allocate_privkey(key);
         if (privkey == NULL) {
             ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
             goto err;
         }
         if (op == KEY_OP_KEYGEN) {
-            if (RAND_priv_bytes(privkey, KEYLENID(id)) <= 0) {
-                OPENSSL_secure_free(privkey);
-                key->privkey = NULL;
+            if (RAND_priv_bytes(privkey, KEYLENID(id)) <= 0)
                 goto err;
-            }
             if (id == EVP_PKEY_X25519) {
                 privkey[0] &= 248;
                 privkey[X25519_KEYLEN - 1] &= 127;
@@ -122,7 +110,7 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
     EVP_PKEY_assign(pkey, id, key);
     return 1;
  err:
-    OPENSSL_free(key);
+    ecx_key_free(key);
     return 0;
 }
 
@@ -258,9 +246,7 @@ static int ecx_security_bits(const EVP_PKEY *pkey)
 
 static void ecx_free(EVP_PKEY *pkey)
 {
-    if (pkey->pkey.ecx != NULL)
-        OPENSSL_secure_clear_free(pkey->pkey.ecx->privkey, KEYLEN(pkey));
-    OPENSSL_free(pkey->pkey.ecx);
+    ecx_key_free(pkey->pkey.ecx);
 }
 
 /* "parameters" are always equal */
@@ -410,6 +396,77 @@ static int ecx_get_pub_key(const EVP_PKEY *pkey, unsigned char *pub,
     return 1;
 }
 
+static size_t ecx_pkey_dirty_cnt(const EVP_PKEY *pkey)
+{
+    /*
+     * We provide no mechanism to "update" an ECX key once it has been set,
+     * therefore we do not have to maintain a dirty count.
+     */
+    return 1;
+}
+
+static int ecx_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
+                              EVP_KEYMGMT *to_keymgmt, OPENSSL_CTX *libctx,
+                              const char *propq)
+{
+    const ECX_KEY *key = from->pkey.ecx;
+    OSSL_PARAM_BLD *tmpl = OSSL_PARAM_BLD_new();
+    OSSL_PARAM *params = NULL;
+    int selection = 0;
+    int rv = 0;
+
+    if (tmpl == NULL)
+        return 0;
+
+    /* A key must at least have a public part */
+    if (!OSSL_PARAM_BLD_push_octet_string(tmpl, OSSL_PKEY_PARAM_PUB_KEY,
+                                          key->pubkey, key->keylen))
+        goto err;
+    selection |= OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+
+    if (key->privkey != NULL) {
+        if (!OSSL_PARAM_BLD_push_octet_string(tmpl,
+                                              OSSL_PKEY_PARAM_PRIV_KEY,
+                                              key->privkey, key->keylen))
+            goto err;
+        selection |= OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
+    }
+
+    params = OSSL_PARAM_BLD_to_param(tmpl);
+
+    /* We export, the provider imports */
+    rv = evp_keymgmt_import(to_keymgmt, to_keydata, selection, params);
+
+ err:
+    OSSL_PARAM_BLD_free(tmpl);
+    OSSL_PARAM_BLD_free_params(params);
+    return rv;
+}
+
+static int ecx_generic_import_from(const OSSL_PARAM params[], void *key,
+                                   int keytype)
+{
+    EVP_PKEY *pkey = key;
+    ECX_KEY *ecx = ecx_key_new(KEYNID2TYPE(keytype), 0);
+
+    if (ecx == NULL) {
+        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!ecx_key_fromdata(ecx, params, 1)
+        || !EVP_PKEY_assign(pkey, keytype, ecx)) {
+        ecx_key_free(ecx);
+        return 0;
+    }
+    return 1;
+}
+
+static int x25519_import_from(const OSSL_PARAM params[], void *key)
+{
+    return ecx_generic_import_from(params, key, EVP_PKEY_X25519);
+}
+
 const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
     EVP_PKEY_X25519,
     EVP_PKEY_X25519,
@@ -451,8 +508,16 @@ const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
     ecx_set_pub_key,
     ecx_get_priv_key,
     ecx_get_pub_key,
+    ecx_pkey_dirty_cnt,
+    ecx_pkey_export_to,
+    x25519_import_from
 };
 
+static int x448_import_from(const OSSL_PARAM params[], void *key)
+{
+    return ecx_generic_import_from(params, key, EVP_PKEY_X448);
+}
+
 const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = {
     EVP_PKEY_X448,
     EVP_PKEY_X448,
@@ -494,6 +559,9 @@ const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = {
     ecx_set_pub_key,
     ecx_get_priv_key,
     ecx_get_pub_key,
+    ecx_pkey_dirty_cnt,
+    ecx_pkey_export_to,
+    x448_import_from
 };
 
 static int ecd_size25519(const EVP_PKEY *pkey)
@@ -568,6 +636,10 @@ static int ecd_sig_info_set448(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
     return 1;
 }
 
+static int ed25519_import_from(const OSSL_PARAM params[], void *key)
+{
+    return ecx_generic_import_from(params, key, EVP_PKEY_ED25519);
+}
 
 const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
     EVP_PKEY_ED25519,
@@ -609,8 +681,16 @@ const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
     ecx_set_pub_key,
     ecx_get_priv_key,
     ecx_get_pub_key,
+    ecx_pkey_dirty_cnt,
+    ecx_pkey_export_to,
+    ed25519_import_from
 };
 
+static int ed448_import_from(const OSSL_PARAM params[], void *key)
+{
+    return ecx_generic_import_from(params, key, EVP_PKEY_ED448);
+}
+
 const EVP_PKEY_ASN1_METHOD ed448_asn1_meth = {
     EVP_PKEY_ED448,
     EVP_PKEY_ED448,
@@ -651,6 +731,9 @@ const EVP_PKEY_ASN1_METHOD ed448_asn1_meth = {
     ecx_set_pub_key,
     ecx_get_priv_key,
     ecx_get_pub_key,
+    ecx_pkey_dirty_cnt,
+    ecx_pkey_export_to,
+    ed448_import_from
 };
 
 static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
@@ -854,6 +937,7 @@ static const EVP_PKEY_METHOD ed448_pkey_meth = {
 
 #ifdef S390X_EC_ASM
 # include "s390x_arch.h"
+# include "internal/constant_time.h"
 
 static void s390x_x25519_mod_p(unsigned char u[32])
 {
@@ -867,16 +951,16 @@ static void s390x_x25519_mod_p(unsigned char u[32])
     u_red[31] = (unsigned char)c;
     c >>= 8;
 
-    for (i = 30; c > 0 && i >= 0; i--) {
+    for (i = 30; i >= 0; i--) {
         c += (unsigned int)u_red[i];
         u_red[i] = (unsigned char)c;
         c >>= 8;
     }
 
-    if (u_red[0] & 0x80) {
-        u_red[0] &= 0x7f;
-        memcpy(u, u_red, sizeof(u_red));
-    }
+    c = (u_red[0] & 0x80) >> 7;
+    u_red[0] &= 0x7f;
+    constant_time_cond_swap_buff(0 - (unsigned char)c,
+                                 u, u_red, sizeof(u_red));
 }
 
 static void s390x_x448_mod_p(unsigned char u[56])
@@ -901,21 +985,19 @@ static void s390x_x448_mod_p(unsigned char u[56])
     u_red[27] = (unsigned char)c;
     c >>= 8;
 
-    for (i = 26; c > 0 && i >= 0; i--) {
+    for (i = 26; i >= 0; i--) {
         c += (unsigned int)u_red[i];
         u_red[i] = (unsigned char)c;
         c >>= 8;
     }
 
-    if (u_red[0] & 0x80) {
-        u_red[0] &= 0x7f;
-        memcpy(u, u_red, sizeof(u_red));
-    }
+    constant_time_cond_swap_buff(0 - (unsigned char)c,
+                                 u, u_red, sizeof(u_red));
 }
 
-static int s390x_x25519_mul(unsigned char u_dst[32],
-                            const unsigned char u_src[32],
-                            const unsigned char d_src[32])
+int s390x_x25519_mul(unsigned char u_dst[32],
+                     const unsigned char u_src[32],
+                     const unsigned char d_src[32])
 {
     union {
         struct {
@@ -946,9 +1028,9 @@ static int s390x_x25519_mul(unsigned char u_dst[32],
     return rc;
 }
 
-static int s390x_x448_mul(unsigned char u_dst[56],
-                          const unsigned char u_src[56],
-                          const unsigned char d_src[56])
+int s390x_x448_mul(unsigned char u_dst[56],
+                   const unsigned char u_src[56],
+                   const unsigned char d_src[56])
 {
     union {
         struct {
@@ -966,7 +1048,7 @@ static int s390x_x448_mul(unsigned char u_dst[56],
     memcpy(param.x448.d_src, d_src, 56);
 
     s390x_flip_endian64(param.x448.u_src, param.x448.u_src);
-    s390x_x448_mod_p(param.x448.u_src);
+    s390x_x448_mod_p(param.x448.u_src + 8);
 
     s390x_flip_endian64(param.x448.d_src, param.x448.d_src);
     param.x448.d_src[63] &= 252;
@@ -1062,10 +1144,9 @@ static int s390x_pkey_ecx_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     };
-    ECX_KEY *key;
+    ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_X25519, 1);
     unsigned char *privkey = NULL, *pubkey;
 
-    key = OPENSSL_zalloc(sizeof(*key));
     if (key == NULL) {
         ECerr(EC_F_S390X_PKEY_ECX_KEYGEN25519, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1073,7 +1154,7 @@ static int s390x_pkey_ecx_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
 
     pubkey = key->pubkey;
 
-    privkey = key->privkey = OPENSSL_secure_malloc(X25519_KEYLEN);
+    privkey = ecx_key_allocate_privkey(key);
     if (privkey == NULL) {
         ECerr(EC_F_S390X_PKEY_ECX_KEYGEN25519, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1092,9 +1173,7 @@ static int s390x_pkey_ecx_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, key);
     return 1;
  err:
-    OPENSSL_secure_clear_free(privkey, X25519_KEYLEN);
-    key->privkey = NULL;
-    OPENSSL_free(key);
+    ecx_key_free(key);
     return 0;
 }
 
@@ -1107,10 +1186,9 @@ static int s390x_pkey_ecx_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     };
-    ECX_KEY *key;
+    ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_X448, 1);
     unsigned char *privkey = NULL, *pubkey;
 
-    key = OPENSSL_zalloc(sizeof(*key));
     if (key == NULL) {
         ECerr(EC_F_S390X_PKEY_ECX_KEYGEN448, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1118,7 +1196,7 @@ static int s390x_pkey_ecx_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
 
     pubkey = key->pubkey;
 
-    privkey = key->privkey = OPENSSL_secure_malloc(X448_KEYLEN);
+    privkey = ecx_key_allocate_privkey(key);
     if (privkey == NULL) {
         ECerr(EC_F_S390X_PKEY_ECX_KEYGEN448, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1136,9 +1214,7 @@ static int s390x_pkey_ecx_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, key);
     return 1;
  err:
-    OPENSSL_secure_clear_free(privkey, X448_KEYLEN);
-    key->privkey = NULL;
-    OPENSSL_free(key);
+    ecx_key_free(key);
     return 0;
 }
 
@@ -1155,10 +1231,10 @@ static int s390x_pkey_ecd_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
     };
     unsigned char x_dst[32], buff[SHA512_DIGEST_LENGTH];
-    ECX_KEY *key;
+    ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_ED25519, 1);
     unsigned char *privkey = NULL, *pubkey;
+    unsigned int sz;
 
-    key = OPENSSL_zalloc(sizeof(*key));
     if (key == NULL) {
         ECerr(EC_F_S390X_PKEY_ECD_KEYGEN25519, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1166,7 +1242,7 @@ static int s390x_pkey_ecd_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
 
     pubkey = key->pubkey;
 
-    privkey = key->privkey = OPENSSL_secure_malloc(ED25519_KEYLEN);
+    privkey = ecx_key_allocate_privkey(key);
     if (privkey == NULL) {
         ECerr(EC_F_S390X_PKEY_ECD_KEYGEN25519, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1175,7 +1251,9 @@ static int s390x_pkey_ecd_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     if (RAND_priv_bytes(privkey, ED25519_KEYLEN) <= 0)
         goto err;
 
-    SHA512(privkey, 32, buff);
+    if (!EVP_Digest(privkey, 32, buff, &sz, EVP_sha512(), NULL))
+        goto err;
+
     buff[0] &= 248;
     buff[31] &= 63;
     buff[31] |= 64;
@@ -1189,9 +1267,7 @@ static int s390x_pkey_ecd_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, key);
     return 1;
  err:
-    OPENSSL_secure_clear_free(privkey, ED25519_KEYLEN);
-    key->privkey = NULL;
-    OPENSSL_free(key);
+    ecx_key_free(key);
     return 0;
 }
 
@@ -1212,11 +1288,10 @@ static int s390x_pkey_ecd_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69, 0x00
     };
     unsigned char x_dst[57], buff[114];
-    ECX_KEY *key;
+    ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_ED448, 1);
     unsigned char *privkey = NULL, *pubkey;
     EVP_MD_CTX *hashctx = NULL;
 
-    key = OPENSSL_zalloc(sizeof(*key));
     if (key == NULL) {
         ECerr(EC_F_S390X_PKEY_ECD_KEYGEN448, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1224,7 +1299,7 @@ static int s390x_pkey_ecd_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
 
     pubkey = key->pubkey;
 
-    privkey = key->privkey = OPENSSL_secure_malloc(ED448_KEYLEN);
+    privkey = ecx_key_allocate_privkey(key);
     if (privkey == NULL) {
         ECerr(EC_F_S390X_PKEY_ECD_KEYGEN448, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1257,9 +1332,7 @@ static int s390x_pkey_ecd_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     EVP_MD_CTX_free(hashctx);
     return 1;
  err:
-    OPENSSL_secure_clear_free(privkey, ED448_KEYLEN);
-    key->privkey = NULL;
-    OPENSSL_free(key);
+    ecx_key_free(key);
     EVP_MD_CTX_free(hashctx);
     return 0;
 }