Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions tests/api/test_evp_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -2702,3 +2702,162 @@ int test_wolfSSL_EVP_PKEY_ed448(void)
return EXPECT_RESULT();
}

int test_wolfSSL_EVP_PKEY_x25519(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE25519)
EVP_PKEY* pkey = NULL;
EVP_PKEY* peer = NULL;
EVP_PKEY_CTX* genCtx = NULL;
EVP_PKEY_CTX* ctx = NULL;
unsigned char rawPriv[32];
unsigned char rawPub[32];
unsigned char secretA[32];
unsigned char secretB[32];
size_t secretLen;
int i;

for (i = 0; i < 32; i++) {
rawPriv[i] = (unsigned char)i;
rawPub[i] = (unsigned char)(0x40 + i);
}

/* Raw import with the correct length reports the X25519 type. */
ExpectNotNull(pkey = EVP_PKEY_new_raw_public_key(
EVP_PKEY_X25519, NULL, rawPub, sizeof(rawPub)));
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_X25519);
EVP_PKEY_free(pkey);
pkey = NULL;

ExpectNotNull(pkey = EVP_PKEY_new_raw_private_key(
EVP_PKEY_X25519, NULL, rawPriv, sizeof(rawPriv)));
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_X25519);

/* X25519 is key-agreement only: signing must be rejected. */
ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL));
ExpectIntNE(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS);
EVP_PKEY_CTX_free(ctx);
ctx = NULL;
EVP_PKEY_free(pkey);
pkey = NULL;

/* Wrong raw lengths are rejected. */
ExpectNull(EVP_PKEY_new_raw_public_key(
EVP_PKEY_X25519, NULL, rawPub, 16));
ExpectNull(EVP_PKEY_new_raw_private_key(
EVP_PKEY_X25519, NULL, rawPriv, 16));

/* Generate two key pairs and confirm ECDH agreement is symmetric. This
* also exercises the little-endian convention used on import/derive. */
ExpectNotNull(genCtx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL));
ExpectIntEQ(EVP_PKEY_keygen_init(genCtx), WOLFSSL_SUCCESS);
ExpectIntEQ(EVP_PKEY_keygen(genCtx, &pkey), WOLFSSL_SUCCESS);
ExpectIntEQ(EVP_PKEY_keygen(genCtx, &peer), WOLFSSL_SUCCESS);
EVP_PKEY_CTX_free(genCtx);
genCtx = NULL;

ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL));
ExpectIntEQ(EVP_PKEY_derive_init(ctx), WOLFSSL_SUCCESS);
ExpectIntEQ(EVP_PKEY_derive_set_peer(ctx, peer), WOLFSSL_SUCCESS);
secretLen = sizeof(secretA);
ExpectIntEQ(EVP_PKEY_derive(ctx, secretA, &secretLen), WOLFSSL_SUCCESS);
ExpectIntEQ((int)secretLen, 32);
EVP_PKEY_CTX_free(ctx);
ctx = NULL;

ExpectNotNull(ctx = EVP_PKEY_CTX_new(peer, NULL));
ExpectIntEQ(EVP_PKEY_derive_init(ctx), WOLFSSL_SUCCESS);
ExpectIntEQ(EVP_PKEY_derive_set_peer(ctx, pkey), WOLFSSL_SUCCESS);
secretLen = sizeof(secretB);
ExpectIntEQ(EVP_PKEY_derive(ctx, secretB, &secretLen), WOLFSSL_SUCCESS);
ExpectIntEQ((int)secretLen, 32);
EVP_PKEY_CTX_free(ctx);
ctx = NULL;

ExpectIntEQ(XMEMCMP(secretA, secretB, 32), 0);

EVP_PKEY_free(peer);
EVP_PKEY_free(pkey);
#endif
return EXPECT_RESULT();
}

