Add X25519/X448 Key Exchange to the default provider
[openssl.git] / crypto / ec / ecx_meth.c
index eace1a88cd8466ec257acf9510a505b51c631f82..88787e0db6c749feea8eb99b27f375881075b567 100644 (file)
@@ -7,27 +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 "internal/param_build.h"
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
+#include "crypto/ecx.h"
 #include "ec_local.h"
 #include "curve448/curve448_local.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 \
@@ -67,7 +65,7 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
         }
     }
 
-    key = OPENSSL_zalloc(sizeof(*key));
+    key = ecx_key_new(KEYLENID(id), 1);
     if (key == NULL) {
         ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
         return 0;
@@ -77,17 +75,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 +117,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 +253,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 +403,48 @@ 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)
+{
+    const ECX_KEY *key = from->pkey.ecx;
+    OSSL_PARAM_BLD tmpl;
+    OSSL_PARAM *params = NULL;
+    int rv = 0;
+
+    ossl_param_bld_init(&tmpl);
+
+    /* 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;
+
+    if (key->privkey != NULL) {
+        if (!ossl_param_bld_push_octet_string(&tmpl,
+                                              OSSL_PKEY_PARAM_PRIV_KEY,
+                                              key->privkey, key->keylen))
+            goto err;
+    }
+
+    params = ossl_param_bld_to_param(&tmpl);
+
+    /* We export, the provider imports */
+    rv = evp_keymgmt_import(to_keymgmt, to_keydata, OSSL_KEYMGMT_SELECT_ALL,
+                            params);
+
+ err:
+    ossl_param_bld_free(params);
+    return rv;
+}
+
 const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
     EVP_PKEY_X25519,
     EVP_PKEY_X25519,
@@ -451,6 +486,8 @@ 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
 };
 
 const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = {
@@ -494,6 +531,8 @@ 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
 };
 
 static int ecd_size25519(const EVP_PKEY *pkey)
@@ -854,6 +893,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 +907,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,16 +941,14 @@ 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],
@@ -966,7 +1004,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 +1100,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(X25519_KEYLEN, 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 +1110,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 +1129,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 +1142,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(X448_KEYLEN, 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 +1152,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 +1170,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 +1187,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(ED25519_KEYLEN, 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 +1198,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 +1207,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 +1223,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 +1244,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(ED448_KEYLEN, 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 +1255,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 +1288,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;
 }