From 7241fe490985a431d08eb3224241c05d6fe7633b Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Wed, 5 Aug 2026 19:35:52 +0800 Subject: [PATCH 1/5] feat: add AES-CCM cipher suites Add TLS 1.2 ECDHE-ECDSA AES-CCM/CCM-8 and TLS 1.3 AES-128-CCM cipher suites using the RustCrypto ccm crate. --- Cargo.lock | 14 +++ Cargo.toml | 2 + src/aead.rs | 1 + src/aead/ccm.rs | 258 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 93 ++++++++++++++++- 5 files changed, 366 insertions(+), 2 deletions(-) create mode 100644 src/aead/ccm.rs diff --git a/Cargo.lock b/Cargo.lock index 3199dc0..4092ca8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,6 +74,18 @@ dependencies = [ "shlex", ] +[[package]] +name = "ccm" +version = "0.6.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4edea5ea70a1285565ac264767613d6c88351a9a0557e7af793a0942590baaed" +dependencies = [ + "aead", + "cipher", + "ctr", + "subtle", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -656,7 +668,9 @@ name = "rustls-rustcrypto" version = "0.0.2-alpha" dependencies = [ "aead", + "aes", "aes-gcm", + "ccm", "chacha20poly1305", "crypto-common", "der", diff --git a/Cargo.toml b/Cargo.toml index e8e5de0..04590bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,9 @@ resolver = "1" # Hack to enable the `custom` feature of `getrandom` # default features often have std breaking no_std and potentially other unwanted [dependencies] aead = { version = "0.6", default-features = false } +aes = { version = "0.9", default-features = false } aes-gcm = { version = "0.11", default-features = false, features = ["aes", "alloc"] } +ccm = { version = "0.6.0-rc.3", default-features = false } chacha20poly1305 = { version = "0.11", default-features = false } crypto-common = { version = "0.2", default-features = false } der = { version = "0.8", default-features = false } diff --git a/src/aead.rs b/src/aead.rs index 6ff57b7..7fa0f15 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -1,6 +1,7 @@ use aead::Buffer; use rustls::crypto::cipher::{BorrowedPayload, PrefixedPayload}; +pub mod ccm; pub mod chacha20; pub mod gcm; diff --git a/src/aead/ccm.rs b/src/aead/ccm.rs new file mode 100644 index 0000000..faa8072 --- /dev/null +++ b/src/aead/ccm.rs @@ -0,0 +1,258 @@ +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +use super::{DecryptBufferAdapter, EncryptBufferAdapter}; + +use aead::AeadInOut; +use aes::{Aes128, Aes256}; +use ccm::{ + Ccm, + consts::{U8, U12, U16}, +}; +use crypto_common::{KeyInit, KeySizeUser}; +use paste::paste; +use rustls::crypto::cipher::{ + self, AeadKey, InboundOpaqueMessage, InboundPlainMessage, MessageDecrypter, MessageEncrypter, + OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, Tls13AeadAlgorithm, + UnsupportedOperationError, +}; +use rustls::{ConnectionTrafficSecrets, ContentType, ProtocolVersion}; + +#[cfg(feature = "tls12")] +use { + aead::AeadCore, + crypto_common::typenum::Unsigned, + rustls::crypto::cipher::{KeyBlockShape, Tls12AeadAlgorithm}, +}; + +/// AES-128-CCM with 16-byte tag and 12-byte nonce (RFC 5116 / RFC 6655). +pub type Aes128Ccm = Ccm; +/// AES-256-CCM with 16-byte tag and 12-byte nonce. +pub type Aes256Ccm = Ccm; +/// AES-128-CCM with 8-byte tag and 12-byte nonce (CCM-8). +pub type Aes128Ccm8 = Ccm; +/// AES-256-CCM with 8-byte tag and 12-byte nonce (CCM-8). +pub type Aes256Ccm8 = Ccm; + +#[cfg(feature = "tls12")] +const TLS12_CCM_EXPLICIT_NONCE_LEN: usize = 8; + +#[cfg(feature = "tls12")] +const TLS12_CCM_OVERHEAD: usize = TLS12_CCM_EXPLICIT_NONCE_LEN + 16; + +#[cfg(feature = "tls12")] +const TLS12_CCM_8_OVERHEAD: usize = TLS12_CCM_EXPLICIT_NONCE_LEN + 8; + +macro_rules! impl_ccm_tls13 { + ($name: ident, $aead: ty, $overhead: expr) => { + paste! { + pub struct []; + + impl Tls13AeadAlgorithm for [] { + fn encrypter(&self, key: AeadKey, iv: cipher::Iv) -> Box { + Box::new([]( + $aead::new_from_slice(key.as_ref()).unwrap(), + iv, + )) + } + + fn decrypter(&self, key: AeadKey, iv: cipher::Iv) -> Box { + Box::new([]( + $aead::new_from_slice(key.as_ref()).unwrap(), + iv, + )) + } + + fn key_len(&self) -> usize { + $aead::key_size() + } + + fn extract_keys( + &self, + _key: AeadKey, + _iv: cipher::Iv, + ) -> Result { + // rustls::ConnectionTrafficSecrets has no CCM variants. + Err(UnsupportedOperationError) + } + } + + struct []($aead, cipher::Iv); + + impl MessageEncrypter for [] { + fn encrypt(&mut self, m: OutboundPlainMessage<'_>, seq: u64) -> Result { + let total_len = self.encrypted_payload_len(m.payload.len()); + let mut payload = PrefixedPayload::with_capacity(total_len); + + let nonce = cipher::Nonce::new(&self.1, seq).0; + let aad = cipher::make_tls13_aad(total_len); + payload.extend_from_chunks(&m.payload); + payload.extend_from_slice(&m.typ.to_array()); + + self.0 + .encrypt_in_place(&nonce.into(), &aad, &mut EncryptBufferAdapter(&mut payload)) + .map_err(|_| rustls::Error::EncryptError) + .map(|_| OutboundOpaqueMessage::new( + ContentType::ApplicationData, + ProtocolVersion::TLSv1_2, + payload, + )) + } + + fn encrypted_payload_len(&self, payload_len: usize) -> usize { + payload_len + 1 + $overhead + } + } + + impl MessageDecrypter for [] { + fn decrypt<'a>(&mut self, mut m: InboundOpaqueMessage<'a>, seq: u64) -> Result, rustls::Error> { + let payload = &mut m.payload; + let nonce = cipher::Nonce::new(&self.1, seq).0; + let aad = cipher::make_tls13_aad(payload.len()); + + self.0 + .decrypt_in_place(&nonce.into(), &aad, &mut DecryptBufferAdapter(payload)) + .map_err(|_| rustls::Error::DecryptError)?; + + m.into_tls13_unpadded_message() + } + } + } + }; +} + +#[cfg(feature = "tls12")] +macro_rules! impl_ccm_tls12 { + ($name: ident, $aead: ty, $nonce: expr, $overhead: expr) => { + paste! { + #[cfg(feature = "tls12")] + pub struct []; + + #[cfg(feature = "tls12")] + impl Tls12AeadAlgorithm for [] { + fn encrypter(&self, key: AeadKey, write_iv: &[u8], explicit: &[u8]) -> Box { + Box::new([]( + $aead::new_from_slice(key.as_ref()).unwrap(), + { + let mut iv: [u8; 12] = [0; 12]; + iv[..4].copy_from_slice(write_iv); + iv[4..].copy_from_slice(explicit); + iv + }, + )) + } + + fn decrypter(&self, dec_key: AeadKey, dec_iv: &[u8]) -> Box { + Box::new([]( + $aead::new_from_slice(dec_key.as_ref()).unwrap(), + dec_iv.try_into().unwrap(), + )) + } + + fn key_block_shape(&self) -> KeyBlockShape { + KeyBlockShape { + enc_key_len: $aead::key_size(), + fixed_iv_len: 4, + explicit_nonce_len: 8, + } + } + + fn extract_keys( + &self, + _key: AeadKey, + _iv: &[u8], + _explicit: &[u8], + ) -> Result { + // rustls::ConnectionTrafficSecrets has no CCM variants. + Err(UnsupportedOperationError) + } + } + + #[cfg(feature = "tls12")] + struct []($aead, [u8; 12]); + + #[cfg(feature = "tls12")] + impl MessageEncrypter for [] { + fn encrypt(&mut self, m: OutboundPlainMessage<'_>, seq: u64) -> Result { + let total_len = self.encrypted_payload_len(m.payload.len()); + let mut payload = PrefixedPayload::with_capacity(total_len); + + let nonce = cipher::Nonce::new(&self.1.into(), seq).0; + let aad = cipher::make_tls12_aad(seq, m.typ, m.version, m.payload.len()); + payload.extend_from_slice(&nonce.as_ref()[4..]); // explicit + payload.extend_from_chunks(&m.payload); + + self.0 + .encrypt_inout_detached(&nonce.into(), &aad, (&mut payload.as_mut()[$nonce..]).into()) + .map(|tag| payload.extend(tag.as_ref() as &[u8])) + .map_err(|_| rustls::Error::EncryptError) + .map(|_| OutboundOpaqueMessage::new(m.typ, m.version, payload)) + } + + fn encrypted_payload_len(&self, payload_len: usize) -> usize { + payload_len + $nonce + <$aead as AeadCore>::TagSize::USIZE + } + } + + #[cfg(feature = "tls12")] + struct []($aead, [u8; 4]); + + #[cfg(feature = "tls12")] + impl MessageDecrypter for [] { + fn decrypt<'a>(&mut self, mut m: InboundOpaqueMessage<'a>, seq: u64) -> Result, rustls::Error> { + type TagSize = <$aead as AeadCore>::TagSize; + + let payload = &m.payload; + + if payload.len() < $overhead { + return Err(rustls::Error::DecryptError); + } + + let nonce: aead::Nonce<$aead> = { + let mut nonce = [0u8; 12]; + nonce[..4].copy_from_slice(&self.1); // dec_iv + nonce[4..].copy_from_slice(&payload[..$nonce]); + nonce.into() + }; + + let aad = cipher::make_tls12_aad(seq, m.typ, m.version, payload.len() - $overhead); + + let payload = &mut m.payload; + let tag_pos = { + let payload = &mut payload[$nonce..]; + let tag_pos = payload.len() - TagSize::to_usize(); + let (msg, tag) = payload.split_at_mut(tag_pos); + + let tag = ccm::Tag::::try_from(&*tag) + .map_err(|_| rustls::Error::DecryptError)?; + self.0 + .decrypt_inout_detached(&nonce, &aad, msg.into(), &tag) + .map_err(|_| rustls::Error::DecryptError)?; + tag_pos + }; + + // Defer truncation until after successful decrypt so a failure cannot + // leave the buffer shifted relative to the wire layout. + payload.rotate_left($nonce); + payload.truncate(tag_pos); + Ok(m.into_plain_message()) + } + } + } + }; +} + +impl_ccm_tls13! {Aes128Ccm, Aes128Ccm, 16} +impl_ccm_tls13! {Aes128Ccm8, Aes128Ccm8, 8} + +#[cfg(feature = "tls12")] +impl_ccm_tls12! {Aes128Ccm, Aes128Ccm, TLS12_CCM_EXPLICIT_NONCE_LEN, TLS12_CCM_OVERHEAD} + +#[cfg(feature = "tls12")] +impl_ccm_tls12! {Aes256Ccm, Aes256Ccm, TLS12_CCM_EXPLICIT_NONCE_LEN, TLS12_CCM_OVERHEAD} + +#[cfg(feature = "tls12")] +impl_ccm_tls12! {Aes128Ccm8, Aes128Ccm8, TLS12_CCM_EXPLICIT_NONCE_LEN, TLS12_CCM_8_OVERHEAD} + +#[cfg(feature = "tls12")] +impl_ccm_tls12! {Aes256Ccm8, Aes256Ccm8, TLS12_CCM_EXPLICIT_NONCE_LEN, TLS12_CCM_8_OVERHEAD} diff --git a/src/lib.rs b/src/lib.rs index 6332bca..97955a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,11 +139,71 @@ pub const TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = aead_alg: &aead::chacha20::Chacha20Poly1305, }); +#[cfg(feature = "tls12")] +pub const TLS_ECDHE_ECDSA_WITH_AES_128_CCM: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + hash_provider: hash::SHA256, + confidentiality_limit: u64::MAX, + }, + kx: rustls::crypto::KeyExchangeAlgorithm::ECDHE, + sign: &TLS12_ECDSA_SCHEMES, + aead_alg: &aead::ccm::Tls12Aes128Ccm, + prf_provider: &rustls::crypto::tls12::PrfUsingHmac(hmac::SHA256), + }); + +#[cfg(feature = "tls12")] +pub const TLS_ECDHE_ECDSA_WITH_AES_256_CCM: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + hash_provider: hash::SHA256, + confidentiality_limit: u64::MAX, + }, + kx: rustls::crypto::KeyExchangeAlgorithm::ECDHE, + sign: &TLS12_ECDSA_SCHEMES, + aead_alg: &aead::ccm::Tls12Aes256Ccm, + prf_provider: &rustls::crypto::tls12::PrfUsingHmac(hmac::SHA256), + }); + +#[cfg(feature = "tls12")] +pub const TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + hash_provider: hash::SHA256, + confidentiality_limit: u64::MAX, + }, + kx: rustls::crypto::KeyExchangeAlgorithm::ECDHE, + sign: &TLS12_ECDSA_SCHEMES, + aead_alg: &aead::ccm::Tls12Aes128Ccm8, + prf_provider: &rustls::crypto::tls12::PrfUsingHmac(hmac::SHA256), + }); + +#[cfg(feature = "tls12")] +pub const TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: SupportedCipherSuite = + SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + hash_provider: hash::SHA256, + confidentiality_limit: u64::MAX, + }, + kx: rustls::crypto::KeyExchangeAlgorithm::ECDHE, + sign: &TLS12_ECDSA_SCHEMES, + aead_alg: &aead::ccm::Tls12Aes256Ccm8, + prf_provider: &rustls::crypto::tls12::PrfUsingHmac(hmac::SHA256), + }); + #[cfg(feature = "tls12")] const TLS_ECDHE_ECDSA_SUITES: &[SupportedCipherSuite] = &[ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, ]; #[cfg(feature = "tls12")] @@ -229,8 +289,37 @@ pub const TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = quic: None, }); -const TLS13_AES_SUITES: &[SupportedCipherSuite] = - &[TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384]; +pub const TLS13_AES_128_CCM_SHA256: SupportedCipherSuite = + SupportedCipherSuite::Tls13(&Tls13CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS13_AES_128_CCM_SHA256, + hash_provider: hash::SHA256, + confidentiality_limit: u64::MAX, + }, + hkdf_provider: &rustls::crypto::tls13::HkdfUsingHmac(hmac::SHA256), + aead_alg: &aead::ccm::Tls13Aes128Ccm, + quic: None, + }); + +pub const TLS13_AES_128_CCM_8_SHA256: SupportedCipherSuite = + SupportedCipherSuite::Tls13(&Tls13CipherSuite { + common: CipherSuiteCommon { + suite: CipherSuite::TLS13_AES_128_CCM_8_SHA256, + hash_provider: hash::SHA256, + confidentiality_limit: u64::MAX, + }, + hkdf_provider: &rustls::crypto::tls13::HkdfUsingHmac(hmac::SHA256), + aead_alg: &aead::ccm::Tls13Aes128Ccm8, + // QUIC header protection requires a 16-byte tag; CCM-8 is too short. + quic: None, + }); + +const TLS13_AES_SUITES: &[SupportedCipherSuite] = &[ + TLS13_AES_128_GCM_SHA256, + TLS13_AES_256_GCM_SHA384, + TLS13_AES_128_CCM_SHA256, + TLS13_AES_128_CCM_8_SHA256, +]; pub const TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls13(&Tls13CipherSuite { From ebb236f23dea431363073f0cecc62fbf47a77781 Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Wed, 5 Aug 2026 19:43:58 +0800 Subject: [PATCH 2/5] fix: rustfmt and enable AES-CCM openssl validation Format CCM AEAD code and remove should_panic from CCM/CCM-8 cipher suite interop tests now that AES-CCM is supported. --- src/aead/ccm.rs | 2 +- validation/local_ping_pong_openssl/src/lib.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/aead/ccm.rs b/src/aead/ccm.rs index faa8072..3c7dac4 100644 --- a/src/aead/ccm.rs +++ b/src/aead/ccm.rs @@ -6,8 +6,8 @@ use super::{DecryptBufferAdapter, EncryptBufferAdapter}; use aead::AeadInOut; use aes::{Aes128, Aes256}; use ccm::{ + consts::{U12, U16, U8}, Ccm, - consts::{U8, U12, U16}, }; use crypto_common::{KeyInit, KeySizeUser}; use paste::paste; diff --git a/validation/local_ping_pong_openssl/src/lib.rs b/validation/local_ping_pong_openssl/src/lib.rs index 14da95c..5222ea6 100644 --- a/validation/local_ping_pong_openssl/src/lib.rs +++ b/validation/local_ping_pong_openssl/src/lib.rs @@ -74,7 +74,6 @@ mod test { } #[test] - #[should_panic] // no_shared_cipher fn vs_openssl_as_client_ccm_sha256() { let cipher_suites = OpenSslCipherSuites { TLS_AES_128_GCM_SHA256: false, @@ -87,7 +86,6 @@ mod test { } #[test] - #[should_panic] // no_shared_cipher fn vs_openssl_as_client_ccm8_sha256() { let cipher_suites = OpenSslCipherSuites { TLS_AES_128_GCM_SHA256: false, From f402f4258e34196f6acc83cb0ec341008fbb2d57 Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Wed, 5 Aug 2026 19:44:37 +0800 Subject: [PATCH 3/5] fix: keep CCM-8 openssl test as should_panic AES-128-CCM interop works; CCM-8 still fails with no shared cipher against the local OpenSSL harness, so leave that expectation in place. --- validation/local_ping_pong_openssl/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/validation/local_ping_pong_openssl/src/lib.rs b/validation/local_ping_pong_openssl/src/lib.rs index 5222ea6..ae7b285 100644 --- a/validation/local_ping_pong_openssl/src/lib.rs +++ b/validation/local_ping_pong_openssl/src/lib.rs @@ -86,6 +86,7 @@ mod test { } #[test] + #[should_panic] // OpenSSL/rustls still do not negotiate TLS_AES_128_CCM_8_SHA256 here fn vs_openssl_as_client_ccm8_sha256() { let cipher_suites = OpenSslCipherSuites { TLS_AES_128_GCM_SHA256: false, From 7d6e903d88370712b16b0eaa75d9792554cbedd5 Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Wed, 5 Aug 2026 19:46:50 +0800 Subject: [PATCH 4/5] fix: expect AES-128-CCM-8 openssl interop to succeed CI OpenSSL negotiates TLS_AES_128_CCM_8_SHA256 successfully, so the should_panic expectation was wrong. --- validation/local_ping_pong_openssl/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/validation/local_ping_pong_openssl/src/lib.rs b/validation/local_ping_pong_openssl/src/lib.rs index ae7b285..5222ea6 100644 --- a/validation/local_ping_pong_openssl/src/lib.rs +++ b/validation/local_ping_pong_openssl/src/lib.rs @@ -86,7 +86,6 @@ mod test { } #[test] - #[should_panic] // OpenSSL/rustls still do not negotiate TLS_AES_128_CCM_8_SHA256 here fn vs_openssl_as_client_ccm8_sha256() { let cipher_suites = OpenSslCipherSuites { TLS_AES_128_GCM_SHA256: false, From dde90cf649008296c8711a1f3a47b31cad097ed1 Mon Sep 17 00:00:00 2001 From: Steve Fan <29133953+stevefan1999-personal@users.noreply.github.com> Date: Wed, 5 Aug 2026 21:04:54 +0800 Subject: [PATCH 5/5] chore(deps): bump to latest prerelease/stable crates --- Cargo.lock | 59 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4092ca8..0b0494f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" +checksum = "f8eb277bec05f56a0e0591f155a484cbd0f4f07ff2905051a48c72f004f7ed58" dependencies = [ "cipher", "cpubits", @@ -66,9 +66,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.67" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" dependencies = [ "find-msvc-tools", "shlex", @@ -232,7 +232,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -405,9 +405,9 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" dependencies = [ "subtle", "typenum", @@ -425,9 +425,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.186" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "log" @@ -560,18 +560,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -642,9 +642,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.42" +version = "0.23.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "log", "once_cell", @@ -656,9 +656,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "zeroize", ] @@ -725,31 +725,31 @@ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", ] [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.3", ] [[package]] @@ -816,6 +816,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "typenum" version = "1.20.1"