Skip to content

Commit beff858

Browse files
Merge pull request #10552 from julek-wolfssl/evp-x25519-x448
Add NID_X25519 and NID_X448 support to the EVP layer
2 parents a31ce6e + df8cc30 commit beff858

6 files changed

Lines changed: 451 additions & 2 deletions

File tree

tests/api/test_evp_pkey.c

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2702,3 +2702,162 @@ int test_wolfSSL_EVP_PKEY_ed448(void)
27022702
return EXPECT_RESULT();
27032703
}
27042704

2705+
int test_wolfSSL_EVP_PKEY_x25519(void)
2706+
{
2707+
EXPECT_DECLS;
2708+
#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE25519)
2709+
EVP_PKEY* pkey = NULL;
2710+
EVP_PKEY* peer = NULL;
2711+
EVP_PKEY_CTX* genCtx = NULL;
2712+
EVP_PKEY_CTX* ctx = NULL;
2713+
unsigned char rawPriv[32];
2714+
unsigned char rawPub[32];
2715+
unsigned char secretA[32];
2716+
unsigned char secretB[32];
2717+
size_t secretLen;
2718+
int i;
2719+
2720+
for (i = 0; i < 32; i++) {
2721+
rawPriv[i] = (unsigned char)i;
2722+
rawPub[i] = (unsigned char)(0x40 + i);
2723+
}
2724+
2725+
/* Raw import with the correct length reports the X25519 type. */
2726+
ExpectNotNull(pkey = EVP_PKEY_new_raw_public_key(
2727+
EVP_PKEY_X25519, NULL, rawPub, sizeof(rawPub)));
2728+
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_X25519);
2729+
EVP_PKEY_free(pkey);
2730+
pkey = NULL;
2731+
2732+
ExpectNotNull(pkey = EVP_PKEY_new_raw_private_key(
2733+
EVP_PKEY_X25519, NULL, rawPriv, sizeof(rawPriv)));
2734+
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_X25519);
2735+
2736+
/* X25519 is key-agreement only: signing must be rejected. */
2737+
ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL));
2738+
ExpectIntNE(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS);
2739+
EVP_PKEY_CTX_free(ctx);
2740+
ctx = NULL;
2741+
EVP_PKEY_free(pkey);
2742+
pkey = NULL;
2743+
2744+
/* Wrong raw lengths are rejected. */
2745+
ExpectNull(EVP_PKEY_new_raw_public_key(
2746+
EVP_PKEY_X25519, NULL, rawPub, 16));
2747+
ExpectNull(EVP_PKEY_new_raw_private_key(
2748+
EVP_PKEY_X25519, NULL, rawPriv, 16));
2749+
2750+
/* Generate two key pairs and confirm ECDH agreement is symmetric. This
2751+
* also exercises the little-endian convention used on import/derive. */
2752+
ExpectNotNull(genCtx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL));
2753+
ExpectIntEQ(EVP_PKEY_keygen_init(genCtx), WOLFSSL_SUCCESS);
2754+
ExpectIntEQ(EVP_PKEY_keygen(genCtx, &pkey), WOLFSSL_SUCCESS);
2755+
ExpectIntEQ(EVP_PKEY_keygen(genCtx, &peer), WOLFSSL_SUCCESS);
2756+
EVP_PKEY_CTX_free(genCtx);
2757+
genCtx = NULL;
2758+
2759+
ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL));
2760+
ExpectIntEQ(EVP_PKEY_derive_init(ctx), WOLFSSL_SUCCESS);
2761+
ExpectIntEQ(EVP_PKEY_derive_set_peer(ctx, peer), WOLFSSL_SUCCESS);
2762+
secretLen = sizeof(secretA);
2763+
ExpectIntEQ(EVP_PKEY_derive(ctx, secretA, &secretLen), WOLFSSL_SUCCESS);
2764+
ExpectIntEQ((int)secretLen, 32);
2765+
EVP_PKEY_CTX_free(ctx);
2766+
ctx = NULL;
2767+
2768+
ExpectNotNull(ctx = EVP_PKEY_CTX_new(peer, NULL));
2769+
ExpectIntEQ(EVP_PKEY_derive_init(ctx), WOLFSSL_SUCCESS);
2770+
ExpectIntEQ(EVP_PKEY_derive_set_peer(ctx, pkey), WOLFSSL_SUCCESS);
2771+
secretLen = sizeof(secretB);
2772+
ExpectIntEQ(EVP_PKEY_derive(ctx, secretB, &secretLen), WOLFSSL_SUCCESS);
2773+
ExpectIntEQ((int)secretLen, 32);
2774+
EVP_PKEY_CTX_free(ctx);
2775+
ctx = NULL;
2776+
2777+
ExpectIntEQ(XMEMCMP(secretA, secretB, 32), 0);
2778+
2779+
EVP_PKEY_free(peer);
2780+
EVP_PKEY_free(pkey);
2781+
#endif
2782+
return EXPECT_RESULT();
2783+
}
2784+
2785+
int test_wolfSSL_EVP_PKEY_x448(void)
2786+
{
2787+
EXPECT_DECLS;
2788+
#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE448)
2789+
EVP_PKEY* pkey = NULL;
2790+
EVP_PKEY* peer = NULL;
2791+
EVP_PKEY_CTX* genCtx = NULL;
2792+
EVP_PKEY_CTX* ctx = NULL;
2793+
unsigned char rawPriv[56];
2794+
unsigned char rawPub[56];
2795+
unsigned char secretA[56];
2796+
unsigned char secretB[56];
2797+
size_t secretLen;
2798+
int i;
2799+
2800+
for (i = 0; i < 56; i++) {
2801+
rawPriv[i] = (unsigned char)i;
2802+
rawPub[i] = (unsigned char)(0x40 + i);
2803+
}
2804+
2805+
/* Raw import with the correct length reports the X448 type. */
2806+
ExpectNotNull(pkey = EVP_PKEY_new_raw_public_key(
2807+
EVP_PKEY_X448, NULL, rawPub, sizeof(rawPub)));
2808+
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_X448);
2809+
EVP_PKEY_free(pkey);
2810+
pkey = NULL;
2811+
2812+
ExpectNotNull(pkey = EVP_PKEY_new_raw_private_key(
2813+
EVP_PKEY_X448, NULL, rawPriv, sizeof(rawPriv)));
2814+
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_X448);
2815+
2816+
/* X448 is key-agreement only: signing must be rejected. */
2817+
ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL));
2818+
ExpectIntNE(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS);
2819+
EVP_PKEY_CTX_free(ctx);
2820+
ctx = NULL;
2821+
EVP_PKEY_free(pkey);
2822+
pkey = NULL;
2823+
2824+
/* Wrong raw lengths are rejected. */
2825+
ExpectNull(EVP_PKEY_new_raw_public_key(
2826+
EVP_PKEY_X448, NULL, rawPub, 16));
2827+
ExpectNull(EVP_PKEY_new_raw_private_key(
2828+
EVP_PKEY_X448, NULL, rawPriv, 16));
2829+
2830+
/* Generate two key pairs and confirm ECDH agreement is symmetric. */
2831+
ExpectNotNull(genCtx = EVP_PKEY_CTX_new_id(EVP_PKEY_X448, NULL));
2832+
ExpectIntEQ(EVP_PKEY_keygen_init(genCtx), WOLFSSL_SUCCESS);
2833+
ExpectIntEQ(EVP_PKEY_keygen(genCtx, &pkey), WOLFSSL_SUCCESS);
2834+
ExpectIntEQ(EVP_PKEY_keygen(genCtx, &peer), WOLFSSL_SUCCESS);
2835+
EVP_PKEY_CTX_free(genCtx);
2836+
genCtx = NULL;
2837+
2838+
ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL));
2839+
ExpectIntEQ(EVP_PKEY_derive_init(ctx), WOLFSSL_SUCCESS);
2840+
ExpectIntEQ(EVP_PKEY_derive_set_peer(ctx, peer), WOLFSSL_SUCCESS);
2841+
secretLen = sizeof(secretA);
2842+
ExpectIntEQ(EVP_PKEY_derive(ctx, secretA, &secretLen), WOLFSSL_SUCCESS);
2843+
ExpectIntEQ((int)secretLen, 56);
2844+
EVP_PKEY_CTX_free(ctx);
2845+
ctx = NULL;
2846+
2847+
ExpectNotNull(ctx = EVP_PKEY_CTX_new(peer, NULL));
2848+
ExpectIntEQ(EVP_PKEY_derive_init(ctx), WOLFSSL_SUCCESS);
2849+
ExpectIntEQ(EVP_PKEY_derive_set_peer(ctx, pkey), WOLFSSL_SUCCESS);
2850+
secretLen = sizeof(secretB);
2851+
ExpectIntEQ(EVP_PKEY_derive(ctx, secretB, &secretLen), WOLFSSL_SUCCESS);
2852+
ExpectIntEQ((int)secretLen, 56);
2853+
EVP_PKEY_CTX_free(ctx);
2854+
ctx = NULL;
2855+
2856+
ExpectIntEQ(XMEMCMP(secretA, secretB, 56), 0);
2857+
2858+
EVP_PKEY_free(peer);
2859+
EVP_PKEY_free(pkey);
2860+
#endif
2861+
return EXPECT_RESULT();
2862+
}
2863+

