Skip to content

Code for QUIC support#24

Open
helkoulak wants to merge 32 commits intowolfSSL:mainfrom
helkoulak:quic-support
Open

Code for QUIC support#24
helkoulak wants to merge 32 commits intowolfSSL:mainfrom
helkoulak:quic-support

Conversation

@helkoulak
Copy link
Copy Markdown

No description provided.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds QUIC support to the wolfcrypt provider by implementing the necessary cryptographic operations and packet protection algorithms required by the QUIC protocol.

  • Adds QUIC-specific header protection and packet encryption/decryption algorithms
  • Implements support for AES-128/256-GCM and ChaCha20-Poly1305 ciphers for QUIC
  • Configures cipher suites with QUIC key factories when the "quic" feature is enabled

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
wolfcrypt-rs/src/bindings.rs Adds lint allowance for unnecessary transmutes
rustls-wolfcrypt-provider/src/types/mod.rs Adds ChaCha cipher object type definition
rustls-wolfcrypt-provider/src/lib.rs Reorganizes imports and adds conditional QUIC support to cipher suites
rustls-wolfcrypt-provider/src/hkdf.rs Adds spacing for formatting
rustls-wolfcrypt-provider/src/error.rs Adds spacing for formatting
rustls-wolfcrypt-provider/src/aead/quic.rs Implements complete QUIC header protection and packet encryption
rustls-wolfcrypt-provider/Cargo.toml Adds "quic" feature flag

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Copy Markdown
Member

@julek-wolfssl julek-wolfssl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff. Does quic get tested in the current CI workflows?

Copy link
Copy Markdown
Contributor

@gasbytes gasbytes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work.
There seems to be some formatting issues that the CI detected, please fix those.
Also address the github copilot reports (mainly some unwraps that need to be refactored to handle errors).
Run clippy locally before committing too, the CI should detect some lints with the newest version.
Thank you.

@helkoulak
Copy link
Copy Markdown
Author

Good stuff. Does quic get tested in the current CI workflows?

Thank you. maybe we need to add --features quic in order for quic code to be compiled.

Nice work. There seems to be some formatting issues that the CI detected, please fix those. Also address the github copilot reports (mainly some unwraps that need to be refactored to handle errors). Run clippy locally before committing too, the CI should detect some lints with the newest version. Thank you.

Thank you. I have corrected the mentioned issues. Hopefully CI tests will runs without errors

@gasbytes
Copy link
Copy Markdown
Contributor

gasbytes commented Sep 25, 2025

Hello @helkoulak, there are still some clippy reports in the CI/CD apparently, it would be great if you could try and fix them.

Thank you. maybe we need to add --features quic in order for quic code to be compiled.

Yes, please feel free to update the current workflows to test that too.

@helkoulak
Copy link
Copy Markdown
Author

Hello @helkoulak, there are still some clippy reports in the CI/CD apparently, it would be great if you could try and fix them.
No problem, I will fix them ASAP.

Thank you. maybe we need to add --features quic in order for quic code to be compiled.

Yes, please feel free to update the current workflows to test that too.
Thank you, will do that ASAP

Copy link
Copy Markdown
Member

@julek-wolfssl julek-wolfssl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work. Still need to dive into src/aead.

cd ../rustls-wolfcrypt-provider/
cargo build --all-features --release
cd ../..
git clone https://github.com/helkoulak/rustls_v0.23.35_test_files.git
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Place these under .github/workflows/rustls or a similar path. I don't see a need to have this in a dedicated repo.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, you are using these files to make modifications to rustls/rustls? If yes, then I would prefer to use a patch file for this. The patch file should be applied with patch -p1 < <path/to/patch/file> in the rustls/rustls root dir.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here is to build a workspace that contains three packages, namely rustls, wolfcrypt-provider, and tests package. It is done this way to break the cyclic dependency between rustls and wolfcrypt-provider. The package tests is created from a modified copy of rustls/tests plus other files like build.rs and own Cargo.toml file.

