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)]
12
use std::os::unix::ffi::OsStrExt;
13
use std::{ffi::CString, fmt::Debug, path::Path};
14

            
15
use 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
};
26
use num_derive::FromPrimitive;
27
use num_traits::FromPrimitive;
28

            
29
/// Trait for marker structs that describe different types of asymmetric DTLS keys (RPK or PKI).
30
#[allow(private_bounds)]
31
pub trait KeyType: KeyTypeSealed {}
32

            
33
/// Sealed trait for key types.
34
pub(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

            
39
impl<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)]
43
pub trait KeyDef: KeyDefSealed {
44
    /// The key type of this key definition.
45
    type KeyType: KeyType;
46
}
47

            
48
/// Sealed trait for key definitions.
49
pub(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.
61
pub(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`.
74
pub(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)]
82
pub trait KeyComponent<KTY: KeyType>: KeyComponentSealed<KTY> {}
83

            
84
impl<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)]
88
pub struct PemFileKeyComponent(CString);
89

            
90
impl AsRawKeyComponent for PemFileKeyComponent {
91
186
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
92
186
        (
93
186
            coap_const_char_ptr_t {
94
186
                s_byte: self.0.as_ptr(),
95
186
            },
96
186
            0,
97
186
        )
98
186
    }
99
}
100

            
101
#[cfg(unix)]
102
impl<T: AsRef<Path>> From<T> for PemFileKeyComponent {
103
18
    fn from(value: T) -> Self {
104
18
        // File paths never contain null-bytes on unix, so we can unwrap here.
105
18
        PemFileKeyComponent(CString::new(value.as_ref().as_os_str().as_bytes()).unwrap())
106
18
    }
107
}
108

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

            
113
impl<T: Into<Vec<u8>>> From<T> for PemMemoryKeyComponent {
114
26
    fn from(value: T) -> Self {
115
26
        PemMemoryKeyComponent(value.into().into_boxed_slice())
116
26
    }
117
}
118

            
119
impl AsRawKeyComponent for PemMemoryKeyComponent {
120
238
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
121
238
        (
122
238
            coap_const_char_ptr_t {
123
238
                u_byte: self.0.as_ptr(),
124
238
            },
125
238
            self.0.len(),
126
238
        )
127
238
    }
128
}
129

            
130
/// Key component that is stored in a DER-encoded file with the given path.
131
#[derive(Clone, Debug)]
132
pub struct DerFileKeyComponent(CString);
133

            
134
impl AsRawKeyComponent for DerFileKeyComponent {
135
138
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
136
138
        (
137
138
            coap_const_char_ptr_t {
138
138
                s_byte: self.0.as_ptr(),
139
138
            },
140
138
            0,
141
138
        )
142
138
    }
143
}
144

            
145
#[cfg(unix)]
146
impl<T: AsRef<Path>> From<T> for DerFileKeyComponent {
147
14
    fn from(value: T) -> Self {
148
14
        // File paths never contain null-bytes on unix, so we can unwrap here.
149
14
        DerFileKeyComponent(CString::new(value.as_ref().as_os_str().as_bytes()).unwrap())
150
14
    }
151
}
152

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

            
157
impl AsRawKeyComponent for DerMemoryKeyComponent {
158
132
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
159
132
        (
160
132
            coap_const_char_ptr_t {
161
132
                u_byte: self.0.as_ptr(),
162
132
            },
163
132
            self.0.len(),
164
132
        )
165
132
    }
166
}
167

            
168
impl<T: Into<Vec<u8>>> From<T> for DerMemoryKeyComponent {
169
12
    fn from(value: T) -> Self {
170
12
        DerMemoryKeyComponent(value.into().into_boxed_slice())
171
12
    }
172
}
173

            
174
/// Key component that is stored as a PKCS11 URI.
175
#[derive(Clone, Debug)]
176
pub struct Pkcs11KeyComponent(CString);
177

            
178
impl 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

            
189
impl<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)]
197
pub struct EngineKeyComponent(CString);
198

            
199
impl 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

            
210
impl<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)]
219
pub 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

            
238
impl From<Asn1PrivateKeyType> for coap_asn1_privatekey_type_t {
239
256
    fn from(value: Asn1PrivateKeyType) -> Self {
240
256
        match value {
241
150
            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
106
            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
256
    }
258
}
259

            
260
impl 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
}