Export both traditional and PQC subkeys in rnp_key_export_autocrypt - #2482
Export both traditional and PQC subkeys in rnp_key_export_autocrypt#2482kaie wants to merge 2 commits into
Conversation
When exporting a key for Autocrypt without specifying a subkey, auto-select up to two encryption subkeys: one traditional (non-PQC) and one PQC (ML-KEM-768+X25519 for v4 keys). If only a PQC subkey exists, export just that one. The resulting Autocrypt payload is a 5-packet sequence for the single-subkey case or a 7-packet sequence when both types are present. Adds a test vector (EdDSA + ECDH Curve25519 + ML-KEM-768+X25519) and a corresponding test guarded by ENABLE_PQC. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2482 +/- ##
==========================================
- Coverage 85.46% 85.43% -0.04%
==========================================
Files 125 125
Lines 22962 22988 +26
==========================================
+ Hits 19625 19640 +15
- Misses 3337 3348 +11 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Thanks Kai! CI is green apart from the two known fleet-wide fuzz jobs, but The two hunks it wants: --- a/src/lib/rnp.cpp
+++ b/src/lib/rnp.cpp
- rnp::Key *cur =
- key->ffi->key_provider.request_key(search, PGP_OP_ENCRYPT, false);
+ rnp::Key *cur = key->ffi->key_provider.request_key(search, PGP_OP_ENCRYPT, false);
--- a/src/tests/ffi-key.cpp
+++ b/src/tests/ffi-key.cpp
- assert_rnp_success(rnp_input_from_path(
- &input, "data/test_key_edge_cases/eddsa-ecdh-mlkem-pub.pgp"));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_key_edge_cases/eddsa-ecdh-mlkem-pub.pgp"));Everything else looks in good shape - we reviewed the auto-selection logic (the is_pqc split, latest-binding checks, and the PQC-only fallback to a 5-packet export) and it reads clean against the autocrypt#461 discussion. Happy to take the second review once the format fix is in. |
ronaldtse
left a comment
There was a problem hiding this comment.
Reviewed and approved - thank you Kai!
What was checked:
- the auto-selection logic in rnp_key_export_autocrypt: the is_pqc() split with newest-creation tie-breaks for both the traditional and PQC picks, and the PQC-only fallback to a plain 5-packet export read correct;
- write_autocrypt's all-or-nothing write with the new 7-packet sequence, including the public-key and valid-binding guards for the extra subkey;
- the explicit-subkey path keeps its original single-subkey semantics;
- the test vector (EdDSA + ECDH Curve25519 + ML-KEM-768+X25519) and the ENABLE_PQC-gated test cover both the dual-subkey and PQC-only cases.
Only remaining item is the trivial clang-format commit discussed above - everything else is green apart from the two fleet-wide fuzz jobs.
@ni4 could you take the second review/approval? This is a Thunderbird-driven follow-up to the autocrypt PQC export discussion (autocrypt/autocrypt#461), extending the machinery from Kai's own #2386.
ni4
left a comment
There was a problem hiding this comment.
Overall LGTM, just two minor comments regarding missing #ifdef ENABLE_PQC for a pqc subkey.
| RNP_LOG("Public key required"); | ||
| return false; | ||
| } | ||
| Signature *pqc_binding = nullptr; |
There was a problem hiding this comment.
@kaie Could you please wrap this in #ifdef ENABLE_PQC? Without it we'll have coverage degradation for non-PQC builds.
| cert->sig.write(memdst.dst()); | ||
| sub.pkt().write(memdst.dst()); | ||
| binding->sig.write(memdst.dst()); | ||
| if (pqc_sub) { |
|
Agreed with @ni4 here - since the auto-selection in rnp_key_export_autocrypt already compiles out the is_pqc() branch for non-PQC builds, these two blocks would be permanently-uncovered lines there. Kai, here is the ready-made patch if it saves you a round-trip: --- a/src/lib/key.cpp
+++ b/src/lib/key.cpp
@@ -1477,6 +1477,7 @@
RNP_LOG("Public key required");
return false;
}
+#if defined(ENABLE_PQC)
Signature *pqc_binding = nullptr;
if (pqc_sub) {
if (pqc_sub->is_secret()) {
@@ -1487,6 +1488,7 @@
return false;
}
}
+#endif
try {
/* write all or nothing */
@@ -1498,10 +1500,12 @@
cert->sig.write(memdst.dst());
sub.pkt().write(memdst.dst());
binding->sig.write(memdst.dst());
+#if defined(ENABLE_PQC)
if (pqc_sub) {
pqc_sub->pkt().write(memdst.dst());
pqc_binding->sig.write(memdst.dst());
}
+#endif
dst_write(&dst, memdst.memory(), memdst.writeb());
return !dst.werr;Also handles ni4's "same as the previous" thread below. The |
When exporting a key for Autocrypt without specifying a subkey, auto-select up to two encryption subkeys: one traditional (non-PQC) and one PQC (ML-KEM-768+X25519 for v4 keys). If only a PQC subkey exists, export just that one. The resulting Autocrypt payload is a 5-packet sequence for the single-subkey case or a 7-packet sequence when both types are present.
Adds a test vector (EdDSA + ECDH Curve25519 + ML-KEM-768+X25519) and a corresponding test guarded by ENABLE_PQC.
The change implements the suggestion discussed here:
https://lists.hostpoint.ch/archives/list/openpgp-email@enigmail.net/thread/SB56PWOWRURNX5MZI2UBWEC3OVS5WMEC/
autocrypt/autocrypt#461