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/pki.rs - Interfaces and types for PKI support in libcoap-rs.
9
 */
10

            
11
use std::{
12
    ffi::{c_uint, CStr, CString},
13
    fmt::Debug,
14
};
15

            
16
use libcoap_sys::{
17
    coap_const_char_ptr_t, coap_dtls_key_t, coap_dtls_key_t__bindgen_ty_1, coap_dtls_pki_t, coap_pki_define_t,
18
    coap_pki_define_t_COAP_PKI_KEY_DEF_DER, coap_pki_define_t_COAP_PKI_KEY_DEF_DER_BUF,
19
    coap_pki_define_t_COAP_PKI_KEY_DEF_ENGINE, coap_pki_define_t_COAP_PKI_KEY_DEF_PEM,
20
    coap_pki_define_t_COAP_PKI_KEY_DEF_PEM_BUF, coap_pki_define_t_COAP_PKI_KEY_DEF_PKCS11, coap_pki_key_define_t,
21
    coap_pki_key_t_COAP_PKI_KEY_DEFINE,
22
};
23

            
24
use crate::{
25
    crypto::{
26
        pki_rpk,
27
        pki_rpk::{
28
            key::{KeyComponentSealed, KeyTypeSealed},
29
            Asn1PrivateKeyType, CertVerificationMode, CertVerifying, CnCallback, DerFileKeyComponent,
30
            DerMemoryKeyComponent, EngineKeyComponent, KeyComponent, KeyDef, KeyDefSealed, NonCertVerifying,
31
            PemFileKeyComponent, PemMemoryKeyComponent, Pkcs11KeyComponent, PkiRpkContext, PkiRpkContextBuilder,
32
            ServerPkiRpkCryptoContext,
33
        },
34
        ClientCryptoContext,
35
    },
36
    session::CoapSession,
37
};
38

            
39
/// (Marker) key type for keys with a certificate signed by a trusted CA.
40
#[derive(Debug, Clone, Copy)]
41
pub struct Pki {}
42

            
43
impl KeyTypeSealed for Pki {
44
230
    fn set_key_type_defaults(ctx: &mut coap_dtls_pki_t) {
45
230
        ctx.is_rpk_not_cert = 0;
46
230
    }
47
}
48

            
49
// If PKI is enabled, implement conversions for PKI contexts to PKI-supporting server/client-side
50
// cryptographic contexts.
51

            
52
impl<'a> From<PkiRpkContext<'a, Pki>> for ServerPkiRpkCryptoContext<'a> {
53
115
    fn from(value: PkiRpkContext<'a, Pki>) -> Self {
54
115
        ServerPkiRpkCryptoContext::Pki(value)
55
115
    }
56
}
57

            
58
impl<'a> From<PkiRpkContext<'a, Pki>> for ClientCryptoContext<'a> {
59
115
    fn from(value: PkiRpkContext<'a, Pki>) -> Self {
60
115
        ClientCryptoContext::Pki(value)
61
115
    }
62
}
63

            
64
impl<'a> PkiRpkContextBuilder<'a, Pki, NonCertVerifying> {
65
    /// Enables PKI certificate verification of the peer's certificate when using the build
66
    /// encryption context.
67
    ///
68
    /// Note: While this will enable peer certificate validation, the other settings relating to
69
    /// certificate validation will not automatically be enabled.
70
    /// In particular, you might want to consider enabling certificate chain validation using
71
    /// [`PkiRpkContextBuilder::cert_chain_validation`].
72
    ///
73
    /// Depending on your circumstances, you might want to add additional root certificates
74
    /// using [`CoapContext::set_pki_root_cas`](crate::CoapContext::set_pki_root_ca_paths).
75
    ///
76
    /// # Implementation details (informative, not covered by semver guarantees)
77
    ///
78
    /// Equivalent to setting `verify_peer_cert` to `1` in the underlying [`coap_dtls_pki_t`]
79
    /// structure.
80
230
    pub fn verify_peer_cert(mut self) -> PkiRpkContextBuilder<'a, Pki, CertVerifying> {
81
230
        self.ctx.raw_cfg.verify_peer_cert = 1;
82
230
        PkiRpkContextBuilder::<Pki, CertVerifying> {
83
230
            ctx: self.ctx,
84
230
            verifying: Default::default(),
85
230
        }
86
230
    }
87
}
88

            
89
impl<'a> PkiRpkContextBuilder<'a, Pki, CertVerifying> {
90
    pub fn new<K: KeyDef<KeyType = Pki> + 'a>(key: K) -> Self {
91
        PkiRpkContextBuilder::<'a, Pki, NonCertVerifying>::new(key).verify_peer_cert()
92
    }