tests/api/test_evp_pkey.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ int test_wolfSSL_EVP_PKEY_print_public(void);
6666
int test_wolfSSL_EVP_PKEY_ed25519(void);
6767
int test_wolfSSL_CTX_use_PrivateKey_ed25519(void);
6868
int test_wolfSSL_EVP_PKEY_ed448(void);
69+
int test_wolfSSL_EVP_PKEY_x25519(void);
70+
int test_wolfSSL_EVP_PKEY_x448(void);
6971

7072
#define TEST_EVP_PKEY_DECLS \
7173
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_CTX_new_id), \
@@ -110,6 +112,8 @@ int test_wolfSSL_EVP_PKEY_ed448(void);
110112
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_print_public), \
111113
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed25519), \
112114
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_CTX_use_PrivateKey_ed25519), \
113-
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed448)
115+
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed448), \
116+
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_x25519), \
117+
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_x448)
114118

115119
#endif /* WOLFCRYPT_TEST_EVP_PKEY_H */

wolfcrypt/src/evp.c

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@
4747
#ifdef HAVE_ED448
4848
#include <wolfssl/wolfcrypt/ed448.h>
4949
#endif
50+
#ifdef HAVE_CURVE25519
51+
#include <wolfssl/wolfcrypt/curve25519.h>
52+
#endif
53+
#ifdef HAVE_CURVE448
54+
#include <wolfssl/wolfcrypt/curve448.h>
55+
#endif
5056

