1#![expect(missing_docs)]
2
3use alloc::borrow::Cow;
4use alloc::vec::Vec;
5
6use crate::crypto::cipher::Payload;
7use crate::error::InvalidMessage;
8use crate::msgs::{Codec, ListLength, NonEmpty, Reader, SizedPayload, TlsListElement};
9
10#[non_exhaustive]
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum ApplicationProtocol<'a> {
13 AcmeTls1,
14 DoT,
15 DoQ,
16 Ftp,
17 Http09,
18 Http10,
19 Http11,
20 Http2,
21 Http3,
22 Imap,
23 Mqtt,
24 Pop3,
25 Postgresql,
26 WebRtc,
27 Other(Cow<'a, [u8]>),
28}
29
30impl<'a> ApplicationProtocol<'a> {
31 fn new(data: Cow<'a, [u8]>) -> Self {
32 match data.as_ref() {
33 b"acme-tls/1" => Self::AcmeTls1,
34 b"dot" => Self::DoT,
35 b"doq" => Self::DoQ,
36 b"ftp" => Self::Ftp,
37 b"http/0.9" => Self::Http09,
38 b"http/1.0" => Self::Http10,
39 b"http/1.1" => Self::Http11,
40 b"h2" => Self::Http2,
41 b"h3" => Self::Http3,
42 b"imap" => Self::Imap,
43 b"mqtt" => Self::Mqtt,
44 b"pop3" => Self::Pop3,
45 b"postgresql" => Self::Postgresql,
46 b"webrtc" => Self::WebRtc,
47 _r => Self::Other(data),
48 }
49 }
50
51 pub fn to_owned(&self) -> ApplicationProtocol<'static> {
52 match self {
53 Self::AcmeTls1 => ApplicationProtocol::AcmeTls1,
54 Self::DoT => ApplicationProtocol::DoT,
55 Self::DoQ => ApplicationProtocol::DoQ,
56 Self::Ftp => ApplicationProtocol::Ftp,
57 Self::Http09 => ApplicationProtocol::Http09,
58 Self::Http10 => ApplicationProtocol::Http10,
59 Self::Http11 => ApplicationProtocol::Http11,
60 Self::Http2 => ApplicationProtocol::Http2,
61 Self::Http3 => ApplicationProtocol::Http3,
62 Self::Imap => ApplicationProtocol::Imap,
63 Self::Mqtt => ApplicationProtocol::Mqtt,
64 Self::Pop3 => ApplicationProtocol::Pop3,
65 Self::Postgresql => ApplicationProtocol::Postgresql,
66 Self::WebRtc => ApplicationProtocol::WebRtc,
67 Self::Other(data) => ApplicationProtocol::Other(Cow::Owned(data.to_vec())),
68 }
69 }
70}
71
72impl<'a> Codec<'a> for ApplicationProtocol<'a> {
73 fn encode(&self, bytes: &mut Vec<u8>) {
74 SizedPayload::<u8, NonEmpty>::from(Payload::Borrowed(self.as_ref())).encode(bytes);
75 }
76
77 fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> {
78 match SizedPayload::<u8, NonEmpty>::read(r)?.inner {
79 Payload::Borrowed(data) => Ok(Self::new(Cow::Borrowed(data))),
80 Payload::Owned(data) => Ok(Self::new(Cow::Owned(data))),
81 }
82 }
83}
84
85impl TlsListElement for ApplicationProtocol<'_> {
87 const SIZE_LEN: ListLength = ListLength::NonZeroU16 {
88 empty_error: InvalidMessage::IllegalEmptyList("ProtocolNames"),
89 };
90}
91
92impl From<Vec<u8>> for ApplicationProtocol<'static> {
93 fn from(data: Vec<u8>) -> Self {
94 Self::new(Cow::Owned(data))
95 }
96}
97
98impl<'a, const N: usize> From<&'a [u8; N]> for ApplicationProtocol<'a> {
99 fn from(data: &'a [u8; N]) -> Self {
100 ApplicationProtocol::from(&data[..])
101 }
102}
103
104impl<'a> From<&'a [u8]> for ApplicationProtocol<'a> {
105 fn from(data: &'a [u8]) -> Self {
106 Self::new(Cow::Borrowed(data))
107 }
108}
109
110impl AsRef<[u8]> for ApplicationProtocol<'_> {
111 fn as_ref(&self) -> &[u8] {
112 match self {
113 Self::AcmeTls1 => b"acme-tls/1",
114 Self::DoT => b"dot",
115 Self::DoQ => b"doq",
116 Self::Ftp => b"ftp",
117 Self::Http09 => b"http/0.9",
118 Self::Http10 => b"http/1.0",
119 Self::Http11 => b"http/1.1",
120 Self::Http2 => b"h2",
121 Self::Http3 => b"h3",
122 Self::Imap => b"imap",
123 Self::Mqtt => b"mqtt",
124 Self::Pop3 => b"pop3",
125 Self::Postgresql => b"postgresql",
126 Self::WebRtc => b"webrtc",
127 Self::Other(data) => data.as_ref(),
128 }
129 }
130}
131
132enum_builder! {
133 #[repr(u8)]
137 pub enum HandshakeType {
138 HelloRequest => 0x00,
139 ClientHello => 0x01,
140 ServerHello => 0x02,
141 HelloVerifyRequest => 0x03,
142 NewSessionTicket => 0x04,
143 EndOfEarlyData => 0x05,
144 HelloRetryRequest => 0x06,
145 EncryptedExtensions => 0x08,
146 Certificate => 0x0b,
147 ServerKeyExchange => 0x0c,
148 CertificateRequest => 0x0d,
149 ServerHelloDone => 0x0e,
150 CertificateVerify => 0x0f,
151 ClientKeyExchange => 0x10,
152 Finished => 0x14,
153 CertificateURL => 0x15,
154 CertificateStatus => 0x16,
155 KeyUpdate => 0x18,
156 CompressedCertificate => 0x19,
157 MessageHash => 0xfe,
158 }
159}
160
161enum_builder! {
162 #[repr(u8)]
166 pub enum ContentType {
167 ChangeCipherSpec => 0x14,
168 Alert => 0x15,
169 Handshake => 0x16,
170 ApplicationData => 0x17,
171 Heartbeat => 0x18,
172 }
173}
174
175enum_builder! {
176 #[repr(u16)]
180 pub enum ProtocolVersion {
181 SSLv2 => 0x0002,
182 SSLv3 => 0x0300,
183 TLSv1_0 => 0x0301,
184 TLSv1_1 => 0x0302,
185 TLSv1_2 => 0x0303,
186 TLSv1_3 => 0x0304,
187 DTLSv1_0 => 0xFEFF,
188 DTLSv1_2 => 0xFEFD,
189 DTLSv1_3 => 0xFEFC,
190 }
191}
192
193enum_builder! {
194 #[repr(u16)]
199 pub enum CertificateCompressionAlgorithm {
200 Zlib => 1,
201 Brotli => 2,
202 Zstd => 3,
203 }
204}
205
206enum_builder! {
207 #[repr(u8)]
213 #[derive(Default)]
214 pub enum CertificateType {
215 #[default]
216 X509 => 0x00,
217 RawPublicKey => 0x02,
218 }
219}
220
221enum_builder! {
222 #[repr(u8)]
228 pub enum EchClientHelloType {
229 ClientHelloOuter => 0,
230 ClientHelloInner => 1
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237 use crate::msgs::{test_enum8, test_enum16};
238
239 #[test]
240 fn test_enums() {
241 test_enum8::<ContentType>(ContentType::ChangeCipherSpec, ContentType::Heartbeat);
242 test_enum8::<HandshakeType>(HandshakeType::HelloRequest, HandshakeType::MessageHash);
243 test_enum16::<CertificateCompressionAlgorithm>(
244 CertificateCompressionAlgorithm::Zlib,
245 CertificateCompressionAlgorithm::Zstd,
246 );
247 test_enum8::<CertificateType>(CertificateType::X509, CertificateType::RawPublicKey);
248 }
249}