rustls/
verify.rs

1use sct;
2use std;
3use std::sync::Arc;
4use webpki;
5
6use crate::anchors::OwnedTrustAnchor;
7use crate::anchors::{DistinguishedNames, RootCertStore};
8use crate::error::TLSError;
9use crate::key::Certificate;
10#[cfg(feature = "logging")]
11use crate::log::{debug, trace, warn};
12use crate::msgs::enums::SignatureScheme;
13use crate::msgs::handshake::DigitallySignedStruct;
14use crate::msgs::handshake::SCTList;
15
16type SignatureAlgorithms = &'static [&'static webpki::SignatureAlgorithm];
17
18/// Which signature verification mechanisms we support.  No particular
19/// order.
20static SUPPORTED_SIG_ALGS: SignatureAlgorithms = &[
21    &webpki::ECDSA_P256_SHA256,
22    &webpki::ECDSA_P256_SHA384,
23    &webpki::ECDSA_P384_SHA256,
24    &webpki::ECDSA_P384_SHA384,
25    &webpki::ED25519,
26    &webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
27    &webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
28    &webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
29    &webpki::RSA_PKCS1_2048_8192_SHA256,
30    &webpki::RSA_PKCS1_2048_8192_SHA384,
31    &webpki::RSA_PKCS1_2048_8192_SHA512,
32    &webpki::RSA_PKCS1_3072_8192_SHA384,
33];
34
35/// Marker types.  These are used to bind the fact some verification
36/// (certificate chain or handshake signature) has taken place into
37/// protocol states.  We use this to have the compiler check that there
38/// are no 'goto fail'-style elisions of important checks before we
39/// reach the traffic stage.
40///
41/// These types are public, but cannot be directly constructed.  This
42/// means their origins can be precisely determined by looking
43/// for their `assertion` constructors.
44pub struct HandshakeSignatureValid(());
45impl HandshakeSignatureValid {
46    /// Make a `HandshakeSignatureValid`
47    pub fn assertion() -> Self {
48        Self { 0: () }
49    }
50}
51
52pub struct FinishedMessageVerified(());
53impl FinishedMessageVerified {
54    pub fn assertion() -> Self {
55        Self { 0: () }
56    }
57}
58
59/// Zero-sized marker type representing verification of a server cert chain.
60pub struct ServerCertVerified(());
61impl ServerCertVerified {
62    /// Make a `ServerCertVerified`
63    pub fn assertion() -> Self {
64        Self { 0: () }
65    }
66}
67
68/// Zero-sized marker type representing verification of a client cert chain.
69pub struct ClientCertVerified(());
70impl ClientCertVerified {
71    /// Make a `ClientCertVerified`
72    pub fn assertion() -> Self {
73        Self { 0: () }
74    }
75}
76
77/// Something that can verify a server certificate chain, and verify
78/// signatures made by certificates.
79pub trait ServerCertVerifier: Send + Sync {
80    /// Verify a the certificate chain `presented_certs` against the roots
81    /// configured in `roots`.  Make sure that `dns_name` is quoted by
82    /// the top certificate in the chain.
83    fn verify_server_cert(
84        &self,
85        roots: &RootCertStore,
86        presented_certs: &[Certificate],
87        dns_name: webpki::DNSNameRef,
88        ocsp_response: &[u8],
89    ) -> Result<ServerCertVerified, TLSError>;
90
91    /// Verify a signature allegedly by the given server certificate.
92    ///
93    /// `message` is not hashed, and needs hashing during the verification.
94    /// The signature and algorithm are within `dss`.  `cert` contains the
95    /// public key to use.
96    ///
97    /// `cert` is the same certificate that was previously validated by a
98    /// call to `verify_server_cert`.
99    ///
100    /// If and only if the signature is valid, return HandshakeSignatureValid.
101    /// Otherwise, return an error -- rustls will send an alert and abort the
102    /// connection.
103    ///
104    /// This method is only called for TLS1.2 handshakes.  Note that, in TLS1.2,
105    /// SignatureSchemes such as `SignatureScheme::ECDSA_NISTP256_SHA256` are not
106    /// in fact bound to the specific curve implied in their name.
107    ///
108    /// This trait method has a default implementation that uses webpki to verify
109    /// the signature.
110    fn verify_tls12_signature(
111        &self,
112        message: &[u8],
113        cert: &Certificate,
114        dss: &DigitallySignedStruct,
115    ) -> Result<HandshakeSignatureValid, TLSError> {
116        verify_signed_struct(message, cert, dss)
117    }
118
119
120    /// Verify a signature allegedly by the given server certificate.
121    ///
122    /// This method is only called for TLS1.3 handshakes.
123    ///
124    /// This method is very similar to `verify_tls12_signature`: but note the
125    /// tighter ECDSA SignatureScheme semantics -- eg `SignatureScheme::ECDSA_NISTP256_SHA256`
126    /// must only validate signatures using public keys on the right curve --
127    /// rustls does not enforce this requirement for you.
128    ///
129    /// This trait method has a default implementation that uses webpki to verify
130    /// the signature.
131    fn verify_tls13_signature(
132        &self,
133        message: &[u8],
134        cert: &Certificate,
135        dss: &DigitallySignedStruct,
136    ) -> Result<HandshakeSignatureValid, TLSError> {
137        verify_tls13(message, cert, dss)
138    }
139
140    /// Return the list of SignatureSchemes that this verifier will handle,
141    /// in `verify_tls12_signature` and `verify_tls13_signature` calls.
142    ///
143    /// This should be in priority order, with the most preferred first.
144    ///
145    /// This trait mehod has a default implementation that reflects the schemes
146    /// supported by webpki.
147    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
148        WebPKIVerifier::verification_schemes()
149    }
150}
151
152/// Something that can verify a client certificate chain
153pub trait ClientCertVerifier: Send + Sync {
154    /// Returns `true` to enable the server to request a client certificate and
155    /// `false` to skip requesting a client certificate. Defaults to `true`.
156    fn offer_client_auth(&self) -> bool {
157        true
158    }
159
160    /// Return `Some(true)` to require a client certificate and `Some(false)` to make
161    /// client authentication optional. Return `None` to abort the connection.
162    /// Defaults to `Some(self.offer_client_auth())`.
163    ///
164    /// `sni` is the server name quoted by the client in its ClientHello; it has
165    /// been validated as a proper DNS name but is otherwise untrusted.
166    fn client_auth_mandatory(&self, _sni: Option<&webpki::DNSName>) -> Option<bool> {
167        Some(self.offer_client_auth())
168    }
169
170    /// Returns the subject names of the client authentication trust anchors to
171    /// share with the client when requesting client authentication.
172    ///
173    /// Return `None` to abort the connection.
174    ///
175    /// `sni` is the server name quoted by the client in its ClientHello; it has
176    /// been validated as a proper DNS name but is otherwise untrusted.
177    fn client_auth_root_subjects(
178        &self,
179        sni: Option<&webpki::DNSName>,
180    ) -> Option<DistinguishedNames>;
181
182    /// Verify a certificate chain. `presented_certs` is the certificate chain from the client.
183    ///
184    /// `sni` is the server name quoted by the client in its ClientHello; it has
185    /// been validated as a proper DNS name but is otherwise untrusted.
186    fn verify_client_cert(
187        &self,
188        presented_certs: &[Certificate],
189        sni: Option<&webpki::DNSName>,
190    ) -> Result<ClientCertVerified, TLSError>;
191
192    /// Verify a signature allegedly by the given server certificate.
193    ///
194    /// `message` is not hashed, and needs hashing during the verification.
195    /// The signature and algorithm are within `dss`.  `cert` contains the
196    /// public key to use.
197    ///
198    /// `cert` is the same certificate that was previously validated by a
199    /// call to `verify_server_cert`.
200    ///
201    /// If and only if the signature is valid, return HandshakeSignatureValid.
202    /// Otherwise, return an error -- rustls will send an alert and abort the
203    /// connection.
204    ///
205    /// This method is only called for TLS1.2 handshakes.  Note that, in TLS1.2,
206    /// SignatureSchemes such as `SignatureScheme::ECDSA_NISTP256_SHA256` are not
207    /// in fact bound to the specific curve implied in their name.
208    ///
209    /// This trait method has a default implementation that uses webpki to verify
210    /// the signature.
211    fn verify_tls12_signature(
212        &self,
213        message: &[u8],
214        cert: &Certificate,
215        dss: &DigitallySignedStruct,
216    ) -> Result<HandshakeSignatureValid, TLSError> {
217        verify_signed_struct(message, cert, dss)
218    }
219
220
221    /// Verify a signature allegedly by the given server certificate.
222    ///
223    /// This method is only called for TLS1.3 handshakes.
224    ///
225    /// This method is very similar to `verify_tls12_signature`: but note the
226    /// tighter ECDSA SignatureScheme semantics -- eg `SignatureScheme::ECDSA_NISTP256_SHA256`
227    /// must only validate signatures using public keys on the right curve --
228    /// rustls does not enforce this requirement for you.
229    ///
230    /// This trait method has a default implementation that uses webpki to verify
231    /// the signature.
232    fn verify_tls13_signature(
233        &self,
234        message: &[u8],
235        cert: &Certificate,
236        dss: &DigitallySignedStruct,
237    ) -> Result<HandshakeSignatureValid, TLSError> {
238        verify_tls13(message, cert, dss)
239    }
240
241    /// Return the list of SignatureSchemes that this verifier will handle,
242    /// in `verify_tls12_signature` and `verify_tls13_signature` calls.
243    ///
244    /// This should be in priority order, with the most preferred first.
245    ///
246    /// This trait mehod has a default implementation that reflects the schemes
247    /// supported by webpki.
248    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
249        WebPKIVerifier::verification_schemes()
250    }
251}
252
253impl ServerCertVerifier for WebPKIVerifier {
254    /// Will verify the certificate is valid in the following ways:
255    /// - Signed by a  trusted `RootCertStore` CA
256    /// - Not Expired
257    /// - Valid for DNS entry
258    /// - OCSP data is present
259    fn verify_server_cert(
260        &self,
261        roots: &RootCertStore,
262        presented_certs: &[Certificate],
263        dns_name: webpki::DNSNameRef,
264        ocsp_response: &[u8],
265    ) -> Result<ServerCertVerified, TLSError> {
266        let (cert, chain, trustroots) = prepare(roots, presented_certs)?;
267        let now = (self.time)()?;
268        let cert = cert
269            .verify_is_valid_tls_server_cert(
270                SUPPORTED_SIG_ALGS,
271                &webpki::TLSServerTrustAnchors(&trustroots),
272                &chain,
273                now,
274            )
275            .map_err(TLSError::WebPKIError)
276            .map(|_| cert)?;
277
278        if !ocsp_response.is_empty() {
279            trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec());
280        }
281
282        cert.verify_is_valid_for_dns_name(dns_name)
283            .map_err(TLSError::WebPKIError)
284            .map(|_| ServerCertVerified::assertion())
285    }
286}
287
288/// Default `ServerCertVerifier`, see the trait impl for more information.
289pub struct WebPKIVerifier {
290    /// time provider
291    pub time: fn() -> Result<webpki::Time, TLSError>,
292}
293
294impl WebPKIVerifier {
295    /// Create a new `WebPKIVerifier`
296    pub fn new() -> WebPKIVerifier {
297        WebPKIVerifier { time: try_now }
298    }
299
300    /// Returns the signature verification methods supported by
301    /// webpki.
302    pub fn verification_schemes() -> Vec<SignatureScheme> {
303        vec![
304            SignatureScheme::ECDSA_NISTP384_SHA384,
305            SignatureScheme::ECDSA_NISTP256_SHA256,
306            SignatureScheme::ED25519,
307            SignatureScheme::RSA_PSS_SHA512,
308            SignatureScheme::RSA_PSS_SHA384,
309            SignatureScheme::RSA_PSS_SHA256,
310            SignatureScheme::RSA_PKCS1_SHA512,
311            SignatureScheme::RSA_PKCS1_SHA384,
312            SignatureScheme::RSA_PKCS1_SHA256,
313        ]
314    }
315}
316
317type CertChainAndRoots<'a, 'b> = (
318    webpki::EndEntityCert<'a>,
319    Vec<&'a [u8]>,
320    Vec<webpki::TrustAnchor<'b>>,
321);
322
323fn prepare<'a, 'b>(
324    roots: &'b RootCertStore,
325    presented_certs: &'a [Certificate],
326) -> Result<CertChainAndRoots<'a, 'b>, TLSError> {
327    if presented_certs.is_empty() {
328        return Err(TLSError::NoCertificatesPresented);
329    }
330
331    // EE cert must appear first.
332    let cert = webpki::EndEntityCert::from(&presented_certs[0].0).map_err(TLSError::WebPKIError)?;
333
334    let chain: Vec<&'a [u8]> = presented_certs
335        .iter()
336        .skip(1)
337        .map(|cert| cert.0.as_ref())
338        .collect();
339
340    let trustroots: Vec<webpki::TrustAnchor> = roots
341        .roots
342        .iter()
343        .map(OwnedTrustAnchor::to_trust_anchor)
344        .collect();
345
346    Ok((cert, chain, trustroots))
347}
348
349fn try_now() -> Result<webpki::Time, TLSError> {
350    webpki::Time::try_from(std::time::SystemTime::now())
351        .map_err(|_| TLSError::FailedToGetCurrentTime)
352}
353
354/// A `ClientCertVerifier` that will ensure that every client provides a trusted
355/// certificate, without any name checking.
356pub struct AllowAnyAuthenticatedClient {
357    roots: RootCertStore,
358}
359
360impl AllowAnyAuthenticatedClient {
361    /// Construct a new `AllowAnyAuthenticatedClient`.
362    ///
363    /// `roots` is the list of trust anchors to use for certificate validation.
364    pub fn new(roots: RootCertStore) -> Arc<dyn ClientCertVerifier> {
365        Arc::new(AllowAnyAuthenticatedClient { roots })
366    }
367}
368
369impl ClientCertVerifier for AllowAnyAuthenticatedClient {
370    fn offer_client_auth(&self) -> bool {
371        true
372    }
373
374    fn client_auth_mandatory(&self, _sni: Option<&webpki::DNSName>) -> Option<bool> {
375        Some(true)
376    }
377
378    fn client_auth_root_subjects(
379        &self,
380        _sni: Option<&webpki::DNSName>,
381    ) -> Option<DistinguishedNames> {
382        Some(self.roots.get_subjects())
383    }
384
385    fn verify_client_cert(
386        &self,
387        presented_certs: &[Certificate],
388        _sni: Option<&webpki::DNSName>,
389    ) -> Result<ClientCertVerified, TLSError> {
390        let (cert, chain, trustroots) = prepare(&self.roots, presented_certs)?;
391        let now = try_now()?;
392        cert.verify_is_valid_tls_client_cert(
393            SUPPORTED_SIG_ALGS,
394            &webpki::TLSClientTrustAnchors(&trustroots),
395            &chain,
396            now,
397        )
398        .map_err(TLSError::WebPKIError)
399        .map(|_| ClientCertVerified::assertion())
400    }
401}
402
403/// A `ClientCertVerifier` that will allow both anonymous and authenticated
404/// clients, without any name checking.
405///
406/// Client authentication will be requested during the TLS handshake. If the
407/// client offers a certificate then this acts like
408/// `AllowAnyAuthenticatedClient`, otherwise this acts like `NoClientAuth`.
409pub struct AllowAnyAnonymousOrAuthenticatedClient {
410    inner: AllowAnyAuthenticatedClient,
411}
412
413impl AllowAnyAnonymousOrAuthenticatedClient {
414    /// Construct a new `AllowAnyAnonymousOrAuthenticatedClient`.
415    ///
416    /// `roots` is the list of trust anchors to use for certificate validation.
417    pub fn new(roots: RootCertStore) -> Arc<dyn ClientCertVerifier> {
418        Arc::new(AllowAnyAnonymousOrAuthenticatedClient {
419            inner: AllowAnyAuthenticatedClient { roots },
420        })
421    }
422}
423
424impl ClientCertVerifier for AllowAnyAnonymousOrAuthenticatedClient {
425    fn offer_client_auth(&self) -> bool {
426        self.inner.offer_client_auth()
427    }
428
429    fn client_auth_mandatory(&self, _sni: Option<&webpki::DNSName>) -> Option<bool> {
430        Some(false)
431    }
432
433    fn client_auth_root_subjects(
434        &self,
435        sni: Option<&webpki::DNSName>,
436    ) -> Option<DistinguishedNames> {
437        self.inner
438            .client_auth_root_subjects(sni)
439    }
440
441    fn verify_client_cert(
442        &self,
443        presented_certs: &[Certificate],
444        sni: Option<&webpki::DNSName>,
445    ) -> Result<ClientCertVerified, TLSError> {
446        self.inner
447            .verify_client_cert(presented_certs, sni)
448    }
449}
450
451/// Turns off client authentication.
452pub struct NoClientAuth;
453
454impl NoClientAuth {
455    /// Constructs a `NoClientAuth` and wraps it in an `Arc`.
456    pub fn new() -> Arc<dyn ClientCertVerifier> {
457        Arc::new(NoClientAuth)
458    }
459}
460
461impl ClientCertVerifier for NoClientAuth {
462    fn offer_client_auth(&self) -> bool {
463        false
464    }
465
466    fn client_auth_root_subjects(
467        &self,
468        _sni: Option<&webpki::DNSName>,
469    ) -> Option<DistinguishedNames> {
470        unimplemented!();
471    }
472
473    fn verify_client_cert(
474        &self,
475        _presented_certs: &[Certificate],
476        _sni: Option<&webpki::DNSName>,
477    ) -> Result<ClientCertVerified, TLSError> {
478        unimplemented!();
479    }
480}
481
482static ECDSA_SHA256: SignatureAlgorithms =
483    &[&webpki::ECDSA_P256_SHA256, &webpki::ECDSA_P384_SHA256];
484
485static ECDSA_SHA384: SignatureAlgorithms =
486    &[&webpki::ECDSA_P256_SHA384, &webpki::ECDSA_P384_SHA384];
487
488static ED25519: SignatureAlgorithms = &[&webpki::ED25519];
489
490static RSA_SHA256: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA256];
491static RSA_SHA384: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA384];
492static RSA_SHA512: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA512];
493static RSA_PSS_SHA256: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY];
494static RSA_PSS_SHA384: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY];
495static RSA_PSS_SHA512: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY];
496
497fn convert_scheme(scheme: SignatureScheme) -> Result<SignatureAlgorithms, TLSError> {
498    match scheme {
499        // nb. for TLS1.2 the curve is not fixed by SignatureScheme.
500        SignatureScheme::ECDSA_NISTP256_SHA256 => Ok(ECDSA_SHA256),
501        SignatureScheme::ECDSA_NISTP384_SHA384 => Ok(ECDSA_SHA384),
502
503        SignatureScheme::ED25519 => Ok(ED25519),
504
505        SignatureScheme::RSA_PKCS1_SHA256 => Ok(RSA_SHA256),
506        SignatureScheme::RSA_PKCS1_SHA384 => Ok(RSA_SHA384),
507        SignatureScheme::RSA_PKCS1_SHA512 => Ok(RSA_SHA512),
508
509        SignatureScheme::RSA_PSS_SHA256 => Ok(RSA_PSS_SHA256),
510        SignatureScheme::RSA_PSS_SHA384 => Ok(RSA_PSS_SHA384),
511        SignatureScheme::RSA_PSS_SHA512 => Ok(RSA_PSS_SHA512),
512
513        _ => {
514            let error_msg = format!("received unadvertised sig scheme {:?}", scheme);
515            Err(TLSError::PeerMisbehavedError(error_msg))
516        }
517    }
518}
519
520fn verify_sig_using_any_alg(
521    cert: &webpki::EndEntityCert,
522    algs: SignatureAlgorithms,
523    message: &[u8],
524    sig: &[u8],
525) -> Result<(), webpki::Error> {
526    // TLS doesn't itself give us enough info to map to a single webpki::SignatureAlgorithm.
527    // Therefore, convert_algs maps to several and we try them all.
528    for alg in algs {
529        match cert.verify_signature(alg, message, sig) {
530            Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey) => continue,
531            res => return res,
532        }
533    }
534
535    Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey)
536}
537
538fn verify_signed_struct(
539    message: &[u8],
540    cert: &Certificate,
541    dss: &DigitallySignedStruct,
542) -> Result<HandshakeSignatureValid, TLSError> {
543    let possible_algs = convert_scheme(dss.scheme)?;
544    let cert = webpki::EndEntityCert::from(&cert.0).map_err(TLSError::WebPKIError)?;
545
546    verify_sig_using_any_alg(&cert, possible_algs, message, &dss.sig.0)
547        .map_err(TLSError::WebPKIError)
548        .map(|_| HandshakeSignatureValid::assertion())
549}
550
551fn convert_alg_tls13(
552    scheme: SignatureScheme,
553) -> Result<&'static webpki::SignatureAlgorithm, TLSError> {
554    use crate::msgs::enums::SignatureScheme::*;
555
556    match scheme {
557        ECDSA_NISTP256_SHA256 => Ok(&webpki::ECDSA_P256_SHA256),
558        ECDSA_NISTP384_SHA384 => Ok(&webpki::ECDSA_P384_SHA384),
559        ED25519 => Ok(&webpki::ED25519),
560        RSA_PSS_SHA256 => Ok(&webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY),
561        RSA_PSS_SHA384 => Ok(&webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY),
562        RSA_PSS_SHA512 => Ok(&webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY),
563        _ => {
564            let error_msg = format!("received unsupported sig scheme {:?}", scheme);
565            Err(TLSError::PeerMisbehavedError(error_msg))
566        }
567    }
568}
569
570/// Constructs the signature message specified in section 4.4.3 of RFC8446.
571pub fn construct_tls13_client_verify_message(handshake_hash: &[u8]) -> Vec<u8> {
572    construct_tls13_verify_message(handshake_hash, b"TLS 1.3, client CertificateVerify\x00")
573}
574
575/// Constructs the signature message specified in section 4.4.3 of RFC8446.
576pub fn construct_tls13_server_verify_message(handshake_hash: &[u8]) -> Vec<u8> {
577    construct_tls13_verify_message(handshake_hash, b"TLS 1.3, server CertificateVerify\x00")
578}
579
580fn construct_tls13_verify_message(handshake_hash: &[u8], context_string_with_0: &[u8]) -> Vec<u8> {
581    let mut msg = Vec::new();
582    msg.resize(64, 0x20u8);
583    msg.extend_from_slice(context_string_with_0);
584    msg.extend_from_slice(handshake_hash);
585    msg
586}
587
588fn verify_tls13(
589    msg: &[u8],
590    cert: &Certificate,
591    dss: &DigitallySignedStruct,
592) -> Result<HandshakeSignatureValid, TLSError> {
593    let alg = convert_alg_tls13(dss.scheme)?;
594
595
596    let cert = webpki::EndEntityCert::from(&cert.0).map_err(TLSError::WebPKIError)?;
597
598    cert.verify_signature(alg, &msg, &dss.sig.0)
599        .map_err(TLSError::WebPKIError)
600        .map(|_| HandshakeSignatureValid::assertion())
601}
602
603fn unix_time_millis() -> Result<u64, TLSError> {
604    std::time::SystemTime::now()
605        .duration_since(std::time::UNIX_EPOCH)
606        .map(|dur| dur.as_secs())
607        .map_err(|_| TLSError::FailedToGetCurrentTime)
608        .and_then(|secs| {
609            secs.checked_mul(1000)
610                .ok_or(TLSError::FailedToGetCurrentTime)
611        })
612}
613
614pub fn verify_scts(cert: &Certificate, scts: &SCTList, logs: &[&sct::Log]) -> Result<(), TLSError> {
615    let mut valid_scts = 0;
616    let now = unix_time_millis()?;
617    let mut last_sct_error = None;
618
619    for sct in scts {
620        #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
621        match sct::verify_sct(&cert.0, &sct.0, now, logs) {
622            Ok(index) => {
623                debug!(
624                    "Valid SCT signed by {} on {}",
625                    logs[index].operated_by, logs[index].description
626                );
627                valid_scts += 1;
628            }
629            Err(e) => {
630                if e.should_be_fatal() {
631                    return Err(TLSError::InvalidSCT(e));
632                }
633                debug!("SCT ignored because {:?}", e);
634                last_sct_error = Some(e);
635            }
636        }
637    }
638
639    /* If we were supplied with some logs, and some SCTs,
640     * but couldn't verify any of them, fail the handshake. */
641    if !logs.is_empty() && !scts.is_empty() && valid_scts == 0 {
642        warn!("No valid SCTs provided");
643        return Err(TLSError::InvalidSCT(last_sct_error.unwrap()));
644    }
645
646    Ok(())
647}