aranya_crypto/tls/
suite.rs1use core::fmt;
2
3use serde::{Deserialize, Serialize};
4use zerocopy::{Immutable, IntoBytes, KnownLayout};
5
6#[repr(u16)]
8#[derive(
9 Copy,
10 Clone,
11 Debug,
12 Eq,
13 PartialEq,
14 Hash,
15 Immutable,
16 IntoBytes,
17 KnownLayout,
18 Serialize,
19 Deserialize,
20)]
21#[non_exhaustive]
22pub(crate) enum Version {
23 Tls13 = u16::to_be(0x0304),
24}
25
26#[repr(u16)]
28#[derive(
29 Copy,
30 Clone,
31 Debug,
32 Eq,
33 PartialEq,
34 Hash,
35 Immutable,
36 IntoBytes,
37 KnownLayout,
38 Serialize,
39 Deserialize,
40)]
41#[non_exhaustive]
42pub enum CipherSuiteId {
43 #[serde(rename = "TLS_AES_128_GCM_SHA256")]
45 TlsAes128GcmSha256 = u16::to_be(0x1301),
46 #[serde(rename = "TLS_AES_256_GCM_SHA384")]
48 TlsAes256GcmSha384 = u16::to_be(0x1302),
49 #[serde(rename = "TLS_CHACHA20_POLY1305_SHA256")]
51 TlsChaCha20Poly1305Sha256 = u16::to_be(0x1303),
52 #[serde(rename = "TLS_AES_128_CCM_SHA256")]
54 TlsAes128CcmSha256 = u16::to_be(0x1304),
55 #[serde(rename = "TLS_AES_128_CCM_8_SHA256")]
57 TlsAes128Ccm8Sha256 = u16::to_be(0x1305),
58}
59
60impl CipherSuiteId {
61 pub const fn all() -> &'static [Self] {
63 use CipherSuiteId::*;
64 &[
65 TlsAes128GcmSha256,
66 TlsAes256GcmSha384,
67 TlsChaCha20Poly1305Sha256,
68 TlsAes128CcmSha256,
69 TlsAes128Ccm8Sha256,
70 ]
71 }
72
73 pub const fn to_bytes(self) -> [u8; 2] {
76 zerocopy::transmute!(self)
77 }
78
79 pub const fn try_from_bytes(bytes: [u8; 2]) -> Option<Self> {
84 use CipherSuiteId::*;
85 let id = match u16::from_be_bytes(bytes) {
86 0x1301 => TlsAes128GcmSha256,
87 0x1302 => TlsAes256GcmSha384,
88 0x1303 => TlsChaCha20Poly1305Sha256,
89 0x1304 => TlsAes128CcmSha256,
90 0x1305 => TlsAes128Ccm8Sha256,
91 _ => return None,
92 };
93 Some(id)
94 }
95}
96
97impl fmt::Display for CipherSuiteId {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 use CipherSuiteId::*;
100 let name = match self {
101 TlsAes128GcmSha256 => "TLS_AES_128_GCM_SHA256",
102 TlsAes256GcmSha384 => "TLS_AES_256_GCM_SHA384",
103 TlsChaCha20Poly1305Sha256 => "TLS_CHACHA20_POLY1305_SHA256",
104 TlsAes128CcmSha256 => "TLS_AES_128_CCM_SHA256",
105 TlsAes128Ccm8Sha256 => "TLS_AES_128_CCM_8_SHA256",
106 };
107 name.fmt(f)
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn test_cipher_suite_id() {
117 use CipherSuiteId::*;
118 let tests = [
119 ([0x13, 0x01], Some(TlsAes128GcmSha256)),
120 ([0x13, 0x02], Some(TlsAes256GcmSha384)),
121 ([0x13, 0x03], Some(TlsChaCha20Poly1305Sha256)),
122 ([0x13, 0x04], Some(TlsAes128CcmSha256)),
123 ([0x13, 0x05], Some(TlsAes128Ccm8Sha256)),
124 ([0x13, 0x00], None),
125 ([0x13, 0x06], None),
126 ];
127 for (idx, (bytes, suite)) in tests.into_iter().enumerate() {
128 let got = CipherSuiteId::try_from_bytes(bytes);
129 assert_eq!(got, suite, "#{idx}");
130
131 let Some(suite) = suite else {
132 continue;
133 };
134
135 assert_eq!(suite.to_bytes(), bytes, "#{idx}");
136
137 let got = suite.as_bytes();
140 let want = suite.to_bytes();
141 assert_eq!(got, want, "#{idx}");
142 }
143 }
144
145 #[test]
146 fn test_cipher_suite_round_trip() {
147 for &suite in CipherSuiteId::all() {
148 let got = CipherSuiteId::try_from_bytes(suite.to_bytes());
149 assert_eq!(got, Some(suite), "{suite}");
150 }
151 }
152}