8000 Support for Raw Public Keys (RFC 7250) by holodorum · Pull Request #2062 · rustls/rustls · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Support for Raw Public Keys (RFC 7250) #2062

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

Merged
merged 6 commits into from
Oct 17, 2024
Merged

Support for Raw Public Keys (RFC 7250) #2062

merged 6 commits into from
Oct 17, 2024

Conversation

holodorum
Copy link
Contributor
@holodorum holodorum commented Jul 31, 2024

This PR implements RFC 7250 (Raw Public Key support) for TLS 1.3. The relevant discussion can be found in this issue, with a detailed comment by @ctz explaining the necessary steps.

Main API changes:

  1. The ServerCertVerifier and ClientCertVerifier traits now include a requires_raw_public_keys() function, while the ServerResolveCert and ClientResolveCert traits now have a only_raw_public_keys() function. Both functions have default implementations that return false.
  2. We provide implementations for ServerResolveCert and ClientResolveCert that always resolve to a specific raw public key (AlwaysResolvesServerRawPublicKeys, AlwaysResolvesClientRawPublicKeys).
  3. We introduce webpki::verify::verify_tls13_signature_with_spki() for signature verification. These functions use webpki::RawPublicKeyEntity, which was added to rustls-webpki in this PR.
  4. Two error values were added to PeerIncompatible:
    • IncorrectCertificateTypeExtension, raised when the local side expects Raw Public Keys but the peer sends an incorrect certificate type extension.
    • UnsolicitedCertificateTypeExtension, raised when the peer sends a certificate type extension, but the local side does not expect Raw Public Keys.
  5. New values were added to handshake::ServerExtension and handshake::ClientExtension:
    • ClientExtension::ServerCertTypes and ClientExtension::ClientCertTypes are used to communicate the CertificateTypes supported by the client.
    • ServerExtension::ServerCertType and ServerExtension::ClientCertType are used to communicate the CertificateType chosen by the server.
  6. The two certificate type extensions, ServerExtension::ServerCertType and ServerExtension::ClientCertType, are added to server_conn::ClientHello for use in the Acceptor API.
  7. We needed to decrypt, modify, and re-encrypt the ServerHello message to test our implementation. For this, tls13::key_schedule::derive_traffic_key() and tls13::key_schedule::derive_traffic_iv() were made public.

Interoperability testing and example implementation:

  1. An example implementation of a server and client using Raw Public Keys can be found in raw_key_openssl_interop.rs. This implementation is tested against an OpenSSL client and server to ensure interoperability with our implementation.

Considerations:

  1. To minimize the impact on the API and ensure backward compatibility, we sometimes use a CertificateDer type for a Raw Public Key instead of the more concise SubjectPublicKeyInfoDer. This approach is used in:
    • CommonState::peer_certificates()
    • The cert field of the CertifiedKey struct.
  2. Our implementation closely follows RFC 7250. The main deviation is our assumption of a-priori knowledge about the peer’s authentication method when using Raw Public Keys (as explained in this comment). This means we never offer a RawPublicKey alongside X509, though the RFC permits it.

Contributors:

This PR was created in collaboration with @aochagavia.

Copy link
codecov bot commented Aug 1, 2024

Codecov Report

Attention: Patch coverage is 98.63481% with 4 lines in your changes missing coverage. Please review.

Project coverage is 94.72%. Comparing base (09885c2) to head (7b0a8ee).
Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
rustls/src/server/hs.rs 96.29% 3 Missing ⚠️
rustls/src/webpki/verify.rs 94.11% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2062      +/-   ##
==========================================
+ Coverage   94.67%   94.72%   +0.05%     
==========================================
  Files         102      102              
  Lines       23471    23753     +282     
==========================================
+ Hits        22220    22499     +279     
- Misses       1251     1254       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ctz
Copy link
Member
ctz commented Aug 23, 2024
  1. The reason being that the openssl server does not return the client_cert_type extension, but instead sends a RawPublicKey directly. Is this common behaviour, and if so would it be better to do the validation of the client_cert_type and server_cert_type extensions somewhere else?