Using a patch file will make in my opinion the script more difficult to understand. In addition to that, in each rustls version new tests are added and some are removed, so this makes the patch file valid for only a specific version of rustls.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same comments apply to macos-build.yml.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would consider moving the rustls tests into a separate workflow.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +23 to +103
impl Ed25519PrivateKey {
/// Extract ED25519 private and if available public key values from a PKCS#8 DER formatted key
fn extract_key_pair(input_key: &[u8]) -> Result<([u8; 32], Option<[u8; 32]>), rustls::Error> {
let mut public_key_raw: [u8; 32] = [0; ED25519_PUB_KEY_SIZE as usize];
let mut private_key_raw: [u8; 32] = [0; ED25519_KEY_SIZE as usize];
let mut skip_bytes: usize;
let mut key_sub_slice = input_key;

const SHORT_FORM_LEN_MAX: u8 = 127;
const TAG_SEQUENCE: u8 = 0x30;
const TAG_OCTET_SEQUENCE: u8 = 0x04;
const TAG_OPTIONAL_SET_OF_ATTRIBUTES: u8 = 0x80; //Implicit, context-specific, and primitive underlying type (SET OF)
const TAG_OPTIONAL_PUBLIC_KEY_BIT_STRING: u8 = 0x81; //Implicit, context-specific, and primitive underlying type (BIT STRING)

// The input key is encoded in PKCS#8 DER format with a structure as in
// https://www.rfc-editor.org/rfc/rfc5958.html
//
// AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey

// OneAsymmetricKey ::= SEQUENCE {
// version Version,
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
// privateKey PrivateKey,
// attributes [0] Attributes OPTIONAL,
// ...,
// [[2: publicKey [1] PublicKey OPTIONAL ]],
// ...
// }

// The key structure must begin with a SEQUENCE tag with at least 2 bytes length if short
// length format is used
if key_sub_slice[0] != TAG_SEQUENCE || key_sub_slice.len() < 2 {
return Err(rustls::Error::General(
"Faulty PKCS#8 ED25519 private key structure".into(),
));
}
// Check which length format and skip tag and length encoding bytes
if key_sub_slice[1] > SHORT_FORM_LEN_MAX {
skip_bytes = (2 + (key_sub_slice[1] & 0x7F)) as usize;
} else {
skip_bytes = 2;
}

// Skip version (3 bytes), algorithm ID sequence (0x30 + length encoding bytes + 5 ID bytes),
skip_bytes += 3 + 7;
key_sub_slice = input_key.get(skip_bytes..).unwrap();

// Check if next bytes are 0x04, 0x22, 0x04, 0x20
if !matches!(
key_sub_slice,
[TAG_OCTET_SEQUENCE, 0x22, TAG_OCTET_SEQUENCE, 0x20, ..]
) {
return Err(rustls::Error::General(
"Faulty PKCS#8 ED25519 private key structure".into(),
));
}

// Copy private key value
skip_bytes += 4;
key_sub_slice = input_key.get(skip_bytes..).unwrap();
private_key_raw.copy_from_slice(&key_sub_slice[..ED25519_KEY_SIZE as usize]);
skip_bytes += ED25519_KEY_SIZE as usize;
key_sub_slice = input_key.get(skip_bytes..).unwrap();

// Check if optional SET OF attributes exists and skip
if key_sub_slice.first() == Some(&TAG_OPTIONAL_SET_OF_ATTRIBUTES) {
skip_bytes += (2 + (key_sub_slice[1])) as usize;
key_sub_slice = input_key.get(skip_bytes..).unwrap();
}

// Check if optional public key value exists. If exists, skip tag, length encoding byte,
// and bits-used byte
if key_sub_slice.first() == Some(&TAG_OPTIONAL_PUBLIC_KEY_BIT_STRING) {
public_key_raw.copy_from_slice(&key_sub_slice[3..(3 + ED25519_KEY_SIZE as usize)]);
Ok((private_key_raw, Some(public_key_raw)))
} else {
Ok((private_key_raw, None))
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to use the ASN parsing in wolfcrypt. You should use wc_Ed25519PrivateKeyDecode which will pick up both priv and pub keys. Then wc_ed25519_export_key can be used to export the raw values. Only downside I see is that privKeySet and pubKeySet are not checked in wc_ed25519_export_key. Feel free to apply the following patch to wolfSSL. I'll submit a PR to wolfssl in a second.

diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c
index a03efb5603..ff59e07310 100644
--- a/wolfcrypt/src/ed25519.c
+++ b/wolfcrypt/src/ed25519.c
@@ -1127,6 +1127,9 @@ int wc_ed25519_export_public(const ed25519_key* key, byte* out, word32* outLen)
         return BUFFER_E;
     }
 
+    if (!key->pubKeySet)
+        return PUBLIC_KEY_E;
+
     *outLen = ED25519_PUB_KEY_SIZE;
     XMEMCPY(out, key->p, ED25519_PUB_KEY_SIZE);
 
@@ -1368,7 +1371,7 @@ int wc_ed25519_export_private_only(const ed25519_key* key, byte* out, word32* ou
 int wc_ed25519_export_private(const ed25519_key* key, byte* out, word32* outLen)
 {
     /* sanity checks on arguments */
-    if (key == NULL || out == NULL || outLen == NULL)
+    if (key == NULL || !key->privKeySet || out == NULL || outLen == NULL)
         return BAD_FUNC_ARG;
 
     if (*outLen < ED25519_PRV_KEY_SIZE) {
@@ -1398,6 +1401,8 @@ int wc_ed25519_export_key(const ed25519_key* key,
 
     /* export public part */
     ret = wc_ed25519_export_public(key, pub, pubSz);
+    if (ret == PUBLIC_KEY_E)
+        ret = 0; /* ignore no public key */
 
     return ret;
 }

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have applied the patch file provided but unfortunately with no luck. As I have explained earlier in our email conversations, the problem lies in the function wc_Ed25519PrivateKeyDecode. It is unable to parse/recognize the public key part found in a PKCS8 DER formatted key pair. Luckily I was able to debug and record where the error exactly happens. I will send it to you per Email.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the function extract_key_pair was the workaround

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid unwrap. I see rust has some ways to use unwrap without panicking. libs shouldn't take down an app. None of the places where unwrap is used are places where failure is catastrophic. Instead an error should be returned and user should be allowed to handle it that way . Maybe unwrap_or_else is appropriate?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine for tests though.

Copy link
Copy Markdown
Author

@helkoulak helkoulak Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have replaced unwrap() completely with functions like ? and map_err to propagate errors instead of panicking.

Copy link
Copy Markdown
Contributor

@gasbytes gasbytes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice work Hosam, I left a couple of comments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me and Juliusz were also thinking that it might be worth to add a feature to print the current provider being used via cargo, since you added the configuration option wolfcrypt-provider.
And add that step before running the testsuite, by grepping the output from stdout and confirming that we are running the full testsuite against the wolfcrypt-provider only.
That would be great.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, this is already done. The command that runs the tests targets only the runner file all_test_suites.rs. And in this runner file you have macros that are annotated with #[cfg(feature = "wolfcrypt-provider")] and print the sentence tests_with_wolfcrypt_. So as per my understanding, there is no way the tests will run against other providers than wolfcrypt-provider. Or did I miss something here?

gasbytes
gasbytes previously approved these changes Jan 28, 2026
Copy link
Copy Markdown
Contributor

@gasbytes gasbytes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work Hosam, LGTM.

@anhu
Copy link
Copy Markdown
Member

anhu commented Mar 10, 2026

Contributor agreement signed, approved and filed.
wolfSSL members, please proceed in the pull request process.

@gasbytes
Copy link
Copy Markdown
Contributor

@helkoulak please rebase your work against the latest main.
Thanks.

@helkoulak
Copy link
Copy Markdown
Author

@helkoulak please rebase your work against the latest main. Thanks.

Will do ASAP. Thank you

…ders like aws and ring as the order affects the success of some rustls tests
…ey value are provided with DER PKCS8 formatted private key
…stls default provider to reduce the code changes by hand when testing
…AesGcmSetKey must be used and not wc_AesSetKey
@helkoulak
Copy link
Copy Markdown
Author

Branch has been rebased against the latest main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants