libcoap_rs/crypto/pki_rpk/
key.rs

1// SPDX-License-Identifier: BSD-2-Clause
2/*
3 * Copyright © The libcoap-rs Contributors, all rights reserved.
4 * This file is part of the libcoap-rs project, see the README file for
5 * general information on this project and the NOTICE.md and LICENSE files
6 * for information regarding copyright ownership and terms of use.
7 *
8 * crypto/pki_rpk/key.rs - Interfaces and types for PKI/RPK keys in libcoap-rs.
9 */
10
11#[cfg(unix)]
12use std::os::unix::ffi::OsStrExt;
13use std::{ffi::CString, fmt::Debug, path::Path};
14
15use libcoap_sys::{
16    coap_asn1_privatekey_type_t, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_CMAC,
17    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DH, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DHX,
18    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA1,
19    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA2, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA3,
20    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA4, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_EC,
21    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HKDF, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HMAC,
22    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_NONE, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA,
23    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA2, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_TLS1_PRF,
24    coap_const_char_ptr_t, coap_dtls_key_t, coap_dtls_pki_t, coap_pki_define_t,
25};
26use num_derive::FromPrimitive;
27use num_traits::FromPrimitive;
28
29/// Trait for marker structs that describe different types of asymmetric DTLS keys (RPK or PKI).
30#[allow(private_bounds)]
31pub trait KeyType: KeyTypeSealed {}
32
33/// Sealed trait for key types.
34pub(super) trait KeyTypeSealed: Debug {
35    /// Applies default settings for this key type to the given encryption context `ctx`.
36    fn set_key_type_defaults(ctx: &mut coap_dtls_pki_t);
37}
38
39impl<T: KeyTypeSealed> KeyType for T {}
40
41/// Trait for types that can be used as a libcoap DTLS asymmetric key definition (RPK or PKI).
42#[allow(private_bounds)]
43pub trait KeyDef: KeyDefSealed {
44    /// The key type of this key definition.
45    type KeyType: KeyType;
46}
47
48/// Sealed trait for key definitions.
49pub(crate) trait KeyDefSealed: Debug {
50    /// Creates a raw key definition based on this key definition.
51    ///
52    /// **Important:** The returned raw definition refers to memory owned by `self`.
53    /// While this function alone can not cause undefined behavior (and is therefore not `unsafe`),
54    /// anything that dereferences the pointers stored in the returned [`coap_dtls_key_t`] (which is
55    /// itself only possible in `unsafe` code) after `self` has been dropped will cause Undefined
56    /// Behavior.
57    fn as_raw_dtls_key(&self) -> coap_dtls_key_t;
58}
59
60/// Trait for types that can be converted to components of an asymmetric DTLS key.
61pub(super) trait AsRawKeyComponent: Sized + Debug {
62    /// Returns a raw [`coap_const_char_ptr_t`] pointing to this key component and a `usize`
63    /// indicating the length of this key component (or `0` if this key type is supposed to be a
64    /// null-terminated string).
65    ///
66    /// **Important:** The returned raw definition refers to memory owned by `self`.
67    /// While this function alone can not cause undefined behavior (and is therefore not `unsafe`),
68    /// anything that dereferences the returned [`coap_const_char_ptr_t`] (which is itself only
69    /// possible in `unsafe` code) after `self` has been dropped will cause Undefined Behavior.
70    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize);
71}
72
73/// Sealed trait for components of an asymmetric DTLS key of the given [`KeyType`] `KTY`.
74pub(super) trait KeyComponentSealed<KTY: KeyType>: AsRawKeyComponent {
75    /// The raw [`coap_pki_define_t`] indicating the type of this key component that should be used
76    /// when using it in a key definition of type `KTY`.
77    const DEFINE_TYPE: coap_pki_define_t;
78}
79
80/// Trait indicating that a type can be used as a DTLS key component of the given [`KeyType`] `KTY`.
81#[allow(private_bounds)]
82pub trait KeyComponent<KTY: KeyType>: KeyComponentSealed<KTY> {}
83
84impl<KTY: KeyType, T: KeyComponentSealed<KTY>> KeyComponent<KTY> for T {}
85
86/// Key component that is stored in a PEM-encoded file with the given path.
87#[derive(Clone, Debug)]
88pub struct PemFileKeyComponent(CString);
89
90impl AsRawKeyComponent for PemFileKeyComponent {
91    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
92        (
93            coap_const_char_ptr_t {
94                s_byte: self.0.as_ptr(),
95            },
96            0,
97        )
98    }
99}
100
101#[cfg(unix)]
102impl<T: AsRef<Path>> From<T> for PemFileKeyComponent {
103    fn from(value: T) -> Self {
104        // File paths never contain null-bytes on unix, so we can unwrap here.
105        PemFileKeyComponent(CString::new(value.as_ref().as_os_str().as_bytes()).unwrap())
106    }
107}
108
109/// Key component that is stored in memory as a PEM-encoded sequence of bytes.
110#[derive(Clone, Debug)]
111pub struct PemMemoryKeyComponent(Box<[u8]>);
112
113impl<T: Into<Vec<u8>>> From<T> for PemMemoryKeyComponent {
114    fn from(value: T) -> Self {
115        PemMemoryKeyComponent(value.into().into_boxed_slice())
116    }
117}
118
119impl AsRawKeyComponent for PemMemoryKeyComponent {
120    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
121        (
122            coap_const_char_ptr_t {
123                u_byte: self.0.as_ptr(),
124            },
125            self.0.len(),
126        )
127    }
128}
129
130/// Key component that is stored in a DER-encoded file with the given path.
131#[derive(Clone, Debug)]
132pub struct DerFileKeyComponent(CString);
133
134impl AsRawKeyComponent for DerFileKeyComponent {
135    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
136        (
137            coap_const_char_ptr_t {
138                s_byte: self.0.as_ptr(),
139            },
140            0,
141        )
142    }
143}
144
145#[cfg(unix)]
146impl<T: AsRef<Path>> From<T> for DerFileKeyComponent {
147    fn from(value: T) -> Self {
148        // File paths never contain null-bytes on unix, so we can unwrap here.
149        DerFileKeyComponent(CString::new(value.as_ref().as_os_str().as_bytes()).unwrap())
150    }
151}
152
153/// Key component that is stored in memory as a DER-encoded sequence of bytes.
154#[derive(Clone, Debug)]
155pub struct DerMemoryKeyComponent(Box<[u8]>);
156
157impl AsRawKeyComponent for DerMemoryKeyComponent {
158    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
159        (
160            coap_const_char_ptr_t {
161                u_byte: self.0.as_ptr(),
162            },
163            self.0.len(),
164        )
165    }
166}
167
168impl<T: Into<Vec<u8>>> From<T> for DerMemoryKeyComponent {
169    fn from(value: T) -> Self {
170        DerMemoryKeyComponent(value.into().into_boxed_slice())
171    }
172}
173
174/// Key component that is stored as a PKCS11 URI.
175#[derive(Clone, Debug)]
176pub struct Pkcs11KeyComponent(CString);
177
178impl AsRawKeyComponent for Pkcs11KeyComponent {
179    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
180        (
181            coap_const_char_ptr_t {
182                s_byte: self.0.as_ptr(),
183            },
184            0,
185        )
186    }
187}
188
189impl<T: Into<CString>> From<T> for Pkcs11KeyComponent {
190    fn from(value: T) -> Self {
191        Pkcs11KeyComponent(value.into())
192    }
193}
194
195/// Key component that is passed to the TLS library verbatim (only supported by OpenSSL).
196#[derive(Clone, Debug)]
197pub struct EngineKeyComponent(CString);
198
199impl AsRawKeyComponent for EngineKeyComponent {
200    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
201        (
202            coap_const_char_ptr_t {
203                s_byte: self.0.as_ptr(),
204            },
205            0,
206        )
207    }
208}
209
210impl<T: Into<CString>> From<T> for EngineKeyComponent {
211    fn from(value: T) -> Self {
212        EngineKeyComponent(value.into())
213    }
214}
215
216/// Private key type for DER/ASN.1 encoded keys.
217#[repr(C)]
218#[derive(Copy, Clone, FromPrimitive, Debug, PartialEq, Eq, Hash, Default)]
219pub enum Asn1PrivateKeyType {
220    #[default]
221    None = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_NONE as isize,
222    Rsa = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA as isize,
223    Rsa2 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA2 as isize,
224    Dsa = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA as isize,
225    Dsa1 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA1 as isize,
226    Dsa2 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA2 as isize,
227    Dsa3 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA3 as isize,
228    Dsa4 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA4 as isize,
229    Dh = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DH as isize,
230    Dhx = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DHX as isize,
231    Ec = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_EC as isize,
232    Hmac = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HMAC as isize,
233    Cmac = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_CMAC as isize,
234    Tls1Prf = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_TLS1_PRF as isize,
235    Hkdf = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HKDF as isize,
236}
237
238impl From<Asn1PrivateKeyType> for coap_asn1_privatekey_type_t {
239    fn from(value: Asn1PrivateKeyType) -> Self {
240        match value {
241            Asn1PrivateKeyType::None => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_NONE,
242            Asn1PrivateKeyType::Rsa => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA,
243            Asn1PrivateKeyType::Rsa2 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA2,
244            Asn1PrivateKeyType::Dsa => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA,
245            Asn1PrivateKeyType::Dsa1 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA1,
246            Asn1PrivateKeyType::Dsa2 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA2,
247            Asn1PrivateKeyType::Dsa3 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA3,
248            Asn1PrivateKeyType::Dsa4 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA4,
249            Asn1PrivateKeyType::Dh => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DH,
250            Asn1PrivateKeyType::Dhx => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DHX,
251            Asn1PrivateKeyType::Ec => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_EC,
252            Asn1PrivateKeyType::Hmac => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HMAC,
253            Asn1PrivateKeyType::Cmac => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_CMAC,
254            Asn1PrivateKeyType::Tls1Prf => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_TLS1_PRF,
255            Asn1PrivateKeyType::Hkdf => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HKDF,
256        }
257    }
258}
259
260impl From<coap_asn1_privatekey_type_t> for Asn1PrivateKeyType {
261    fn from(value: coap_asn1_privatekey_type_t) -> Self {
262        FromPrimitive::from_isize(value as isize).expect("unknown ASN1 private key type")
263    }
264}