There is no reason for openssl to send client_cert_type as it is not going to ask for client authentication. If I add -verify 1 then it does send it (though it fails later in the handshake with a decode error, not sure if that is something i've done wrong locally). That means, I think, that the call to process_client_cert_type_extension must happen later, during tls12::ExpectCertificateRequest.

Would be good to automate the running of rpk_example.rs against openssl in openssl-tests/.

Copy link
Member
@cpu cpu left a comment

Choose a reason for hiding this comment

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

Here's some comments/suggestions from a rough first pass.

Beyond the mechanics of the implementation I'm also interested in how this interacts with revocation. This is one of the aspects of raw public keys that I think deserves explicit attention in our documentation. As I understand it there isn't any mechanism for revocation checking when you've forgone certificates in favour of raw public keys. E.g. neither CRLs, nor OCSP will cover these entities.

Does that match your understanding? Should a client or server configuration that's configured with both CRLs and raw public keys fail in an obvious manner?

@cpu
Copy link
Member
cpu commented Aug 26, 2024

Whenever possible I used the SubjectPublicKeyInfoDer type. However, sometimes the best option seems casting to a CertificateDer type. For example in AlwaysResolvesClientRawPublicKeys::new().

I'm curious what other reviewers think of this aspect. From my perspective it seems unfortunate/subpar to be doing this cast since we know the SPKI DER isn't certificate DER. It feels like we want a more type-safe way of representing the union of the two but I'm not sure what kind of flexibility we have to rework this without breaking changes.

@ctz
Copy link
Member
ctz commented Aug 27, 2024

Whenever possible I used the SubjectPublicKeyInfoDer type. However, sometimes the best option seems casting to a CertificateDer type. For example in AlwaysResolvesClientRawPublicKeys::new().

I'm curious what other reviewers think of this aspect. From my perspective it seems unfortunate/subpar to be doing this cast since we know the SPKI DER isn't certificate DER. It feels like we want a more type-safe way of representing the union of the two but I'm not sure what kind of flexibility we have to rework this without breaking changes.

Speaking strictly at the level of public API changes, I would really like to avoid the 99.9999% of users -- who have no interest in or use for RPK -- from having to think about this.

eg, fn peer_certificates(&self) -- I think it would be quite bad if we changed the return type of this to enum CertOrRpk { ... } and force those users to discard the statically-unreachable Rpk variant. Similarly, I would like to avoid adding a parallel fn raw_public_key(&self) because (frankly) I don't think this feature will ever gain common use to warrant separate public API surface and the mental load that adds to users.

@djc
Copy link
Member
djc commented Aug 27, 2024

eg, fn peer_certificates(&self) -- I think it would be quite bad if we changed the return type of this to enum CertOrRpk { ... } and force those users to discard the statically-unreachable Rpk variant.

Agreed. In Quinn we call this peer_identity() and model it as Box<dyn Any>. I don't think we should model it as Any here (since that would make life harder for the 99.9%) but might make sense to provide a method alias that is slightly less specific?

Similarly, I would like to avoid adding a parallel fn raw_public_key(&self) because (frankly) I don't think this feature will ever gain common use to warrant separate public API surface and the mental load that adds to users.

Hmm, not sure -- I might prefer a parallel function if that means we can avoid sticking not-certificate DER in a CertificateDer which IMO is also a pretty bad anti-pattern.

@ctz
Copy link
Member
ctz commented Aug 27, 2024

there is a decode error when running the example against openssl with --verify 1. However, this only happens when using tls1.2 not tls1.3. Reading the logs it seems to be a problem related to the tag/length of the rpk, any idea why this is the case in tls1.2 (but not tls1.3)?

RFC7250 has:

struct {
       select(certificate_type){

            // certificate type defined in this document.
            case RawPublicKey:
              opaque ASN.1_subjectPublicKeyInfo<1..2^24-1>;

           // X.509 certificate defined in [RFC 5246](https://datatracker.ietf.org/doc/html/rfc5246)
           case X.509:
             ASN.1Cert certificate_list<0..2^24-1>;

           // Additional certificate type based on
           // "TLS Certificate Types" subregistry
       };
   } Certificate;

This means the encoding of a single x509 certificate with value 0xaa is:

  00 00 04
     00 00 01
        aa

and the encoding of a single raw public key is:

  00 00 01
     aa

I think that means it is necessary to introduce an additional HandshakePayload variant, plus the context to know when to decode it (observe above, that certificate_type is not actually in the message anywhere.) Painful!

Do you need this feature for TLS1.2?

@cpu
Copy link
Member
cpu commented Aug 27, 2024

I might prefer a parallel function if that means we can avoid sticking not-certificate DER in a CertificateDer which IMO is also a pretty bad anti-pattern.

I was thinking similar here. I'm fully in agreement that we want to avoid making the subject of raw public keys front-and-center for the average user, but it doesn't seem too egregious to have a parallel function like this.

@ctz
Copy link
Member
ctz commented Aug 27, 2024

I guess that was just one example. To completely avoid putting an RPK into a CertificateDer in the public API, we'd also need to provide RPK variants of:

  1. sign::CertifiedKey (or modalise it, but that would be a breaking change)
  2. client::ResolvesClientCert for (1), and its slot in ClientConfig
  3. server::ResolvesServerCert for (1), and its slot in ServerConfig
  4. ServerCertVerifier, and its slot in ClientConfig
  5. ClientCertVerifier, and its slot in ServerConfig

(I'm not sure that's a complete list.)

@holodorum
Copy link
Contributor Author

Beyond the mechanics of the implementation I'm also interested in how this interacts with revocation. This is one of the aspects of raw public keys that I think deserves explicit attention in our documentation. As I understand it there isn't any mechanism for revocation checking when you've forgone certificates in favour of raw public keys. E.g. neither CRLs, nor OCSP will cover these entities.

Does that match your understanding? Should a client or server configuration that's configured with both CRLs and raw public keys fail in an obvious manner?

In the RFC 7250 §6 a few comments are made regarding security considerations. There is no mention of either CRL or OCSP. Just different methods to authenticate raw public keys out-of-band.

The assumption we made following @ctz's comment is that when someone decides to use RPK's they have pretty specific a-priori knowledge about the server and how it will be authenticated (and vice versa). I'm not sure if it should happen that a server is using both CRLs and raw public keys (unless using the Acceptor api), in that case it might be a good idea to indeed fail.

What do you think?

@holodorum
Copy link
Contributor Author

there is a decode error when running the example against openssl with --verify 1. However, this only happens when using tls1.2 not tls1.3. Reading the logs it seems to be a problem related to the tag/length of the rpk, any idea why this is the case in tls1.2 (but not tls1.3)?

RFC7250 has:

struct {
       select(certificate_type){

            // certificate type defined in this document.
            case RawPublicKey:
              opaque ASN.1_subjectPublicKeyInfo<1..2^24-1>;

           // X.509 certificate defined in [RFC 5246](https://datatracker.ietf.org/doc/html/rfc5246)
           case X.509:
             ASN.1Cert certificate_list<0..2^24-1>;

           // Additional certificate type based on
           // "TLS Certificate Types" subregistry
       };
   } Certificate;

This means the encoding of a single x509 certificate with value 0xaa is:

  00 00 04
     00 00 01
        aa

and the encoding of a single raw public key is:

  00 00 01
     aa

I think that means it is necessary to introduce an additional HandshakePayload variant, plus the context to know when to decode it (observe above, that certificate_type is not actually in the message anywhere.) Painful!

Do you need this feature for TLS1.2?

Thank you @ctz!! That clarifies things a lot. Very painful indeed.
One thing I don't understand yet is why this is different in TLS1.2 and TLS1.3, is there a default decoding done in TLS1.2 and a way to not use it?

@ctz
Copy link
Member
ctz commented Aug 28, 2024

One thing I don't understand yet is why this is different in TLS1.2 and TLS1.3

TLS1.3 has a CertificateEntry struct in the way, and ensuring there is only one is done with prose rather than the wire encoding.

@aochagavia
Copy link
Contributor
aochagavia commented Aug 29, 2024

Thanks for the review work! I've been lurking here for a while, as I'm helping a bit behind the scenes. It looks like there are a few decisions still to be made, and I wanted to provide my 2 cents.

Could we avoid supporting TLS 1.2?

It turns out that supporting TLS 1.2 adds some undesirable complexity. @cpu pointed out the branching it introduces, and @ctz that we'd probably need a new HandshakePayload variant. That's painful and it would be nice to forgo TLS 1.2 support if possible. Since the main stakeholder for this feature is Solana, and they dropped TLS 1.2 support in 2023 (see this PR), it looks like we can indeed skip TLS 1.2 here :)

