1
// SPDX-License-Identifier: BSD-2-Clause
2
/*
3
 * crypto/pki_rpk/key.rs - Interfaces and types for PKI/RPK keys in libcoap-rs.
4
 * This file is part of the libcoap-rs crate, see the README and LICENSE files for
5
 * more information and terms of use.
6
 * Copyright © 2021-2024 The NAMIB Project Developers, all rights reserved.
7
 * See the README as well as the LICENSE file for more information.
8
 */
9

            
10
use libcoap_sys::{
11
    coap_asn1_privatekey_type_t, coap_const_char_ptr_t, coap_dtls_key_t, coap_dtls_pki_t, coap_pki_define_t,
12
};
13
use num_derive::FromPrimitive;
14
use num_traits::FromPrimitive;
15
use std::ffi::CString;
16
use std::fmt::Debug;
17
#[cfg(unix)]
18
use std::os::unix::ffi::OsStrExt;
19
use std::path::Path;
20

            
21
/// Trait for marker structs that describe different types of asymmetric DTLS keys (RPK or PKI).
22
#[allow(private_bounds)]
23
pub trait KeyType: KeyTypeSealed {}
24

            
25
/// Sealed trait for key types.
26
pub(super) trait KeyTypeSealed: Debug {
27
    /// Applies default settings for this key type to the given encryption context `ctx`.
28
    fn set_key_type_defaults(ctx: &mut coap_dtls_pki_t);
29
}
30

            
31
impl<T: KeyTypeSealed> KeyType for T {}
32

            
33
/// Trait for types that can be used as a libcoap DTLS asymmetric key definition (RPK or PKI).
34
#[allow(private_bounds)]
35
pub trait KeyDef: KeyDefSealed {
36
    /// The key type of this key definition.
37
    type KeyType: KeyType;
38
}
39

            
40
/// Sealed trait for key definitions.
41
pub(crate) trait KeyDefSealed: Debug {
42
    /// Creates a raw key definition based on this key definition.
43
    ///
44
    /// **Important:** The returned raw definition refers to memory owned by `self`.
45
    /// While this function alone can not cause undefined behavior (and is therefore not `unsafe`),
46
    /// anything that dereferences the pointers stored in the returned [`coap_dtls_key_t`] (which is
47
    /// itself only possible in `unsafe` code) after `self` has been dropped will cause Undefined
48
    /// Behavior.
49
    fn as_raw_dtls_key(&self) -> coap_dtls_key_t;
50
}
51

            
52
/// Trait for types that can be converted to components of an asymmetric DTLS key.
53
pub(super) trait AsRawKeyComponent: Sized + Debug {
54
    /// Returns a raw [`coap_const_char_ptr_t`] pointing to this key component and a `usize`
55
    /// indicating the length of this key component (or `0` if this key type is supposed to be a
56
    /// null-terminated string).
57
    ///
58
    /// **Important:** The returned raw definition refers to memory owned by `self`.
59
    /// While this function alone can not cause undefined behavior (and is therefore not `unsafe`),
60
    /// anything that dereferences the returned [`coap_const_char_ptr_t`] (which is itself only
61
    /// possible in `unsafe` code) after `self` has been dropped will cause Undefined Behavior.
62
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize);
63
}
64

            
65
/// Sealed trait for components of an asymmetric DTLS key of the given [`KeyType`] `KTY`.
66
pub(super) trait KeyComponentSealed<KTY: KeyType>: AsRawKeyComponent {
67
    /// The raw [`coap_pki_define_t`] indicating the type of this key component that should be used
68
    /// when using it in a key definition of type `KTY`.
69
    const DEFINE_TYPE: coap_pki_define_t;
70
}
71

            
72
/// Trait indicating that a type can be used as a DTLS key component of the given [`KeyType`] `KTY`.
73
#[allow(private_bounds)]
74
pub trait KeyComponent<KTY: KeyType>: KeyComponentSealed<KTY> {}
75

            
76
impl<KTY: KeyType, T: KeyComponentSealed<KTY>> KeyComponent<KTY> for T {}
77

            
78
/// Key component that is stored in a PEM-encoded file with the given path.
79
#[derive(Clone, Debug)]
80
pub struct PemFileKeyComponent(CString);
81

            
82
impl AsRawKeyComponent for PemFileKeyComponent {
83
186
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
84
186
        (
85
186
            coap_const_char_ptr_t {
86
186
                s_byte: self.0.as_ptr(),
87
186
            },
88
186
            0,
89
186
        )
90
186
    }
91
}
92

            
93
#[cfg(unix)]
94
impl<T: AsRef<Path>> From<T> for PemFileKeyComponent {
95
18
    fn from(value: T) -> Self {
96
18
        // File paths never contain null-bytes on unix, so we can unwrap here.
97
18
        PemFileKeyComponent(CString::new(value.as_ref().as_os_str().as_bytes()).unwrap())
98
18
    }
99
}
100

            
101
/// Key component that is stored in memory as a PEM-encoded sequence of bytes.
102
#[derive(Clone, Debug)]
103
pub struct PemMemoryKeyComponent(Box<[u8]>);
104

            
105
impl<T: Into<Vec<u8>>> From<T> for PemMemoryKeyComponent {
106
26
    fn from(value: T) -> Self {
107
26
        PemMemoryKeyComponent(value.into().into_boxed_slice())
108
26
    }
109
}
110

            
111
impl AsRawKeyComponent for PemMemoryKeyComponent {
112
238
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
113
238
        (
114
238
            coap_const_char_ptr_t {
115
238
                u_byte: self.0.as_ptr(),
116
238
            },
117
238
            self.0.len(),
118
238
        )
119
238
    }
