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

            
11
use std::{ffi::CString, fmt::Debug};
12

            
13
use libcoap_sys::{
14
    coap_const_char_ptr_t, coap_dtls_key_t, coap_dtls_key_t__bindgen_ty_1, coap_dtls_pki_t, coap_pki_define_t,
15
    coap_pki_define_t_COAP_PKI_KEY_DEF_PEM, coap_pki_define_t_COAP_PKI_KEY_DEF_PKCS11_RPK,
16
    coap_pki_define_t_COAP_PKI_KEY_DEF_RPK_BUF, coap_pki_key_define_t, coap_pki_key_t_COAP_PKI_KEY_DEFINE,
17
};
18

            
19
use crate::{
20
    crypto::{
21
        pki_rpk,
22
        pki_rpk::{
23
            key::{KeyComponentSealed, KeyTypeSealed},
24
            Asn1PrivateKeyType, CnCallback, KeyComponent, KeyDef, KeyDefSealed, NonCertVerifying,
25
            PemMemoryKeyComponent, Pkcs11KeyComponent, PkiRpkContext, PkiRpkContextBuilder, ServerPkiRpkCryptoContext,
26
        },
27
        ClientCryptoContext,
28
    },
29
    session::CoapSession,
30
};
31

            
32
/// (Marker) key type for asymmetric DTLS keys not signed by a CA (raw public keys).
33
#[derive(Debug, Clone, Copy)]
34
pub struct Rpk {}
35

            
36
impl KeyTypeSealed for Rpk {
37
26
    fn set_key_type_defaults(ctx: &mut coap_dtls_pki_t) {
38
26
        ctx.is_rpk_not_cert = 1;
39
26
    }
40
}
41

            
42
// If PKI is enabled, implement conversions for PKI contexts to RPK-supporting server/client-side
43
// cryptographic contexts.
44

            
45
impl<'a> From<PkiRpkContext<'a, Rpk>> for ClientCryptoContext<'a> {
46
13
    fn from(value: PkiRpkContext<'a, Rpk>) -> Self {
47
13
        ClientCryptoContext::Rpk(value)
48
13
    }
