1use alloc::boxed::Box;
10use alloc::vec::Vec;
11use core::time::Duration;
12
13use crate::rng::OsRng;
14
15use super::config::Config;
16use super::error::Error;
17use super::version::ProtocolVersion;
18
19#[derive(Copy, Clone, PartialEq, Eq, Debug)]
21pub enum HandshakeStatus {
22 Complete,
24 WantRead,
27 WantWrite,
30}
31
32pub struct Connection {
39 inner: Engine,
40 pending_dtls: alloc::collections::VecDeque<Vec<u8>>,
44}
45
46#[allow(clippy::large_enum_variant)]
47enum Engine {
48 ClientTls13(Box<super::conn::ClientConnection>),
50 ClientTls12(Box<super::conn::ClientConnection12>),
52 ServerTls13(Box<super::conn::ServerConnection<OsRng>>),
54 ServerTls12(Box<super::conn::ServerConnection12<OsRng>>),
56 ClientDtls13(Box<crate::dtls::DtlsClientConnection13>),
58 ClientDtls12(Box<crate::dtls::DtlsClientConnection12>),
60 ServerDtls13(Box<crate::dtls::DtlsServerConnection13<OsRng>>),
62 ServerDtls12(Box<crate::dtls::DtlsServerConnection12<OsRng>>),
64}
65
66impl Connection {
67 pub fn client(config: &Config) -> Result<Self, Error> {
69 config.check_versions()?;
70 let inner = match config.max_version {
71 ProtocolVersion::TLSv1_3 => Engine::ClientTls13(Box::new(build_tls13_client(config)?)),
72 ProtocolVersion::TLSv1_2 => Engine::ClientTls12(Box::new(build_tls12_client(config)?)),
73 #[cfg(feature = "tls-legacy")]
76 ProtocolVersion::TLSv1_1 | ProtocolVersion::TLSv1_0 | ProtocolVersion::SSLv3 => {
77 Engine::ClientTls12(Box::new(build_tls12_client(config)?))
78 }
79 ProtocolVersion::DTLSv1_3 => {
80 Engine::ClientDtls13(Box::new(build_dtls13_client(config)?))
81 }
82 ProtocolVersion::DTLSv1_2 => {
83 Engine::ClientDtls12(Box::new(build_dtls12_client(config)?))
84 }
85 _ => return Err(Error::UnsupportedVersion),
86 };
87 Ok(Connection {
88 inner,
89 pending_dtls: alloc::collections::VecDeque::new(),
90 })
91 }
92
93 pub fn server(config: &Config) -> Result<Self, Error> {
96 config.check_versions()?;
97 if config.identity.is_none() {
98 return Err(Error::InappropriateState);
99 }
100 let inner = match config.max_version {
101 ProtocolVersion::TLSv1_3 => Engine::ServerTls13(Box::new(build_tls13_server(config)?)),
102 ProtocolVersion::TLSv1_2 => Engine::ServerTls12(Box::new(build_tls12_server(config)?)),
103 #[cfg(feature = "tls-legacy")]
104 ProtocolVersion::TLSv1_1 | ProtocolVersion::TLSv1_0 | ProtocolVersion::SSLv3 => {
105 Engine::ServerTls12(Box::new(build_tls12_server(config)?))
106 }
107 ProtocolVersion::DTLSv1_3 => {
108 Engine::ServerDtls13(Box::new(build_dtls13_server(config)?))
109 }
110 ProtocolVersion::DTLSv1_2 => {
111 Engine::ServerDtls12(Box::new(build_dtls12_server(config)?))
112 }
113 _ => return Err(Error::UnsupportedVersion),
114 };
115 Ok(Connection {
116 inner,
117 pending_dtls: alloc::collections::VecDeque::new(),
118 })
119 }
120
121 pub fn handshake(&mut self) -> Result<HandshakeStatus, Error> {
123 if self.is_handshake_complete() {
124 return Ok(HandshakeStatus::Complete);
125 }
126 self.refill_dtls_pending();
128 if self.wants_write() {
129 Ok(HandshakeStatus::WantWrite)
130 } else {
131 Ok(HandshakeStatus::WantRead)
132 }
133 }
134
135 pub fn feed(&mut self, wire_in: &[u8]) -> Result<usize, Error> {
138 match &mut self.inner {
139 Engine::ClientTls13(c) => {
140 c.read_tls(wire_in);
141 c.process_new_packets()?;
142 }
143 Engine::ClientTls12(c) => {
144 c.read_tls(wire_in);
145 c.process_new_packets()?;
146 }
147 Engine::ServerTls13(c) => {
148 c.read_tls(wire_in);
149 c.process_new_packets()?;
150 }
151 Engine::ServerTls12(c) => {
152 c.read_tls(wire_in);
153 c.process_new_packets()?;
154 }
155 Engine::ClientDtls12(c) => c.feed_datagram(wire_in)?,
156 Engine::ClientDtls13(c) => c.feed_datagram(wire_in)?,
157 Engine::ServerDtls12(c) => c.feed_datagram(wire_in)?,
158 Engine::ServerDtls13(c) => c.feed_datagram(wire_in)?,
159 }
160 self.refill_dtls_pending();
162 Ok(wire_in.len())
163 }
164
165 pub fn pop(&mut self) -> Result<Vec<u8>, Error> {
168 let bytes: Vec<u8> = match &mut self.inner {
169 Engine::ClientTls13(c) => c.write_tls(),
170 Engine::ClientTls12(c) => c.write_tls(),
171 Engine::ServerTls13(c) => c.write_tls(),
172 Engine::ServerTls12(c) => c.write_tls(),
173 _ => {
174 if self.pending_dtls.is_empty() {
176 let drained = match &mut self.inner {
177 Engine::ClientDtls12(c) => c.pop_outbound_datagrams(),
178 Engine::ClientDtls13(c) => c.pop_outbound_datagrams(),
179 Engine::ServerDtls12(c) => c.pop_outbound_datagrams(),
180 Engine::ServerDtls13(c) => c.pop_outbound_datagrams(),
181 _ => Vec::new(),
182 };
183 for dg in drained {
184 self.pending_dtls.push_back(dg);
185 }
186 }
187 self.pending_dtls.pop_front().unwrap_or_default()
188 }
189 };
190 Ok(bytes)
191 }
192
193 pub fn send(&mut self, app: &[u8]) -> Result<(), Error> {
195 match &mut self.inner {
196 Engine::ClientTls13(c) => c.send_application_data(app),
197 Engine::ClientTls12(c) => c.send_application_data(app),
198 Engine::ServerTls13(c) => c.send_application_data(app),
199 Engine::ServerTls12(c) => c.send_application_data(app),
200 Engine::ClientDtls12(c) => c.send(app),
201 Engine::ClientDtls13(c) => c.send(app),
202 Engine::ServerDtls12(c) => c.send(app),
203 Engine::ServerDtls13(c) => c.send(app),
204 }
205 }
206
207 pub fn recv(&mut self) -> Result<Vec<u8>, Error> {
209 Ok(match &mut self.inner {
210 Engine::ClientTls13(c) => c.take_received_plaintext(),
211 Engine::ClientTls12(c) => c.take_received_plaintext(),
212 Engine::ServerTls13(c) => c.take_received_plaintext(),
213 Engine::ServerTls12(c) => c.take_received_plaintext(),
214 Engine::ClientDtls12(c) => c.take_received(),
215 Engine::ClientDtls13(c) => c.take_received(),
216 Engine::ServerDtls12(c) => c.take_received(),
217 Engine::ServerDtls13(c) => c.take_received(),
218 })
219 }
220
221 pub fn close(&mut self) -> Result<(), Error> {
224 match &mut self.inner {
225 Engine::ClientTls13(c) => c.send_close_notify(),
226 Engine::ClientTls12(c) => c.send_close_notify(),
227 Engine::ServerTls13(c) => c.send_close_notify(),
228 Engine::ServerTls12(c) => c.send_close_notify(),
229 _ => {}
232 }
233 Ok(())
234 }
235
236 pub fn is_handshake_complete(&self) -> bool {
238 match &self.inner {
239 Engine::ClientTls13(c) => !c.is_handshaking(),
240 Engine::ClientTls12(c) => !c.is_handshaking(),
241 Engine::ServerTls13(c) => !c.is_handshaking(),
242 Engine::ServerTls12(c) => !c.is_handshaking(),
243 Engine::ClientDtls12(c) => c.is_handshake_complete(),
244 Engine::ClientDtls13(c) => c.is_handshake_complete(),
245 Engine::ServerDtls12(c) => c.is_handshake_complete(),
246 Engine::ServerDtls13(c) => c.is_handshake_complete(),
247 }
248 }
249
250 pub fn negotiated_version(&self) -> Option<ProtocolVersion> {
253 match &self.inner {
254 Engine::ClientTls13(_) | Engine::ServerTls13(_) => Some(ProtocolVersion::TLSv1_3),
255 Engine::ClientTls12(c) => c.negotiated_protocol_version(),
258 Engine::ServerTls12(c) => c.negotiated_protocol_version(),
259 Engine::ClientDtls12(_) | Engine::ServerDtls12(_) => Some(ProtocolVersion::DTLSv1_2),
260 Engine::ClientDtls13(_) | Engine::ServerDtls13(_) => Some(ProtocolVersion::DTLSv1_3),
261 }
262 }
263
264 pub fn negotiated_cipher_suite(&self) -> Option<u16> {
269 match &self.inner {
270 Engine::ClientTls13(c) => c.negotiated_cipher_suite(),
271 Engine::ClientTls12(c) => c.negotiated_cipher_suite(),
272 Engine::ServerTls13(c) => {
273 c.negotiated_cipher_suite()
277 }
278 Engine::ServerTls12(c) => c.negotiated_cipher_suite(),
279 Engine::ClientDtls13(c) => c.negotiated_cipher_suite(),
280 Engine::ServerDtls13(c) => c.negotiated_cipher_suite(),
281 Engine::ClientDtls12(c) => c.negotiated_cipher_suite(),
282 Engine::ServerDtls12(c) => c.negotiated_cipher_suite(),
283 }
284 }
285
286 pub fn negotiated_cipher_suite_name(&self) -> Option<&'static str> {
291 self.negotiated_cipher_suite().map(cipher_suite_name)
292 }
293
294 pub fn alpn_selected(&self) -> Option<&[u8]> {
296 match &self.inner {
297 Engine::ClientTls13(c) => c.alpn_protocol(),
298 Engine::ClientTls12(c) => c.alpn_protocol(),
299 Engine::ServerTls13(c) => c.alpn_protocol(),
300 Engine::ServerTls12(c) => c.alpn_protocol(),
301 Engine::ClientDtls13(c) => c.alpn_protocol(),
302 _ => None,
303 }
304 }
305
306 pub fn peer_server_name(&self) -> Option<&str> {
311 match &self.inner {
312 Engine::ServerTls13(c) => c.peer_server_name(),
313 Engine::ServerTls12(c) => c.peer_server_name(),
314 _ => None,
315 }
316 }
317
318 pub fn peer_certificates(&self) -> &[Vec<u8>] {
320 match &self.inner {
321 Engine::ClientTls13(c) => c.peer_certificates(),
322 Engine::ClientTls12(c) => c.peer_certificates(),
323 Engine::ServerTls13(c) => c.peer_certificates(),
324 Engine::ServerTls12(c) => c.peer_certificates(),
325 Engine::ClientDtls13(c) => c.peer_certificates(),
326 _ => &[],
327 }
328 }
329
330 pub fn next_timeout(&self) -> Option<Duration> {
332 match &self.inner {
333 Engine::ClientDtls12(c) => c.next_timeout(),
334 Engine::ClientDtls13(c) => c.next_timeout(),
335 Engine::ServerDtls12(c) => c.next_timeout(),
336 Engine::ServerDtls13(c) => c.next_timeout(),
337 _ => None,
338 }
339 }
340
341 pub fn on_timeout(&mut self, now: Duration) {
344 match &mut self.inner {
345 Engine::ClientDtls12(c) => c.on_timeout(now),
346 Engine::ClientDtls13(c) => c.on_timeout(now),
347 Engine::ServerDtls12(c) => c.on_timeout(now),
348 Engine::ServerDtls13(c) => c.on_timeout(now),
349 _ => {}
350 }
351 }
352
353 fn wants_write(&self) -> bool {
354 match &self.inner {
355 Engine::ClientTls13(c) => c.wants_write(),
356 Engine::ClientTls12(c) => c.wants_write(),
357 Engine::ServerTls13(c) => c.wants_write(),
358 Engine::ServerTls12(c) => c.wants_write(),
359 _ => !self.pending_dtls.is_empty(),
361 }
362 }
363
364 fn refill_dtls_pending(&mut self) {
367 let drained: Vec<Vec<u8>> = match &mut self.inner {
368 Engine::ClientDtls12(c) => c.pop_outbound_datagrams(),
369 Engine::ClientDtls13(c) => c.pop_outbound_datagrams(),
370 Engine::ServerDtls12(c) => c.pop_outbound_datagrams(),
371 Engine::ServerDtls13(c) => c.pop_outbound_datagrams(),
372 _ => return,
373 };
374 for dg in drained {
375 self.pending_dtls.push_back(dg);
376 }
377 }
378}
379
380fn cipher_suite_name(id: u16) -> &'static str {
384 match id {
385 0x1301 => "TLS_AES_128_GCM_SHA256",
386 0x1302 => "TLS_AES_256_GCM_SHA384",
387 0x1303 => "TLS_CHACHA20_POLY1305_SHA256",
388 0xC02B => "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
389 0xC02C => "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
390 0xC02F => "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
391 0xC030 => "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
392 0xCCA8 => "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
393 0xCCA9 => "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
394 0x000A => "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
396 0x002F => "TLS_RSA_WITH_AES_128_CBC_SHA",
397 0x0035 => "TLS_RSA_WITH_AES_256_CBC_SHA",
398 0x003C => "TLS_RSA_WITH_AES_128_CBC_SHA256",
399 0x003D => "TLS_RSA_WITH_AES_256_CBC_SHA256",
400 0xC012 => "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
401 0xC013 => "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
402 0xC014 => "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
403 0xC027 => "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
404 0xC028 => "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA256",
405 _ => "UNKNOWN",
406 }
407}
408
409fn client_server_name(cfg: &Config) -> Result<&str, Error> {
418 match cfg.server_name.as_deref() {
419 Some(name) => Ok(name),
420 None if !cfg.verify_certificates => Ok(""),
421 None => Err(Error::MissingServerName),
422 }
423}
424
425fn build_tls13_client(cfg: &Config) -> Result<super::conn::ClientConnection, Error> {
426 let mut cc = super::conn::ClientConfig::new(cfg.roots.clone_store());
427 cc.verify_certificates = cfg.verify_certificates;
428 cc.cipher_suites = cfg.cipher_suites.clone();
429 if !cfg.alpn_protocols.is_empty() {
430 cc = cc.with_alpn(cfg.alpn_protocols.clone());
431 }
432 if !cfg.crls.is_empty() {
433 cc = cc.with_crls(cfg.crls.clone_store());
434 }
435 if let Some(t) = cfg.verification_time.clone() {
436 cc.verification_time = Some(t);
437 }
438 if let Some(rsl) = cfg.record_size_limit {
439 cc = cc.with_record_size_limit(rsl);
440 }
441 cc = cc.with_signature_policy(cfg.signature_policy.clone());
442 if let Some(id) = &cfg.identity {
443 let cc_cfg = client_cert_from_signing(id);
444 if let Some(c) = cc_cfg {
445 cc = cc.with_client_cert(c);
446 }
447 }
448 cc = cc.with_server_cert_type_preference(cfg.server_cert_type_preference.clone());
449 cc = cc.with_client_cert_type_preference(cfg.client_cert_type_preference.clone());
450 for spki in &cfg.expected_raw_public_keys {
451 cc = cc.add_expected_raw_public_key(spki.clone());
452 }
453 cc.key_log = cfg.key_log.clone();
454 #[cfg(feature = "ech")]
455 {
456 cc.ech = cfg.ech.clone();
457 }
458 #[cfg(feature = "cert-compression")]
459 {
460 cc = cc.with_cert_compression_algorithms(cfg.cert_compression_algorithms.clone());
461 }
462 let server_name = client_server_name(cfg)?;
463 Ok(super::conn::ClientConnection::new(
464 cc,
465 server_name,
466 &mut OsRng,
467 ))
468}
469
470fn build_tls12_client(cfg: &Config) -> Result<super::conn::ClientConnection12, Error> {
471 let mut cc = super::conn::ClientConfig12::new(cfg.roots.clone_store());
472 cc.verify_certificates = cfg.verify_certificates;
473 cc.cipher_suites = cfg.cipher_suites.clone();
474 if !cfg.alpn_protocols.is_empty() {
475 cc = cc.with_alpn(cfg.alpn_protocols.clone());
476 }
477 if !cfg.crls.is_empty() {
478 cc = cc.with_crls(cfg.crls.clone_store());
479 }
480 if let Some(t) = cfg.verification_time.clone() {
481 cc = cc.with_verification_time(t);
482 }
483 if let Some(rsl) = cfg.record_size_limit {
484 cc = cc.with_record_size_limit(rsl);
485 }
486 cc = cc.with_signature_policy(cfg.signature_policy.clone());
487 if let Some(id) = &cfg.identity {
488 let cc_cfg = client_cert_from_signing(id);
489 if let Some(c) = cc_cfg {
490 cc = cc.with_client_cert(c);
491 }
492 }
493 cc.key_log = cfg.key_log.clone();
494 #[cfg(feature = "tls-legacy")]
495 {
496 cc = cc.with_min_version(cfg.min_version);
497 if cfg.max_version.as_u16() < ProtocolVersion::TLSv1_2.as_u16() {
500 cc = cc.with_max_version(cfg.max_version);
501 }
502 }
503 let server_name = client_server_name(cfg)?;
504 Ok(super::conn::ClientConnection12::new(
505 cc,
506 server_name,
507 &mut OsRng,
508 ))
509}
510
511fn build_tls13_server(cfg: &Config) -> Result<super::conn::ServerConnection<OsRng>, Error> {
512 let id = cfg.identity.as_ref().ok_or(Error::InappropriateState)?;
513 let chain = id.cert_chain.clone();
514 let mut sc = match &id.key {
515 super::config::SigningKey::Rsa(k) => super::conn::ServerConfig::with_rsa(chain, k.clone()),
516 super::config::SigningKey::Ecdsa(k) => {
517 super::conn::ServerConfig::with_ecdsa(chain, k.clone())
518 }
519 super::config::SigningKey::Ed25519(k) => {
520 super::conn::ServerConfig::with_ed25519(chain, k.clone())
521 }
522 super::config::SigningKey::Ed448(k) => {
523 super::conn::ServerConfig::with_ed448(chain, k.clone())
524 }
525 super::config::SigningKey::MlDsa44(k) => {
526 super::conn::ServerConfig::with_mldsa44(chain, k.clone())
527 }
528 super::config::SigningKey::MlDsa65(k) => {
529 super::conn::ServerConfig::with_mldsa65(chain, k.clone())
530 }
531 super::config::SigningKey::MlDsa87(k) => {
532 super::conn::ServerConfig::with_mldsa87(chain, k.clone())
533 }
534 };
535 if !cfg.alpn_protocols.is_empty() {
536 sc = sc.with_alpn(cfg.alpn_protocols.clone());
537 }
538 if !cfg.crls.is_empty() {
539 sc = sc.with_crls(cfg.crls.clone_store());
540 }
541 if let Some(rsl) = cfg.record_size_limit {
542 sc = sc.with_record_size_limit(rsl);
543 }
544 if let Some(ca) = &cfg.client_auth {
545 sc = sc.with_client_auth(ca.roots.clone_store(), ca.required);
546 }
547 if let Some(tk) = cfg.ticket_key {
548 sc = sc.with_ticket_key(tk);
549 }
550 if cfg.max_early_data_size > 0 {
551 sc = sc.with_max_early_data(cfg.max_early_data_size);
552 }
553 #[cfg(feature = "std")]
554 if let Some(rw) = cfg.replay_window.clone() {
555 sc = sc.with_replay_window(rw);
556 }
557 if let Some(crl) = cfg.stapled_crl.clone() {
558 sc = sc.with_stapled_crl(crl);
559 }
560 if let Some(ocsp) = cfg.stapled_ocsp_response.clone() {
561 sc = sc.with_stapled_ocsp_response(ocsp);
562 }
563 sc = sc.with_server_cert_type_preference(cfg.server_cert_type_preference.clone());
564 sc = sc.with_client_cert_type_preference(cfg.client_cert_type_preference.clone());
565 if let Some(spki) = cfg.raw_public_key_spki.clone() {
566 sc = sc.with_raw_public_key_spki(spki);
567 }
568 sc = sc.with_signature_policy(cfg.signature_policy.clone());
569 #[cfg(feature = "cert-compression")]
570 {
571 sc = sc.with_cert_compression_algorithms(cfg.cert_compression_algorithms.clone());
572 }
573 #[cfg(feature = "ech")]
574 if let Some(ech) = cfg.ech_server.clone() {
575 sc = sc.with_ech_server(ech);
576 }
577 if let Some(g) = cfg.preferred_key_exchange_group {
578 sc = sc.with_preferred_key_exchange_group(g);
579 }
580 if let Some(t) = cfg.verification_time.clone() {
581 sc = sc.with_verification_time(t);
582 }
583 sc.key_log = cfg.key_log.clone();
584 Ok(super::conn::ServerConnection::new(sc, OsRng))
585}
586
587fn build_tls12_server(cfg: &Config) -> Result<super::conn::ServerConnection12<OsRng>, Error> {
588 let id = cfg.identity.as_ref().ok_or(Error::InappropriateState)?;
589 let chain = id.cert_chain.clone();
590 let mut sc = id
591 .key
592 .try_into_server_config_12(chain)
593 .ok_or(Error::UnsupportedVersion)?;
594 if !cfg.alpn_protocols.is_empty() {
595 sc = sc.with_alpn(cfg.alpn_protocols.clone());
596 }
597 if !cfg.crls.is_empty() {
598 sc = sc.with_crls(cfg.crls.clone_store());
599 }
600 if let Some(rsl) = cfg.record_size_limit {
601 sc = sc.with_record_size_limit(rsl);
602 }
603 if let Some(ca) = &cfg.client_auth {
604 sc = sc.with_client_auth(ca.roots.clone_store(), ca.required);
605 }
606 if let Some(tk) = cfg.ticket_key {
607 sc = sc.with_ticket_key(tk);
608 }
609 if let Some(ocsp) = cfg.stapled_ocsp_response.clone() {
610 sc = sc.with_stapled_ocsp_response(ocsp);
611 }
612 sc = sc.with_signature_policy(cfg.signature_policy.clone());
613 if let Some(t) = cfg.verification_time.clone() {
614 sc = sc.with_verification_time(t);
615 }
616 sc.key_log = cfg.key_log.clone();
617 #[cfg(feature = "tls-legacy")]
618 {
619 sc = sc.with_min_version(cfg.min_version);
620 }
621 Ok(super::conn::ServerConnection12::new(sc, OsRng))
622}
623
624fn build_dtls12_client(cfg: &Config) -> Result<crate::dtls::DtlsClientConnection12, Error> {
625 let server_name = client_server_name(cfg)?;
626 let mut dc = crate::dtls::ClientConfig12Internal::new(cfg.roots.clone_store(), server_name);
627 if !cfg.verify_certificates {
628 dc = dc.without_certificate_verification();
629 }
630 if !cfg.crls.is_empty() {
631 dc = dc.with_crls(cfg.crls.clone_store());
632 }
633 if let Some(t) = cfg.verification_time.clone() {
634 dc = dc.with_verification_time(t);
635 }
636 dc = dc.with_signature_policy(cfg.signature_policy.clone());
637 dc.key_log = cfg.key_log.clone();
638 Ok(crate::dtls::DtlsClientConnection12::new(
639 dc,
640 Vec::new(),
641 &mut OsRng,
642 ))
643}
644
645fn build_dtls13_client(cfg: &Config) -> Result<crate::dtls::DtlsClientConnection13, Error> {
646 let server_name = client_server_name(cfg)?;
647 let mut dc = crate::dtls::ClientConfig13Internal::new(cfg.roots.clone_store(), server_name);
648 if !cfg.verify_certificates {
649 dc = dc.without_certificate_verification();
650 }
651 if !cfg.crls.is_empty() {
652 dc = dc.with_crls(cfg.crls.clone_store());
653 }
654 if let Some(t) = cfg.verification_time.clone() {
655 dc = dc.with_verification_time(t);
656 }
657 dc = dc.with_signature_policy(alloc::sync::Arc::new(cfg.signature_policy.clone()));
658 dc.max_record_size = cfg.max_record_size;
659 dc.key_log = cfg.key_log.clone();
660 Ok(crate::dtls::DtlsClientConnection13::new(
661 dc,
662 Vec::new(),
663 &mut OsRng,
664 ))
665}
666
667fn build_dtls12_server(cfg: &Config) -> Result<crate::dtls::DtlsServerConnection12<OsRng>, Error> {
668 let id = cfg.identity.as_ref().ok_or(Error::InappropriateState)?;
669 if cfg.require_cookie && cfg.cookie_secret.is_none() {
675 return Err(Error::InappropriateState);
676 }
677 let chain = id.cert_chain.clone();
678 let mut sc = match &id.key {
679 super::config::SigningKey::Ecdsa(k) => {
680 crate::dtls::ServerConfig12Internal::with_ecdsa(chain, k.clone())
681 }
682 super::config::SigningKey::Rsa(k) => {
683 crate::dtls::ServerConfig12Internal::with_rsa(chain, k.clone())
684 }
685 _ => return Err(Error::UnsupportedVersion),
688 };
689 if let Some(secret) = cfg.cookie_secret {
690 sc = sc.with_cookie_secret(secret);
691 }
692 if !cfg.require_cookie {
693 sc = sc.require_cookie_exchange(false);
694 }
695 sc.key_log = cfg.key_log.clone();
696 Ok(crate::dtls::DtlsServerConnection12::new(
697 alloc::sync::Arc::new(sc),
698 Vec::new(),
699 OsRng,
700 ))
701}
702
703fn build_dtls13_server(cfg: &Config) -> Result<crate::dtls::DtlsServerConnection13<OsRng>, Error> {
704 let id = cfg.identity.as_ref().ok_or(Error::InappropriateState)?;
705 if cfg.require_cookie && cfg.cookie_secret.is_none() {
709 return Err(Error::InappropriateState);
710 }
711 let chain = id.cert_chain.clone();
712 let server_key = id.key.to_server_key_13();
713 let mut sc = crate::dtls::ServerConfig13Internal::with_signing_key(chain, server_key);
714 if let Some(secret) = cfg.cookie_secret {
715 sc = sc.with_cookie_secret(secret);
716 }
717 if !cfg.require_cookie {
718 sc = sc.with_no_cookie();
719 }
720 sc.key_log = cfg.key_log.clone();
721 Ok(crate::dtls::DtlsServerConnection13::new(
722 alloc::sync::Arc::new(sc),
723 Vec::new(),
724 OsRng,
725 ))
726}
727
728fn client_cert_from_signing(id: &super::config::Identity) -> Option<super::conn::ClientCertConfig> {
729 Some(match &id.key {
730 super::config::SigningKey::Rsa(k) => {
731 super::conn::ClientCertConfig::with_rsa(id.cert_chain.clone(), k.clone())
732 }
733 super::config::SigningKey::Ecdsa(k) => {
734 super::conn::ClientCertConfig::with_ecdsa(id.cert_chain.clone(), k.clone())
735 }
736 super::config::SigningKey::Ed25519(k) => {
737 super::conn::ClientCertConfig::with_ed25519(id.cert_chain.clone(), k.clone())
738 }
739 super::config::SigningKey::Ed448(k) => {
740 super::conn::ClientCertConfig::with_ed448(id.cert_chain.clone(), k.clone())
741 }
742 super::config::SigningKey::MlDsa44(k) => {
743 super::conn::ClientCertConfig::with_mldsa44(id.cert_chain.clone(), k.clone())
744 }
745 super::config::SigningKey::MlDsa65(k) => {
746 super::conn::ClientCertConfig::with_mldsa65(id.cert_chain.clone(), k.clone())
747 }
748 super::config::SigningKey::MlDsa87(k) => {
749 super::conn::ClientCertConfig::with_mldsa87(id.cert_chain.clone(), k.clone())
750 }
751 })
752}
753
754#[cfg(test)]
755mod tests {
756 use super::*;
757 use crate::ec::{BoxedEcdsaPrivateKey, CurveId};
758 use crate::hash::Sha256;
759 use crate::rng::HmacDrbg;
760 use crate::x509::{CertSigner, Certificate, DistinguishedName, Time, Validity};
761
762 fn dtls_server_cfg_without_cookie_secret(max_version: ProtocolVersion) -> Config {
765 let mut rng = HmacDrbg::<Sha256>::new(b"h3-dtls-cookie", b"nonce", &[]);
766 let key = BoxedEcdsaPrivateKey::generate(CurveId::P256, &mut rng);
767 let name = DistinguishedName::common_name("dtls.example");
768 let validity = Validity::new(
769 Time::utc(2024, 1, 1, 0, 0, 0),
770 Time::utc(2034, 1, 1, 0, 0, 0),
771 );
772 let cert = Certificate::self_signed_general(
773 &CertSigner::Ecdsa(&key),
774 &name,
775 &validity,
776 1,
777 false,
778 &["dtls.example"],
779 )
780 .unwrap();
781 Config::builder()
782 .versions(max_version, max_version)
783 .identity(
784 alloc::vec![cert.to_der().to_vec()],
785 super::super::config::SigningKey::Ecdsa(key),
786 )
787 .build()
788 }
789
790 #[test]
796 fn dtls_server_refuses_construction_without_cookie_secret() {
797 let cfg = dtls_server_cfg_without_cookie_secret(ProtocolVersion::DTLSv1_2);
799 assert!(cfg.require_cookie);
800 assert!(cfg.cookie_secret.is_none());
801 match Connection::server(&cfg) {
802 Err(Error::InappropriateState) => {}
803 Err(e) => panic!("expected InappropriateState, got {e:?}"),
804 Ok(_) => panic!("DTLS 1.2 server must refuse construction"),
805 }
806
807 let cfg = dtls_server_cfg_without_cookie_secret(ProtocolVersion::DTLSv1_3);
809 match Connection::server(&cfg) {
810 Err(Error::InappropriateState) => {}
811 Err(e) => panic!("expected InappropriateState, got {e:?}"),
812 Ok(_) => panic!("DTLS 1.3 server must refuse construction"),
813 }
814
815 let mut cfg = dtls_server_cfg_without_cookie_secret(ProtocolVersion::DTLSv1_3);
817 cfg.cookie_secret = Some([0x42u8; 32]);
818 assert!(Connection::server(&cfg).is_ok());
819
820 let mut cfg = dtls_server_cfg_without_cookie_secret(ProtocolVersion::DTLSv1_3);
822 cfg.require_cookie = false;
823 assert!(Connection::server(&cfg).is_ok());
824 }
825
826 #[test]
836 fn client_server_name_required_only_when_verifying() {
837 for v in [
838 ProtocolVersion::TLSv1_3,
839 ProtocolVersion::TLSv1_2,
840 ProtocolVersion::DTLSv1_3,
841 ProtocolVersion::DTLSv1_2,
842 ] {
843 let cfg = Config::builder().versions(v, v).build();
845 assert!(cfg.verify_certificates && cfg.server_name.is_none());
846 match Connection::client(&cfg) {
847 Err(Error::MissingServerName) => {}
848 Err(e) => panic!("{v:?}: expected MissingServerName, got {e:?}"),
849 Ok(_) => panic!("{v:?}: verifying client must require server_name"),
850 }
851
852 let cfg = Config::builder()
854 .versions(v, v)
855 .verify_certificates(false)
856 .build();
857 assert!(cfg.server_name.is_none());
858 assert!(
859 Connection::client(&cfg).is_ok(),
860 "{v:?}: verify-off client must not require server_name"
861 );
862
863 let cfg = Config::builder()
865 .versions(v, v)
866 .verify_certificates(false)
867 .server_name("example.test")
868 .build();
869 assert!(Connection::client(&cfg).is_ok(), "{v:?}: explicit SNI ok");
870 }
871 }
872
873 #[test]
876 fn cipher_suite_name_table() {
877 assert_eq!(cipher_suite_name(0x1301), "TLS_AES_128_GCM_SHA256");
878 assert_eq!(cipher_suite_name(0x1302), "TLS_AES_256_GCM_SHA384");
879 assert_eq!(cipher_suite_name(0x1303), "TLS_CHACHA20_POLY1305_SHA256");
880 assert_eq!(
881 cipher_suite_name(0xC02B),
882 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
883 );
884 assert_eq!(
885 cipher_suite_name(0xC02C),
886 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
887 );
888 assert_eq!(
889 cipher_suite_name(0xC02F),
890 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
891 );
892 assert_eq!(
893 cipher_suite_name(0xC030),
894 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
895 );
896 assert_eq!(
897 cipher_suite_name(0xCCA8),
898 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
899 );
900 assert_eq!(
901 cipher_suite_name(0xCCA9),
902 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
903 );
904 assert_eq!(cipher_suite_name(0xFFFF), "UNKNOWN");
905 }
906
907 #[test]
912 fn negotiated_cipher_suite_is_none_before_handshake() {
913 let mut rng = HmacDrbg::<Sha256>::new(b"suite-none", b"nonce", &[]);
914 let key = BoxedEcdsaPrivateKey::generate(CurveId::P256, &mut rng);
915 let validity = Validity::new(
916 Time::utc(2024, 1, 1, 0, 0, 0),
917 Time::utc(2034, 1, 1, 0, 0, 0),
918 );
919 let cert = Certificate::self_signed_general(
920 &CertSigner::Ecdsa(&key),
921 &DistinguishedName::common_name("suite.example"),
922 &validity,
923 1,
924 false,
925 &["suite.example"],
926 )
927 .unwrap();
928
929 let cfg = Config::builder()
932 .tls_only()
933 .server_name("suite.example")
934 .build();
935 let client = Connection::client(&cfg).unwrap();
936 assert!(client.negotiated_cipher_suite().is_none());
937 assert!(client.negotiated_cipher_suite_name().is_none());
938
939 let cfg = Config::builder()
941 .tls_only()
942 .identity(
943 alloc::vec![cert.to_der().to_vec()],
944 super::super::config::SigningKey::Ecdsa(key),
945 )
946 .build();
947 let server = Connection::server(&cfg).unwrap();
948 assert!(server.negotiated_cipher_suite().is_none());
949 }
950}