Where should the example code live?

@djc voiced some concerns on letting the example code live in this repository, to which @cpu responded with his opinion. There's no consensus yet, but the issue is small enough that I guess it can be easily decided once @ctz tells us what he thinks.

CertificateDer and SPKI DERs

@cpu mentioned it's unfortunate to be representing an SPKI DER as a struct of the CertificateDer type, since they are not the same. I think everyone agrees, but it looks like a significant amount of internal refactoring would be required to achieve a clean separation between the two (while preserving backwards-compatibility in the API). See, for instance, this non-exhaustive list @ctz came up with.

I guess the issue boils down to choosing between (1) an inconsistency in the CertificateDer type, which sometimes contains an SPKI DER; and (2) consistent types at the cost of more complex internals. Personally, I feel inclined towards 1 (maybe you could consider Raw Public Keys as a kind of certificate, since the RFC says they are a new "certificate type", so the name CertificateDer is not that inconsistent in the end). Regardless, I guess you'd better pick whatever is easiest to maintain long-term.

@holodorum
Copy link
Contributor Author
holodorum commented Aug 29, 2024

Thanks for the feedback and all the work so far. Except for the comments on rpk_example.rs, we've incorporated all the feedback. In case I wasn't sure whether our approach is correct I left the conversation unresolved.
For now I think a few things need to happen:

  • Create an example that is in line with the rest of the examples, either in its own repository or in this repository.
  • Basic positive interop tests against OpenSSL 3.2.
  • Improve the tests for clients/servers rejecting the peer for missing RPK support
  • Get full test coverage.
  • Update the documentation where necessary
  • Depending on the outcome of the dialogue refactor the scenarios where a RPK is wrapped in a CertificateDer

If there's anything I'm forgetting please let me know!

Copy link
Member
@cpu cpu left a comment

Choose a reason for hiding this comment

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

Here's another round of feedback. Thanks!

In the RFC 7250 §6 a few comments are made regarding security considerations. There is no mention of either CRL or OCSP. Just different methods to authenticate raw public keys out-of-band.

Indeed :-( I think that's an oversight. I'm not sure it merits an errata but it feels like a missing piece to me.

The assumption we made following @ctz's #423 (comment) is that when someone decides to use RPK's they have pretty specific a-priori knowledge about the server and how it will be authenticated (and vice versa).

I agree with the assumption Ctz & you folks are making. I'm mainly advocating that this patchset should try to explicitly document the need for that a-priori knowledge in very strong & obvious language.

I'm not sure if it should happen that a server is using both CRLs and raw public keys (unless using the Acceptor api), in that case it might be a good idea to indeed fail.

You're right, I think the main concern I had (a client/server configuration with both CRLs and RPK configured) isn't possible based on this impl 👍 I think the Acceptor API shouldn't introduce any additional risk.

I guess the issue boils down to choosing between (1) an inconsistency in the CertificateDer type, which sometimes contains an SPKI DER; and (2) consistent types at the cost of more complex internals. Personally, I feel inclined towards 1

I think I'm coming around to (1) as well short any other ideas that can be implemented within semver without complicating the API for the normal use-case.

@cpu
Copy link
Member
cpu commented Sep 13, 2024

I think we have consensus on the open questions now (?) - is it accurate to say we're waiting on another round of updates to finish some of the TODO's from this comment and then we're in the final stretch for code-review with an eye towards merging?

@holodorum
Copy link
Contributor Author

@cpu I think so too! Thanks for this round of feedback. Most of it is already processed, and beginning next week I'll finish it and push everything.

@holodorum
Copy link
Contributor Author

We've incorporated all the feedback and finished the todo's. Thanks for all the great help and feedback so far. Hopefully we can get this merged soon ;)

Two remarks about the OpenSSL tests and the example:

  • Create an example that is in line with the rest of the examples, either in its own repository or in this repository.
  • Basic positive interop tests against OpenSSL 3.2.

The 'example' is not really in line with the rest of the examples right now, since it is living in openssl-tests. There was some discussion over adding a niche example, maybe this is the best of both worlds. There is an example implementation for using raw keys, and we don't need to duplicate code to test against OpenSSL.

The OpenSSL tests fail at the moment, most likely because the runner has OpenSSL 3.0 instead of 3.2. Is it better to add a new workflow for OpenSSL tests with OpenSSL 3.2 installed on the runner or is it okay to modify the existing workflow and run all tests against OpenSSL 3.2?