5157
static const struct s_ent {
5258
const enum wc_HashType macType;
@@ -2767,7 +2773,7 @@ int wolfSSL_EVP_PKEY_CTX_ctrl_str(WOLFSSL_EVP_PKEY_CTX *ctx,
27672773
#endif /* NO_WOLFSSL_STUB */
27682774

27692775
#if (!defined(NO_DH) && defined(WOLFSSL_DH_EXTRA)) || defined(HAVE_ECC) || \
2770-
defined(HAVE_HKDF)
2776+
defined(HAVE_HKDF) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
27712777
int wolfSSL_EVP_PKEY_derive(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
27722778
{
27732779
int len;
@@ -2884,6 +2890,54 @@ int wolfSSL_EVP_PKEY_derive(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *key, size_
28842890
*keylen = (size_t)len;
28852891
break;
28862892
#endif
2893+
#ifdef HAVE_CURVE25519
2894+
case WC_EVP_PKEY_X25519:
2895+
if (!ctx->pkey->curve25519 || !ctx->peerKey->curve25519) {
2896+
return WOLFSSL_FAILURE;
2897+
}
2898+
len = CURVE25519_KEYSIZE;
2899+
if (key) {
2900+
word32 len32 = (word32)*keylen;
2901+
if (*keylen < (size_t)len) {
2902+
WOLFSSL_MSG("buffer too short");
2903+
return WOLFSSL_FAILURE;
2904+
}
2905+
/* X25519 shared secret is little-endian (RFC 7748). */
2906+
if (wc_curve25519_shared_secret_ex(ctx->pkey->curve25519,
2907+
ctx->peerKey->curve25519, key, &len32,
2908+
EC25519_LITTLE_ENDIAN) != 0) {
2909+
WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed");
2910+
return WOLFSSL_FAILURE;
2911+
}
2912+
len = (int)len32;
2913+
}
2914+
*keylen = (size_t)len;
2915+
break;
2916+
#endif
2917+
#ifdef HAVE_CURVE448
2918+
case WC_EVP_PKEY_X448:
2919+
if (!ctx->pkey->curve448 || !ctx->peerKey->curve448) {
2920+
return WOLFSSL_FAILURE;
2921+
}
2922+
len = CURVE448_KEY_SIZE;
2923+
if (key) {
2924+
word32 len32 = (word32)*keylen;
2925+
if (*keylen < (size_t)len) {
2926+
WOLFSSL_MSG("buffer too short");
2927+
return WOLFSSL_FAILURE;
2928+
}
2929+
/* X448 shared secret is little-endian (RFC 7748). */
2930+
if (wc_curve448_shared_secret_ex(ctx->pkey->curve448,
2931+
ctx->peerKey->curve448, key, &len32,
2932+
EC448_LITTLE_ENDIAN) != 0) {
2933+
WOLFSSL_MSG("wc_curve448_shared_secret_ex failed");
2934+
return WOLFSSL_FAILURE;
2935+
}
2936+
len = (int)len32;
2937+
}
2938+
*keylen = (size_t)len;
2939+
break;
2940+
#endif
28872941
#ifdef HAVE_HKDF
28882942
case WC_EVP_PKEY_HKDF:
28892943
(void)len;
@@ -3761,6 +3815,12 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx,
37613815
if (ctx->pkey == NULL ||
37623816
(ctx->pkey->type != WC_EVP_PKEY_EC &&
37633817
ctx->pkey->type != WC_EVP_PKEY_RSA &&
3818+
#ifdef HAVE_CURVE25519
3819+
ctx->pkey->type != WC_EVP_PKEY_X25519 &&
3820+
#endif
3821+
#ifdef HAVE_CURVE448
3822+
ctx->pkey->type != WC_EVP_PKEY_X448 &&
3823+
#endif
37643824
ctx->pkey->type != WC_EVP_PKEY_DH)) {
37653825
WOLFSSL_MSG("Key not set or key type not supported");
37663826
return WOLFSSL_FAILURE;
@@ -3821,6 +3881,57 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx,
38213881
}
38223882
}
38233883
break;
3884+
#endif
3885+
#ifdef HAVE_CURVE25519
3886+
case WC_EVP_PKEY_X25519:
3887+
if (pkey->curve25519 == NULL) {
3888+
pkey->curve25519 = (curve25519_key*)XMALLOC(
3889+
sizeof(curve25519_key), pkey->heap, DYNAMIC_TYPE_CURVE25519);
3890+
if (pkey->curve25519 == NULL) {
3891+
ret = MEMORY_E;
3892+
break;
3893+
}
3894+
if (wc_curve25519_init_ex(pkey->curve25519, pkey->heap,
3895+
INVALID_DEVID) != 0) {
3896+
XFREE(pkey->curve25519, pkey->heap, DYNAMIC_TYPE_CURVE25519);
3897+
pkey->curve25519 = NULL;
3898+
break;
3899+
}
3900+
#ifdef WOLFSSL_CURVE25519_BLINDING
3901+
/* Use the EVP_PKEY's RNG for scalar blinding on derive. */
3902+
(void)wc_curve25519_set_rng(pkey->curve25519, &pkey->rng);
3903+
#endif
3904+
pkey->ownCurve25519 = 1;
3905+
}
3906+
/* Reuse the RNG already initialized on the EVP_PKEY. */
3907+
if (wc_curve25519_make_key(&pkey->rng, CURVE25519_KEYSIZE,
3908+
pkey->curve25519) == 0) {
3909+
ret = WOLFSSL_SUCCESS;
3910+
}
3911+
break;
3912+
#endif
3913+
#ifdef HAVE_CURVE448
3914+
case WC_EVP_PKEY_X448:
3915+
if (pkey->curve448 == NULL) {
3916+
pkey->curve448 = (curve448_key*)XMALLOC(sizeof(curve448_key),
3917+
pkey->heap, DYNAMIC_TYPE_CURVE448);
3918+
if (pkey->curve448 == NULL) {
3919+
ret = MEMORY_E;
3920+
break;
3921+
}
3922+
if (wc_curve448_init(pkey->curve448) != 0) {
3923+
XFREE(pkey->curve448, pkey->heap, DYNAMIC_TYPE_CURVE448);
3924+
pkey->curve448 = NULL;
3925+
break;
3926+
}
3927+
pkey->ownCurve448 = 1;
3928+
}
3929+
/* Reuse the RNG already initialized on the EVP_PKEY. */
3930+
if (wc_curve448_make_key(&pkey->rng, CURVE448_KEY_SIZE,
3931+
pkey->curve448) == 0) {
3932+
ret = WOLFSSL_SUCCESS;
3933+
}
3934+
break;
38243935
#endif
38253936
default:
38263937
break;
@@ -3871,6 +3982,16 @@ int wolfSSL_EVP_PKEY_size(WOLFSSL_EVP_PKEY *pkey)
38713982
return wc_ecc_sig_size((ecc_key*)(pkey->ecc->internal));
38723983
#endif /* HAVE_ECC */
38733984

3985+
#ifdef HAVE_CURVE25519
3986+
case WC_EVP_PKEY_X25519:
3987+
return CURVE25519_KEYSIZE;
3988+
#endif
3989+
3990+
#ifdef HAVE_CURVE448
3991+
case WC_EVP_PKEY_X448:
3992+
return CURVE448_KEY_SIZE;
3993+
#endif
3994+
38743995
default:
38753996
break;
38763997
}
@@ -11822,6 +11943,27 @@ void wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY* key)
1182211943
break;
1182311944
#endif /* HAVE_ED448 */
1182411945

11946+
#ifdef HAVE_CURVE25519
11947+
case WC_EVP_PKEY_X25519:
11948+
if (key->curve25519 != NULL && key->ownCurve25519 == 1) {
11949+
wc_curve25519_free(key->curve25519);
11950+
XFREE(key->curve25519, key->heap,
11951+
DYNAMIC_TYPE_CURVE25519);
11952+
key->curve25519 = NULL;
11953+
}
11954+
break;
11955+
#endif /* HAVE_CURVE25519 */
11956+
11957+
#ifdef HAVE_CURVE448
11958+
case WC_EVP_PKEY_X448:
11959+
if (key->curve448 != NULL && key->ownCurve448 == 1) {
11960+
wc_curve448_free(key->curve448);
11961+
XFREE(key->curve448, key->heap, DYNAMIC_TYPE_CURVE448);
11962+
key->curve448 = NULL;
11963+
}
11964+
break;
11965+
#endif /* HAVE_CURVE448 */
11966+
1182511967
#ifdef HAVE_HKDF
1182611968
case WC_EVP_PKEY_HKDF:
1182711969
XFREE(key->hkdfSalt, NULL, DYNAMIC_TYPE_SALT);

0 commit comments

Comments
 (0)