120
}
121

            
122
/// Key component that is stored in a DER-encoded file with the given path.
123
#[derive(Clone, Debug)]
124
pub struct DerFileKeyComponent(CString);
125

            
126
impl AsRawKeyComponent for DerFileKeyComponent {
127
138
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
128
138
        (
129
138
            coap_const_char_ptr_t {
130
138
                s_byte: self.0.as_ptr(),
131
138
            },
132
138
            0,
133
138
        )
134
138
    }
135
}
136

            
137
#[cfg(unix)]
138
impl<T: AsRef<Path>> From<T> for DerFileKeyComponent {
139
14
    fn from(value: T) -> Self {
140
14
        // File paths never contain null-bytes on unix, so we can unwrap here.
141
14
        DerFileKeyComponent(CString::new(value.as_ref().as_os_str().as_bytes()).unwrap())
142
14
    }
143
}
144

            
145
/// Key component that is stored in memory as a DER-encoded sequence of bytes.
146
#[derive(Clone, Debug)]
147
pub struct DerMemoryKeyComponent(Box<[u8]>);
148

            
149
impl AsRawKeyComponent for DerMemoryKeyComponent {
150
132
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
151
132
        (
152
132
            coap_const_char_ptr_t {
153
132
                u_byte: self.0.as_ptr(),
154
132
            },
155
132
            self.0.len(),
156
132
        )
157
132
    }
158
}
159

            
160
impl<T: Into<Vec<u8>>> From<T> for DerMemoryKeyComponent {
161
12
    fn from(value: T) -> Self {
162
12
        DerMemoryKeyComponent(value.into().into_boxed_slice())
163
12
    }
164
}
165

            
166
/// Key component that is stored as a PKCS11 URI.
167
#[derive(Clone, Debug)]
168
pub struct Pkcs11KeyComponent(CString);
169

            
170
impl AsRawKeyComponent for Pkcs11KeyComponent {
171
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
172
        (
173
            coap_const_char_ptr_t {
174
                s_byte: self.0.as_ptr(),
175
            },
176
            0,
177
        )
178
    }
179
}
180

            
181
impl<T: Into<CString>> From<T> for Pkcs11KeyComponent {
182
    fn from(value: T) -> Self {
183
        Pkcs11KeyComponent(value.into())
184
    }
185
}
186

            
187
/// Key component that is passed to the TLS library verbatim (only supported by OpenSSL).
188
#[derive(Clone, Debug)]
189
pub struct EngineKeyComponent(CString);
190

            
191
impl AsRawKeyComponent for EngineKeyComponent {
192
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
193
        (
194
            coap_const_char_ptr_t {
195
                s_byte: self.0.as_ptr(),
196
            },
197
            0,
198
        )
199
    }
200
}
201

            
202
impl<T: Into<CString>> From<T> for EngineKeyComponent {
203
    fn from(value: T) -> Self {
204
        EngineKeyComponent(value.into())
205
    }
206
}
207

            
208
/// Private key type for DER/ASN.1 encoded keys.
209
#[repr(C)]
210
#[derive(Copy, Clone, FromPrimitive, Debug, PartialEq, Eq, Hash, Default)]
211
pub enum Asn1PrivateKeyType {
212
    #[default]
213
    None = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_NONE as isize,
214
    Rsa = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_RSA as isize,
215
    Rsa2 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_RSA2 as isize,
216
    Dsa = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA as isize,
217
    Dsa1 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA1 as isize,
218
    Dsa2 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA2 as isize,
219
    Dsa3 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA3 as isize,
220
    Dsa4 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA4 as isize,
221
    Dh = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DH as isize,
222
    Dhx = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DHX as isize,
223
    Ec = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_EC as isize,
224
    Hmac = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_HMAC as isize,
225
    Cmac = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_CMAC as isize,
226
    Tls1Prf = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_TLS1_PRF as isize,
227
    Hkdf = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_HKDF as isize,
228
}
229

            
230
impl From<Asn1PrivateKeyType> for coap_asn1_privatekey_type_t {
231
256
    fn from(value: Asn1PrivateKeyType) -> Self {
232
256
        match value {
233
150
            Asn1PrivateKeyType::None => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_NONE,
234
            Asn1PrivateKeyType::Rsa => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_RSA,
235
            Asn1PrivateKeyType::Rsa2 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_RSA2,
236
            Asn1PrivateKeyType::Dsa => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA,
237
            Asn1PrivateKeyType::Dsa1 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA1,
238
            Asn1PrivateKeyType::Dsa2 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA2,
239
            Asn1PrivateKeyType::Dsa3 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA3,
240
            Asn1PrivateKeyType::Dsa4 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA4,
241
            Asn1PrivateKeyType::Dh => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DH,
242
            Asn1PrivateKeyType::Dhx => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DHX,
243
106
            Asn1PrivateKeyType::Ec => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_EC,
244
            Asn1PrivateKeyType::Hmac => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_HMAC,
245
            Asn1PrivateKeyType::Cmac => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_CMAC,
246
            Asn1PrivateKeyType::Tls1Prf => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_TLS1_PRF,
247
            Asn1PrivateKeyType::Hkdf => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_HKDF,
248
        }
249
256
    }
250
}
251

            
252
impl From<coap_asn1_privatekey_type_t> for Asn1PrivateKeyType {
253
    fn from(value: coap_asn1_privatekey_type_t) -> Self {
254
        FromPrimitive::from_isize(value as isize).expect("unknown ASN1 private key type")
255
    }
256
}