@cpu
Copy link
Member
cpu commented Sep 27, 2024

there was some discussion over adding a niche example, maybe this is the best of both worlds. There is an example implementation for using raw keys, and we don't need to duplicate code to test against OpenSSL.

Seems reasonable to me 👍

The OpenSSL tests fail at the moment, most likely because the runner has OpenSSL 3.0 instead of 3.2. Is it better to add a new workflow for OpenSSL tests with OpenSSL 3.2 installed on the runner or is it okay to modify the existing workflow and run all tests against OpenSSL 3.2?

I think testing against one version is likely sufficient unless someone has strong opinions. 3.2 also ships certificate compression and it might be nice to have interop testing for that some day.

Copy link
Member
@ctz ctz left a comment

Choose a reason for hiding this comment

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

Thanks for persevering with this -- I feel it is pretty close.

@cpu cpu self-requested a review October 2, 2024 17:02
@cpu
Copy link
Member
cpu commented Oct 2, 2024

cpu self-requested a review now

I will catch up with the progress in this branch ~tomorrow/friday. Thank you!

Copy link
Member
@djc djc left a comment

Choose a reason for hiding this comment

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

Thanks for all the work on this!

Copy link
rustls-benchmarking bot commented Oct 7, 2024

Benchmark results

Instruction counts

Significant differences

⚠️ There are significant instruction count differences

Click to expand
Scenario Baseline Candidate Diff Threshold
handshake_session_id_ring_1.2_rsa_aes_server 4235449 4250539 ⚠️ 15090 (0.36%) 0.20%
handshake_session_id_aws_lc_rs_1.2_rsa_aes_server 3876261 3890031 ⚠️ 13770 (0.36%) 0.20%
handshake_tickets_ring_1.2_rsa_aes_server 4678423 4693603 ⚠️ 15180 (0.32%) 0.20%
handshake_tickets_aws_lc_rs_1.2_rsa_aes_server 4998335 5012105 ⚠️ 13770 (0.28%) 0.20%

Other differences

