diff --git a/src/pk.c b/src/pk.c index 1aaf40d065..4544baaf10 100644 --- a/src/pk.c +++ b/src/pk.c @@ -6262,6 +6262,16 @@ WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_bio_PrivateKey(WOLFSSL_BIO* bio, case DHk: type = WC_EVP_PKEY_DH; break; + #ifdef HAVE_ED25519 + case ED25519k: + type = WC_EVP_PKEY_ED25519; + break; + #endif + #ifdef HAVE_ED448 + case ED448k: + type = WC_EVP_PKEY_ED448; + break; + #endif default: type = WOLFSSL_FATAL_ERROR; break; @@ -6409,6 +6419,16 @@ WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY **key, case DHk: type = WC_EVP_PKEY_DH; break; + #ifdef HAVE_ED25519 + case ED25519k: + type = WC_EVP_PKEY_ED25519; + break; + #endif + #ifdef HAVE_ED448 + case ED448k: + type = WC_EVP_PKEY_ED448; + break; + #endif default: type = WOLFSSL_FATAL_ERROR; break; diff --git a/src/ssl.c b/src/ssl.c index 58cd6701c0..47b13a8513 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -17747,6 +17747,14 @@ word32 nid2oid(int nid, int grp) return CTC_SHA3_512wECDSA; #endif #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case WC_NID_ED25519: + return CTC_ED25519; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case WC_NID_ED448: + return CTC_ED448; + #endif /* HAVE_ED448 */ } break; @@ -17765,6 +17773,14 @@ word32 nid2oid(int nid, int grp) case WC_NID_X9_62_id_ecPublicKey: return ECDSAk; #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case WC_NID_ED25519: + return ED25519k; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case WC_NID_ED448: + return ED448k; + #endif /* HAVE_ED448 */ } break; @@ -18123,6 +18139,14 @@ int oid2nid(word32 oid, int grp) return WC_NID_ecdsa_with_SHA3_512; #endif #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case CTC_ED25519: + return WC_NID_ED25519; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case CTC_ED448: + return WC_NID_ED448; + #endif /* HAVE_ED448 */ } break; @@ -18145,6 +18169,14 @@ int oid2nid(word32 oid, int grp) case ECDSAk: return WC_NID_X9_62_id_ecPublicKey; #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + return WC_NID_ED25519; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + return WC_NID_ED448; + #endif /* HAVE_ED448 */ } break; diff --git a/src/ssl_load.c b/src/ssl_load.c index 0a0fb9e467..d77ccb31d6 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -5256,6 +5256,18 @@ int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey) WOLFSSL_MSG("populating ECC key"); ret = ECC_populate_EVP_PKEY(pkey, pkey->ecc); break; + #endif + #ifdef HAVE_ED25519 + case WC_EVP_PKEY_ED25519: + /* DER is already stored in pkey->pkey.ptr by d2i_evp_pkey. */ + WOLFSSL_MSG("populating Ed25519 key"); + break; + #endif + #ifdef HAVE_ED448 + case WC_EVP_PKEY_ED448: + /* DER is already stored in pkey->pkey.ptr by d2i_evp_pkey. */ + WOLFSSL_MSG("populating Ed448 key"); + break; #endif default: ret = 0; diff --git a/tests/api/test_evp_pkey.c b/tests/api/test_evp_pkey.c index 931f2b3804..eee753125e 100644 --- a/tests/api/test_evp_pkey.c +++ b/tests/api/test_evp_pkey.c @@ -2357,3 +2357,146 @@ int test_wolfSSL_EVP_PKEY_print_public(void) return EXPECT_RESULT(); } +int test_wolfSSL_EVP_PKEY_ed25519(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) + WOLFSSL_EVP_PKEY* pkey = NULL; + const unsigned char* p; + + /* Known-valid Ed25519 public key matching server_ed25519_key. The bytes + * are the raw 32-byte BIT STRING contents from + * ./certs/ed25519/server-ed25519-key.der so the import succeeds even + * under strict point-validation. */ + static const unsigned char rawPub[32] = { + 0x23, 0xaa, 0x4d, 0x60, 0x50, 0xe0, 0x13, 0xd3, + 0x3a, 0xed, 0xab, 0xf6, 0xa9, 0xcc, 0x4a, 0xfe, + 0xd7, 0x4d, 0x2f, 0xd2, 0x5b, 0x1a, 0x10, 0x05, + 0xef, 0x5a, 0x41, 0x25, 0xce, 0x1b, 0x53, 0x78 + }; + + /* SPKI wrapper around the same known-valid public key (the full + * contents of ./certs/ed25519/server-ed25519-key.der). */ + static const unsigned char spkiPub[] = { + 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, + 0x23, 0xaa, 0x4d, 0x60, 0x50, 0xe0, 0x13, 0xd3, + 0x3a, 0xed, 0xab, 0xf6, 0xa9, 0xcc, 0x4a, 0xfe, + 0xd7, 0x4d, 0x2f, 0xd2, 0x5b, 0x1a, 0x10, 0x05, + 0xef, 0x5a, 0x41, 0x25, 0xce, 0x1b, 0x53, 0x78 + }; + + /* Exercise the WC_EVP_PKEY_ED25519 case in d2i_evp_pkey() + * including the algId match for the PKCS#8 wrapper. */ + p = server_ed25519_key; + ExpectNotNull(pkey = wolfSSL_d2i_PrivateKey(EVP_PKEY_ED25519, NULL, + &p, (long)sizeof_server_ed25519_key)); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; + + p = spkiPub; + ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(spkiPub))); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; + + /* Exercise d2iTryEd25519Key's raw fallback where the caller passes + * the raw bytes from the SPKI BIT STRING rather than a wrapped SPKI. */ + p = rawPub; + ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(rawPub))); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; + + { + static const unsigned char junk[16] = { 0 }; + const unsigned char* jp = junk; + ExpectNull(wolfSSL_d2i_PUBKEY(NULL, &jp, (long)sizeof(junk))); + } +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_use_PrivateKey_ed25519(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) && \ + !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL_EVP_PKEY* pkey = NULL; + const unsigned char* p; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* Load the matching Ed25519 server cert */ + ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx, server_ed25519_cert, + (long)sizeof_server_ed25519_cert, WOLFSSL_FILETYPE_ASN1), + WOLFSSL_SUCCESS); + + /* Decode the Ed25519 private key as a WOLFSSL_EVP_PKEY */ + p = server_ed25519_key; + ExpectNotNull(pkey = wolfSSL_d2i_PrivateKey(EVP_PKEY_ED25519, NULL, + &p, (long)sizeof_server_ed25519_key)); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519); + + /* Load the pkey and check for success */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WOLFSSL_SUCCESS); + + wolfSSL_EVP_PKEY_free(pkey); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_EVP_PKEY_ed448(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED448) + WOLFSSL_EVP_PKEY* pkey = NULL; + const unsigned char* p; + + /* Known-valid Ed448 public key: the raw 57-byte BIT STRING contents + * from ./certs/ed448/server-ed448-key.der so the import succeeds even + * under strict point-validation. */ + static const unsigned char rawPub[57] = { + 0x54, 0x81, 0x39, 0x01, 0xeb, 0x37, 0xd9, 0xa9, + 0x07, 0xcd, 0x01, 0xbc, 0x9d, 0x70, 0x16, 0xc2, + 0x2c, 0x2b, 0x75, 0x5b, 0x63, 0xdb, 0xee, 0x3a, + 0x2d, 0x44, 0x92, 0x46, 0xb4, 0x7b, 0x07, 0x03, + 0x4f, 0xa2, 0xae, 0x86, 0x86, 0xdc, 0x8b, 0x4b, + 0x2c, 0x7f, 0xe8, 0x6b, 0x14, 0x8d, 0x58, 0xdd, + 0x6d, 0xe7, 0x6f, 0x3a, 0x05, 0x95, 0xa8, 0xef, + 0x00 + }; + + /* SPKI wrapper around the same known-valid public key (the full + * contents of ./certs/ed448/server-ed448-key.der). */ + static const unsigned char spkiPub[] = { + 0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x71, 0x03, 0x3a, 0x00, + 0x54, 0x81, 0x39, 0x01, 0xeb, 0x37, 0xd9, 0xa9, + 0x07, 0xcd, 0x01, 0xbc, 0x9d, 0x70, 0x16, 0xc2, + 0x2c, 0x2b, 0x75, 0x5b, 0x63, 0xdb, 0xee, 0x3a, + 0x2d, 0x44, 0x92, 0x46, 0xb4, 0x7b, 0x07, 0x03, + 0x4f, 0xa2, 0xae, 0x86, 0x86, 0xdc, 0x8b, 0x4b, + 0x2c, 0x7f, 0xe8, 0x6b, 0x14, 0x8d, 0x58, 0xdd, + 0x6d, 0xe7, 0x6f, 0x3a, 0x05, 0x95, 0xa8, 0xef, + 0x00 + }; + + /* SPKI path. */ + p = spkiPub; + ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(spkiPub))); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED448); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; + + /* Raw 57-byte fallback path. */ + p = rawPub; + ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(rawPub))); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED448); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; +#endif + return EXPECT_RESULT(); +} + diff --git a/tests/api/test_evp_pkey.h b/tests/api/test_evp_pkey.h index e11d5b9c8c..2f60056d3e 100644 --- a/tests/api/test_evp_pkey.h +++ b/tests/api/test_evp_pkey.h @@ -60,6 +60,9 @@ int test_wolfSSL_EVP_MD_ecc_signing(void); int test_wolfSSL_EVP_PKEY_encrypt(void); int test_wolfSSL_EVP_PKEY_derive(void); 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); #define TEST_EVP_PKEY_DECLS \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_CTX_new_id), \ @@ -97,6 +100,9 @@ int test_wolfSSL_EVP_PKEY_print_public(void); TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_MD_ecc_signing), \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_encrypt), \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_derive), \ - TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_print_public) + 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) #endif /* WOLFCRYPT_TEST_EVP_PKEY_H */ diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index b802958a9e..f8f0a264b2 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -41,6 +41,12 @@ #include #include #include +#ifdef HAVE_ED25519 +#include +#endif +#ifdef HAVE_ED448 +#include +#endif static const struct s_ent { const enum wc_HashType macType; @@ -11679,6 +11685,26 @@ void wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY* key) break; #endif /* ! NO_DH ... */ + #ifdef HAVE_ED25519 + case WC_EVP_PKEY_ED25519: + if (key->ed25519 != NULL && key->ownEd25519 == 1) { + wc_ed25519_free(key->ed25519); + XFREE(key->ed25519, key->heap, DYNAMIC_TYPE_ED25519); + key->ed25519 = NULL; + } + break; + #endif /* HAVE_ED25519 */ + + #ifdef HAVE_ED448 + case WC_EVP_PKEY_ED448: + if (key->ed448 != NULL && key->ownEd448 == 1) { + wc_ed448_free(key->ed448); + XFREE(key->ed448, key->heap, DYNAMIC_TYPE_ED448); + key->ed448 = NULL; + } + break; + #endif /* HAVE_ED448 */ + #ifdef HAVE_HKDF case WC_EVP_PKEY_HKDF: XFREE(key->hkdfSalt, NULL, DYNAMIC_TYPE_SALT); diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index bf0b3cf6af..e0dff16cf8 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -231,6 +231,173 @@ static int d2iTryEccKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } #endif /* HAVE_ECC && OPENSSL_EXTRA */ +#ifdef HAVE_ED25519 +/** + * Try to make an Ed25519 EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 on allocation/initialization failure + * @return WOLFSSL_FATAL_ERROR if the input is not an Ed25519 key. + */ +static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + ed25519_key* edKey = NULL; + word32 keyIdx = 0; + int isEdKey; + int ret = 1; + void* heap = NULL; + + if (*out != NULL) { + heap = (*out)->heap; + } + + edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap, + DYNAMIC_TYPE_ED25519); + if (edKey == NULL) { + return 0; + } + if (wc_ed25519_init_ex(edKey, heap, INVALID_DEVID) != 0) { + XFREE(edKey, heap, DYNAMIC_TYPE_ED25519); + return 0; + } + + /* Try decoding data as an Ed25519 private/public key. The input may be + * either a DER-encoded SubjectPublicKeyInfo / PKCS#8 PrivateKeyInfo + * (the normal d2i_PUBKEY input) or a raw key (as passed from + * CopyDecodedToX509 where dCert->publicKey is the raw bytes from the + * SPKI BIT STRING). Try the structured form first, then fall back to + * the raw import. */ + if (priv) { + isEdKey = (wc_Ed25519PrivateKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + if (!isEdKey && memSz == ED25519_KEY_SIZE) { + keyIdx = (word32)memSz; + isEdKey = (wc_ed25519_import_private_only(mem, (word32)memSz, + edKey) == 0); + } + } + else { + isEdKey = (wc_Ed25519PublicKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + if (!isEdKey && memSz == ED25519_PUB_KEY_SIZE) { + keyIdx = (word32)memSz; + isEdKey = (wc_ed25519_import_public(mem, (word32)memSz, edKey) + == 0); + } + } + + if (!isEdKey) { + wc_ed25519_free(edKey); + XFREE(edKey, heap, DYNAMIC_TYPE_ED25519); + return WOLFSSL_FATAL_ERROR; + } + + /* Create an EVP PKEY object holding the input bytes. These are the + * SPKI / PKCS#8 DER on the structured path, or the raw 32-byte key + * on the raw fallback path. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED25519); + if (ret == 1) { + (*out)->ownEd25519 = 1; + (*out)->ed25519 = edKey; + } + else { + wc_ed25519_free(edKey); + XFREE(edKey, heap, DYNAMIC_TYPE_ED25519); + } + + return ret; +} +#endif /* HAVE_ED25519 */ + +#ifdef HAVE_ED448 +/** + * Try to make an Ed448 EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 on allocation/initialization failure. + * @return WOLFSSL_FATAL_ERROR if the input is not an Ed448 key. + */ +static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + ed448_key* edKey = NULL; + word32 keyIdx = 0; + int isEdKey; + int ret = 1; + void* heap = NULL; + + if (*out != NULL) { + heap = (*out)->heap; + } + + edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448); + if (edKey == NULL) { + return 0; + } + if (wc_ed448_init_ex(edKey, heap, INVALID_DEVID) != 0) { + XFREE(edKey, heap, DYNAMIC_TYPE_ED448); + return 0; + } + + /* Try decoding data as an Ed448 private/public key. The input may be + * either a DER-encoded SubjectPublicKeyInfo / PKCS#8 PrivateKeyInfo + * (the normal d2i_PUBKEY input) or a raw key (as passed from + * CopyDecodedToX509 where dCert->publicKey is the raw bytes from the + * SPKI BIT STRING). Try the structured form first, then fall back to + * the raw import. */ + if (priv) { + isEdKey = (wc_Ed448PrivateKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + if (!isEdKey && memSz == ED448_KEY_SIZE) { + keyIdx = (word32)memSz; + isEdKey = (wc_ed448_import_private_only(mem, (word32)memSz, + edKey) == 0); + } + } + else { + isEdKey = (wc_Ed448PublicKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + if (!isEdKey && memSz == ED448_PUB_KEY_SIZE) { + keyIdx = (word32)memSz; + isEdKey = (wc_ed448_import_public(mem, (word32)memSz, edKey) + == 0); + } + } + + if (!isEdKey) { + wc_ed448_free(edKey); + XFREE(edKey, heap, DYNAMIC_TYPE_ED448); + return WOLFSSL_FATAL_ERROR; + } + + /* Create an EVP PKEY object holding the input bytes. These are the + * SPKI / PKCS#8 DER on the structured path, or the raw 57-byte key + * on the raw fallback path. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED448); + if (ret == 1) { + (*out)->ownEd448 = 1; + (*out)->ed448 = edKey; + } + else { + wc_ed448_free(edKey); + XFREE(edKey, heap, DYNAMIC_TYPE_ED448); + } + + return ret; +} +#endif /* HAVE_ED448 */ + #if !defined(NO_DSA) /** * Try to make a DSA EVP PKEY from data. @@ -404,24 +571,23 @@ static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, key = (DhKey*)dhObj->internal; /* Try decoding data as a DH public key. */ if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) { - ret = 0; + wolfSSL_DH_free(dhObj); + return WOLFSSL_FATAL_ERROR; } - if (ret == 1) { - /* DH key has data and is external to DH object. */ - elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; - if (priv) { - elements |= ELEMENT_PRV; - } - if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS ) { - ret = 0; - } + /* DH key has data and is external to DH object. */ + elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; + if (priv) { + elements |= ELEMENT_PRV; + } + if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS ) { + ret = 0; } if (ret == 1) { /* Create an EVP PKEY object. */ ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH); } if (ret == 1) { - /* Put RSA key object into EVP PKEY object. */ + /* Put DH key object into EVP PKEY object. */ (*out)->ownDh = 1; (*out)->dh = dhObj; } @@ -687,6 +853,18 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey_try(WOLFSSL_EVP_PKEY** out, #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ +#ifdef HAVE_ED25519 + if (d2iTryEd25519Key(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 + if (d2iTryEd448Key(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* HAVE_ED448 */ #ifdef HAVE_FALCON if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) { ; @@ -918,7 +1096,14 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, ) || (type == WC_EVP_PKEY_EC && algId != ECDSAk) || (type == WC_EVP_PKEY_DSA && algId != DSAk) || - (type == WC_EVP_PKEY_DH && algId != DHk)) { + (type == WC_EVP_PKEY_DH && algId != DHk) + #ifdef HAVE_ED25519 + || (type == WC_EVP_PKEY_ED25519 && algId != ED25519k) + #endif + #ifdef HAVE_ED448 + || (type == WC_EVP_PKEY_ED448 && algId != ED448k) + #endif + ) { WOLFSSL_MSG("PKCS8 does not match EVP key type"); return NULL; } @@ -1023,6 +1208,96 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* HAVE_DH */ #endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */ +#ifdef HAVE_ED25519 + case WC_EVP_PKEY_ED25519: + { + ed25519_key* edKey; + word32 keyIdx = 0; + int isEdKey; + + edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), local->heap, + DYNAMIC_TYPE_ED25519); + if (edKey == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wc_ed25519_init_ex(edKey, local->heap, INVALID_DEVID) != 0) { + XFREE(edKey, local->heap, DYNAMIC_TYPE_ED25519); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (priv) { + isEdKey = (wc_Ed25519PrivateKeyDecode(p, &keyIdx, edKey, + (word32)local->pkey_sz) == 0); + if (!isEdKey && local->pkey_sz == ED25519_KEY_SIZE) { + isEdKey = (wc_ed25519_import_private_only(p, + (word32)local->pkey_sz, edKey) == 0); + } + } + else { + isEdKey = (wc_Ed25519PublicKeyDecode(p, &keyIdx, edKey, + (word32)local->pkey_sz) == 0); + if (!isEdKey && local->pkey_sz == ED25519_PUB_KEY_SIZE) { + isEdKey = (wc_ed25519_import_public(p, + (word32)local->pkey_sz, edKey) == 0); + } + } + if (!isEdKey) { + wc_ed25519_free(edKey); + XFREE(edKey, local->heap, DYNAMIC_TYPE_ED25519); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + local->ownEd25519 = 1; + local->ed25519 = edKey; + break; + } +#endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 + case WC_EVP_PKEY_ED448: + { + ed448_key* edKey; + word32 keyIdx = 0; + int isEdKey; + + edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), local->heap, + DYNAMIC_TYPE_ED448); + if (edKey == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wc_ed448_init_ex(edKey, local->heap, INVALID_DEVID) != 0) { + XFREE(edKey, local->heap, DYNAMIC_TYPE_ED448); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (priv) { + isEdKey = (wc_Ed448PrivateKeyDecode(p, &keyIdx, edKey, + (word32)local->pkey_sz) == 0); + if (!isEdKey && local->pkey_sz == ED448_KEY_SIZE) { + isEdKey = (wc_ed448_import_private_only(p, + (word32)local->pkey_sz, edKey) == 0); + } + } + else { + isEdKey = (wc_Ed448PublicKeyDecode(p, &keyIdx, edKey, + (word32)local->pkey_sz) == 0); + if (!isEdKey && local->pkey_sz == ED448_PUB_KEY_SIZE) { + isEdKey = (wc_ed448_import_public(p, + (word32)local->pkey_sz, edKey) == 0); + } + } + if (!isEdKey) { + wc_ed448_free(edKey); + XFREE(edKey, local->heap, DYNAMIC_TYPE_ED448); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + local->ownEd448 = 1; + local->ed448 = edKey; + break; + } +#endif /* HAVE_ED448 */ default: WOLFSSL_MSG("Unsupported key type"); wolfSSL_EVP_PKEY_free(local); diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index f4ee44cd00..dc41bd11a4 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -450,6 +450,12 @@ enum { WC_EVP_PKEY_HKDF = WC_NID_hkdf, WC_EVP_PKEY_FALCON = 300, /* Randomly picked value. */ WC_EVP_PKEY_DILITHIUM = 301, /* Randomly picked value. */ +#ifdef HAVE_ED25519 + WC_EVP_PKEY_ED25519 = WC_NID_ED25519, +#endif +#ifdef HAVE_ED448 + WC_EVP_PKEY_ED448 = WC_NID_ED448, +#endif WC_AES_128_CFB1_TYPE = 24, WC_AES_192_CFB1_TYPE = 25, WC_AES_256_CFB1_TYPE = 26, @@ -517,6 +523,12 @@ enum { #define EVP_PKEY_HKDF WC_EVP_PKEY_HKDF #define EVP_PKEY_FALCON WC_EVP_PKEY_FALCON #define EVP_PKEY_DILITHIUM WC_EVP_PKEY_DILITHIUM +#ifdef HAVE_ED25519 +#define EVP_PKEY_ED25519 WC_EVP_PKEY_ED25519 +#endif +#ifdef HAVE_ED448 +#define EVP_PKEY_ED448 WC_EVP_PKEY_ED448 +#endif #define AES_128_CFB1_TYPE WC_AES_128_CFB1_TYPE #define AES_192_CFB1_TYPE WC_AES_192_CFB1_TYPE #define AES_256_CFB1_TYPE WC_AES_256_CFB1_TYPE diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index df5e272365..81160a57dc 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -602,6 +602,12 @@ struct WOLFSSL_EVP_PKEY { #ifndef NO_DH WOLFSSL_DH* dh; #endif + #ifdef HAVE_ED25519 + struct ed25519_key* ed25519; + #endif + #ifdef HAVE_ED448 + struct ed448_key* ed448; + #endif WC_RNG rng; #ifdef HAVE_HKDF const WOLFSSL_EVP_MD* hkdfMd; @@ -627,6 +633,12 @@ struct WOLFSSL_EVP_PKEY { WC_BITFIELD ownEcc:1; /* if struct owns ECC and should free it */ WC_BITFIELD ownDsa:1; /* if struct owns DSA and should free it */ WC_BITFIELD ownRsa:1; /* if struct owns RSA and should free it */ +#ifdef HAVE_ED25519 + WC_BITFIELD ownEd25519:1; /* if struct owns Ed25519 and should free it */ +#endif +#ifdef HAVE_ED448 + WC_BITFIELD ownEd448:1; /* if struct owns Ed448 and should free it */ +#endif };