-
Notifications
You must be signed in to change notification settings - Fork 739
feat: add pure mlkem_1024 definition #5468
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
Conversation
433500c
to
e80ba80
Compare
@@ -71,6 +71,7 @@ | |||
#define TLS_PQ_KEM_GROUP_ID_SECP256R1_MLKEM_768 0x11EB | |||
#define TLS_PQ_KEM_GROUP_ID_X25519_MLKEM_768 0x11EC | |||
#define TLS_PQ_KEM_GROUP_ID_SECP384R1_MLKEM_1024 0x11ED | |||
#define TLS_PQ_KEM_GROUP_ID_MLKEM_1024 0x0202 |
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.
Value found from https://datatracker.ietf.org/doc/html/draft-ietf-tls-mlkem-04 section 4.1
5ac540c
to
e80ba80
Compare
08b4f09
to
5dd9352
Compare
tls/s2n_tls13_handshake.c
Outdated
/* If the negotiated KEM group is pure PQ (no ECDHE), then only the PQ shared secret is used. */ | ||
if (kem_group->curve == &s2n_ecc_curve_placeholder_for_pure_pq) { | ||
POSIX_GUARD(s2n_alloc(shared_secret, pq_shared_secret->size)); | ||
POSIX_CHECKED_MEMCPY(shared_secret->data, pq_shared_secret->data, pq_shared_secret->size); | ||
return S2N_SUCCESS; | ||
} |
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.
I think this is better, but still not the cleanest way to do this. You're still copying the hybrid logic instead of reusing it. It would be very easy for a developer to later add some safety check or something that accidentally only applies to hybrid, not pure. We should always treat the hybrid and pure mlkem secret calculations the same way. The only difference should be the ecc concatenation.
We already branch on calculating the ecc shared secret on client/server-- could you add a "neither, don't calculate at all" first branch down there? Then we branch on send_kem_first-- could you add an "only kem" branch down there?
/* Re-inject PQ secret for traffic secret derivation. | ||
* The first compute_shared_secret wipes it, so we need to restore state for testing. */ |
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.
This still didn't sound right to me. Why would you need to reset the shared secret after calculating the shared secret? How would that work outside of this test? So I dug into the code.
I was NOT right about what was going on here. s2n_tls13_compute_shared_secret
is only called as part of s2n_extract_handshake_secret
. s2n_tls13_derive_secret
calls s2n_tls13_extract_secret
, which calls s2n_extract_handshake_secret
, which as mentioned calls s2n_tls13_compute_shared_secret
.
So basically, the initialization is strange because this is actually two separate, unrelated tests. This test isn't doing things sequentially to mimic the actual use of these methods in code. Also, you're actually already testing s2n_tls13_compute_shared_secret by testing s2n_tls13_derive_secret.
I think you need to either:
- Remove the s2n_tls13_compute_shared_secret part of the test.
- Separate the s2n_tls13_compute_shared_secret and s2n_tls13_derive_secret tests. They should not be performed on the same connection in sequence. That's misleading and could lead to one test unexpectedly influencing the other, missing mistakes.
I'd suggest 2. I'm guessing s2n_tls13_compute_shared_secret is tested separately to make errors in that part of the calculation more obvious. The assertion that client == server seems a little weak, but that's better than nothing if we can't assert on an exact value.
However, it's also possible that the test you based this test off of just predates the rework of secret derivation, and didn't really make a deliberate choice to test s2n_tls13_compute_shared_secret separately. It might have been part of a messy later refactor to incorporate the new secret derivation structure. The dangers of copy/paste.
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.
Oh I guess there's also:
3. Remove the s2n_tls13_derive_secret part of the test.
You did only make changes to s2n_tls13_compute_shared_secret, so maybe testing that is sufficient. You'd definitely need a stronger assertion then tho.
d3dcf61
to
bba3b34
Compare
int s2n_tls13_compute_pq_shared_secret(struct s2n_connection *conn, struct s2n_blob *shared_secret) | ||
{ |
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.
Does this need to be this complicated? Why wouldn't 411d852 work? I checked, and that passes s2n_tls13_pure_pq_shared_secret_test. It's just my suggestions from #5468 (comment), except we don't even need the branch on send_kem_first.
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.
Ah okay switching to your proposal, I was confused on your suggestion.
shared secret test addtional compute clang format add back renamed file added file feedback use defer cleanup remove comments s2n_set_up_pure_pq_conns combine hybrid + pure into 1 function removal of comments renamed testing files fixed comment renamed files revert back and added static renamed to &s2n_ecc_curve_placeholder_for_pure_pq; added comment on pure mlkem tracking Refactored pure pq shared secret test clang formatting updated feedback remove deriving secret and changed placeholder name refactor compute pq feedback remove typo clang formatting added label and iterate through all security policies clang format feedback ecc must be not null
ed4cbb2
to
01e4ee7
Compare
/* Test: check all security policies don't contain the placeholder curve "s2n_ecc_curve_none" */ | ||
{ | ||
for (size_t policy_index = 0; security_policy_selection[policy_index].version != NULL; policy_index++) { | ||
const struct s2n_security_policy *security_policy = security_policy_selection[policy_index].security_policy; | ||
const struct s2n_ecc_preferences *ecc_preferences = security_policy->ecc_preferences; | ||
EXPECT_NOT_NULL(ecc_preferences); | ||
|
||
for (size_t curve_index = 0; curve_index < ecc_preferences->count; curve_index++) { | ||
EXPECT_NOT_EQUAL(ecc_preferences->ecc_curves[curve_index], &s2n_ecc_curve_none); | ||
} | ||
} | ||
}; |
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.
Nit: we'll likely reuse this loop for any other ecc preference validation we need to do. I'd suggest naming the test something more generic, like "validate all ecc preferences" and move this more specific test name down to line 56 where you make the assertion.
Resolved issues:
Partially addresses #5152
Description of changes:
Callouts:
Testing: