-
Notifications
You must be signed in to change notification settings - Fork 995
Ed25519 support in the OpenSSL compatibility layer #10722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5518,8 +5518,8 @@ int wolfSSL_ED25519_verify(const unsigned char *msg, unsigned int msgSz, | |
|
|
||
| #endif /* OPENSSL_EXTRA && HAVE_ED25519 */ | ||
|
|
||
| #if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \ | ||
| defined(HAVE_ED25519) | ||
| #if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ | ||
| defined(OPENSSL_EXTRA_X509_SMALL)) && defined(HAVE_ED25519) | ||
| /* Allocate and initialize a new ed25519_key. | ||
| * | ||
| * @param [in] heap Heap hint for memory allocation. | ||
|
|
@@ -5570,7 +5570,8 @@ void wolfSSL_ED25519_free(ed25519_key* key) | |
| #endif | ||
| } | ||
| } | ||
| #endif /* (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) && HAVE_ED25519 */ | ||
| #endif /* (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL || OPENSSL_EXTRA_X509_SMALL) && | ||
| * HAVE_ED25519 */ | ||
|
|
||
| /******************************************************************************* | ||
| * END OF ED25519 API | ||
|
|
@@ -7373,6 +7374,27 @@ int pkcs8_encode(WOLFSSL_EVP_PKEY* pkey, byte* key, word32* keySz) | |
| curveOid = NULL; | ||
| oidSz = 0; | ||
| } | ||
| #endif | ||
| #if defined(HAVE_ED25519) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 [Low] pkcs8_encode Ed25519 branch assumes cached DER is a private PKCS#8 without validating The new Ed25519 branch unconditionally returns Fix: Add a |
||
| else if (pkey->type == WC_EVP_PKEY_ED25519) { | ||
| /* The cached DER is already a PKCS#8 PrivateKeyInfo (set when the | ||
| * key was generated or decoded), so return it as-is (same as the | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 [Medium] Non-ASCII em-dash in comment violates wolfSSL ASCII-only convention The new comment contains a UTF-8 em-dash (U+2014) instead of an ASCII hyphen: "so return it as-is — same as the". wolfSSL source is expected to be 7-bit ASCII only; this is the sole non-ASCII byte introduced across all five changed files and will trip ASCII/whitespace lint checks. Use Fix: Replace the em-dash with an ASCII hyphen to comply with the repository's ASCII-only source policy.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 [Low] Non-ASCII em-dash in comment violates ASCII-only convention The comment introduced by this PR contains a UTF-8 em-dash (U+2014) rather than ASCII. wolfSSL source must be 7-bit ASCII (no em/en dashes, smart quotes, etc.). This is the only non-ASCII byte introduced across the changed files (verified via a non-ASCII scan of all five files; the rest are clean). Fix: Replace the em-dash with |
||
| * DH special case above). */ | ||
| if (keySz == NULL) | ||
| return BAD_FUNC_ARG; | ||
| /* The cached DER must be present; e.g. an Ed25519 EVP_PKEY built | ||
| * from wolfSSL_X509_get_pubkey() holds only a raw public key, not a | ||
| * PKCS#8 private key, so reject rather than emit bogus output. */ | ||
| if (pkey->pkey.ptr == NULL || pkey->pkey_sz <= 0) | ||
| return BAD_FUNC_ARG; | ||
|
|
||
| *keySz = (word32)pkey->pkey_sz; | ||
| if (key == NULL) | ||
| return LENGTH_ONLY_E; | ||
|
|
||
| XMEMCPY(key, pkey->pkey.ptr, (size_t)pkey->pkey_sz); | ||
| return pkey->pkey_sz; | ||
| } | ||
| #endif | ||
| else { | ||
| ret = NOT_COMPILED_IN; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6481,6 +6481,11 @@ WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) | |
| x509->pubKeyOID == ML_DSA_87k) { | ||
| key->type = WC_EVP_PKEY_DILITHIUM; | ||
| } | ||
| #endif | ||
| #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) | ||
| else if (x509->pubKeyOID == ED25519k) { | ||
| key->type = WC_EVP_PKEY_ED25519; | ||
| } | ||
| #endif | ||
| else { | ||
| key->type = WC_EVP_PKEY_EC; | ||
|
|
@@ -6572,6 +6577,29 @@ WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) | |
| } | ||
| } | ||
| #endif /* NO_DSA */ | ||
|
|
||
| /* decode Ed25519 key */ | ||
| #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) | ||
| if (key->type == WC_EVP_PKEY_ED25519) { | ||
| key->ed25519 = wolfSSL_ED25519_new(x509->heap, INVALID_DEVID); | ||
| if (key->ed25519 == NULL) { | ||
| wolfSSL_EVP_PKEY_free(key); | ||
| return NULL; | ||
| } | ||
| key->ownEd25519 = 1; | ||
|
|
||
| /* The X.509 public key buffer holds the raw Ed25519 key | ||
| * (CopyDecodedToX509 / StoreKey store the BIT STRING | ||
| * contents), so import it directly. */ | ||
| if (wc_ed25519_import_public( | ||
| (const unsigned char*)key->pkey.ptr, | ||
| (word32)key->pkey_sz, key->ed25519) != 0) { | ||
| WOLFSSL_MSG("wc_ed25519_import_public failed"); | ||
| wolfSSL_EVP_PKEY_free(key); | ||
| return NULL; | ||
| } | ||
| } | ||
| #endif /* HAVE_ED25519 */ | ||
| } | ||
| } | ||
| return key; | ||
|
|
@@ -9010,6 +9038,12 @@ static int verifyX509orX509REQ(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, | |
| const byte* der; | ||
| int derSz = 0; | ||
| int type; | ||
| const byte* pubKey; | ||
| int pubKeySz; | ||
| #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT) | ||
| byte edPubKey[ED25519_PUB_KEY_SIZE]; | ||
| word32 edPubKeySz = (word32)sizeof(edPubKey); | ||
| #endif | ||
|
|
||
| (void)req; | ||
|
|
||
|
|
@@ -9023,6 +9057,10 @@ static int verifyX509orX509REQ(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, | |
| return WOLFSSL_FATAL_ERROR; | ||
| } | ||
|
|
||
| /* Most key types verify against the cached public-key DER. */ | ||
| pubKey = (const byte*)pkey->pkey.ptr; | ||
| pubKeySz = pkey->pkey_sz; | ||
|
|
||
| switch (pkey->type) { | ||
| case WC_EVP_PKEY_RSA: | ||
| type = RSAk; | ||
|
|
@@ -9036,6 +9074,23 @@ static int verifyX509orX509REQ(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, | |
| type = DSAk; | ||
| break; | ||
|
|
||
| #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT) | ||
| case WC_EVP_PKEY_ED25519: | ||
| /* The signature check needs the raw public key; for Ed25519 | ||
| * pkey->pkey.ptr holds a PKCS#8 private blob (or nothing), so | ||
| * export the public key from the ed25519_key instead. */ | ||
| if (pkey->ed25519 == NULL || | ||
| wc_ed25519_export_public(pkey->ed25519, edPubKey, | ||
| &edPubKeySz) != 0) { | ||
| WOLFSSL_MSG("Unable to export Ed25519 public key"); | ||
| return WOLFSSL_FATAL_ERROR; | ||
| } | ||
| pubKey = edPubKey; | ||
| pubKeySz = (int)edPubKeySz; | ||
| type = ED25519k; | ||
| break; | ||
| #endif | ||
|
|
||
| default: | ||
| WOLFSSL_MSG("Unknown pkey key type"); | ||
| return WOLFSSL_FATAL_ERROR; | ||
|
|
@@ -9044,11 +9099,11 @@ static int verifyX509orX509REQ(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, | |
| #ifdef WOLFSSL_CERT_REQ | ||
| if (req) | ||
| ret = CheckCSRSignaturePubKey(der, (word32)derSz, x509->heap, | ||
| (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type); | ||
| (unsigned char*)pubKey, pubKeySz, type); | ||
| else | ||
| #endif | ||
| ret = CheckCertSignaturePubKey(der, (word32)derSz, x509->heap, | ||
| (unsigned char*)pkey->pkey.ptr, pkey->pkey_sz, type); | ||
| (unsigned char*)pubKey, pubKeySz, type); | ||
| if (ret == 0) { | ||
| return WOLFSSL_SUCCESS; | ||
| } | ||
|
|
@@ -12225,6 +12280,14 @@ static int CertFromX509(Cert* cert, WOLFSSL_X509* x509) | |
| int hashType; | ||
| int sigType = WOLFSSL_FAILURE; | ||
|
|
||
| #if defined(HAVE_ED25519) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 [Low] Use CTC_ED25519 instead of ED25519k for signature-type return value
Fix: Return |
||
| /* Ed25519 carries its own hash, so md is unused (and may be NULL). | ||
| * Resolve it before touching md. */ | ||
| if (pkey->type == WC_EVP_PKEY_ED25519) { | ||
| return CTC_ED25519; | ||
| } | ||
| #endif | ||
|
|
||
| /* Convert key type and hash algorithm to a signature algorithm */ | ||
| if (wolfSSL_EVP_get_hashinfo(md, &hashType, NULL) | ||
| == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) | ||
|
|
@@ -12337,6 +12400,9 @@ static int CertFromX509(Cert* cert, WOLFSSL_X509* x509) | |
| #ifndef NO_DSA | ||
| DsaKey* dsa = NULL; | ||
| #endif | ||
| #if defined(HAVE_ED25519) | ||
| ed25519_key* ed25519 = NULL; | ||
| #endif | ||
| #if defined(HAVE_FALCON) | ||
| falcon_key* falcon = NULL; | ||
| #endif | ||
|
|
@@ -12472,6 +12538,28 @@ static int CertFromX509(Cert* cert, WOLFSSL_X509* x509) | |
| key = (void*)dsa; | ||
| } | ||
| #endif | ||
| #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) | ||
| if (x509->pubKeyOID == ED25519k) { | ||
| ed25519 = wolfSSL_ED25519_new(NULL, INVALID_DEVID); | ||
| if (ed25519 == NULL) { | ||
| WOLFSSL_MSG("Failed to allocate memory for ed25519_key"); | ||
| XFREE(cert, NULL, DYNAMIC_TYPE_CERT); | ||
| return WOLFSSL_FAILURE; | ||
| } | ||
|
|
||
| type = ED25519_TYPE; | ||
| /* The X.509 public key buffer holds the raw Ed25519 key. */ | ||
| ret = wc_ed25519_import_public(x509->pubKey.buffer, | ||
| x509->pubKey.length, ed25519); | ||
| if (ret != 0) { | ||
| WOLFSSL_ERROR_VERBOSE(ret); | ||
| wolfSSL_ED25519_free(ed25519); | ||
| XFREE(cert, NULL, DYNAMIC_TYPE_CERT); | ||
| return ret; | ||
| } | ||
| key = (void*)ed25519; | ||
| } | ||
| #endif | ||
| #if defined(HAVE_FALCON) | ||
| if ((x509->pubKeyOID == FALCON_LEVEL1k) || | ||
| (x509->pubKeyOID == FALCON_LEVEL5k)) { | ||
|
|
@@ -12723,6 +12811,11 @@ static int CertFromX509(Cert* cert, WOLFSSL_X509* x509) | |
| XFREE(ecc, NULL, DYNAMIC_TYPE_ECC); | ||
| } | ||
| #endif | ||
| #if defined(HAVE_ED25519) | ||
| if (x509->pubKeyOID == ED25519k) { | ||
| wolfSSL_ED25519_free(ed25519); | ||
| } | ||
| #endif | ||
| #ifndef NO_DSA | ||
| if (x509->pubKeyOID == DSAk) { | ||
| wc_FreeDsaKey(dsa); | ||
|
|
@@ -12807,6 +12900,12 @@ static int CertFromX509(Cert* cert, WOLFSSL_X509* x509) | |
| key = pkey->ecc->internal; | ||
| } | ||
| #endif | ||
| #if defined(HAVE_ED25519) | ||
| if (pkey->type == WC_EVP_PKEY_ED25519) { | ||
| type = ED25519_TYPE; | ||
| key = pkey->ed25519; | ||
| } | ||
| #endif | ||
|
|
||
| /* Sign the certificate (request) body. */ | ||
| ret = wc_InitRng(&rng); | ||
|
|
@@ -12895,11 +12994,24 @@ int wolfSSL_X509_sign(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey, | |
|
|
||
| WOLFSSL_ENTER("wolfSSL_X509_sign"); | ||
|
|
||
| if (x509 == NULL || pkey == NULL || md == NULL) { | ||
| if (x509 == NULL || pkey == NULL) { | ||
| ret = WOLFSSL_FAILURE; | ||
| goto out; | ||
| } | ||
|
|
||
| /* Most key types require an explicit digest. Ed25519 is the exception: | ||
| * it signs with a NULL digest (the key has a built-in hash). Kept as a | ||
| * dedicated block since other algorithms may grow similar edge cases. */ | ||
| if (md == NULL) { | ||
| #if defined(HAVE_ED25519) | ||
| if (pkey->type != WC_EVP_PKEY_ED25519) | ||
| #endif | ||
| { | ||
| ret = WOLFSSL_FAILURE; | ||
| goto out; | ||
| } | ||
| } | ||
|
|
||
| x509->sigOID = wolfSSL_sigTypeFromPKEY((WOLFSSL_EVP_MD*)md, pkey); | ||
| if ((ret = wolfssl_x509_make_der(x509, 0, der, &derSz, 0)) != | ||
| WOLFSSL_SUCCESS) { | ||
|
|
@@ -16408,6 +16520,30 @@ int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey) | |
| cert->pubKeyOID = ECDSAk; | ||
| } | ||
| break; | ||
| #endif | ||
| #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT) | ||
| case WC_EVP_PKEY_ED25519: | ||
| { | ||
| word32 rawLen = ED25519_PUB_KEY_SIZE; | ||
|
|
||
| if (pkey->ed25519 == NULL) | ||
| return WOLFSSL_FAILURE; | ||
|
|
||
| /* Store the RAW public key: wolfSSL keeps an X.509 Ed25519 | ||
| * public key as the bare key bytes (see StoreKey / | ||
| * CopyDecodedToX509), not a SubjectPublicKeyInfo. */ | ||
| p = (byte*)XMALLOC(rawLen, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); | ||
| if (p == NULL) | ||
| return WOLFSSL_FAILURE; | ||
|
|
||
| if (wc_ed25519_export_public(pkey->ed25519, p, &rawLen) != 0) { | ||
| XFREE(p, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); | ||
| return WOLFSSL_FAILURE; | ||
| } | ||
| derSz = (int)rawLen; | ||
| cert->pubKeyOID = ED25519k; | ||
| } | ||
| break; | ||
| #endif | ||
| default: | ||
| return WOLFSSL_FAILURE; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟠 [Medium] pkcs8_encode Ed25519 special case lacks NULL guard on pkey-pkey.ptr
The new Ed25519 branch copies the cached DER with
XMEMCPY(key, pkey->pkey.ptr, pkey->pkey_sz)but only checkskeySz == NULL. Unlike the DH special case it mirrors, it does not validate thatpkey->pkey.ptr(orpkey->ed25519) is non-NULL /pkey_sz > 0. The DH branch above is reached only after confirmingpkey->dh->priv_key || pub_keyare set, which implies the buffer is populated; the Ed25519 branch has no such precondition. An Ed25519WOLFSSL_EVP_PKEYwhosepkey.ptrwas never cached (e.g. a key populated only via the in-memoryed25519object) would dereference NULL here.Fix: Add a
pkey->pkey.ptr == NULL || pkey->pkey_sz <= 0guard before the copy, returning BAD_FUNC_ARG, to match the defensive style of the surrounding branches.