feat: enable draft-pqc feature on pgp crate

This is needed to have support of v6 PQC keys
by the time users start generating profiles
using such keys.

Test key was generated with rsop/v0.10.0-16-gd98265f
(commit d98265f821e7bb181d06da1d634c5c4668d89e83)
using the command
cargo run --features draft-pqc generate-key \
          --profile draft-ietf-openpgp-pqc-14-v6-ed25519-mlkem768x25519
This commit is contained in:
link2xt
2026-04-30 23:09:10 +02:00
parent 4e8f6dc083
commit 9908be06dc
8 changed files with 167 additions and 5 deletions

80
Cargo.lock generated
View File

@@ -2608,6 +2608,25 @@ dependencies = [
"libm",
]
[[package]]
name = "hybrid-array"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2d35805454dc9f8662a98d6d61886ffe26bd465f5960e0e55345c70d5c0d2a9"
dependencies = [
"typenum",
]
[[package]]
name = "hybrid-array"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "891d15931895091dea5c47afa5b3c9a01ba634b311919fd4d41388fa0e3d76af"
dependencies = [
"typenum",
"zeroize",
]
[[package]]
name = "hyper"
version = "1.9.0"
@@ -3257,6 +3276,16 @@ dependencies = [
"cpufeatures 0.2.17",
]
[[package]]
name = "kem"
version = "0.3.0-pre.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b8645470337db67b01a7f966decf7d0bafedbae74147d33e641c67a91df239f"
dependencies = [
"rand_core 0.6.4",
"zeroize",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
@@ -3470,6 +3499,35 @@ dependencies = [
"windows-sys 0.61.1",
]
[[package]]
name = "ml-dsa"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac4a46643af2001eafebcc37031fc459eb72d45057aac5d7a15b00046a2ad6db"
dependencies = [
"const-oid",
"hybrid-array 0.3.1",
"num-traits",
"pkcs8",
"rand_core 0.6.4",
"sha3",
"signature",
"zeroize",
]
[[package]]
name = "ml-kem"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de49b3df74c35498c0232031bb7e85f9389f913e2796169c8ab47a53993a18f"
dependencies = [
"hybrid-array 0.2.3",
"kem",
"rand_core 0.6.4",
"sha3",
"zeroize",
]
[[package]]
name = "moka"
version = "0.12.10"
@@ -4205,6 +4263,8 @@ dependencies = [
"k256",
"log",
"md-5",
"ml-dsa",
"ml-kem",
"nom 8.0.0",
"num-bigint-dig",
"num-traits",
@@ -4223,6 +4283,7 @@ dependencies = [
"sha2",
"sha3",
"signature",
"slh-dsa",
"smallvec",
"snafu",
"twofish",
@@ -5687,6 +5748,25 @@ dependencies = [
"autocfg",
]
[[package]]
name = "slh-dsa"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd2f20f4049197e03db1104a6452f4d9e96665d79f880198dce4a7026ba5f267"
dependencies = [
"const-oid",
"digest",
"hmac",
"hybrid-array 0.3.1",
"pkcs8",
"rand_core 0.6.4",
"sha2",
"sha3",
"signature",
"typenum",
"zerocopy",
]
[[package]]
name = "smallvec"
version = "1.15.1"

View File

@@ -78,7 +78,7 @@ num-derive = "0.4"
num-traits = { workspace = true }
parking_lot = "0.12.4"
percent-encoding = "2.3"
pgp = { version = "0.19.0", default-features = false }
pgp = { version = "0.19.0", features = ["draft-pqc"], default-features = false }
pin-project = "1"
qrcodegen = "1.7.0"
quick-xml = { version = "0.39", features = ["escape-html"] }

View File

@@ -43,7 +43,12 @@ ignore = [
# hickory-proto 0.25.2 quadratic complexity issue.
# Dependency of iroh 0.35.0, cannot be updated as of 2026-05-02.
# <https://rustsec.org/advisories/RUSTSEC-2026-0119>
"RUSTSEC-2026-0119"
"RUSTSEC-2026-0119",
# Timing side channel in ml-dsa dependency of rPGP.
# We enable PQC for encryption rather than signatures.
# <https://rustsec.org/advisories/RUSTSEC-2025-0144>
"RUSTSEC-2025-0144",
]
[bans]
@@ -62,6 +67,7 @@ skip = [
{ name = "getrandom", version = "0.2.12" },
{ name = "heck", version = "0.4.1" },
{ name = "http", version = "0.2.12" },
{ name = "hybrid-array", version = "0.2.3" },
{ name = "linux-raw-sys", version = "0.4.14" },
{ name = "lru", version = "0.12.5" },
{ name = "netlink-packet-route", version = "0.17.1" },

View File

@@ -570,9 +570,11 @@ pub async fn preconfigure_keypair(context: &Context, secret_data: &str) -> Resul
pub struct Fingerprint(Vec<u8>);
impl Fingerprint {
/// Creates new 160-bit (20 bytes) fingerprint.
/// Creates new fingerprint.
///
/// It is 160-bit (20 bytes) for v4 keys and 32 bytes for v6 keys.
pub fn new(v: Vec<u8>) -> Fingerprint {
debug_assert_eq!(v.len(), 20);
debug_assert!(v.len() == 20 || v.len() == 32);
Fingerprint(v)
}

View File

@@ -356,7 +356,7 @@ impl MimeMessage {
let decrypted_msg; // Decrypted signed OpenPGP message.
let expected_sender_fingerprint: Option<String>;
let (mail, is_encrypted) = match decrypt::decrypt(context, &mail).await {
let (mail, is_encrypted) = match Box::pin(decrypt::decrypt(context, &mail)).await {
Ok(Some((mut msg, expected_sender_fp))) => {
mail_raw = msg.as_data_vec().unwrap_or_default();

View File

@@ -847,4 +847,21 @@ mod tests {
assert!(merge_openpgp_certificates(alice.clone(), bob.clone()).is_err());
assert!(merge_openpgp_certificates(bob.clone(), alice.clone()).is_err());
}
/// Test PQC support.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_pqc() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let pqc = &tcm.pqc().await;
let pqc_received_message = tcm.send_recv_accept(alice, pqc, "Hi!").await;
let pqc_chat_id = pqc_received_message.chat_id;
let pqc_sent = pqc.send_text(pqc_chat_id, "Hello back!").await;
let alice_rcvd = alice.recv_msg(&pqc_sent).await;
assert_eq!(alice_rcvd.text, "Hello back!");
Ok(())
}
}

View File

@@ -137,6 +137,17 @@ impl TestContextManager {
.await
}
/// Returns a new "device" with a preconfigured v6 PQC key.
pub async fn pqc(&mut self) -> TestContext {
TestContext::builder()
.with_key_pair(pqc_keypair())
.with_address("pqc@example.org".to_string())
.with_id_offset(7000)
.with_log_sink(self.log_sink.clone())
.build(Some(&mut self.used_names))
.await
}
/// Creates a new unconfigured test account.
pub async fn unconfigured(&mut self) -> TestContext {
TestContext::builder()
@@ -1426,6 +1437,13 @@ pub fn fiona_keypair() -> SignedSecretKey {
key::SignedSecretKey::from_asc(include_str!("../test-data/key/fiona-secret.asc")).unwrap()
}
/// Loads a pre-generated v6 PQC keypair from disk.
///
/// Like [alice_keypair] but a different key and identity.
pub fn pqc_keypair() -> SignedSecretKey {
key::SignedSecretKey::from_asc(include_str!("../test-data/key/pqc-secret.asc")).unwrap()
}
/// Utility to help wait for and retrieve events.
///
/// This buffers the events in order they are emitted. This allows consuming events in

View File

@@ -0,0 +1,39 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
xUsGaf8NSRsAAAAgYy+GaofURMeV0+bcZZGY2ZdAamU+LG69ONjd3haVU3cAhm6G
IT/UEgFgVdPEhiXER9cfPLiCgkiw/L5mrAZfuLfCqgYfGwgAAABLBQJp/w1JIiEG
hys0q6D+DFWPnwQoWtuX0mL6ovH2kCjWmDufAFmB0+QCGwMCHgkECwkIBwYVCg4J
CAwBFg0nCQIIAgcCCQEIAQcBAAAAAEGQEO9Py9Q7njj1WXhtn1wMJSLBdHBE+qQu
RaCaiWkY5l4EWLlVRPAjX2bBSGq6n3+M+H6oFpOHETAX8IcFSxc260UD+PM0jQpV
H6ReNy7PBCQKx8RrBmn/DUkjAAAEwPmkVcPy1ye0/7D9nDQCkENUGry97iLkpcw/
tLJfzL5gJAdzrPkDkyukHxrO7kiUx+mzpiGZRZeyRgBd5YQ+mTgGrptxXLFHcKFR
79Fjg1UjgHEFjxCkCHUfnNcGZVM3p5skESnNgzsgFGiODfKhM4ew3AFgkUc5LNZj
Zgpgt4ETIhylbLUY89ccfNpKnQeJl3cv8lvA/yqhoUutJXwZQ/qYKFnEIGEBTFto
hLZn0KauF9KYOYvOV4yjeZQBlxSPNAWj9SqSNcalpTUFzwoQVSsqWwiys1PEzGAu
twQVKsZ3e/hlZAyR4eGMiYEmCEy7qjuaOJsqHQuW7hdOHWdVRUpRHOtfj3QAzdc0
CehVbyCRJVwnTSKiT3AYsdACH8U7mhI5/VxeSHNRIDN1Y6g6N5sx6Wur/HuKGFwx
L4urdPdpJJgyLXR8GUkL/yeqUhogu4mbVAmULbq2BCIKFNpMyGdhnDugN6Sp5MWc
GOxCW7CASuBYPHW/rto0C4M/3gCtN2sPtRAhOsXNBBhMqLlzzCgawulCiGtNjHUK
HsVhghgYwKRBT7vLSKDNsCVizzoZxNQq8yUEXpFIRsTGt3wYoigZn4wOSpmQbxGe
P3Uc2GWuuukCBNEP5oW4+TCFaNw5mvZgZwl5n4K34poxVgpqBIM2m2fEu8oyLPJZ
bBxnbty3MUAdLpxv+0otGSHJF4xa3lsEyUdr6+JZZXohNXKoyjeJMGo6qPkvCADI
upMnDSYZeLU5bVstHWS6otuRMEcjdLBkYfqfzBhkzbptscaUXzsaK4cd/iQzAA1r
A0ygvcA78Vo363cElNAJh3lntrZZGpBYnzcU/zLACKAVJCYPy3Cj8Al8x+gHP0Yr
ZSOYdZA1q9s2Kuqk7upCpcYDZ+uXGZs3ubA0TYCcO3FKhAwLhzJad5WApBFETYt2
3KJEwgEjQaCs7sNNiwaKxhLC2VJhUckgluGs5iUu9ck5jdU+N9MqTmloF/u2Gok8
QEqF9+DBhPg/fJoI9sN8sIyLrksEUQsm59mvJbVWOpxtbwpWZ+J4cat4azHE0khy
rolL6lZqDJYW4xVeoAVl5iccicjE6mJLemoxf6iJdohi5cN5JXyZtgtdsbIesJib
BLPJVahmv5W1Q4RmrwEp5Ua4xra5Mcac4PeINTOkGMErIhdvnuxEH/Cxd8VKhNlU
vdty4MOyUOkRRPhOMNKUyTkwS9yjprK3QbhEJgrJygHCGpQ0jwp9PrtKqNnOONSX
t4ZORuiAYHDFz3DPlJhLLzNoAJse0RAyolkPThoMl2JlY5ci8pVHb+Ed/kaeFxnE
UJJIOZvDFfNCFCM5CCXG/2pi/icA7nHPDFVBeYPMz1B5vrgmdDNMMFVQNMBtrroT
4pi1N5U4+EAv1vah40akQ/iFcfZjt4sE/jG0M0NCWqHBDPO7e0ae+2IqnIJmsHjL
N1ak3egY00CnRHdrPCkOkhooFIHA1hYxIwyP07qfkhUBNwSqZ4AfF8UW/nuLjeaj
ajEWz3zGLvQpfHSobEGPQKk+eIA1fOVeAuJAUAmJz5YO1Dk4OfczeQqQiOhtv+qe
PYaZQfBFJVamGocDHomPQkP/IvAJhuO9xWPapqbdRwGfVRJZgGsAy89mT1w0PU1C
u6VpIoyZB2J9LZkw9qb9sRRJAr2gpWGBD4CCmPZ8d17ZGDcIr8o+eI+bo5eKf+1j
6NhsjM7AmIccStNxZYWE4ZucvYYbPvT3ns/TNa7BH2DBqfGK84PawosGGBsIAAAA
LAUCaf8NSQIbDCIhBocrNKug/gxVj58EKFrbl9Ji+qLx9pAo1pg7nwBZgdPkAAAA
ADrcEIqnwTwJoiZAxzK+w7uQFHzsYMWIj8x+DKsn7D1silKINHDnFSrlSKRtbAW6
x9+HrN/nvR7bOnXZvZhz7lQ3Lp3YUdzEcqRMj8BWW8IXdm0C
-----END PGP PRIVATE KEY BLOCK-----