93
}
94

            
95
impl<'a, V: CertVerificationMode> PkiRpkContextBuilder<'a, Pki, V> {
96
    /// Sets the common name validator for this encryption context.
97
    ///
98
    /// The common name validator's [`validate_cn`](PkiCnValidator::validate_cn) function will be
99
    /// called after the TLS level validation checks have been completed in order to check whether
100
    /// the common name provided by the peer is allowed/as expected.
101
    ///
102
    /// # Implementation details (informative, not covered by semver guarantees)
103
    ///
104
    /// Setting a `cn_validator` will set the `validate_cn_call_back` of the underlying
105
    /// [`coap_dtls_pki_t`] to a wrapper function, which will then call the CN validator.
106
    pub fn cn_validator(mut self, validator: impl PkiCnValidator + 'a) -> Self {
107
        self.ctx.cn_callback = Some(CnCallback::Pki(Box::new(validator)));
108
        self.ctx.raw_cfg.validate_cn_call_back = Some(pki_rpk::dtls_pki_cn_callback::<Pki>);
109
        self
110
    }
111
}
112

            
113
/// Trait for types that can check whether a peer's or CA certificate's common name is allowed/as
114
/// expected for a session.
115
pub trait PkiCnValidator {
116
    /// Validates the common name of a peer or intermediate certificate.
117
    ///
118
    /// Aside from the common name given as `cn`, this function is also provided with the raw bytes
119
    /// of the ASN.1/DER encoded public certificate (`asn1_public_cert`), the respective `session`,
120
    /// the TLS library's `validated` status and the current `depth` that should be validated.
121
    ///
122
    /// `depth` will be 0 for the peer's certificate, and larger than 0 for a CA certificate.
123
    ///
124
    /// Should return `true` if the connection is to be accepted and `false` if the connection
125
    /// should be aborted.
126
    ///
127
    /// See [the libcoap documentation](https://libcoap.net/doc/reference/4.3.5/group__dtls.html#gaef7a2800757a4922102311c94c3fa529)
128
    /// for more background information.
129
    fn validate_cn(
130
        &self,
131
        cn: &CStr,
132
        asn1_public_cert: &[u8],
133
        session: &CoapSession,
134
        depth: c_uint,
135
        validated: bool,
136
    ) -> bool;
137
}
138

            
139
impl<T: Fn(&CStr, &[u8], &CoapSession, c_uint, bool) -> bool> PkiCnValidator for T {
140
    fn validate_cn(
141
        &self,
142
        cn: &CStr,
143
        asn1_public_cert: &[u8],
144
        session: &CoapSession,
145
        depth: c_uint,
146
        validated: bool,
147
    ) -> bool {
148
        self(cn, asn1_public_cert, session, depth, validated)
149
    }
150
}
151

            
152
/// Key definition for a DTLS key consisting of a private key and a CA-signed certificate.
153
///
154
/// Optionally, it may also contain a CA certificate whose name will be sent to clients to indicate
155
/// the key that they should themselves send.
156
///
157
/// # Note on key construction
158
///
159
/// For maximum compatibility, you should stick to the `with_*` constructors defined for this type.
160
/// While in theory you could use an arbitrary combination of key component types for a key
161
/// definition, those defined using `with_*` match explicit key types provided in libcoap and should
162
/// therefore always be supported.
163
///
164
/// # The CA certificate field
165
///
166
/// **Important:** The CA certificate field/parameter is not to be confused with the CA certificate
167
/// you may set while configuring HTTP servers. The CA certificate will **not** be sent in full to
168
/// the peer during connection establishment and does not have to refer to the CA that signed the
169
/// public certificate.
170
/// It will only be used to set the CA list sent to the client for client certificate validation.
171
///
172
/// Therefore, in order for TLS certificate validation to succeed, the peer must already know the
173
/// root CA's and all intermediate CAs' certificates.
174
#[derive(Clone, Debug)]
175
pub struct PkiKeyDef<CA: KeyComponent<Pki>, PK: KeyComponent<Pki>, SK: KeyComponent<Pki>> {
176
    ca_cert: Option<CA>,
177
    public_cert: PK,
178
    private_key: SK,
179
    user_pin: Option<CString>,
180
    asn1_private_key_type: Asn1PrivateKeyType,
181
}
182

            
183
impl<CA: KeyComponent<Pki>, PK: KeyComponent<Pki>, SK: KeyComponent<Pki>> PkiKeyDef<CA, PK, SK> {
184
    /// Creates a new key definition using the given components.
185
    ///
186
    /// # Parameters
187
    ///
188
    /// - `ca_cert`:     The certificate of the CA whose name should be provided to clients when
189
    ///                  requesting client certificates.
190
    ///                  **Important:** See the section in the struct-level documentation regarding
191
    ///                  this field for more information.
192
    /// - `public_cert`: The public (signed) certificate of this key.
193
    /// - `private_key`: The private key.
194
    /// - `user_pin`:    The PIN that should be used when unlocking a token (for PKCS11 keys stored
195
    ///                  on a token, ignored otherwise)
196
    /// - `asn1_private_key_type`: The type of the private key (only used for DER/ASN.1 encoded
197
    ///                  keys).
198
22
    pub fn new(
199
22
        ca_cert: Option<CA>,
200
22
        public_cert: PK,
201
22
        private_key: SK,
202
22
        user_pin: Option<CString>,
203
22
        asn1_private_key_type: Asn1PrivateKeyType,
204
22
    ) -> Self {
205
22
        Self {
206
22
            ca_cert,
207
22
            public_cert,
208
22
            private_key,
209
22
            user_pin,
210
22
            asn1_private_key_type,
211
22
        }
212
22
    }
213
}
214

            
215
impl PkiKeyDef<PemFileKeyComponent, PemFileKeyComponent, PemFileKeyComponent> {
216
    /// Creates a new key definition using PEM-encoded files as components.
217
    ///
218
    /// See the documentation of [PkiKeyDef::new] for more information on the parameters, especially
219
    /// regarding the `ca_cert` field.
220
6
    pub fn with_pem_files(
221
6
        ca_cert: Option<impl Into<PemFileKeyComponent>>,
222
6
        public_cert: impl Into<PemFileKeyComponent>,
223
6
        private_key: impl Into<PemFileKeyComponent>,
224
6
    ) -> Self {
225
6
        Self::new(
226
6
            ca_cert.map(|v| v.into()),
227
6
            public_cert.into(),
228
6
            private_key.into(),
229
6
            None,
230
6
            Asn1PrivateKeyType::None,
231
6
        )
232
6
    }
233
}
234

            
235
impl PkiKeyDef<PemMemoryKeyComponent, PemMemoryKeyComponent, PemMemoryKeyComponent> {
236
    /// Creates a new key definition using PEM-encoded byte sequences in memory as components.
237
    ///
238
    /// See the documentation of [`PkiKeyDef::new`] for more information on the parameters, especially
239
    /// regarding the `ca_cert` field.
240
6
    pub fn with_pem_memory(
241
6
        ca_cert: Option<impl Into<PemMemoryKeyComponent>>,
242
6
        public_cert: impl Into<PemMemoryKeyComponent>,
243
6
        private_key: impl Into<PemMemoryKeyComponent>,
244
6
    ) -> Self {
245
6
        Self::new(
246
6
            ca_cert.map(|v| v.into()),
247
6
            public_cert.into(),
248
6
            private_key.into(),
249
6
            None,
250
6
            Asn1PrivateKeyType::None,
251
6
        )
252
6
    }
253
}
254

            
255
impl PkiKeyDef<DerFileKeyComponent, DerFileKeyComponent, DerFileKeyComponent> {
256
    /// Creates a new key definition using DER-encoded files as components.
257
    ///
258
    /// See the documentation of [`PkiKeyDef::new`] for more information on the parameters, especially
259
    /// regarding the `ca_cert` field.
260
6
    pub fn with_asn1_files(
261
6
        ca_cert: Option<impl Into<DerFileKeyComponent>>,
262
6
        public_cert: impl Into<DerFileKeyComponent>,
263
6
        private_key: impl Into<DerFileKeyComponent>,
264
6
        private_key_type: Asn1PrivateKeyType,
265
6
    ) -> Self {
266
6
        Self::new(
267
6
            ca_cert.map(|v| v.into()),
268
6
            public_cert.into(),
269
6
            private_key.into(),
270
6
            None,
271
6
            private_key_type,
272
6
        )
273
6
    }
274
}
275

            
276
impl PkiKeyDef<DerMemoryKeyComponent, DerMemoryKeyComponent, DerMemoryKeyComponent> {
277
    /// Creates a new key definition using DER-encoded byte sequences in memory as components.
278
    ///
279
    /// See the documentation of [`PkiKeyDef::new`] for more information on the parameters, especially
280
    /// regarding the `ca_cert` field.
281
4
    pub fn with_asn1_memory(
282
4
        ca_cert: Option<impl Into<DerMemoryKeyComponent>>,
283
4
        public_cert: impl Into<DerMemoryKeyComponent>,
284
4
        private_key: impl Into<DerMemoryKeyComponent>,
285
4
        private_key_type: Asn1PrivateKeyType,
286
4
    ) -> Self {
287
4
        Self::new(
288
4
            ca_cert.map(|v| v.into()),
289
4
            public_cert.into(),
290
4
            private_key.into(),
291
4
            None,
292
4
            private_key_type,
293
4
        )
294
4
    }
295
}
296

            
297
impl PkiKeyDef<Pkcs11KeyComponent, Pkcs11KeyComponent, Pkcs11KeyComponent> {
298
    /// Creates a new key definition using PKCS11 URIs as components.
299
    ///
300
    /// See the documentation of [`PkiKeyDef::new`] for more information on the parameters, especially
301
    /// regarding the `ca_cert` field.
302
    pub fn with_pkcs11(
303
        ca_cert: Option<impl Into<Pkcs11KeyComponent>>,
304
        public_cert: impl Into<Pkcs11KeyComponent>,
305
        private_key: impl Into<Pkcs11KeyComponent>,
306
        user_pin: Option<CString>,
307
    ) -> Self {
308
        Self::new(
309
            ca_cert.map(|v| v.into()),
310
            public_cert.into(),
311
            private_key.into(),
312
            user_pin,
313
            Asn1PrivateKeyType::None,
314
        )
315
    }
316
}
317

            
318
impl<CA: KeyComponent<Pki>, PK: KeyComponent<Pki>, SK: KeyComponent<Pki>> KeyDefSealed for PkiKeyDef<CA, PK, SK> {
319
22
    fn as_raw_dtls_key(&self) -> coap_dtls_key_t {
320
22
        let (ca, ca_len) = self.ca_cert.as_ref().map(|v| v.as_raw_key_component()).unwrap_or((
321
22
            coap_const_char_ptr_t {
322
22
                u_byte: std::ptr::null(),
323
22
            },
324
22
            0,
325
22
        ));
326
22
        let (public_cert, public_cert_len) = self.public_cert.as_raw_key_component();
327
22
        let (private_key, private_key_len) = self.private_key.as_raw_key_component();
328
22

            
329
22
        coap_dtls_key_t {
330
22
            key_type: coap_pki_key_t_COAP_PKI_KEY_DEFINE,
331
22
            key: coap_dtls_key_t__bindgen_ty_1 {
332
22
                define: coap_pki_key_define_t {
333
22
                    ca,
334
22
                    public_cert,
335
22
                    private_key,
336
22
                    ca_len,
337
22
                    public_cert_len,
338
22
                    private_key_len,
339
22
                    ca_def: <CA as KeyComponentSealed<Pki>>::DEFINE_TYPE,
340
22
                    public_cert_def: <PK as KeyComponentSealed<Pki>>::DEFINE_TYPE,
341
22
                    private_key_def: <SK as KeyComponentSealed<Pki>>::DEFINE_TYPE,
342
22
                    private_key_type: self.asn1_private_key_type.into(),
343
22
                    user_pin: self.user_pin.as_ref().map(|v| v.as_ptr()).unwrap_or(std::ptr::null()),
344
22
                },
345
22
            },
346
22
        }
347
22
    }
348
}
349

            
350
impl<CA: KeyComponent<Pki>, PK: KeyComponent<Pki>, SK: KeyComponent<Pki>> KeyDef for PkiKeyDef<CA, PK, SK> {
351
    type KeyType = Pki;
352
}
353

            
354
impl KeyComponentSealed<Pki> for PemFileKeyComponent {
355
    const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_PEM;
356
}
357

            
358
impl KeyComponentSealed<Pki> for PemMemoryKeyComponent {
359
    const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_PEM_BUF;
360
}
361

            
362
impl KeyComponentSealed<Pki> for DerFileKeyComponent {
363
    const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_DER;
364
}
365

            
366
impl KeyComponentSealed<Pki> for DerMemoryKeyComponent {
367
    const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_DER_BUF;
368
}
369

            
370
impl KeyComponentSealed<Pki> for Pkcs11KeyComponent {
371
    const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_PKCS11;
372
}
373

            
374
impl KeyComponentSealed<Pki> for EngineKeyComponent {
375
    const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_ENGINE;
376
}