int test_wolfSSL_EVP_PKEY_x448(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE448)
EVP_PKEY* pkey = NULL;
EVP_PKEY* peer = NULL;
EVP_PKEY_CTX* genCtx = NULL;
EVP_PKEY_CTX* ctx = NULL;
unsigned char rawPriv[56];
unsigned char rawPub[56];
unsigned char secretA[56];
unsigned char secretB[56];
size_t secretLen;
int i;

for (i = 0; i < 56; i++) {
rawPriv[i] = (unsigned char)i;
rawPub[i] = (unsigned char)(0x40 + i);
}

/* Raw import with the correct length reports the X448 type. */
ExpectNotNull(pkey = EVP_PKEY_new_raw_public_key(
EVP_PKEY_X448, NULL, rawPub, sizeof(rawPub)));
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_X448);
EVP_PKEY_free(pkey);
pkey = NULL;

ExpectNotNull(pkey = EVP_PKEY_new_raw_private_key(
EVP_PKEY_X448, NULL, rawPriv, sizeof(rawPriv)));
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_X448);

/* X448 is key-agreement only: signing must be rejected. */
ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL));
ExpectIntNE(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS);
EVP_PKEY_CTX_free(ctx);
ctx = NULL;
EVP_PKEY_free(pkey);
pkey = NULL;

/* Wrong raw lengths are rejected. */
ExpectNull(EVP_PKEY_new_raw_public_key(
EVP_PKEY_X448, NULL, rawPub, 16));
ExpectNull(EVP_PKEY_new_raw_private_key(
EVP_PKEY_X448, NULL, rawPriv, 16));

/* Generate two key pairs and confirm ECDH agreement is symmetric. */
ExpectNotNull(genCtx = EVP_PKEY_CTX_new_id(EVP_PKEY_X448, NULL));
ExpectIntEQ(EVP_PKEY_keygen_init(genCtx), WOLFSSL_SUCCESS);
ExpectIntEQ(EVP_PKEY_keygen(genCtx, &pkey), WOLFSSL_SUCCESS);
ExpectIntEQ(EVP_PKEY_keygen(genCtx, &peer), WOLFSSL_SUCCESS);
EVP_PKEY_CTX_free(genCtx);
genCtx = NULL;

ExpectNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL));
ExpectIntEQ(EVP_PKEY_derive_init(ctx), WOLFSSL_SUCCESS);
ExpectIntEQ(EVP_PKEY_derive_set_peer(ctx, peer), WOLFSSL_SUCCESS);
secretLen = sizeof(secretA);
ExpectIntEQ(EVP_PKEY_derive(ctx, secretA, &secretLen), WOLFSSL_SUCCESS);
ExpectIntEQ((int)secretLen, 56);
EVP_PKEY_CTX_free(ctx);
ctx = NULL;

ExpectNotNull(ctx = EVP_PKEY_CTX_new(peer, NULL));
ExpectIntEQ(EVP_PKEY_derive_init(ctx), WOLFSSL_SUCCESS);
ExpectIntEQ(EVP_PKEY_derive_set_peer(ctx, pkey), WOLFSSL_SUCCESS);
secretLen = sizeof(secretB);
ExpectIntEQ(EVP_PKEY_derive(ctx, secretB, &secretLen), WOLFSSL_SUCCESS);
ExpectIntEQ((int)secretLen, 56);
EVP_PKEY_CTX_free(ctx);
ctx = NULL;

ExpectIntEQ(XMEMCMP(secretA, secretB, 56), 0);

EVP_PKEY_free(peer);
EVP_PKEY_free(pkey);
#endif
return EXPECT_RESULT();
}

6 changes: 5 additions & 1 deletion tests/api/test_evp_pkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ int test_wolfSSL_EVP_PKEY_print_public(void);
int test_wolfSSL_EVP_PKEY_ed25519(void);
int test_wolfSSL_CTX_use_PrivateKey_ed25519(void);
int test_wolfSSL_EVP_PKEY_ed448(void);
int test_wolfSSL_EVP_PKEY_x25519(void);
int test_wolfSSL_EVP_PKEY_x448(void);

