1#![cfg_attr(
35 feature = "dtls-rpk",
36 doc = r##"
37Creating and connecting a client-side session with DTLS RPK configured:
38```no_run
39use libcoap_rs::CoapContext;
40use libcoap_rs::crypto::pki_rpk::{NonCertVerifying, PkiRpkContextBuilder, Rpk, RpkKeyDef};
41use libcoap_rs::session::{CoapClientSession, CoapSession};
42
43// RPK is only supported if the key is provided as a byte array in memory, providing file paths
44// directly is unsupported.
45let client_private_key = Vec::from(include_str!("../../../resources/test-keys/client/client.key.pem"));
46let client_public_key = Vec::from(include_str!("../../../resources/test-keys/client/client.pub.pem"));
47
48// Create key definition.
49let client_key_def = RpkKeyDef::with_pem_memory(client_public_key, client_private_key);
50
51// Create the cryptography context. Note that you might have to explicitly specify that
52// PKI certificate validation should not be performed, even though enabling it while passing a
53// RPK key definition is impossible due to a lack of a constructor for
54// `PkiRpkContextBuilder<Rpk, CertVerifying>`.
55// This is a type system limitation.
56let crypto_ctx = PkiRpkContextBuilder::<_, NonCertVerifying>::new(client_key_def);
57
58let key_validator = |asn1_public_key: &[u8], session: &CoapSession, validated: bool| {
59 if !validated {
60 false
61 } else {
62 // Here, you would add code to validate that the peer's public key is actually the one you
63 // expect, and return either true (accept key) or false (reject key).
64 // `asn1_encoded_key` should be the certificate structure defined in
65 // [RFC 7250, section 3](https://datatracker.ietf.org/doc/html/rfc7250#section-3), which you
66 // might be able to parse with crates like
67 // [x509-cert](https://docs.rs/x509-cert/latest/x509_cert/index.html) and
68 // [spki](https://docs.rs/spki/0.7.3/spki/index.html) to obtain and match the
69 // SubjectPublicKeyInformation encoded within.
70 //
71 // Instead of using a lambda like this, you could also implement `RpkValidator` on any
72 // arbitrary type of your choice, e.g., a structure containing a storage of allowed public
73 // keys.
74 # true
75 }
76};
77
78// Set the RPK validator and build the context.
79let crypto_ctx = crypto_ctx.rpk_validator(key_validator).build();
80
81let mut coap_ctx = CoapContext::new().expect("unable to create CoAP context");
82let session = CoapClientSession::connect_dtls(&mut coap_ctx, "example.com:5684".parse().unwrap(), crypto_ctx);
83
84// The session might not be immediately established, but you can already create and send
85// requests as usual after this point.
86// To check for errors and/or disconnections, you might want to call and check the return value
87// of `session.state()` occasionally.
88// For error handling, you might also want to register an event handler with the CoAP context.
89// Remaining code omitted for brevity, see the crate-level docs for a full example of client
90// operation.
91```
92
93Creating a server that supports DTLS RPK configured:
94```no_run
95use libcoap_rs::CoapContext;
96use libcoap_rs::crypto::pki_rpk::{NonCertVerifying, PkiRpkContextBuilder, Rpk, RpkKeyDef};
97use libcoap_rs::session::{CoapClientSession, CoapSession};
98
99fn key_validator(asn1_public_key: &[u8], session: &CoapSession, validated: bool) -> bool {
100 // Here, you would add code to validate that the peer's public key is actually the one you
101 // expect, and return either true (accept key) or false (reject key).
102 // `asn1_encoded_key` should be the certificate structure defined in
103 // [RFC 7250, section 3](https://datatracker.ietf.org/doc/html/rfc7250#section-3), which you
104 // might be able to parse with crates like
105 // [x509-cert](https://docs.rs/x509-cert/latest/x509_cert/index.html) and
106 // [spki](https://docs.rs/spki/0.7.3/spki/index.html) to obtain and match the
107 // SubjectPublicKeyInformation encoded within.
108 //
109 // Instead of using a function like this, you could also implement `RpkValidator` on any
110 // arbitrary type of your choice, e.g., a structure containing a storage of allowed public
111 // keys.
112 # true
113}
114
115// RPK is only supported if the key is provided as a byte array in memory, providing file paths
116// directly is unsupported.
117let server_private_key = Vec::from(include_str!("../../../resources/test-keys/server/server.key.pem"));
118let server_public_key = Vec::from(include_str!("../../../resources/test-keys/server/server.pub.pem"));
119
120// Create key definition.
121let server_key_def = RpkKeyDef::with_pem_memory(server_public_key, server_private_key);
122
123// Create the cryptography context. Note that you might have to explicitly specify that
124// PKI certificate validation should not be performed, even though enabling it while passing a
125// RPK key definition is impossible due to a lack of a constructor for
126// `PkiRpkContextBuilder<Rpk, CertVerifying>`.
127// This is a type system limitation.
128let crypto_ctx = PkiRpkContextBuilder::<_, NonCertVerifying>::new(server_key_def);
129// Set the RPK validator and build the context.
130let crypto_ctx = crypto_ctx.rpk_validator(key_validator).build();
131
132let mut coap_ctx = CoapContext::new().expect("unable to create CoAP context");
133coap_ctx.set_pki_rpk_context(crypto_ctx);
134coap_ctx.add_endpoint_dtls("[::1]:5684".parse().unwrap()).expect("unable to create DTLS endpoint");
135
136// For error handling, you might want to register an event handler with the CoAP context.
137// Remaining code omitted for brevity, see the crate-level docs for a full example of server
138// operation.
139```
140"##
141)]
142#![cfg_attr(
143 feature = "dtls-pki",
144 doc = r##"
145
146Creating and connecting a client-side session with DTLS PKI configured:
147```no_run
148use std::ffi::{c_uint, CStr};
149use std::net::SocketAddr;
150use libcoap_rs::CoapContext;
151use libcoap_rs::crypto::pki_rpk::{CertVerifying, PkiKeyDef, PkiRpkContextBuilder};
152use libcoap_rs::session::{CoapClientSession, CoapSession};
153use std::ffi::CString;
154
155// Paths to private key and certificate.
156// The certificate may also contain intermediates. However, they might *not* be provided to the
157// peer (i.e., the peer might have to already know all intermediates beforehand in order for
158// validation to succeed).
159let client_private_key = "../../../resources/test-keys/client/client.key.pem";
160let client_public_cert = "../../../resources/test-keys/client/client.crt.pem";
161
162// Create key definition.
163// Note: the first argument (`ca_cert`) is not used to send intermediates and root certificates
164// to the peer (unlike what you might expect if you have experience setting up HTTP servers).
165// It is exclusively used to determine a list of CA names that a server will provide to a client
166// to indicate to it which certificates it should send.
167// For client-side operation, `ca_cert` is not used.
168let client_key_def = PkiKeyDef::with_pem_files(
169 None::<String>,
170 client_public_cert,
171 client_private_key);
172
173// The name of the server we want to connect to.
174let server_name = "example.com";
175
176// Validator function for certificate common names.
177// Typically, this function should have the following behavior:
178// - If !validated, something went wrong during TLS-level certificate checks, so reject.
179// - If depth == 0, we are checking the client certificate, whose common name should equal the
180// server name we want to connect to, return the equality check result.
181// - If depth > 0, we are checking an intermediate or root CA certificate. As we usually trust
182// all CAs in the trust store and validation of those is already performed by the TLS library,
183// always accept.
184let c_server_name = CString::new(server_name).unwrap();
185let cn_validator = |
186 cn: &CStr,
187 asn1_public_cert: &[u8],
188 session: &CoapSession,
189 depth: c_uint,
190 validated: bool| {
191 if !validated {
192 false
193 } else if depth == 0 {
194 cn == c_server_name.as_c_str()
195 } else {
196 true
197 }
198};
199
200// Create the cryptography context. Note that you must explicitly specify whether
201// PKI certificate validation should be performed using the context builder's generics.
202let crypto_ctx = PkiRpkContextBuilder::<_, CertVerifying>::new(client_key_def)
203 // Provide the server with a Server Name Indication (might be required by
204 // some servers to use the right certificate and by mbedTLS for certificate
205 // validation).
206 .client_sni(server_name).unwrap()
207 // Use the CN validator we defined earlier.
208 .cn_validator(cn_validator)
209 // Enable certificate chain validation (in case you have intermediate CAs) and set
210 // verification depth (recommended value here is 3).
211 .cert_chain_validation(3)
212 .build();
213
214let mut coap_ctx = CoapContext::new().expect("unable to create CoAP context");
215let session = CoapClientSession::connect_dtls(
216 &mut coap_ctx,
217 SocketAddr::new(server_name.parse().expect("error in name resolution"), 5684),
218 crypto_ctx);
219
220// The session might not be immediately established, but you can already create and send
221// requests as usual after this point.
222// To check for errors and/or disconnections, you might want to call and check the return value
223// of `session.state()` occasionally.
224// For error handling, you might also want to register an event handler with the CoAP context.
225// Remaining code omitted for brevity, see the crate-level docs for a full example of client
226// operation.
227```
228
229Creating a server that supports DTLS RPK configured:
230```no_run
231use std::ffi::{c_uint, CStr};
232use std::net::SocketAddr;
233use libcoap_rs::CoapContext;
234use libcoap_rs::crypto::pki_rpk::{CertVerifying, PkiKeyDef, PkiRpkContextBuilder, KeyDef, Pki};
235use libcoap_rs::session::{CoapClientSession, CoapSession};
236use std::ffi::CString;
237
238// Paths to private key and certificate.
239// The certificate may also contain intermediates. However, they might *not* be provided to the
240// peer (i.e., the peer might have to already know all intermediates beforehand in order for
241// validation to succeed).
242let server_private_key = "../../../resources/test-keys/server/server.key.pem";
243let server_public_cert = "../../../resources/test-keys/server/server.crt.pem";
244let ca_cert = "../../../resources/test-keys/ca/ca.crt.pem";
245
246// Create key definition.
247// Note: the first argument (`ca_cert`) is not used to send intermediates and root certificates
248// to the peer (unlike what you might expect if you have experience setting up HTTP servers).
249// It is exclusively used to determine a list of CA names that a server will provide to a client
250// to indicate to it which certificates it should send.
251let server_key_def = PkiKeyDef::with_pem_files(Some(ca_cert), server_public_cert, server_private_key);
252
253// The name of the server we use.
254let server_name = "example.com";
255
256// Key provider for Server Name Indications.
257// If the client provides a server name using the Server Name Indication extension, this
258// callback is called to determine the key the server should use instead of the one provided as
259// the default to `PkiRpkContextBuilder::new`.
260// Typically, you would want to maintain a map from potential server names to key definitions,
261// and return either `Some(Box::new(key))` for the appropriate map entry or `None` if the server
262// name is unknown.
263let c_server_name = CString::new(server_name).unwrap();
264let sni_cb = |sni: &CStr| -> Option<Box<dyn KeyDef<KeyType = Pki>>> {
265 (sni == c_server_name.as_c_str()).then_some(Box::new(server_key_def.clone()))
266};
267
268// Just like the client, the server may also have a CN validator defined to determine whether
269// the common name of the client is acceptable. Here, we omit this validator for brevity.
270
271// Create the cryptography context. Note that you must explicitly specify whether
272// PKI certificate validation should be performed using the context builder's generics.
273let crypto_ctx = PkiRpkContextBuilder::<_, CertVerifying>::new(server_key_def.clone())
274 .sni_key_provider(sni_cb)
275 // Enable certificate chain validation (in case you have intermediate CAs) and set
276 // verification depth (recommended value here is 3).
277 .cert_chain_validation(3)
278 .build();
279
280let mut coap_ctx = CoapContext::new().expect("unable to create CoAP context");
281coap_ctx.set_pki_rpk_context(crypto_ctx);
282coap_ctx.add_endpoint_dtls("[::1]:5684".parse().unwrap()).expect("unable to create DTLS endpoint");
283
284// For error handling, you might want to register an event handler with the CoAP context.
285// Remaining code omitted for brevity, see the crate-level docs for a full example of server
286// operation.
287```
288"##
289)]
290
291mod key;
293#[cfg(feature = "dtls-pki")]
295mod pki;
296#[cfg(feature = "dtls-rpk")]
298mod rpk;
299
300use std::{
301 cell::RefCell,
302 ffi::{c_char, c_int, c_uint, c_void, CStr, CString, NulError},
303 fmt::{Debug, Formatter},
304 marker::PhantomData,
305 ptr::NonNull,
306 rc::{Rc, Weak},
307};
308
309pub use key::*;
310use libcoap_sys::{
311 coap_context_set_pki, coap_context_t, coap_dtls_key_t, coap_dtls_pki_t, coap_new_client_session_pki, coap_proto_t,
312 coap_session_t, COAP_DTLS_PKI_SETUP_VERSION,
313};
314#[cfg(feature = "dtls-pki")]
315pub use pki::*;
316#[cfg(feature = "dtls-rpk")]
317pub use rpk::*;
318
319use crate::{
320 error::{ContextConfigurationError, SessionCreationError},
321 session::CoapSession,
322 types::CoapAddress,
323 CoapContext,
324};
325
326#[derive(Clone, Debug)]
328pub enum ServerPkiRpkCryptoContext<'a> {
329 #[cfg(feature = "dtls-pki")]
331 Pki(PkiRpkContext<'a, Pki>),
332 #[cfg(feature = "dtls-rpk")]
334 Rpk(PkiRpkContext<'a, Rpk>),
335}
336
337impl ServerPkiRpkCryptoContext<'_> {
338 pub(crate) unsafe fn apply_to_context(
348 &self,
349 ctx: NonNull<coap_context_t>,
350 ) -> Result<(), ContextConfigurationError> {
351 match self {
352 #[cfg(feature = "dtls-pki")]
353 ServerPkiRpkCryptoContext::Pki(v) => v.apply_to_context(ctx),
354 #[cfg(feature = "dtls-rpk")]
355 ServerPkiRpkCryptoContext::Rpk(v) => v.apply_to_context(ctx),
356 }
357 }
358}
359
360pub struct NonCertVerifying;
367
368pub struct CertVerifying;
375
376trait CertVerificationModeSealed {}
377
378#[allow(private_bounds)]
380pub trait CertVerificationMode: CertVerificationModeSealed {}
381
382impl CertVerificationModeSealed for NonCertVerifying {}
383
384impl CertVerificationModeSealed for CertVerifying {}
385
386impl CertVerificationMode for NonCertVerifying {}
387
388impl CertVerificationMode for CertVerifying {}
389
390pub struct PkiRpkContextBuilder<'a, KTY: KeyType, V: CertVerificationMode> {
392 ctx: PkiRpkContextInner<'a, KTY>,
393 verifying: PhantomData<V>,
394}
395
396impl<'a, KTY: KeyType> PkiRpkContextBuilder<'a, KTY, NonCertVerifying> {
397 pub fn new<K: KeyDef<KeyType = KTY> + 'a>(key: K) -> Self {
405 let mut result = PkiRpkContextBuilder::<KTY, NonCertVerifying> {
406 ctx: PkiRpkContextInner {
407 raw_cfg: Box::new(coap_dtls_pki_t {
408 version: COAP_DTLS_PKI_SETUP_VERSION as u8,
409 verify_peer_cert: 0,
410 check_common_ca: 0,
411 allow_self_signed: 0,
412 allow_expired_certs: 0,
413 cert_chain_validation: 0,
414 cert_chain_verify_depth: 0,
415 check_cert_revocation: 0,
416 allow_no_crl: 0,
417 allow_expired_crl: 0,
418 allow_bad_md_hash: 0,
419 allow_short_rsa_length: 0,
420 is_rpk_not_cert: 0,
421 use_cid: 0,
422 reserved: Default::default(),
423 validate_cn_call_back: None,
424 cn_call_back_arg: std::ptr::null_mut(),
425 validate_sni_call_back: None,
426 sni_call_back_arg: std::ptr::null_mut(),
427 additional_tls_setup_call_back: None,
428 client_sni: std::ptr::null_mut(),
429 pki_key: key.as_raw_dtls_key(),
430 }),
431 provided_keys: vec![Box::new(key)],
432 provided_key_descriptors: vec![],
433 cn_callback: None,
434 sni_key_provider: None,
435 client_sni: None,
436 },
437 verifying: Default::default(),
438 };
439 KTY::set_key_type_defaults(result.ctx.raw_cfg.as_mut());
440 result
441 }
442}
443
444impl<KTY: KeyType, V: CertVerificationMode> PkiRpkContextBuilder<'_, KTY, V> {
445 pub fn use_cid(mut self, use_cid: bool) -> Self {
456 self.ctx.raw_cfg.use_cid = use_cid.into();
457 self
458 }
459
460 pub fn client_sni(mut self, client_sni: impl Into<Vec<u8>>) -> Result<Self, NulError> {
477 let sni = CString::new(client_sni.into())?
482 .into_bytes_with_nul()
483 .into_boxed_slice();
484 self.ctx.client_sni = Some(sni);
485 self.ctx.raw_cfg.client_sni = self.ctx.client_sni.as_mut().unwrap().as_mut_ptr() as *mut c_char;
486 Ok(self)
487 }
488}
489
490impl<KTY: KeyType> PkiRpkContextBuilder<'_, KTY, CertVerifying> {
491 pub fn check_common_ca(mut self, check_common_ca: bool) -> Self {
497 self.ctx.raw_cfg.check_common_ca = check_common_ca.into();
498 self
499 }
500
501 pub fn allow_self_signed(mut self, allow_self_signed: bool) -> Self {
509 self.ctx.raw_cfg.allow_self_signed = allow_self_signed.into();
510 self
511 }
512
513 pub fn allow_expired_certs(mut self, allow_expired_certs: bool) -> Self {
519 self.ctx.raw_cfg.allow_expired_certs = allow_expired_certs.into();
520 self
521 }
522
523 pub fn cert_chain_validation(mut self, cert_chain_verify_depth: u8) -> Self {
533 self.ctx.raw_cfg.cert_chain_validation = if cert_chain_verify_depth == 0 { 0 } else { 1 };
534 self.ctx.raw_cfg.cert_chain_verify_depth = cert_chain_verify_depth;
535 self
536 }
537
538 pub fn check_cert_revocation(mut self, check_cert_revocation: bool) -> Self {
544 self.ctx.raw_cfg.check_cert_revocation = check_cert_revocation.into();
545 self
546 }
547
548 pub fn allow_no_crl(mut self, allow_no_crl: bool) -> Self {
555 self.ctx.raw_cfg.allow_no_crl = allow_no_crl.into();
556 self
557 }
558
559 pub fn allow_expired_crl(mut self, allow_expired_crl: bool) -> Self {
566 self.ctx.raw_cfg.allow_expired_crl = allow_expired_crl.into();
567 self
568 }
569
570 pub fn allow_bad_md_hash(mut self, allow_bad_md_hash: bool) -> Self {
576 self.ctx.raw_cfg.allow_bad_md_hash = allow_bad_md_hash.into();
577 self
578 }
579
580 pub fn allow_short_rsa_length(mut self, allow_short_rsa_length: bool) -> Self {
586 self.ctx.raw_cfg.allow_short_rsa_length = allow_short_rsa_length.into();
587 self
588 }
589}
590
591impl<'a, KTY: KeyType, V: CertVerificationMode> PkiRpkContextBuilder<'a, KTY, V> {
592 pub fn sni_key_provider(mut self, sni_key_provider: impl PkiRpkSniKeyProvider<KTY> + 'a) -> Self {
603 self.ctx.sni_key_provider = Some(Box::new(sni_key_provider));
604 self.ctx.raw_cfg.validate_sni_call_back = Some(dtls_pki_sni_callback::<KTY>);
605 self
606 }
607
608 pub fn build(self) -> PkiRpkContext<'a, KTY> {
610 let ctx = Rc::new(RefCell::new(self.ctx));
611 {
612 let mut ctx_borrow = ctx.borrow_mut();
613 if ctx_borrow.raw_cfg.validate_cn_call_back.is_some() {
614 ctx_borrow.raw_cfg.cn_call_back_arg = Rc::downgrade(&ctx).into_raw() as *mut c_void;
615 }
616 if ctx_borrow.raw_cfg.validate_sni_call_back.is_some() {
617 ctx_borrow.raw_cfg.sni_call_back_arg = Rc::downgrade(&ctx).into_raw() as *mut c_void;
618 }
619 }
620 PkiRpkContext { inner: ctx }
621 }
622}
623
624struct PkiRpkContextInner<'a, KTY: KeyType> {
626 raw_cfg: Box<coap_dtls_pki_t>,
628 provided_keys: Vec<Box<dyn KeyDef<KeyType = KTY> + 'a>>,
630 provided_key_descriptors: Vec<*mut coap_dtls_key_t>,
639 cn_callback: Option<CnCallback<'a>>,
642 sni_key_provider: Option<Box<dyn PkiRpkSniKeyProvider<KTY> + 'a>>,
644 client_sni: Option<Box<[u8]>>,
648}
649
650impl<KTY: KeyType> Debug for PkiRpkContextInner<'_, KTY> {
651 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
652 f.debug_struct("PkiContextInner")
653 .field(
654 "raw_cfg",
655 &format!("(does not implement Debug), address: {:p}", self.raw_cfg),
656 )
657 .field("provided_keys", &self.provided_keys)
658 .field(
659 "provided_key_descriptors",
660 &format!(
661 "(values do not implement Debug), length: {}",
662 self.provided_key_descriptors.len()
663 ),
664 )
665 .field("cn_callback", &"(value does not implement Debug)")
666 .field("sni_key_provider", &"(value does not implement Debug)")
667 .field("client_sni", &self.client_sni)
668 .finish()
669 }
670}
671
672impl<KTY: KeyType> Drop for PkiRpkContextInner<'_, KTY> {
673 fn drop(&mut self) {
674 for key_ref in std::mem::take(&mut self.provided_key_descriptors).into_iter() {
675 unsafe {
680 drop(Box::from_raw(key_ref));
681 }
682 }
683 if !self.raw_cfg.cn_call_back_arg.is_null() {
684 unsafe {
687 Weak::from_raw(self.raw_cfg.cn_call_back_arg as *mut RefCell<Self>);
688 }
689 }
690 if !self.raw_cfg.sni_call_back_arg.is_null() {
691 unsafe {
694 Weak::from_raw(self.raw_cfg.sni_call_back_arg as *mut RefCell<Self>);
695 }
696 }
697 }
698}
699
700#[derive(Clone, Debug)]
705pub struct PkiRpkContext<'a, KTY: KeyType> {
706 inner: Rc<RefCell<PkiRpkContextInner<'a, KTY>>>,
708}
709
710impl<KTY: KeyType> PkiRpkContext<'_, KTY> {
711 pub(crate) unsafe fn create_raw_session(
717 &self,
718 ctx: &mut CoapContext<'_>,
719 addr: &CoapAddress,
720 proto: coap_proto_t,
721 ) -> Result<NonNull<coap_session_t>, SessionCreationError> {
722 {
725 let mut inner = (*self.inner).borrow_mut();
726 NonNull::new(unsafe {
727 coap_new_client_session_pki(
728 ctx.as_mut_raw_context(),
729 std::ptr::null(),
730 addr.as_raw_address(),
731 proto,
732 inner.raw_cfg.as_mut(),
733 )
734 })
735 .ok_or(SessionCreationError::Unknown)
736 }
737 }
738
739 unsafe fn apply_to_context(&self, mut ctx: NonNull<coap_context_t>) -> Result<(), ContextConfigurationError> {
751 let mut inner = self.inner.borrow_mut();
752 match unsafe { coap_context_set_pki(ctx.as_mut(), inner.raw_cfg.as_mut()) } {
755 1 => Ok(()),
756 _ => Err(ContextConfigurationError::Unknown),
757 }
758 }
759}
760
761impl<'a, KTY: KeyType> PkiRpkContext<'a, KTY> {
762 #[cfg_attr(not(feature = "dtls-pki"), allow(unused_variables))]
768 fn cn_callback(
769 &self,
770 cn: &CStr,
771 asn1_public_cert: &[u8],
772 session: &CoapSession,
773 depth: c_uint,
774 validated: bool,
775 ) -> c_int {
776 let inner = (*self.inner).borrow();
777 if match inner.cn_callback.as_ref().unwrap() {
780 #[cfg(feature = "dtls-pki")]
781 CnCallback::Pki(pki) => pki.validate_cn(cn, asn1_public_cert, session, depth, validated),
782 #[cfg(feature = "dtls-rpk")]
783 CnCallback::Rpk(rpk) => rpk.validate_rpk(asn1_public_cert, session, validated),
784 } {
785 1
786 } else {
787 0
788 }
789 }
790
791 fn sni_callback(&self, sni: &CStr) -> *mut coap_dtls_key_t {
799 let mut inner = self.inner.borrow_mut();
800 let key = inner.sni_key_provider.as_ref().unwrap().key_for_sni(sni);
803 if let Some(key) = key {
804 let key_ref = Box::into_raw(Box::new(key.as_raw_dtls_key()));
805 inner.provided_keys.push(key);
806 inner.provided_key_descriptors.push(key_ref);
807 key_ref
808 } else {
809 std::ptr::null_mut()
810 }
811 }
812
813 unsafe fn from_raw(raw_ctx: *const RefCell<PkiRpkContextInner<'a, KTY>>) -> Self {
824 assert!(!raw_ctx.is_null(), "provided raw DTLS PKI context was null");
825 let inner_weak = Weak::from_raw(raw_ctx);
826 let inner = inner_weak
827 .upgrade()
828 .expect("provided DTLS PKI context was already dropped!");
829 let _ = Weak::into_raw(inner_weak);
830 PkiRpkContext { inner }
831 }
832}
833
834enum CnCallback<'a> {
839 #[cfg(feature = "dtls-pki")]
841 Pki(Box<dyn PkiCnValidator + 'a>),
842 #[cfg(feature = "dtls-rpk")]
844 Rpk(Box<dyn RpkValidator + 'a>),
845}
846
847pub trait PkiRpkSniKeyProvider<KTY: KeyType> {
849 fn key_for_sni(&self, sni: &CStr) -> Option<Box<dyn KeyDef<KeyType = KTY>>>;
856}
857
858impl<KTY: KeyType, T: Fn(&CStr) -> Option<Box<dyn KeyDef<KeyType = KTY>>>> PkiRpkSniKeyProvider<KTY> for T {
859 fn key_for_sni(&self, sni: &CStr) -> Option<Box<dyn KeyDef<KeyType = KTY>>> {
860 self(sni)
861 }
862}
863
864unsafe extern "C" fn dtls_pki_cn_callback<KTY: KeyType>(
875 cn: *const c_char,
876 asn1_public_cert: *const u8,
877 asn1_length: usize,
878 session: *mut coap_session_t,
879 depth: c_uint,
880 validated: c_int,
881 arg: *mut c_void,
882) -> c_int {
883 let session = CoapSession::from_raw(session);
884 let cn = CStr::from_ptr(cn);
885 let asn1_public_cert = std::slice::from_raw_parts(asn1_public_cert, asn1_length);
886 let validated = validated == 1;
887 let context = PkiRpkContext::from_raw(arg as *const RefCell<PkiRpkContextInner<KTY>>);
888 context.cn_callback(cn, asn1_public_cert, &session, depth, validated)
889}
890
891unsafe extern "C" fn dtls_pki_sni_callback<KTY: KeyType>(sni: *const c_char, arg: *mut c_void) -> *mut coap_dtls_key_t {
901 let sni = CStr::from_ptr(sni);
902 let context = PkiRpkContext::from_raw(arg as *const RefCell<PkiRpkContextInner<KTY>>);
903 context.sni_callback(sni)
904}