foctet_net/tls/
verifier.rs

1//! TLS 1.3 certificates and handshakes handling for foctet
2//!
3//! This module handles a verification of a client/server certificate chain
4//! and signatures allegedly by the given certificates.
5
6use std::sync::Arc;
7
8use foctet_core::id::NodeId;
9use rustls::{
10    client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
11    crypto::ring::cipher_suite::{
12        TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256,
13    },
14    pki_types::{CertificateDer, ServerName, UnixTime},
15    server::danger::{ClientCertVerified, ClientCertVerifier},
16    CertificateError, DigitallySignedStruct, DistinguishedName, OtherError, SignatureScheme,
17    SupportedCipherSuite, SupportedProtocolVersion,
18};
19
20use crate::tls::cert;
21
22/// The protocol versions supported by this verifier.
23///
24/// The spec says:
25///
26/// > The foctet handshake uses TLS 1.3 (and higher).
27/// > Endpoints MUST NOT negotiate lower TLS versions.
28pub(crate) static PROTOCOL_VERSIONS: &[&SupportedProtocolVersion] = &[&rustls::version::TLS13];
29/// A list of the TLS 1.3 cipher suites supported by rustls.
30// By default rustls creates client/server configs with both
31// TLS 1.3 __and__ 1.2 cipher suites. But we don't need 1.2.
32pub(crate) static CIPHERSUITES: &[SupportedCipherSuite] = &[
33    // TLS1.3 suites
34    TLS13_CHACHA20_POLY1305_SHA256,
35    TLS13_AES_256_GCM_SHA384,
36    TLS13_AES_128_GCM_SHA256,
37];
38
39/// Implementation of the `rustls` certificate verification traits for foctet.
40///
41/// Only TLS 1.3 is supported. TLS 1.2 should be disabled in the configuration of `rustls`.
42#[derive(Debug)]
43pub(crate) struct FoctetCertificateVerifier {
44    /// The node ID we intend to connect to
45    remote_node_id: Option<NodeId>,
46}
47
48/// Foctet requires the following of X.509 server certificate chains:
49///
50/// - Exactly one certificate must be presented.
51/// - The certificate must be self-signed.
52/// - The certificate must have a valid foctet extension that includes a signature of its public
53///   key.
54impl FoctetCertificateVerifier {
55    pub(crate) fn new() -> Self {
56        Self {
57            remote_node_id: None,
58        }
59    }
60    pub(crate) fn with_remote_node_id(remote_node_id: Option<NodeId>) -> Self {
61        Self { remote_node_id }
62    }
63
64    /// Return the list of SignatureSchemes that this verifier will handle,
65    /// in `verify_tls12_signature` and `verify_tls13_signature` calls.
66    ///
67    /// This should be in priority order, with the most preferred first.
68    fn verification_schemes() -> Vec<SignatureScheme> {
69        vec![
70            // TODO SignatureScheme::ECDSA_NISTP521_SHA512 is not supported by `ring` yet
71            SignatureScheme::ECDSA_NISTP384_SHA384,
72            SignatureScheme::ECDSA_NISTP256_SHA256,
73            // TODO SignatureScheme::ED448 is not supported by `ring` yet
74            SignatureScheme::ED25519,
75            // In particular, RSA SHOULD NOT be used unless
76            // no elliptic curve algorithms are supported.
77            SignatureScheme::RSA_PSS_SHA512,
78            SignatureScheme::RSA_PSS_SHA384,
79            SignatureScheme::RSA_PSS_SHA256,
80            SignatureScheme::RSA_PKCS1_SHA512,
81            SignatureScheme::RSA_PKCS1_SHA384,
82            SignatureScheme::RSA_PKCS1_SHA256,
83        ]
84    }
85}
86
87impl ServerCertVerifier for FoctetCertificateVerifier {
88    fn verify_server_cert(
89        &self,
90        end_entity: &CertificateDer,
91        intermediates: &[CertificateDer],
92        _server_name: &rustls::pki_types::ServerName,
93        _ocsp_response: &[u8],
94        _now: rustls::pki_types::UnixTime,
95    ) -> Result<ServerCertVerified, rustls::Error> {
96        let node_id = verify_presented_certs(end_entity, intermediates)?;
97
98        if let Some(remote_node_id) = self.remote_node_id {
99            // The public host key allows the node to calculate the node ID of the node
100            // it is connecting to. Clients MUST verify that the node ID derived from
101            // the certificate matches the node ID they intended to connect to,
102            // and MUST abort the connection if there is a mismatch.
103            if remote_node_id != node_id {
104                return Err(rustls::Error::InvalidCertificate(
105                    CertificateError::ApplicationVerificationFailure,
106                ));
107            }
108        }
109
110        Ok(ServerCertVerified::assertion())
111    }
112
113    fn verify_tls12_signature(
114        &self,
115        _message: &[u8],
116        _cert: &CertificateDer,
117        _dss: &DigitallySignedStruct,
118    ) -> Result<HandshakeSignatureValid, rustls::Error> {
119        unreachable!("`PROTOCOL_VERSIONS` only allows TLS 1.3")
120    }
121
122    fn verify_tls13_signature(
123        &self,
124        message: &[u8],
125        cert: &CertificateDer,
126        dss: &DigitallySignedStruct,
127    ) -> Result<HandshakeSignatureValid, rustls::Error> {
128        verify_tls13_signature(cert, dss.scheme, message, dss.signature())
129    }
130
131    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
132        Self::verification_schemes()
133    }
134}
135
136/// Foctet requires the following of X.509 client certificate chains:
137///
138/// - Exactly one certificate must be presented. In particular, client authentication is mandatory
139///   in foctet.
140/// - The certificate must be self-signed.
141/// - The certificate must have a valid foctet extension that includes a signature of its public
142///   key.
143impl ClientCertVerifier for FoctetCertificateVerifier {
144    fn offer_client_auth(&self) -> bool {
145        true
146    }
147
148    fn root_hint_subjects(&self) -> &[DistinguishedName] {
149        &[]
150    }
151
152    fn verify_client_cert(
153        &self,
154        end_entity: &CertificateDer,
155        intermediates: &[CertificateDer],
156        _now: rustls::pki_types::UnixTime,
157    ) -> Result<ClientCertVerified, rustls::Error> {
158        verify_presented_certs(end_entity, intermediates)?;
159
160        Ok(ClientCertVerified::assertion())
161    }
162
163    fn verify_tls12_signature(
164        &self,
165        _message: &[u8],
166        _cert: &CertificateDer,
167        _dss: &DigitallySignedStruct,
168    ) -> Result<HandshakeSignatureValid, rustls::Error> {
169        unreachable!("`PROTOCOL_VERSIONS` only allows TLS 1.3")
170    }
171
172    fn verify_tls13_signature(
173        &self,
174        message: &[u8],
175        cert: &CertificateDer,
176        dss: &DigitallySignedStruct,
177    ) -> Result<HandshakeSignatureValid, rustls::Error> {
178        verify_tls13_signature(cert, dss.scheme, message, dss.signature())
179    }
180
181    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
182        Self::verification_schemes()
183    }
184}
185
186/// When receiving the certificate chain, an endpoint
187/// MUST check these conditions and abort the connection attempt if
188/// (a) the presented certificate is not yet valid, OR
189/// (b) if it is expired.
190/// Endpoints MUST abort the connection attempt if more than one certificate is received,
191/// or if the certificate’s self-signature is not valid.
192fn verify_presented_certs(
193    end_entity: &CertificateDer,
194    intermediates: &[CertificateDer],
195) -> Result<NodeId, rustls::Error> {
196    if !intermediates.is_empty() {
197        return Err(rustls::Error::General(
198            "foctet-tls requires exactly one certificate".into(),
199        ));
200    }
201
202    let cert = match cert::parse(end_entity) {
203        Ok(cert) => cert,
204        Err(_) => {
205            return Err(rustls::Error::InvalidCertificate(
206                CertificateError::BadEncoding,
207            ))
208        }
209    };
210
211    Ok(cert.node_id())
212}
213
214fn verify_tls13_signature(
215    cert: &CertificateDer,
216    signature_scheme: SignatureScheme,
217    message: &[u8],
218    signature: &[u8],
219) -> Result<HandshakeSignatureValid, rustls::Error> {
220    match cert::parse(cert)?.verify_signature(signature_scheme, message, signature) {
221        Ok(()) => {}
222        Err(_) => {
223            return Err(rustls::Error::InvalidCertificate(
224                CertificateError::BadSignature,
225            ))
226        }
227    }
228
229    Ok(HandshakeSignatureValid::assertion())
230}
231
232impl From<cert::ParseError> for rustls::Error {
233    fn from(cert::ParseError(e): cert::ParseError) -> Self {
234        use webpki::Error::*;
235        match e {
236            BadDer => rustls::Error::InvalidCertificate(CertificateError::BadEncoding),
237            e => {
238                rustls::Error::InvalidCertificate(CertificateError::Other(OtherError(Arc::new(e))))
239            }
240        }
241    }
242}
243impl From<cert::VerificationError> for rustls::Error {
244    fn from(cert::VerificationError(e): cert::VerificationError) -> Self {
245        use webpki::Error::*;
246        match e {
247            InvalidSignatureForPublicKey => {
248                rustls::Error::InvalidCertificate(CertificateError::BadSignature)
249            }
250            other => rustls::Error::InvalidCertificate(CertificateError::Other(OtherError(
251                Arc::new(other),
252            ))),
253        }
254    }
255}
256
257/// Dummy certificate verifier that treats any certificate as valid.
258/// NOTE, such verification is vulnerable to MITM attacks, but convenient for testing.
259#[derive(Debug)]
260pub struct SkipServerVerification(Arc<rustls::crypto::CryptoProvider>);
261
262impl SkipServerVerification {
263    #[allow(dead_code)]
264    pub fn new() -> Arc<Self> {
265        Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider())))
266    }
267}
268
269impl ServerCertVerifier for SkipServerVerification {
270    fn verify_server_cert(
271        &self,
272        _end_entity: &CertificateDer<'_>,
273        _intermediates: &[CertificateDer<'_>],
274        _server_name: &ServerName<'_>,
275        _ocsp: &[u8],
276        _now: UnixTime,
277    ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
278        Ok(rustls::client::danger::ServerCertVerified::assertion())
279    }
280
281    fn verify_tls12_signature(
282        &self,
283        message: &[u8],
284        cert: &CertificateDer<'_>,
285        dss: &rustls::DigitallySignedStruct,
286    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
287        rustls::crypto::verify_tls12_signature(
288            message,
289            cert,
290            dss,
291            &self.0.signature_verification_algorithms,
292        )
293    }
294
295    fn verify_tls13_signature(
296        &self,
297        message: &[u8],
298        cert: &CertificateDer<'_>,
299        dss: &rustls::DigitallySignedStruct,
300    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
301        rustls::crypto::verify_tls13_signature(
302            message,
303            cert,
304            dss,
305            &self.0.signature_verification_algorithms,
306        )
307    }
308
309    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
310        self.0.signature_verification_algorithms.supported_schemes()
311    }
312}