rustls/quic.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
use alloc::boxed::Box;
use alloc::collections::VecDeque;
use alloc::vec::Vec;
#[cfg(feature = "std")]
use core::fmt::Debug;
/// This module contains optional APIs for implementing QUIC TLS.
use crate::common_state::Side;
use crate::crypto::cipher::{AeadKey, Iv};
use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock};
use crate::enums::AlertDescription;
use crate::error::Error;
use crate::tls13::key_schedule::{
hkdf_expand_label, hkdf_expand_label_aead_key, hkdf_expand_label_block,
};
use crate::tls13::Tls13CipherSuite;
#[cfg(feature = "std")]
mod connection {
use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use core::fmt::{self, Debug};
use core::ops::{Deref, DerefMut};
use pki_types::ServerName;
use super::{DirectionalKeys, KeyChange, Version};
use crate::client::{ClientConfig, ClientConnectionData};
use crate::common_state::{CommonState, Protocol, DEFAULT_BUFFER_LIMIT};
use crate::conn::{ConnectionCore, SideData};
use crate::enums::{AlertDescription, ContentType, ProtocolVersion};
use crate::error::Error;
use crate::msgs::deframer::buffers::{DeframerVecBuffer, Locator};
use crate::msgs::handshake::{ClientExtension, ServerExtension};
use crate::msgs::message::InboundPlainMessage;
use crate::server::{ServerConfig, ServerConnectionData};
use crate::vecbuf::ChunkVecBuffer;
/// A QUIC client or server connection.
#[derive(Debug)]
pub enum Connection {
/// A client connection
Client(ClientConnection),
/// A server connection
Server(ServerConnection),
}
impl Connection {
/// Return the TLS-encoded transport parameters for the session's peer.
///
/// See [`ConnectionCommon::quic_transport_parameters()`] for more details.
pub fn quic_transport_parameters(&self) -> Option<&[u8]> {
match self {
Self::Client(conn) => conn.quic_transport_parameters(),
Self::Server(conn) => conn.quic_transport_parameters(),
}
}
/// Compute the keys for encrypting/decrypting 0-RTT packets, if available
pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
match self {
Self::Client(conn) => conn.zero_rtt_keys(),
Self::Server(conn) => conn.zero_rtt_keys(),
}
}
/// Consume unencrypted TLS handshake data.
///
/// Handshake data obtained from separate encryption levels should be supplied in separate calls.
pub fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
match self {
Self::Client(conn) => conn.read_hs(plaintext),
Self::Server(conn) => conn.read_hs(plaintext),
}
}
/// Emit unencrypted TLS handshake data.
///
/// When this returns `Some(_)`, the new keys must be used for future handshake data.
pub fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> {
match self {
Self::Client(conn) => conn.write_hs(buf),
Self::Server(conn) => conn.write_hs(buf),
}
}
/// Emit the TLS description code of a fatal alert, if one has arisen.
///
/// Check after `read_hs` returns `Err(_)`.
pub fn alert(&self) -> Option<AlertDescription> {
match self {
Self::Client(conn) => conn.alert(),
Self::Server(conn) => conn.alert(),
}
}
/// Derives key material from the agreed connection secrets.
///
/// This function fills in `output` with `output.len()` bytes of key
/// material derived from the master session secret using `label`
/// and `context` for diversification. Ownership of the buffer is taken
/// by the function and returned via the Ok result to ensure no key
/// material leaks if the function fails.
///
/// See RFC5705 for more details on what this does and is for.
///
/// For TLS1.3 connections, this function does not use the
/// "early" exporter at any point.
///
/// This function fails if called prior to the handshake completing;
/// check with [`CommonState::is_handshaking`] first.
#[inline]
pub fn export_keying_material<T: AsMut<[u8]>>(
&self,
output: T,
label: &[u8],
context: Option<&[u8]>,
) -> Result<T, Error> {
match self {
Self::Client(conn) => conn
.core
.export_keying_material(output, label, context),
Self::Server(conn) => conn
.core
.export_keying_material(output, label, context),
}
}
}
impl Deref for Connection {
type Target = CommonState;
fn deref(&self) -> &Self::Target {
match self {
Self::Client(conn) => &conn.core.common_state,
Self::Server(conn) => &conn.core.common_state,
}
}
}
impl DerefMut for Connection {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Self::Client(conn) => &mut conn.core.common_state,
Self::Server(conn) => &mut conn.core.common_state,
}
}
}
/// A QUIC client connection.
pub struct ClientConnection {
inner: ConnectionCommon<ClientConnectionData>,
}
impl ClientConnection {
/// Make a new QUIC ClientConnection.
///
/// This differs from `ClientConnection::new()` in that it takes an extra `params` argument,
/// which contains the TLS-encoded transport parameters to send.
pub fn new(
config: Arc<ClientConfig>,
quic_version: Version,
name: ServerName<'static>,
params: Vec<u8>,
) -> Result<Self, Error> {
if !config.supports_version(ProtocolVersion::TLSv1_3) {
return Err(Error::General(
"TLS 1.3 support is required for QUIC".into(),
));
}
if !config.supports_protocol(Protocol::Quic) {
return Err(Error::General(
"at least one ciphersuite must support QUIC".into(),
));
}
let ext = match quic_version {
Version::V1Draft => ClientExtension::TransportParametersDraft(params),
Version::V1 | Version::V2 => ClientExtension::TransportParameters(params),
};
let mut inner = ConnectionCore::for_client(config, name, vec![ext], Protocol::Quic)?;
inner.common_state.quic.version = quic_version;
Ok(Self {
inner: inner.into(),
})
}
/// Returns True if the server signalled it will process early data.
///
/// If you sent early data and this returns false at the end of the
/// handshake then the server will not process the data. This
/// is not an error, but you may wish to resend the data.
pub fn is_early_data_accepted(&self) -> bool {
self.inner.core.is_early_data_accepted()
}
}
impl Deref for ClientConnection {
type Target = ConnectionCommon<ClientConnectionData>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for ClientConnection {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl Debug for ClientConnection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("quic::ClientConnection")
.finish()
}
}
impl From<ClientConnection> for Connection {
fn from(c: ClientConnection) -> Self {
Self::Client(c)
}
}
/// A QUIC server connection.
pub struct ServerConnection {
inner: ConnectionCommon<ServerConnectionData>,
}
impl ServerConnection {
/// Make a new QUIC ServerConnection.
///
/// This differs from `ServerConnection::new()` in that it takes an extra `params` argument,
/// which contains the TLS-encoded transport parameters to send.
pub fn new(
config: Arc<ServerConfig>,
quic_version: Version,
params: Vec<u8>,
) -> Result<Self, Error> {
if !config.supports_version(ProtocolVersion::TLSv1_3) {
return Err(Error::General(
"TLS 1.3 support is required for QUIC".into(),
));
}
if !config.supports_protocol(Protocol::Quic) {
return Err(Error::General(
"at least one ciphersuite must support QUIC".into(),
));
}
if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff {
return Err(Error::General(
"QUIC sessions must set a max early data of 0 or 2^32-1".into(),
));
}
let ext = match quic_version {
Version::V1Draft => ServerExtension::TransportParametersDraft(params),
Version::V1 | Version::V2 => ServerExtension::TransportParameters(params),
};
let mut core = ConnectionCore::for_server(config, vec![ext])?;
core.common_state.protocol = Protocol::Quic;
core.common_state.quic.version = quic_version;
Ok(Self { inner: core.into() })
}
/// Explicitly discard early data, notifying the client
///
/// Useful if invariants encoded in `received_resumption_data()` cannot be respected.
///
/// Must be called while `is_handshaking` is true.
pub fn reject_early_data(&mut self) {
self.inner.core.reject_early_data()
}
/// Retrieves the server name, if any, used to select the certificate and
/// private key.
///
/// This returns `None` until some time after the client's server name indication
/// (SNI) extension value is processed during the handshake. It will never be
/// `None` when the connection is ready to send or process application data,
/// unless the client does not support SNI.
///
/// This is useful for application protocols that need to enforce that the
/// server name matches an application layer protocol hostname. For
/// example, HTTP/1.1 servers commonly expect the `Host:` header field of
/// every request on a connection to match the hostname in the SNI extension
/// when the client provides the SNI extension.
///
/// The server name is also used to match sessions during session resumption.
pub fn server_name(&self) -> Option<&str> {
self.inner.core.get_sni_str()
}
}
impl Deref for ServerConnection {
type Target = ConnectionCommon<ServerConnectionData>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for ServerConnection {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl Debug for ServerConnection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("quic::ServerConnection")
.finish()
}
}
impl From<ServerConnection> for Connection {
fn from(c: ServerConnection) -> Self {
Self::Server(c)
}
}
/// A shared interface for QUIC connections.
pub struct ConnectionCommon<Data> {
core: ConnectionCore<Data>,
deframer_buffer: DeframerVecBuffer,
sendable_plaintext: ChunkVecBuffer,
}
impl<Data: SideData> ConnectionCommon<Data> {
/// Return the TLS-encoded transport parameters for the session's peer.
///
/// While the transport parameters are technically available prior to the
/// completion of the handshake, they cannot be fully trusted until the
/// handshake completes, and reliance on them should be minimized.
/// However, any tampering with the parameters will cause the handshake
/// to fail.
pub fn quic_transport_parameters(&self) -> Option<&[u8]> {
self.core
.common_state
.quic
.params
.as_ref()
.map(|v| v.as_ref())
}
/// Compute the keys for encrypting/decrypting 0-RTT packets, if available
pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
let suite = self
.core
.common_state
.suite
.and_then(|suite| suite.tls13())?;
Some(DirectionalKeys::new(
suite,
suite.quic?,
self.core
.common_state
.quic
.early_secret
.as_ref()?,
self.core.common_state.quic.version,
))
}
/// Consume unencrypted TLS handshake data.
///
/// Handshake data obtained from separate encryption levels should be supplied in separate calls.
pub fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
let range = self.deframer_buffer.extend(plaintext);
self.core.hs_deframer.input_message(
InboundPlainMessage {
typ: ContentType::Handshake,
version: ProtocolVersion::TLSv1_3,
payload: &self.deframer_buffer.filled()[range.clone()],
},
&Locator::new(self.deframer_buffer.filled()),
range.end,
);
// `core.process_new_packets` should not process any data in `deframer_buffer`;
// it is already ready in `hs_deframer`.
self.deframer_buffer.processed = range.end;
self.core
.hs_deframer
.coalesce(self.deframer_buffer.filled_mut())?;
self.core
.process_new_packets(&mut self.deframer_buffer, &mut self.sendable_plaintext)?;
Ok(())
}
/// Emit unencrypted TLS handshake data.
///
/// When this returns `Some(_)`, the new keys must be used for future handshake data.
pub fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> {
self.core
.common_state
.quic
.write_hs(buf)
}
/// Emit the TLS description code of a fatal alert, if one has arisen.
///
/// Check after `read_hs` returns `Err(_)`.
pub fn alert(&self) -> Option<AlertDescription> {
self.core.common_state.quic.alert
}
}
impl<Data> Deref for ConnectionCommon<Data> {
type Target = CommonState;
fn deref(&self) -> &Self::Target {
&self.core.common_state
}
}
impl<Data> DerefMut for ConnectionCommon<Data> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.core.common_state
}
}
impl<Data> From<ConnectionCore<Data>> for ConnectionCommon<Data> {
fn from(core: ConnectionCore<Data>) -> Self {
Self {
core,
deframer_buffer: DeframerVecBuffer::default(),
sendable_plaintext: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)),
}
}
}
}
#[cfg(feature = "std")]
pub use connection::{ClientConnection, Connection, ConnectionCommon, ServerConnection};
#[derive(Default)]
pub(crate) struct Quic {
/// QUIC transport parameters received from the peer during the handshake
pub(crate) params: Option<Vec<u8>>,
pub(crate) alert: Option<AlertDescription>,
pub(crate) hs_queue: VecDeque<(bool, Vec<u8>)>,
pub(crate) early_secret: Option<OkmBlock>,
pub(crate) hs_secrets: Option<Secrets>,
pub(crate) traffic_secrets: Option<Secrets>,
/// Whether keys derived from traffic_secrets have been passed to the QUIC implementation
#[cfg(feature = "std")]
pub(crate) returned_traffic_keys: bool,
pub(crate) version: Version,
}
#[cfg(feature = "std")]
impl Quic {
pub(crate) fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> {
while let Some((_, msg)) = self.hs_queue.pop_front() {
buf.extend_from_slice(&msg);
if let Some(&(true, _)) = self.hs_queue.front() {
if self.hs_secrets.is_some() {
// Allow the caller to switch keys before proceeding.
break;
}
}
}
if let Some(secrets) = self.hs_secrets.take() {
return Some(KeyChange::Handshake {
keys: Keys::new(&secrets),
});
}
if let Some(mut secrets) = self.traffic_secrets.take() {
if !self.returned_traffic_keys {
self.returned_traffic_keys = true;
let keys = Keys::new(&secrets);
secrets.update();
return Some(KeyChange::OneRtt {
keys,
next: secrets,
});
}
}
None
}
}
/// Secrets used to encrypt/decrypt traffic
#[derive(Clone)]
pub struct Secrets {
/// Secret used to encrypt packets transmitted by the client
pub(crate) client: OkmBlock,
/// Secret used to encrypt packets transmitted by the server
pub(crate) server: OkmBlock,
/// Cipher suite used with these secrets
suite: &'static Tls13CipherSuite,
quic: &'static dyn Algorithm,
side: Side,
version: Version,
}
impl Secrets {
pub(crate) fn new(
client: OkmBlock,
server: OkmBlock,
suite: &'static Tls13CipherSuite,
quic: &'static dyn Algorithm,
side: Side,
version: Version,
) -> Self {
Self {
client,
server,
suite,
quic,
side,
version,
}
}
/// Derive the next set of packet keys
pub fn next_packet_keys(&mut self) -> PacketKeySet {
let keys = PacketKeySet::new(self);
self.update();
keys
}
pub(crate) fn update(&mut self) {
self.client = hkdf_expand_label_block(
self.suite
.hkdf_provider
.expander_for_okm(&self.client)
.as_ref(),
self.version.key_update_label(),
&[],
);
self.server = hkdf_expand_label_block(
self.suite
.hkdf_provider
.expander_for_okm(&self.server)
.as_ref(),
self.version.key_update_label(),
&[],
);
}
fn local_remote(&self) -> (&OkmBlock, &OkmBlock) {
match self.side {
Side::Client => (&self.client, &self.server),
Side::Server => (&self.server, &self.client),
}
}
}
/// Keys used to communicate in a single direction
pub struct DirectionalKeys {
/// Encrypts or decrypts a packet's headers
pub header: Box<dyn HeaderProtectionKey>,
/// Encrypts or decrypts the payload of a packet
pub packet: Box<dyn PacketKey>,
}
impl DirectionalKeys {
pub(crate) fn new(
suite: &'static Tls13CipherSuite,
quic: &'static dyn Algorithm,
secret: &OkmBlock,
version: Version,
) -> Self {
let builder = KeyBuilder::new(secret, version, quic, suite.hkdf_provider);
Self {
header: builder.header_protection_key(),
packet: builder.packet_key(),
}
}
}
/// All AEADs we support have 16-byte tags.
const TAG_LEN: usize = 16;
/// Authentication tag from an AEAD seal operation.
pub struct Tag([u8; TAG_LEN]);
impl From<&[u8]> for Tag {
fn from(value: &[u8]) -> Self {
let mut array = [0u8; TAG_LEN];
array.copy_from_slice(value);
Self(array)
}
}
impl AsRef<[u8]> for Tag {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
/// How a `Tls13CipherSuite` generates `PacketKey`s and `HeaderProtectionKey`s.
pub trait Algorithm: Send + Sync {
/// Produce a `PacketKey` encrypter/decrypter for this suite.
///
/// `suite` is the entire suite this `Algorithm` appeared in.
/// `key` and `iv` is the key material to use.
fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn PacketKey>;
/// Produce a `HeaderProtectionKey` encrypter/decrypter for this suite.
///
/// `key` is the key material, which is `aead_key_len()` bytes in length.
fn header_protection_key(&self, key: AeadKey) -> Box<dyn HeaderProtectionKey>;
/// The length in bytes of keys for this Algorithm.
///
/// This controls the size of `AeadKey`s presented to `packet_key()` and `header_protection_key()`.
fn aead_key_len(&self) -> usize;
/// Whether this algorithm is FIPS-approved.
fn fips(&self) -> bool {
false
}
}
/// A QUIC header protection key
pub trait HeaderProtectionKey: Send + Sync {
/// Adds QUIC Header Protection.
///
/// `sample` must contain the sample of encrypted payload; see
/// [Header Protection Sample].
///
/// `first` must reference the first byte of the header, referred to as
/// `packet[0]` in [Header Protection Application].
///
/// `packet_number` must reference the Packet Number field; this is
/// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application].
///
/// Returns an error without modifying anything if `sample` is not
/// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]),
/// or `packet_number` is longer than allowed (see [Packet Number Encoding and Decoding]).
///
/// Otherwise, `first` and `packet_number` will have the header protection added.
///
/// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1
/// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2
/// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1
fn encrypt_in_place(
&self,
sample: &[u8],
first: &mut u8,
packet_number: &mut [u8],
) -> Result<(), Error>;
/// Removes QUIC Header Protection.
///
/// `sample` must contain the sample of encrypted payload; see
/// [Header Protection Sample].
///
/// `first` must reference the first byte of the header, referred to as
/// `packet[0]` in [Header Protection Application].
///
/// `packet_number` must reference the Packet Number field; this is
/// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application].
///
/// Returns an error without modifying anything if `sample` is not
/// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]),
/// or `packet_number` is longer than allowed (see
/// [Packet Number Encoding and Decoding]).
///
/// Otherwise, `first` and `packet_number` will have the header protection removed.
///
/// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1
/// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2
/// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1
fn decrypt_in_place(
&self,
sample: &[u8],
first: &mut u8,
packet_number: &mut [u8],
) -> Result<(), Error>;
/// Expected sample length for the key's algorithm
fn sample_len(&self) -> usize;
}
/// Keys to encrypt or decrypt the payload of a packet
pub trait PacketKey: Send + Sync {
/// Encrypt a QUIC packet
///
/// Takes a `packet_number`, used to derive the nonce; the packet `header`, which is used as
/// the additional authenticated data; and the `payload`. The authentication tag is returned if
/// encryption succeeds.
///
/// Fails if and only if the payload is longer than allowed by the cipher suite's AEAD algorithm.
fn encrypt_in_place(
&self,
packet_number: u64,
header: &[u8],
payload: &mut [u8],
) -> Result<Tag, Error>;
/// Decrypt a QUIC packet
///
/// Takes the packet `header`, which is used as the additional authenticated data, and the
/// `payload`, which includes the authentication tag.
///
/// If the return value is `Ok`, the decrypted payload can be found in `payload`, up to the
/// length found in the return value.
fn decrypt_in_place<'a>(
&self,
packet_number: u64,
header: &[u8],
payload: &'a mut [u8],
) -> Result<&'a [u8], Error>;
/// Tag length for the underlying AEAD algorithm
fn tag_len(&self) -> usize;
/// Number of QUIC messages that can be safely encrypted with a single key of this type.
///
/// Once a `MessageEncrypter` produced for this suite has encrypted more than
/// `confidentiality_limit` messages, an attacker gains an advantage in distinguishing it
/// from an ideal pseudorandom permutation (PRP).
///
/// This is to be set on the assumption that messages are maximally sized --
/// 2 ** 16. For non-QUIC TCP connections see [`CipherSuiteCommon::confidentiality_limit`][csc-limit].
///
/// [csc-limit]: crate::crypto::CipherSuiteCommon::confidentiality_limit
fn confidentiality_limit(&self) -> u64;
/// Number of QUIC messages that can be safely decrypted with a single key of this type
///
/// Once a `MessageDecrypter` produced for this suite has failed to decrypt `integrity_limit`
/// messages, an attacker gains an advantage in forging messages.
///
/// This is not relevant for TLS over TCP (which is also implemented in this crate)
/// because a single failed decryption is fatal to the connection.
/// However, this quantity is used by QUIC.
fn integrity_limit(&self) -> u64;
}
/// Packet protection keys for bidirectional 1-RTT communication
pub struct PacketKeySet {
/// Encrypts outgoing packets
pub local: Box<dyn PacketKey>,
/// Decrypts incoming packets
pub remote: Box<dyn PacketKey>,
}
impl PacketKeySet {
fn new(secrets: &Secrets) -> Self {
let (local, remote) = secrets.local_remote();
let (version, alg, hkdf) = (secrets.version, secrets.quic, secrets.suite.hkdf_provider);
Self {
local: KeyBuilder::new(local, version, alg, hkdf).packet_key(),
remote: KeyBuilder::new(remote, version, alg, hkdf).packet_key(),
}
}
}
pub(crate) struct KeyBuilder<'a> {
expander: Box<dyn HkdfExpander>,
version: Version,
alg: &'a dyn Algorithm,
}
impl<'a> KeyBuilder<'a> {
pub(crate) fn new(
secret: &OkmBlock,
version: Version,
alg: &'a dyn Algorithm,
hkdf: &'a dyn Hkdf,
) -> Self {
Self {
expander: hkdf.expander_for_okm(secret),
version,
alg,
}
}
/// Derive packet keys
pub(crate) fn packet_key(&self) -> Box<dyn PacketKey> {
let aead_key_len = self.alg.aead_key_len();
let packet_key = hkdf_expand_label_aead_key(
self.expander.as_ref(),
aead_key_len,
self.version.packet_key_label(),
&[],
);
let packet_iv =
hkdf_expand_label(self.expander.as_ref(), self.version.packet_iv_label(), &[]);
self.alg
.packet_key(packet_key, packet_iv)
}
/// Derive header protection keys
pub(crate) fn header_protection_key(&self) -> Box<dyn HeaderProtectionKey> {
let header_key = hkdf_expand_label_aead_key(
self.expander.as_ref(),
self.alg.aead_key_len(),
self.version.header_key_label(),
&[],
);
self.alg
.header_protection_key(header_key)
}
}
/// Produces QUIC initial keys from a TLS 1.3 ciphersuite and a QUIC key generation algorithm.
#[derive(Clone, Copy)]
pub struct Suite {
/// The TLS 1.3 ciphersuite used to derive keys.
pub suite: &'static Tls13CipherSuite,
/// The QUIC key generation algorithm used to derive keys.
pub quic: &'static dyn Algorithm,
}
impl Suite {
/// Produce a set of initial keys given the connection ID, side and version
pub fn keys(&self, client_dst_connection_id: &[u8], side: Side, version: Version) -> Keys {
Keys::initial(
version,
self.suite,
self.quic,
client_dst_connection_id,
side,
)
}
}
/// Complete set of keys used to communicate with the peer
pub struct Keys {
/// Encrypts outgoing packets
pub local: DirectionalKeys,
/// Decrypts incoming packets
pub remote: DirectionalKeys,
}
impl Keys {
/// Construct keys for use with initial packets
pub fn initial(
version: Version,
suite: &'static Tls13CipherSuite,
quic: &'static dyn Algorithm,
client_dst_connection_id: &[u8],
side: Side,
) -> Self {
const CLIENT_LABEL: &[u8] = b"client in";
const SERVER_LABEL: &[u8] = b"server in";
let salt = version.initial_salt();
let hs_secret = suite
.hkdf_provider
.extract_from_secret(Some(salt), client_dst_connection_id);
let secrets = Secrets {
version,
client: hkdf_expand_label_block(hs_secret.as_ref(), CLIENT_LABEL, &[]),
server: hkdf_expand_label_block(hs_secret.as_ref(), SERVER_LABEL, &[]),
suite,
quic,
side,
};
Self::new(&secrets)
}
fn new(secrets: &Secrets) -> Self {
let (local, remote) = secrets.local_remote();
Self {
local: DirectionalKeys::new(secrets.suite, secrets.quic, local, secrets.version),
remote: DirectionalKeys::new(secrets.suite, secrets.quic, remote, secrets.version),
}
}
}
/// Key material for use in QUIC packet spaces
///
/// QUIC uses 4 different sets of keys (and progressive key updates for long-running connections):
///
/// * Initial: these can be created from [`Keys::initial()`]
/// * 0-RTT keys: can be retrieved from [`ConnectionCommon::zero_rtt_keys()`]
/// * Handshake: these are returned from [`ConnectionCommon::write_hs()`] after `ClientHello` and
/// `ServerHello` messages have been exchanged
/// * 1-RTT keys: these are returned from [`ConnectionCommon::write_hs()`] after the handshake is done
///
/// Once the 1-RTT keys have been exchanged, either side may initiate a key update. Progressive
/// update keys can be obtained from the [`Secrets`] returned in [`KeyChange::OneRtt`]. Note that
/// only packet keys are updated by key updates; header protection keys remain the same.
pub enum KeyChange {
/// Keys for the handshake space
Handshake {
/// Header and packet keys for the handshake space
keys: Keys,
},
/// Keys for 1-RTT data
OneRtt {
/// Header and packet keys for 1-RTT data
keys: Keys,
/// Secrets to derive updated keys from
next: Secrets,
},
}
/// QUIC protocol version
///
/// Governs version-specific behavior in the TLS layer
#[non_exhaustive]
#[derive(Clone, Copy, Debug)]
pub enum Version {
/// Draft versions 29, 30, 31 and 32
V1Draft,
/// First stable RFC
V1,
/// Anti-ossification variant of V1
V2,
}
impl Version {
fn initial_salt(self) -> &'static [u8; 20] {
match self {
Self::V1Draft => &[
// https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#section-5.2
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61,
0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99,
],
Self::V1 => &[
// https://www.rfc-editor.org/rfc/rfc9001.html#name-initial-secrets
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
],
Self::V2 => &[
// https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-initial-salt-2
0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26,
0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9,
],
}
}
/// Key derivation label for packet keys.
pub(crate) fn packet_key_label(&self) -> &'static [u8] {
match self {
Self::V1Draft | Self::V1 => b"quic key",
Self::V2 => b"quicv2 key",
}
}
/// Key derivation label for packet "IV"s.
pub(crate) fn packet_iv_label(&self) -> &'static [u8] {
match self {
Self::V1Draft | Self::V1 => b"quic iv",
Self::V2 => b"quicv2 iv",
}
}
/// Key derivation for header keys.
pub(crate) fn header_key_label(&self) -> &'static [u8] {
match self {
Self::V1Draft | Self::V1 => b"quic hp",
Self::V2 => b"quicv2 hp",
}
}
fn key_update_label(&self) -> &'static [u8] {
match self {
Self::V1Draft | Self::V1 => b"quic ku",
Self::V2 => b"quicv2 ku",
}
}
}
impl Default for Version {
fn default() -> Self {
Self::V1
}
}
#[cfg(test)]
mod tests {
use std::prelude::v1::*;
use super::PacketKey;
use crate::quic::HeaderProtectionKey;
#[test]
fn auto_traits() {
fn assert_auto<T: Send + Sync>() {}
assert_auto::<Box<dyn PacketKey>>();
assert_auto::<Box<dyn HeaderProtectionKey>>();
}
}