libcoap_rs/crypto/pki_rpk/
key.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
// SPDX-License-Identifier: BSD-2-Clause
/*
 * Copyright © The libcoap-rs Contributors, all rights reserved.
 * This file is part of the libcoap-rs project, see the README file for
 * general information on this project and the NOTICE.md and LICENSE files
 * for information regarding copyright ownership and terms of use.
 *
 * crypto/pki_rpk/key.rs - Interfaces and types for PKI/RPK keys in libcoap-rs.
 */

#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
use std::{ffi::CString, fmt::Debug, path::Path};

use libcoap_sys::{
    coap_asn1_privatekey_type_t, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_CMAC,
    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DH, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DHX,
    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA1,
    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA2, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA3,
    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA4, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_EC,
    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HKDF, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HMAC,
    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_NONE, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA,
    coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA2, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_TLS1_PRF,
    coap_const_char_ptr_t, coap_dtls_key_t, coap_dtls_pki_t, coap_pki_define_t,
};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;

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

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

impl<T: KeyTypeSealed> KeyType for T {}

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

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

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

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

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

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

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

impl AsRawKeyComponent for PemFileKeyComponent {
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
        (
            coap_const_char_ptr_t {
                s_byte: self.0.as_ptr(),
            },
            0,
        )
    }
}

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

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

impl<T: Into<Vec<u8>>> From<T> for PemMemoryKeyComponent {
    fn from(value: T) -> Self {
        PemMemoryKeyComponent(value.into().into_boxed_slice())
    }
}

impl AsRawKeyComponent for PemMemoryKeyComponent {
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
        (
            coap_const_char_ptr_t {
                u_byte: self.0.as_ptr(),
            },
            self.0.len(),
        )
    }
}

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

impl AsRawKeyComponent for DerFileKeyComponent {
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
        (
            coap_const_char_ptr_t {
                s_byte: self.0.as_ptr(),
            },
            0,
        )
    }
}

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

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

impl AsRawKeyComponent for DerMemoryKeyComponent {
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
        (
            coap_const_char_ptr_t {
                u_byte: self.0.as_ptr(),
            },
            self.0.len(),
        )
    }
}

impl<T: Into<Vec<u8>>> From<T> for DerMemoryKeyComponent {
    fn from(value: T) -> Self {
        DerMemoryKeyComponent(value.into().into_boxed_slice())
    }
}

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

impl AsRawKeyComponent for Pkcs11KeyComponent {
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
        (
            coap_const_char_ptr_t {
                s_byte: self.0.as_ptr(),
            },
            0,
        )
    }
}

impl<T: Into<CString>> From<T> for Pkcs11KeyComponent {
    fn from(value: T) -> Self {
        Pkcs11KeyComponent(value.into())
    }
}

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

impl AsRawKeyComponent for EngineKeyComponent {
    fn as_raw_key_component(&self) -> (coap_const_char_ptr_t, usize) {
        (
            coap_const_char_ptr_t {
                s_byte: self.0.as_ptr(),
            },
            0,
        )
    }
}

impl<T: Into<CString>> From<T> for EngineKeyComponent {
    fn from(value: T) -> Self {
        EngineKeyComponent(value.into())
    }
}

/// Private key type for DER/ASN.1 encoded keys.
#[repr(C)]
#[derive(Copy, Clone, FromPrimitive, Debug, PartialEq, Eq, Hash, Default)]
pub enum Asn1PrivateKeyType {
    #[default]
    None = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_NONE as isize,
    Rsa = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA as isize,
    Rsa2 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA2 as isize,
    Dsa = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA as isize,
    Dsa1 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA1 as isize,
    Dsa2 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA2 as isize,
    Dsa3 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA3 as isize,
    Dsa4 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA4 as isize,
    Dh = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DH as isize,
    Dhx = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DHX as isize,
    Ec = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_EC as isize,
    Hmac = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HMAC as isize,
    Cmac = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_CMAC as isize,
    Tls1Prf = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_TLS1_PRF as isize,
    Hkdf = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HKDF as isize,
}

impl From<Asn1PrivateKeyType> for coap_asn1_privatekey_type_t {
    fn from(value: Asn1PrivateKeyType) -> Self {
        match value {
            Asn1PrivateKeyType::None => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_NONE,
            Asn1PrivateKeyType::Rsa => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA,
            Asn1PrivateKeyType::Rsa2 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA2,
            Asn1PrivateKeyType::Dsa => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA,
            Asn1PrivateKeyType::Dsa1 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA1,
            Asn1PrivateKeyType::Dsa2 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA2,
            Asn1PrivateKeyType::Dsa3 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA3,
            Asn1PrivateKeyType::Dsa4 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA4,
            Asn1PrivateKeyType::Dh => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DH,
            Asn1PrivateKeyType::Dhx => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DHX,
            Asn1PrivateKeyType::Ec => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_EC,
            Asn1PrivateKeyType::Hmac => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HMAC,
            Asn1PrivateKeyType::Cmac => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_CMAC,
            Asn1PrivateKeyType::Tls1Prf => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_TLS1_PRF,
            Asn1PrivateKeyType::Hkdf => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HKDF,
        }
    }
}

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