#define TEST_EVP_PKEY_DECLS \
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_CTX_new_id), \
Expand Down Expand Up @@ -110,6 +112,8 @@ int test_wolfSSL_EVP_PKEY_ed448(void);
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_print_public), \
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed25519), \
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_CTX_use_PrivateKey_ed25519), \
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed448)
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed448), \
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_x25519), \
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_x448)

#endif /* WOLFCRYPT_TEST_EVP_PKEY_H */
144 changes: 143 additions & 1 deletion wolfcrypt/src/evp.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
#ifdef HAVE_ED448
#include <wolfssl/wolfcrypt/ed448.h>
#endif
#ifdef HAVE_CURVE25519
#include <wolfssl/wolfcrypt/curve25519.h>
#endif
#ifdef HAVE_CURVE448
#include <wolfssl/wolfcrypt/curve448.h>
#endif

static const struct s_ent {
const enum wc_HashType macType;
Expand Down Expand Up @@ -2767,7 +2773,7 @@ int wolfSSL_EVP_PKEY_CTX_ctrl_str(WOLFSSL_EVP_PKEY_CTX *ctx,
#endif /* NO_WOLFSSL_STUB */

#if (!defined(NO_DH) && defined(WOLFSSL_DH_EXTRA)) || defined(HAVE_ECC) || \
defined(HAVE_HKDF)
defined(HAVE_HKDF) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
int wolfSSL_EVP_PKEY_derive(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
{
int len;
Expand Down Expand Up @@ -2884,6 +2890,54 @@ int wolfSSL_EVP_PKEY_derive(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *key, size_
*keylen = (size_t)len;
break;
#endif
#ifdef HAVE_CURVE25519
case WC_EVP_PKEY_X25519:
if (!ctx->pkey->curve25519 || !ctx->peerKey->curve25519) {
return WOLFSSL_FAILURE;
}
len = CURVE25519_KEYSIZE;
if (key) {
word32 len32 = (word32)*keylen;
if (*keylen < (size_t)len) {
WOLFSSL_MSG("buffer too short");
return WOLFSSL_FAILURE;
}
/* X25519 shared secret is little-endian (RFC 7748). */
if (wc_curve25519_shared_secret_ex(ctx->pkey->curve25519,
ctx->peerKey->curve25519, key, &len32,
EC25519_LITTLE_ENDIAN) != 0) {
WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed");
return WOLFSSL_FAILURE;
}
len = (int)len32;
}
*keylen = (size_t)len;
break;
#endif
#ifdef HAVE_CURVE448
case WC_EVP_PKEY_X448:
if (!ctx->pkey->curve448 || !ctx->peerKey->curve448) {
return WOLFSSL_FAILURE;
}
len = CURVE448_KEY_SIZE;
if (key) {
word32 len32 = (word32)*keylen;
if (*keylen < (size_t)len) {
WOLFSSL_MSG("buffer too short");
return WOLFSSL_FAILURE;
}
/* X448 shared secret is little-endian (RFC 7748). */
if (wc_curve448_shared_secret_ex(ctx->pkey->curve448,
ctx->peerKey->curve448, key, &len32,
EC448_LITTLE_ENDIAN) != 0) {
WOLFSSL_MSG("wc_curve448_shared_secret_ex failed");
return WOLFSSL_FAILURE;
}
len = (int)len32;
}
*keylen = (size_t)len;
break;
#endif
#ifdef HAVE_HKDF
case WC_EVP_PKEY_HKDF:
(void)len;
Expand Down Expand Up @@ -3761,6 +3815,12 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx,
if (ctx->pkey == NULL ||
(ctx->pkey->type != WC_EVP_PKEY_EC &&
ctx->pkey->type != WC_EVP_PKEY_RSA &&
#ifdef HAVE_CURVE25519
ctx->pkey->type != WC_EVP_PKEY_X25519 &&
#endif
#ifdef HAVE_CURVE448
ctx->pkey->type != WC_EVP_PKEY_X448 &&
#endif
ctx->pkey->type != WC_EVP_PKEY_DH)) {
WOLFSSL_MSG("Key not set or key type not supported");
return WOLFSSL_FAILURE;
Expand Down Expand Up @@ -3821,6 +3881,57 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx,
}
}
break;
#endif
#ifdef HAVE_CURVE25519
case WC_EVP_PKEY_X25519:
if (pkey->curve25519 == NULL) {
pkey->curve25519 = (curve25519_key*)XMALLOC(
sizeof(curve25519_key), pkey->heap, DYNAMIC_TYPE_CURVE25519);
if (pkey->curve25519 == NULL) {
ret = MEMORY_E;
break;
}
if (wc_curve25519_init_ex(pkey->curve25519, pkey->heap,
INVALID_DEVID) != 0) {
XFREE(pkey->curve25519, pkey->heap, DYNAMIC_TYPE_CURVE25519);
pkey->curve25519 = NULL;
break;
}
#ifdef WOLFSSL_CURVE25519_BLINDING
/* Use the EVP_PKEY's RNG for scalar blinding on derive. */
(void)wc_curve25519_set_rng(pkey->curve25519, &pkey->rng);
#endif
pkey->ownCurve25519 = 1;
}
/* Reuse the RNG already initialized on the EVP_PKEY. */
if (wc_curve25519_make_key(&pkey->rng, CURVE25519_KEYSIZE,
pkey->curve25519) == 0) {
ret = WOLFSSL_SUCCESS;
}
break;
#endif
#ifdef HAVE_CURVE448
case WC_EVP_PKEY_X448:
if (pkey->curve448 == NULL) {
pkey->curve448 = (curve448_key*)XMALLOC(sizeof(curve448_key),
pkey->heap, DYNAMIC_TYPE_CURVE448);
if (pkey->curve448 == NULL) {
ret = MEMORY_E;
break;
}
if (wc_curve448_init(pkey->curve448) != 0) {
XFREE(pkey->curve448, pkey->heap, DYNAMIC_TYPE_CURVE448);
pkey->curve448 = NULL;
break;
}
pkey->ownCurve448 = 1;
}
/* Reuse the RNG already initialized on the EVP_PKEY. */
if (wc_curve448_make_key(&pkey->rng, CURVE448_KEY_SIZE,
pkey->curve448) == 0) {
ret = WOLFSSL_SUCCESS;
}
break;
#endif
default:
break;
Expand Down Expand Up @@ -3871,6 +3982,16 @@ int wolfSSL_EVP_PKEY_size(WOLFSSL_EVP_PKEY *pkey)
return wc_ecc_sig_size((ecc_key*)(pkey->ecc->internal));
#endif /* HAVE_ECC */

#ifdef HAVE_CURVE25519
case WC_EVP_PKEY_X25519:
return CURVE25519_KEYSIZE;
#endif

#ifdef HAVE_CURVE448
case WC_EVP_PKEY_X448:
return CURVE448_KEY_SIZE;
#endif

default:
break;
}
Expand Down Expand Up @@ -11818,6 +11939,27 @@ void wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY* key)
break;
#endif /* HAVE_ED448 */

#ifdef HAVE_CURVE25519
case WC_EVP_PKEY_X25519:
if (key->curve25519 != NULL && key->ownCurve25519 == 1) {
wc_curve25519_free(key->curve25519);
XFREE(key->curve25519, key->heap,
DYNAMIC_TYPE_CURVE25519);
key->curve25519 = NULL;
}
break;
#endif /* HAVE_CURVE25519 */

#ifdef HAVE_CURVE448
case WC_EVP_PKEY_X448:
if (key->curve448 != NULL && key->ownCurve448 == 1) {
wc_curve448_free(key->curve448);
XFREE(key->curve448, key->heap, DYNAMIC_TYPE_CURVE448);
key->curve448 = NULL;
}
break;
#endif /* HAVE_CURVE448 */

#ifdef HAVE_HKDF
case WC_EVP_PKEY_HKDF:
XFREE(key->hkdfSalt, NULL, DYNAMIC_TYPE_SALT);
Expand Down
Loading
Loading