Click to expand
Scenario Baseline Candidate Diff Threshold
handshake_no_resume_aws_lc_rs_1.3_ecdsap384_aes_client 8562715 8577637 14922 (0.17%) 1.11%
handshake_no_resume_aws_lc_rs_1.3_rsa_chacha_server 10790131 10803486 13355 (0.12%) 1.09%
handshake_no_resume_aws_lc_rs_1.3_ecdsap256_aes_client 3082295 3084565 2270 (0.07%) 0.29%
handshake_no_resume_aws_lc_rs_1.3_ecdsap256_chacha_client 3084756 3086726 1970 (0.06%) 0.28%
handshake_no_resume_aws_lc_rs_1.2_rsa_aes_server 10441266 10434770 -6496 (-0.06%) 1.40%
handshake_no_resume_aws_lc_rs_1.3_rsa_aes_server 10832211 10825534 -6677 (-0.06%) 1.16%
handshake_no_resume_aws_lc_rs_1.3_ecdsap256_aes_server 1278062 1278690 628 (0.05%) 0.20%
handshake_session_id_aws_lc_rs_1.3_ecdsap384_aes_server 32130664 32146159 15495 (0.05%) 0.20%
handshake_session_id_aws_lc_rs_1.3_ecdsap256_chacha_server 32077660 32093115 15455 (0.05%) 0.20%
handshake_session_id_aws_lc_rs_1.3_ecdsap384_chacha_server 32077758 32093000 15242 (0.05%) 0.20%
handshake_session_id_aws_lc_rs_1.3_rsa_aes_server 32127734 32142966 15232 (0.05%) 0.20%
handshake_session_id_aws_lc_rs_1.3_rsa_chacha_server 32074847 32090003 15156 (0.05%) 0.20%
handshake_no_resume_ring_1.3_ecdsap256_aes_client 3623216 3621507 -1709 (-0.05%) 0.43%
handshake_session_id_aws_lc_rs_1.3_ecdsap256_aes_server 32130914 32145990 15076 (0.05%) 0.20%
handshake_tickets_aws_lc_rs_1.3_ecdsap256_chacha_server 34143985 34159943 15958 (0.05%) 0.20%
handshake_tickets_aws_lc_rs_1.3_rsa_chacha_server 34140555 34156220 15665 (0.05%) 0.20%
handshake_tickets_aws_lc_rs_1.3_ecdsap256_aes_server 34138107 34153593 15486 (0.05%) 0.20%
handshake_tickets_aws_lc_rs_1.3_ecdsap384_aes_server 34137983 34153402 15419 (0.05%) 0.20%
handshake_tickets_aws_lc_rs_1.3_rsa_aes_server 34134813 34150195 15382 (0.05%) 0.20%
handshake_tickets_aws_lc_rs_1.3_ecdsap384_chacha_server 34144172 34159456 15284 (0.04%) 0.20%
handshake_tickets_ring_1.3_rsa_chacha_server 43869164 43885604 16440 (0.04%) 0.20%
handshake_tickets_ring_1.3_ecdsap384_chacha_server 43872239 43888679 16440 (0.04%) 0.20%
handshake_tickets_ring_1.3_ecdsap256_chacha_server 43872279 43888719 16440 (0.04%) 0.20%
handshake_tickets_ring_1.3_rsa_aes_server 43959794 43976204 16410 (0.04%) 0.20%
handshake_tickets_ring_1.3_ecdsap384_aes_server 43962869 43979279 16410 (0.04%) 0.20%
handshake_tickets_ring_1.3_ecdsap256_aes_server 43962909 43979319 16410 (0.04%) 0.20%
handshake_no_resume_aws_lc_rs_1.3_ecdsap256_chacha_server 1280402 1280878 476 (0.04%) 0.20%
handshake_session_id_ring_1.3_rsa_chacha_server 43196929 43212649 15720 (0.04%) 0.20%
handshake_session_id_ring_1.3_ecdsap384_chacha_server 43199567 43215287 15720 (0.04%) 0.20%
handshake_session_id_ring_1.3_ecdsap256_chacha_server 43199586 43215306 15720 (0.04%) 0.20%
handshake_session_id_ring_1.3_rsa_aes_server 43304599 43320289 15690 (0.04%) 0.20%
handshake_session_id_ring_1.3_ecdsap384_aes_server 43307237 43322927 15690 (0.04%) 0.20%
handshake_session_id_ring_1.3_ecdsap256_aes_server 43307256 43322946 15690 (0.04%) 0.20%
handshake_session_id_ring_1.2_rsa_aes_client 4235199 4236729 1530 (0.04%) 0.20%
handshake_no_resume_ring_1.3_ecdsap256_chacha_server 1663907 1664455 548 (0.03%) 1.04%
handshake_no_resume_ring_1.3_ecdsap256_aes_server 1662531 1663078 547 (0.03%) 1.04%
handshake_tickets_ring_1.2_rsa_aes_client 4496133 4497513 1380 (0.03%) 0.20%
handshake_no_resume_aws_lc_rs_1.3_ecdsap384_chacha_server 2178146 2178777 631 (0.03%) 0.20%
transfer_no_resume_aws_lc_rs_1.2_rsa_aes_server 46446231 46434713 -11518 (-0.02%) 0.20%
handshake_no_resume_aws_lc_rs_1.3_ecdsap384_chacha_client 8597426 8599212 1786 (0.02%) 0.79%
handshake_no_resume_aws_lc_rs_1.3_ecdsap384_aes_server 2175308 2175663 355 (0.02%) 0.20%
handshake_tickets_aws_lc_rs_1.3_ecdsap256_aes_client 30722888 30726665 3777 (0.01%) 0.20%
handshake_session_id_aws_lc_rs_1.3_ecdsap384_chacha_client 30309621 30313309 3688 (0.01%) 0.20%
handshake_session_id_aws_lc_rs_1.3_ecdsap256_aes_client 30345215 30348881 3666 (0.01%) 0.20%
handshake_tickets_aws_lc_rs_1.3_rsa_aes_client 30745438 30749099 3661 (0.01%) 0.20%
handshake_session_id_aws_lc_rs_1.3_ecdsap256_chacha_client 30309173 30312717 3544 (0.01%) 0.20%
handshake_session_id_aws_lc_rs_1.3_ecdsap384_aes_client 30345713 30349258 3545 (0.01%) 0.20%
handshake_session_id_aws_lc_rs_1.3_rsa_chacha_client 30323741 30327250 3509 (0.01%) 0.20%
handshake_tickets_aws_lc_rs_1.3_ecdsap384_aes_client 30723046 30726587 3541 (0.01%) 0.20%
handshake_tickets_aws_lc_rs_1.3_ecdsap384_chacha_client 30757224 30760765 3541 (0.01%) 0.20%
handshake_session_id_aws_lc_rs_1.3_rsa_aes_client 30359779 30363267 3488 (0.01%) 0.20%
handshake_tickets_aws_lc_rs_1.3_ecdsap256_chacha_client 30757167 30760676 3509 (0.01%) 0.20%
handshake_tickets_aws_lc_rs_1.3_rsa_chacha_client 30779564 30783065 3501 (0.01%) 0.20%
handshake_no_resume_aws_lc_rs_1.3_rsa_aes_client 1925770 1925964 194 (0.01%) 0.20%
handshake_no_resume_aws_lc_rs_1.3_rsa_chacha_client 1932498 1932685 187 (0.01%) 0.20%
handshake_session_id_ring_1.3_ecdsap384_chacha_client 41707084 41710636 3552 (0.01%) 0.20%
handshake_session_id_ring_1.3_ecdsap384_aes_client 41795074 41798626 3552 (0.01%) 0.20%
handshake_session_id_ring_1.3_rsa_chacha_client 41720842 41724372 3530 (0.01%) 0.20%
handshake_session_id_ring_1.3_ecdsap256_chacha_client 41706618 41710146 3528 (0.01%) 0.20%
handshake_tickets_ring_1.3_ecdsap384_chacha_client 42168561 42172123 3562 (0.01%) 0.20%
handshake_session_id_ring_1.3_rsa_aes_client 41808832 41812362 3530 (0.01%) 0.20%
handshake_session_id_ring_1.3_ecdsap256_aes_client 41794608 41798136 3528 (0.01%) 0.20%
handshake_tickets_ring_1.3_ecdsap384_aes_client 42241863 42245425 3562 (0.01%) 0.20%
handshake_tickets_ring_1.3_rsa_chacha_client 42182528 42186068 3540 (0.01%) 0.20%
handshake_tickets_ring_1.3_ecdsap256_chacha_client 42168063 42171601 3538 (0.01%) 0.20%
handshake_tickets_ring_1.3_rsa_aes_client 42255758 42259298 3540 (0.01%) 0.20%
handshake_tickets_ring_1.3_ecdsap256_aes_client 42241293 42244831 3538 (0.01%) 0.20%
handshake_no_resume_ring_1.3_ecdsap384_aes_server 7617002 7617559 557 (0.01%) 0.20%
handshake_no_resume_ring_1.3_ecdsap384_chacha_server 7619145 7619693 548 (0.01%) 0.20%
handshake_no_resume_ring_1.3_rsa_aes_client 2656121 2656291 170 (0.01%) 0.20%
handshake_no_resume_ring_1.3_rsa_chacha_client 2661986 2662156 170 (0.01%) 0.20%
handshake_session_id_aws_lc_rs_1.2_rsa_aes_client 3873175 3873385 210 (0.01%) 0.20%
handshake_no_resume_ring_1.3_rsa_chacha_server 11481252 11481800 548 (0.00%) 0.20%
handshake_no_resume_ring_1.3_rsa_aes_server 11475297 11475844 547 (0.00%) 0.20%
handshake_no_resume_ring_1.2_rsa_aes_server 11291823 11292292 469 (0.00%) 0.20%
handshake_no_resume_aws_lc_rs_1.2_rsa_aes_client 1717404 1717456 52 (0.00%) 0.20%
transfer_no_resume_ring_1.2_rsa_aes_client 58235168 58236449 1281 (0.00%) 0.20%
handshake_no_resume_ring_1.2_rsa_aes_client 2563491 2563535 44 (0.00%) 0.20%
handshake_tickets_aws_lc_rs_1.2_rsa_aes_client 4215679 4215739 60 (0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_ecdsap384_aes_client 58254052 58253411 -641 (-0.00%) 0.20%
transfer_no_resume_ring_1.3_ecdsap256_aes_client 58341600 58340960 -640 (-0.00%) 0.20%
transfer_no_resume_ring_1.3_rsa_aes_client 58352502 58351862 -640 (-0.00%) 0.20%
transfer_no_resume_ring_1.3_ecdsap384_aes_client 58348746 58348107 -639 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_ecdsap256_aes_client 58251821 58251184 -637 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_rsa_aes_client 58256131 58255495 -636 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_ecdsap384_chacha_client 92714862 92714212 -650 (-0.00%) 0.20%
transfer_no_resume_ring_1.3_ecdsap256_chacha_client 92673769 92673122 -647 (-0.00%) 0.20%
transfer_no_resume_ring_1.3_rsa_chacha_client 92684671 92684024 -647 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_rsa_chacha_client 92718857 92718212 -645 (-0.00%) 0.20%
transfer_no_resume_ring_1.3_ecdsap384_chacha_client 92682834 92682191 -643 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_ecdsap256_chacha_client 92712625 92711985 -640 (-0.00%) 0.20%
handshake_no_resume_ring_1.3_ecdsap384_aes_client 35183008 35183215 207 (0.00%) 0.20%
handshake_no_resume_ring_1.3_ecdsap384_chacha_client 35184913 35185103 190 (0.00%) 0.20%
handshake_no_resume_ring_1.3_ecdsap256_chacha_client 3624946 3624958 12 (0.00%) 0.45%
transfer_no_resume_ring_1.3_ecdsap384_aes_server 46470691 46470681 -10 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_ecdsap384_aes_server 46460135 46460143 8 (0.00%) 0.20%
transfer_no_resume_ring_1.3_rsa_aes_server 46487101 46487093 -8 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_rsa_chacha_server 80661859 80661847 -12 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_rsa_aes_server 46480087 46480092 5 (0.00%) 0.20%
transfer_no_resume_ring_1.3_rsa_chacha_server 80554934 80554926 -8 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_ecdsap256_chacha_server 80648879 80648887 8 (0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_ecdsap384_chacha_server 80641259 80641254 -5 (-0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.3_ecdsap256_aes_server 46467119 46467121 2 (0.00%) 0.20%
transfer_no_resume_aws_lc_rs_1.2_rsa_aes_client 68683803 68683805 2 (0.00%) 0.20%
transfer_no_resume_ring_1.3_ecdsap256_chacha_server 80535647 80535645 -2 (-0.00%) 0.20%
transfer_no_resume_ring_1.2_rsa_aes_server 46389596 46389597 1 (0.00%) 0.20%
transfer_no_resume_ring_1.3_ecdsap256_aes_server 46467813 46467813 0 (0.00%) 0.20%
transfer_no_resume_ring_1.3_ecdsap384_chacha_server 80540448 80540448 0 (0.00%) 0.20%

Wall-time

Significant differences

There are no significant wall-time differences

Other differences

Click to expand
Scenario Baseline Candidate Diff Threshold
handshake_no_resume_aws_lc_rs_1.3_rsa_chacha 1.12 ms 1.08 ms -0.04 ms (-3.43%) 9.19%
handshake_no_resume_aws_lc_rs_1.3_rsa_aes 1.12 ms 1.09 ms -0.03 ms (-2.95%) 8.86%
handshake_no_resume_aws_lc_rs_1.2_rsa_aes 1.08 ms 1.06 ms -0.03 ms (-2.49%) 3.88%
handshake_session_id_aws_lc_rs_1.2_rsa_aes 1.63 ms 1.59 ms -0.04 ms (-2.30%) 5.28%
handshake_tickets_aws_lc_rs_1.2_rsa_aes 1.79 ms 1.76 ms -0.03 ms (-1.51%) 5.37%
handshake_tickets_aws_lc_rs_1.3_rsa_chacha 5.60 ms 5.55 ms -0.05 ms (-0.95%) 2.72%
handshake_session_id_aws_lc_rs_1.3_rsa_chacha 5.25 ms 5.21 ms -0.05 ms (-0.94%) 2.59%
transfer_no_resume_aws_lc_rs_1.2_rsa_aes 5.13 ms 5.09 ms -0.04 ms (-0.83%) 4.54%
transfer_no_resume_aws_lc_rs_1.3_rsa_aes 5.11 ms 5.07 ms -0.04 ms (-0.70%) 4.74%
handshake_session_id_aws_lc_rs_1.3_rsa_aes 5.25 ms 5.22 ms -0.03 ms (-0.52%) 2.18%
handshake_session_id_ring_1.2_rsa_aes 1.52 ms 1.51 ms -0.01 ms (-0.47%) 2.69%
handshake_tickets_aws_lc_rs_1.3_rsa_aes 5.56 ms 5.54 ms -0.02 ms (-0.45%) 2.71%
transfer_no_resume_aws_lc_rs_1.3_rsa_chacha 13.61 ms 13.56 ms -0.05 ms (-0.37%) 1.66%
handshake_no_resume_aws_lc_rs_1.3_ecdsap384_aes 1.18 ms 1.18 ms 0.00 ms (0.35%) 1.77%
handshake_tickets_ring_1.3_rsa_aes 7.17 ms 7.19 ms 0.02 ms (0.34%) 1.22%
handshake_tickets_ring_1.3_rsa_chacha 7.12 ms 7.14 ms 0.02 ms (0.33%) 1.00%
handshake_no_resume_ring_1.3_ecdsap256_aes 502.37 µs 503.82 µs 1.46 µs (0.29%) 3.29%
handshake_tickets_ring_1.3_ecdsap384_aes 9.76 ms 9.79 ms 0.03 ms (0.28%) 1.00%
handshake_tickets_ring_1.3_ecdsap384_chacha 9.71 ms 9.74 ms 0.03 ms (0.27%) 1.00%
handshake_no_resume_aws_lc_rs_1.3_ecdsap384_chacha 1.18 ms 1.18 ms 0.00 ms (0.26%) 1.85%
handshake_tickets_aws_lc_rs_1.3_ecdsap256_aes 4.89 ms 4.90 ms 0.01 ms (0.23%) 2.50%
handshake_session_id_aws_lc_rs_1.3_ecdsap256_chacha 4.57 ms 4.56 ms -0.01 ms (-0.22%) 1.76%
handshake_no_resume_ring_1.3_rsa_aes 992.88 µs 994.98 µs 2.10 µs (0.21%) 1.25%
handshake_tickets_aws_lc_rs_1.3_ecdsap256_chacha 4.91 ms 4.90 ms -0.01 ms (-0.21%) 2.30%
handshake_session_id_ring_1.3_rsa_aes 7.06 ms 7.07 ms 0.01 ms (0.21%) 1.06%
handshake_session_id_aws_lc_rs_1.3_ecdsap384_aes 5.29 ms 5.30 ms 0.01 ms (0.20%) 2.01%
handshake_session_id_ring_1.3_rsa_chacha 7.01 ms 7.02 ms 0.01 ms (0.19%) 1.00%
transfer_no_resume_aws_lc_rs_1.3_ecdsap256_aes 4.44 ms 4.43 ms -0.01 ms (-0.18%) 5.73%
handshake_no_resume_ring_1.3_rsa_chacha 996.08 µs 994.31 µs -1.76 µs (-0.18%) 1.40%
handshake_no_resume_ring_1.3_ecdsap256_chacha 499.15 µs 499.97 µs 0.81 µs (0.16%) 2.60%
handshake_tickets_ring_1.3_ecdsap256_chacha 6.64 ms 6.65 ms 0.01 ms (0.16%) 1.33%
handshake_tickets_ring_1.3_ecdsap256_aes 6.69 ms 6.70 ms 0.01 ms (0.15%) 1.04%
handshake_session_id_aws_lc_rs_1.3_ecdsap256_aes 4.57 ms 4.58 ms 0.01 ms (0.15%) 1.96%
handshake_tickets_aws_lc_rs_1.3_ecdsap384_aes 5.61 ms 5.62 ms 0.01 ms (0.15%) 2.17%
handshake_session_id_ring_1.3_ecdsap384_aes 9.64 ms 9.66 ms 0.01 ms (0.14%) 1.00%
handshake_tickets_aws_lc_rs_1.3_ecdsap384_chacha 5.62 ms 5.61 ms -0.01 ms (-0.11%) 2.19%
transfer_no_resume_ring_1.3_ecdsap256_aes 6.33 ms 6.34 ms 0.01 ms (0.10%) 3.06%
transfer_no_resume_ring_1.2_rsa_aes 6.75 ms 6.75 ms -0.01 ms (-0.10%) 3.08%
transfer_no_resume_aws_lc_rs_1.3_ecdsap384_aes 5.17 ms 5.16 ms -0.00 ms (-0.10%) 4.76%
transfer_no_resume_ring_1.3_rsa_chacha 13.44 ms 13.43 ms -0.01 ms (-0.07%) 1.43%
handshake_no_resume_ring_1.3_ecdsap384_chacha 3.59 ms 3.59 ms 0.00 ms (0.07%) 1.00%
handshake_session_id_ring_1.3_ecdsap256_aes 6.56 ms 6.57 ms 0.00 ms (0.06%) 1.01%
handshake_no_resume_aws_lc_rs_1.3_ecdsap256_aes 457.77 µs 458.06 µs 0.29 µs (0.06%) 4.32%
handshake_session_id_ring_1.3_ecdsap384_chacha 9.61 ms 9.61 ms 0.00 ms (0.05%) 1.00%
transfer_no_resume_ring_1.3_ecdsap384_chacha 16.04 ms 16.04 ms -0.01 ms (-0.05%) 1.29%
handshake_no_resume_ring_1.2_rsa_aes 989.87 µs 989.48 µs -0.39 µs (-0.04%) 1.16%
handshake_session_id_ring_1.3_ecdsap256_chacha 6.52 ms 6.52 ms 0.00 ms (0.04%) 1.27%
handshake_no_resume_ring_1.3_ecdsap384_aes 3.60 ms 3.60 ms 0.00 ms (0.04%) 1.00%
handshake_session_id_aws_lc_rs_1.3_ecdsap384_chacha 5.27 ms 5.27 ms -0.00 ms (-0.03%) 1.77%
transfer_no_resume_ring_1.3_rsa_aes 6.83 ms 6.82 ms -0.00 ms (-0.03%) 3.47%
transfer_no_resume_aws_lc_rs_1.3_ecdsap256_chacha 12.91 ms 12.90 ms -0.00 ms (-0.02%) 1.73%
handshake_no_resume_aws_lc_rs_1.3_ecdsap256_chacha 457.05 µs 457.12 µs 0.07 µs (0.01%) 4.12%
handshake_tickets_ring_1.2_rsa_aes 1.59 ms 1.59 ms -0.00 ms (-0.01%) 2.36%
transfer_no_resume_aws_lc_rs_1.3_ecdsap384_chacha 13.63 ms 13.63 ms -0.00 ms (-0.01%) 1.53%
transfer_no_resume_ring_1.3_ecdsap384_aes 9.43 ms 9.43 ms -0.00 ms (-0.00%) 1.79%
transfer_no_resume_ring_1.3_ecdsap256_chacha 12.94 ms 12.94 ms -0.00 ms (-0.00%) 1.51%

Additional information

Historical results

Checkout details:

Copy link
Member
@cpu cpu left a comment

Choose a reason for hiding this comment

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

Very nice work, thank you for sticking with this.

I had a fair number of comments but they're all pretty insubstantial and should be easy fixes. I'm happy to +1 after that.

@cpu
Copy link
Member
cpu commented Oct 7, 2024

Now might be a good point to update the PR description as well if you're up for it.

Copy link
Member
@ctz ctz left a comment

Choose a reason for hiding this comment

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

Modulo the outstanding comments, this LGTM

holodorum and others added 5 commits October 17, 2024 10:08
Co-authored-by: Adolfo Ochagavía <github@adolfo.ochagavia.nl>
Co-authored-by: Adolfo Ochagavía <github@adolfo.ochagavia.nl>
Co-authored-by: Adolfo Ochagavía <github@adolfo.ochagavia.nl>
Co-authored-by: Adolfo Ochagavía <github@adolfo.ochagavia.nl>
- Added `requires_raw_public_keys()` to `ServerCertVerifier` and
  `ClientCertVerifier` traits, and `only_raw_public_keys()` to
  `ServerResolveCert` and `ClientResolveCert` traits, with default
  implementations returning `false`.
- Introduced `AlwaysResolvesServerRawPublicKeys` and
  `AlwaysResolvesClientRawPublicKeys` for raw public key resolution.
- Implemented `webpki::verify::verify_tls13_signature_with_spki()`
  using `webpki::RawPublicKeyEntity` for signature verification.
- Added new error values to `PeerIncompatible`:
  - `IncorrectCertificateTypeExtension`
  - `UnsolicitedCertificateTypeExtension`
- Expanded `handshake::ServerExtension` and `handshake::ClientExtension`
  to include `CertificateType` support.
- Modified `server_conn::ClientHello` to include certificate type
  extensions for `Acceptor` API.
- Made `tls13::key_schedule::derive_traffic_key()` and
  `tls13::key_schedule::derive_traffic_iv()` public for testing.

Considerations:
- To maintain backward compatibility, we use `CertificateDer` for
  Raw Public Keys instead of `SubjectPublicKeyInfoDer` in
  `CommonState::peer_certificates()` and the `cert` field of
  `CertifiedKey`.
- We assume a-priori knowledge of the peer's authentication method
  when using Raw Public Keys, deviating slightly from RFC 7250. We do
  not offer both `RawPublicKey` and `X509`, though the RFC allows it.

Co-authored-by: Adolfo Ochagavía <github@adolfo.ochagavia.nl>
@holodorum
Copy link
Contributor Author

Thanks for all the thorough feedback and consistent input! I just processed the last outstanding comments (sorry that it took a bit longer), and I think it's ready to merge!

Co-authored-by: Adolfo Ochagavía <github@adolfo.ochagavia.nl>
Copy link
Member
@cpu cpu 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, thanks again :-)

@cpu cpu added this pull request to the merge queue Oct 17, 2024
Merged via the queue into rustls:main with commit 75ecfff Oct 17, 2024
32 checks passed
@cpu cpu mentioned this pull request Oct 27, 2024
@ripatel-fd
Copy link

@cpu @holodorum Hmm... This seems broken. After the latest rustls release, my peers stopped being able to handshake with rustls.

I believe this is because this implementation is not RFC 7250 compliant. rustls server configs that have an X.509 cert but no raw public key will now terminate handshakes with a TLS alert, if those servers see a ClientHello advertising both X.509 and RPK as a supported client certificate type. The correct behavior per RFC 7250 Section 4.2 is to either omit the server_certificate_type extension, or to respond with client_certificate_type X.509.

I tried to hack around this problem on the rustls server side but stumbled across an API design issue.
The resolve function of the ResolvesClientCert::resolve and the CertVerifier traits don't provide the certificate type to callbacks. The selected client certificate type is part of handshake state and is required to correctly parse a certificate. I understand the design decision to not support multiple certificate types in the "safe" user API. For more advanced use cases, it would be nice to have the ability to support both via a custom ResolvesServerCert.

In pseudocode, I would expect the API to look more like so:

fn verify(cert, client_cert_type) {
    match(client_cert_type) {
        RPK => verify_rpk(cert),
        X.509 => verify_x509(cert),
    }
}

Do you mind if I open GitHub issues and provide test cases for the aforementioned two issues? Or is the above intended behavior? Many thanks in advance.

@cpu
Copy link
Member
cpu commented Dec 4, 2024

Do you mind if I open GitHub issues and provide test cases for the aforementioned two issues?

A separate issue sounds great. It will be easier to discuss there.

@ripatel-fd
Copy link

@cpu Thank you for the quick response, I submitted these two issues: #2257 #2258.

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.

6 participants
0