49
}
50

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

            
57
impl<'a> PkiRpkContextBuilder<'a, Rpk, NonCertVerifying> {
58
    /// Sets the raw public key validator for this encryption context.
59
    ///
60
    /// The raw public key validator's [`validate_rpk`](RpkValidator::validate_rpk) function will be
61
    /// called after the TLS-level validation checks have been completed in order to check whether
62
    /// the RPK provided by the peer is allowed/as expected.
63
    ///
64
    /// # Implementation details (informative, not covered by semver guarantees)
65
    ///
66
    /// Setting an RPK validator will set the `validate_cn_call_back` of the underlying
67
    /// [`coap_dtls_pki_t`] to a wrapper function, which will then call the RPK validator.
68
    pub fn rpk_validator(mut self, validator: impl RpkValidator + 'a) -> Self {
69
        self.ctx.cn_callback = Some(CnCallback::Rpk(Box::new(validator)));
70
        self.ctx.raw_cfg.validate_cn_call_back = Some(pki_rpk::dtls_pki_cn_callback::<Rpk>);
71
        self
72
    }
73
}
74

            
75
/// Trait for types that can validate that a raw public key is the one expected for a given peer.
76
pub trait RpkValidator {
77
    /// Validates the raw public key of a peer.
78
    ///
79
    /// This function is provided with the public key (`asn1_public_key`), the respective `session`,
80
    /// and the TLS library's `validated` status, and should return `true` if the connection is to
81
    /// be accepted and `false` if the connection should be aborted.
82
    ///
83
    /// `asn1_encoded_key` should be the certificate structure defined in
84
    /// [RFC 7250, section 3](https://datatracker.ietf.org/doc/html/rfc7250#section-3), which you
85
    /// might be able to parse with crates like
86
    /// [x509-cert](https://docs.rs/x509-cert/latest/x509_cert/index.html) and
87
    /// [spki](https://docs.rs/spki/0.7.3/spki/index.html) to obtain and match the
88
    /// SubjectPublicKeyInformation encoded within.
89
    ///
90
    /// See [the libcoap documentation](https://libcoap.net/doc/reference/4.3.5/group__dtls.html#gaef7a2800757a4922102311c94c3fa529)
91
    /// for more information.
92
    fn validate_rpk(&self, asn1_public_key: &[u8], session: &CoapSession, validated: bool) -> bool;
93
}
94

            
95
impl<T: Fn(&[u8], &CoapSession, bool) -> bool> RpkValidator for T {
96
    fn validate_rpk(&self, asn1_public_key: &[u8], session: &CoapSession, validated: bool) -> bool {
97
        self(asn1_public_key, session, validated)
98
    }
99
}
100

            
101
/// Key definition for a DTLS key consisting of a private and public key component without a signed
102
/// certificate.
103
///
104
/// # Note on key construction
105
///
106
/// For maximum compatibility, you should stick to the `with_*` constructors defined for this type.
107
/// While in theory you could use an arbitrary combination of key component types for a key
108
/// definition, those defined using `with_*` match explicit key types provided in libcoap and should
109
/// therefore always be supported.
110
#[derive(Clone, Debug)]
111
pub struct RpkKeyDef<PK: KeyComponent<Rpk>, SK: KeyComponent<Rpk>> {
112
    public_key: PK,
113
    private_key: SK,
114
    user_pin: Option<CString>,
115
    asn1_private_key_type: Asn1PrivateKeyType,
116
}
117

            
118
impl<PK: KeyComponent<Rpk>, SK: KeyComponent<Rpk>> RpkKeyDef<PK, SK> {
119
    /// Creates a new key definition using the given components.
120
    ///
121
    /// # Parameters
122
    ///
123
    /// - `public_key`:  The public key component of this key.
124
    /// - `private_key`: The private key.
125
    /// - `user_pin`:    The PIN that should be used when unlocking a token (for PKCS11 keys stored
126
    ///                  on a token, ignored otherwise)
127
    /// - `asn1_private_key_type`: The type of the private key (only used for DER/ASN.1 encoded
128
    ///                  keys).
129
4
    pub fn new(
130
4
        public_key: PK,
131
4
        private_key: SK,
132
4
        user_pin: Option<CString>,
133
4
        asn1_private_key_type: Asn1PrivateKeyType,
134
4
    ) -> Self {
135
4
        Self {
136
4
            public_key,
137
4
            private_key,
138
4
            user_pin,
139
4
            asn1_private_key_type,
140
4
        }
141
4
    }
142
}
143

            
144
impl RpkKeyDef<PemMemoryKeyComponent, PemMemoryKeyComponent> {
145
    /// Creates a new key definition using PEM-encoded byte sequences in memory as components.
146
    ///
147
    /// See the documentation of [`RpkKeyDef::new`] for more information on the parameters.
148
4
    pub fn with_pem_memory(
149
4
        public_key: impl Into<PemMemoryKeyComponent>,
150
4
        private_key: impl Into<PemMemoryKeyComponent>,
151
4
    ) -> Self {
152
4
        Self::new(public_key.into(), private_key.into(), None, Asn1PrivateKeyType::None)
153
4
    }
154
}
155

            
156
impl RpkKeyDef<Pkcs11KeyComponent, Pkcs11KeyComponent> {
157
    /// Creates a new key definition using PKCS11 URIs as components.
158
    ///
159
    /// See the documentation of [`RpkKeyDef::new`] for more information on the parameters.
160
    pub fn with_pkcs11(
161
        public_key: impl Into<Pkcs11KeyComponent>,
162
        private_key: impl Into<Pkcs11KeyComponent>,
163
        user_pin: Option<CString>,
164
    ) -> Self {
165
        Self::new(
166
            public_key.into(),
167
            private_key.into(),
168
            user_pin,
169
            Asn1PrivateKeyType::None,
170
        )
171
    }
172
}
173

            
174
impl<PK: KeyComponent<Rpk>, SK: KeyComponent<Rpk>> KeyDefSealed for RpkKeyDef<PK, SK> {
175
4
    fn as_raw_dtls_key(&self) -> coap_dtls_key_t {
176
4
        let (public_cert, public_cert_len) = self.public_key.as_raw_key_component();
177
4
        let (private_key, private_key_len) = self.private_key.as_raw_key_component();
178
4

            
179
4
        coap_dtls_key_t {
180
4
            key_type: coap_pki_key_t_COAP_PKI_KEY_DEFINE,
181
4
            key: coap_dtls_key_t__bindgen_ty_1 {
182
4
                define: coap_pki_key_define_t {
183
4
                    ca: coap_const_char_ptr_t {
184
4
                        u_byte: std::ptr::null(),
185
4
                    },
186
4
                    public_cert,
187
4
                    private_key,
188
4
                    ca_len: 0,
189
4
                    public_cert_len,
190
4
                    private_key_len,
191
4
                    ca_def: coap_pki_define_t_COAP_PKI_KEY_DEF_PEM,
192
4
                    public_cert_def: <PK as KeyComponentSealed<Rpk>>::DEFINE_TYPE,
193
4
                    private_key_def: <SK as KeyComponentSealed<Rpk>>::DEFINE_TYPE,
194
4
                    private_key_type: self.asn1_private_key_type.into(),
195
4
                    user_pin: self.user_pin.as_ref().map(|v| v.as_ptr()).unwrap_or(std::ptr::null()),
196
4
                },
197
4
            },
198
4
        }
199
4
    }
200
}
201

            
202
impl<PK: KeyComponent<Rpk>, SK: KeyComponent<Rpk>> KeyDef for RpkKeyDef<PK, SK> {
203
    type KeyType = Rpk;
204
}
205

            
206
impl KeyComponentSealed<Rpk> for PemMemoryKeyComponent {
207
    const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_RPK_BUF;
208
}
209

            
210
impl KeyComponentSealed<Rpk> for Pkcs11KeyComponent {
211
    const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_PKCS11_RPK;
212
}