1
#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))]
2
#![doc = include_str!("../README.md")]
3
// @@ begin lint list maintained by maint/add_warning @@
4
#![allow(renamed_and_removed_lints)] // @@REMOVE_WHEN(ci_arti_stable)
5
#![allow(unknown_lints)] // @@REMOVE_WHEN(ci_arti_nightly)
6
#![warn(missing_docs)]
7
#![warn(noop_method_call)]
8
#![warn(unreachable_pub)]
9
#![warn(clippy::all)]
10
#![deny(clippy::await_holding_lock)]
11
#![deny(clippy::cargo_common_metadata)]
12
#![deny(clippy::cast_lossless)]
13
#![deny(clippy::checked_conversions)]
14
#![warn(clippy::cognitive_complexity)]
15
#![deny(clippy::debug_assert_with_mut_call)]
16
#![deny(clippy::exhaustive_enums)]
17
#![deny(clippy::exhaustive_structs)]
18
#![deny(clippy::expl_impl_clone_on_copy)]
19
#![deny(clippy::fallible_impl_from)]
20
#![deny(clippy::implicit_clone)]
21
#![deny(clippy::large_stack_arrays)]
22
#![warn(clippy::manual_ok_or)]
23
#![deny(clippy::missing_docs_in_private_items)]
24
#![warn(clippy::needless_borrow)]
25
#![warn(clippy::needless_pass_by_value)]
26
#![warn(clippy::option_option)]
27
#![deny(clippy::print_stderr)]
28
#![deny(clippy::print_stdout)]
29
#![warn(clippy::rc_buffer)]
30
#![deny(clippy::ref_option_ref)]
31
#![warn(clippy::semicolon_if_nothing_returned)]
32
#![warn(clippy::trait_duplication_in_bounds)]
33
#![deny(clippy::unchecked_duration_subtraction)]
34
#![deny(clippy::unnecessary_wraps)]
35
#![warn(clippy::unseparated_literal_suffix)]
36
#![deny(clippy::unwrap_used)]
37
#![deny(clippy::mod_module_files)]
38
#![allow(clippy::let_unit_value)] // This can reasonably be done for explicitness
39
#![allow(clippy::uninlined_format_args)]
40
#![allow(clippy::significant_drop_in_scrutinee)] // arti/-/merge_requests/588/#note_2812945
41
#![allow(clippy::result_large_err)] // temporary workaround for arti#587
42
#![allow(clippy::needless_raw_string_hashes)] // complained-about code is fine, often best
43
#![allow(clippy::needless_lifetimes)] // See arti#1765
44
#![allow(mismatched_lifetime_syntaxes)] // temporary workaround for arti#2060
45
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
46

            
47
mod err;
48
pub mod rsa;
49

            
50
use caret::caret_int;
51
use tor_bytes::{Error as BytesError, Result as BytesResult};
52
use tor_bytes::{Readable, Reader};
53
use tor_llcrypto::pk::*;
54

            
55
use std::time;
56

            
57
pub use err::CertError;
58

            
59
#[cfg(feature = "encode")]
60
mod encode;
61
#[cfg(feature = "encode")]
62
pub use encode::EncodedEd25519Cert;
63
#[cfg(feature = "encode")]
64
pub use err::CertEncodeError;
65

            
66
/// A Result defined to use CertError
67
type CertResult<T> = std::result::Result<T, CertError>;
68

            
69
caret_int! {
70
    /// Recognized values for Tor's certificate type field.
71
    ///
72
    /// In the names used here, "X_V_Y" means "key X verifying key Y",
73
    /// whereas "X_CC_Y" means "key X cross-certifying key Y".  In both
74
    /// cases, X is the key that is doing the signing, and Y is the key
75
    /// or object that is getting signed.
76
    ///
77
    /// Not every one of these types is valid for an Ed25519
78
    /// certificate.  Some are for X.509 certs in a CERTS cell; some
79
    /// are for RSA->Ed crosscerts in a CERTS cell.
80
    pub struct CertType(u8) {
81
        /// TLS link key, signed with RSA identity. X.509 format. (Obsolete)
82
        TLS_LINK_X509 = 0x01,
83
        /// Self-signed RSA identity certificate. X.509 format. (Legacy)
84
        RSA_ID_X509 = 0x02,
85
        /// RSA lnk authentication key signed with RSA identity
86
        /// key. X.509 format. (Obsolete)
87
        LINK_AUTH_X509 = 0x03,
88

            
89
        /// Identity verifying a signing key, directly.
90
        IDENTITY_V_SIGNING = 0x04,
91

            
92
        /// Signing key verifying a TLS certificate by digest.
93
        SIGNING_V_TLS_CERT = 0x05,
94

            
95
        /// Signing key verifying a link authentication key.
96
        SIGNING_V_LINK_AUTH = 0x06,
97

            
98
        /// RSA identity key certifying an Ed25519 identity key. RSA
99
        /// crosscert format. (Legacy)
100
        RSA_ID_V_IDENTITY = 0x07,
101

            
102
        /// For onion services: short-term descriptor signing key
103
        /// (`KP_hs_desc_sign`), signed with blinded onion service identity
104
        /// (`KP_hs_blind_id`).
105
        HS_BLINDED_ID_V_SIGNING = 0x08,
106

            
107
        /// For onion services: Introduction point authentication key
108
        /// (`KP_hs_ipt_sid`), signed with short term descriptor signing key
109
        /// (`KP_hs_desc_sign`).
110
        ///
111
        /// This one is, sadly, a bit complicated. In the original specification
112
        /// it was meant to be a cross-certificate, where the signature would be
113
        /// _on_ the descriptor signing key, _signed with_ the intro TID key.
114
        /// But we got it backwards in the C Tor implementation, and now, for
115
        /// compatibility, we are stuck doing it backwards in the future.
116
        ///
117
        /// If we find in the future that it is actually important to
118
        /// cross-certify these keys (as originally intended), then we should
119
        /// add a new certificate type, and put the new certificate in the onion
120
        /// service descriptor.
121
        HS_IP_V_SIGNING = 0x09,
122

            
123
        /// An ntor key converted to a ed25519 key, cross-certifying an
124
        /// identity key.
125
        NTOR_CC_IDENTITY = 0x0A,
126

            
127
        /// For onion services: Ntor encryption key (`KP_hss_ntor`),
128
        /// converted to ed25519, signed with the descriptor signing key
129
        /// (`KP_hs_desc_sign`).
130
        ///
131
        /// As with [`HS_IP_V_SIGNING`](CertType::HS_IP_V_SIGNING), this
132
        /// certificate type is backwards.  In the original specification it was
133
        /// meant to be a cross certificate, with the signing and signed keys
134
        /// reversed.
135
        HS_IP_CC_SIGNING = 0x0B,
136

            
137
        /// For relays: family key certifying membership of a relay
138
        /// by signing its identity.
139
        FAMILY_V_IDENTITY = 0x0C,
140
    }
141
}
142

            
143
caret_int! {
144
    /// Extension identifiers for extensions in certificates.
145
    pub struct ExtType(u8) {
146
        /// Extension indicating an Ed25519 key that signed this certificate.
147
        ///
148
        /// Certificates do not always contain the key that signed them.
149
        SIGNED_WITH_ED25519_KEY = 0x04,
150
    }
151
}
152

            
153
caret_int! {
154
    /// Identifiers for the type of key or object getting signed.
155
    pub struct KeyType(u8) {
156
        /// Identifier for an Ed25519 key.
157
        ED25519_KEY = 0x01,
158
        /// Identifier for the SHA256 of an DER-encoded RSA key.
159
        SHA256_OF_RSA = 0x02,
160
        /// Identifies the SHA256 of an X.509 certificate.
161
        SHA256_OF_X509 = 0x03,
162
    }
163
}
164

            
165
/// Structure for an Ed25519-signed certificate as described in Tor's
166
/// cert-spec.txt.
167
#[derive(Debug, Clone)]
168
#[cfg_attr(feature = "encode", derive(derive_builder::Builder))]
169
#[cfg_attr(
170
    feature = "encode",
171
    builder(name = "Ed25519CertConstructor", build_fn(skip))
172
)]
173
pub struct Ed25519Cert {
174
    /// How many _hours_ after the epoch will this certificate expire?
175
    #[cfg_attr(feature = "encode", builder(setter(custom)))]
176
    exp_hours: u32,
177
    /// Type of the certificate; recognized values are in certtype::*
178
    cert_type: CertType,
179
    /// The key or object being certified.
180
    cert_key: CertifiedKey,
181
    /// A list of extensions.
182
    #[allow(unused)]
183
    #[cfg_attr(feature = "encode", builder(setter(custom)))]
184
    extensions: Vec<CertExt>,
185
    /// The key that signed this cert.
186
    ///
187
    /// Once the cert has been unwrapped from an KeyUnknownCert, this field will
188
    /// be set.  If there is a `SignedWithEd25519` extension in
189
    /// `self.extensions`, this will match it.
190
    #[cfg_attr(feature = "encode", builder(setter(custom)))]
191
    signed_with: Option<ed25519::Ed25519Identity>,
192
}
193

            
194
/// One of the data types that can be certified by an Ed25519Cert.
195
#[derive(Debug, Clone)]
196
#[non_exhaustive]
197
pub enum CertifiedKey {
198
    /// An Ed25519 public key, signed directly.
199
    Ed25519(ed25519::Ed25519Identity),
200
    /// The SHA256 digest of a DER-encoded RsaPublicKey
201
    RsaSha256Digest([u8; 32]),
202
    /// The SHA256 digest of an X.509 certificate.
203
    X509Sha256Digest([u8; 32]),
204
    /// Some unrecognized key type.
205
    Unrecognized(UnrecognizedKey),
206
}
207

            
208
/// A key whose type we didn't recognize.
209
#[derive(Debug, Clone)]
210
pub struct UnrecognizedKey {
211
    /// Actual type of the key.
212
    key_type: KeyType,
213
    /// digest of the key, or the key itself.
214
    key_digest: [u8; 32],
215
}
216

            
217
impl CertifiedKey {
218
    /// Return the byte that identifies the type of this key.
219
32928
    pub fn key_type(&self) -> KeyType {
220
32928
        match self {
221
32862
            CertifiedKey::Ed25519(_) => KeyType::ED25519_KEY,
222
2
            CertifiedKey::RsaSha256Digest(_) => KeyType::SHA256_OF_RSA,
223
62
            CertifiedKey::X509Sha256Digest(_) => KeyType::SHA256_OF_X509,
224

            
225
2
            CertifiedKey::Unrecognized(u) => u.key_type,
226
        }
227
32928
    }
228
    /// Return the bytes that are used for the body of this certified
229
    /// key or object.
230
33486
    pub fn as_bytes(&self) -> &[u8] {
231
33486
        match self {
232
32800
            CertifiedKey::Ed25519(k) => k.as_bytes(),
233
2
            CertifiedKey::RsaSha256Digest(k) => &k[..],
234
682
            CertifiedKey::X509Sha256Digest(k) => &k[..],
235
2
            CertifiedKey::Unrecognized(u) => &u.key_digest[..],
236
        }
237
33486
    }
238
    /// If this is an Ed25519 public key, return Some(key).
239
    /// Otherwise, return None.
240
19778
    pub fn as_ed25519(&self) -> Option<&ed25519::Ed25519Identity> {
241
19778
        match self {
242
19654
            CertifiedKey::Ed25519(k) => Some(k),
243
124
            _ => None,
244
        }
245
19778
    }
246
    /// Try to extract a CertifiedKey from a Reader, given that we have
247
    /// already read its type as `key_type`.
248
19908
    fn from_reader(key_type: KeyType, r: &mut Reader<'_>) -> BytesResult<Self> {
249
19908
        Ok(match key_type {
250
19160
            KeyType::ED25519_KEY => CertifiedKey::Ed25519(r.extract()?),
251
2
            KeyType::SHA256_OF_RSA => CertifiedKey::RsaSha256Digest(r.extract()?),
252
744
            KeyType::SHA256_OF_X509 => CertifiedKey::X509Sha256Digest(r.extract()?),
253
            _ => CertifiedKey::Unrecognized(UnrecognizedKey {
254
2
                key_type,
255
2
                key_digest: r.extract()?,
256
            }),
257
        })
258
19908
    }
259
}
260

            
261
/// An extension in a Tor certificate.
262
#[derive(Debug, Clone)]
263
enum CertExt {
264
    /// Indicates which Ed25519 public key signed this cert.
265
    SignedWithEd25519(SignedWithEd25519Ext),
266
    /// An extension whose identity we don't recognize.
267
    Unrecognized(UnrecognizedExt),
268
}
269

            
270
/// Any unrecognized extension on a Tor certificate.
271
#[derive(Debug, Clone)]
272
#[allow(unused)]
273
struct UnrecognizedExt {
274
    /// True iff this extension must be understand in order to validate the
275
    /// certificate.
276
    affects_validation: bool,
277
    /// The type of the extension
278
    ext_type: ExtType,
279
    /// The body of the extension.
280
    body: Vec<u8>,
281
}
282

            
283
impl CertExt {
284
    /// Return the identifier code for this Extension.
285
15998
    fn ext_id(&self) -> ExtType {
286
15998
        match self {
287
15996
            CertExt::SignedWithEd25519(_) => ExtType::SIGNED_WITH_ED25519_KEY,
288
2
            CertExt::Unrecognized(u) => u.ext_type,
289
        }
290
15998
    }
291
}
292

            
293
/// Extension indicating that a key that signed a given certificate.
294
#[derive(Debug, Clone)]
295
struct SignedWithEd25519Ext {
296
    /// The key that signed the certificate including this extension.
297
    pk: ed25519::Ed25519Identity,
298
}
299

            
300
impl Readable for CertExt {
301
16126
    fn take_from(b: &mut Reader<'_>) -> BytesResult<Self> {
302
16126
        let len = b.take_u16()?;
303
16126
        let ext_type: ExtType = b.take_u8()?.into();
304
16126
        let flags = b.take_u8()?;
305
16126
        let body = b.take(len as usize)?;
306

            
307
16126
        Ok(match ext_type {
308
            ExtType::SIGNED_WITH_ED25519_KEY => CertExt::SignedWithEd25519(SignedWithEd25519Ext {
309
16059
                pk: ed25519::Ed25519Identity::from_bytes(body).ok_or_else(|| {
310
62
                    BytesError::InvalidMessage("wrong length on Ed25519 key".into())
311
63
                })?,
312
            }),
313
            _ => {
314
68
                if (flags & 1) != 0 {
315
64
                    return Err(BytesError::InvalidMessage(
316
64
                        "unrecognized certificate extension, with 'affects_validation' flag set."
317
64
                            .into(),
318
64
                    ));
319
4
                }
320
4
                CertExt::Unrecognized(UnrecognizedExt {
321
4
                    affects_validation: false,
322
4
                    ext_type,
323
4
                    body: body.into(),
324
4
                })
325
            }
326
        })
327
16126
    }
328
}
329

            
330
impl Ed25519Cert {
331
    /// Try to decode a certificate from a byte slice.
332
    ///
333
    /// This function returns an error if the byte slice is not
334
    /// completely exhausted.
335
    ///
336
    /// Note that the resulting KeyUnknownCertificate is not checked
337
    /// for validity at all: you will need to provide it with an expected
338
    /// signing key, then check it for timeliness and well-signedness.
339
20090
    pub fn decode(cert: &[u8]) -> BytesResult<KeyUnknownCert> {
340
20090
        let mut r = Reader::from_slice(cert);
341
20090
        let v = r.take_u8()?;
342
20090
        if v != 1 {
343
            // This would be something other than a "v1" certificate. We don't
344
            // understand those.
345
124
            return Err(BytesError::InvalidMessage(
346
124
                "Unrecognized certificate version".into(),
347
124
            ));
348
19966
        }
349
19966
        let cert_type = r.take_u8()?.into();
350
19966
        let exp_hours = r.take_u32()?;
351
19904
        let mut cert_key_type = r.take_u8()?.into();
352

            
353
        // This is a workaround for a tor bug: the key type is
354
        // wrong. It was fixed in tor#40124, which got merged into Tor
355
        // 0.4.5.x and later.
356
19904
        if cert_type == CertType::SIGNING_V_TLS_CERT && cert_key_type == KeyType::ED25519_KEY {
357
            cert_key_type = KeyType::SHA256_OF_X509;
358
19904
        }
359

            
360
19904
        let cert_key = CertifiedKey::from_reader(cert_key_type, &mut r)?;
361
19904
        let n_exts = r.take_u8()?;
362
19904
        let mut extensions = Vec::new();
363
19904
        for _ in 0..n_exts {
364
16120
            let e: CertExt = r.extract()?;
365
15996
            extensions.push(e);
366
        }
367

            
368
19780
        let sig_offset = r.consumed();
369
19780
        let signature: ed25519::Signature = r.extract()?;
370
19780
        r.should_be_exhausted()?;
371

            
372
19780
        let keyext = extensions
373
19780
            .iter()
374
20038
            .find(|e| e.ext_id() == ExtType::SIGNED_WITH_ED25519_KEY);
375

            
376
19780
        let included_pkey = match keyext {
377
15996
            Some(CertExt::SignedWithEd25519(s)) => Some(s.pk),
378
3784
            _ => None,
379
        };
380

            
381
19780
        Ok(KeyUnknownCert {
382
19780
            cert: UncheckedCert {
383
19780
                cert: Ed25519Cert {
384
19780
                    exp_hours,
385
19780
                    cert_type,
386
19780
                    cert_key,
387
19780
                    extensions,
388
19780

            
389
19780
                    signed_with: included_pkey,
390
19780
                },
391
19780
                text: cert[0..sig_offset].into(),
392
19780
                signature,
393
19780
            },
394
19780
        })
395
20090
    }
396

            
397
    /// Return the time at which this certificate becomes expired
398
19594
    pub fn expiry(&self) -> std::time::SystemTime {
399
19594
        let d = std::time::Duration::new(u64::from(self.exp_hours) * 3600, 0);
400
19594
        std::time::SystemTime::UNIX_EPOCH + d
401
19594
    }
402

            
403
    /// Return true iff this certificate will be expired at the time `when`.
404
1304
    pub fn is_expired_at(&self, when: std::time::SystemTime) -> bool {
405
1304
        when >= self.expiry()
406
1304
    }
407

            
408
    /// Return the signed key or object that is authenticated by this
409
    /// certificate.
410
12774
    pub fn subject_key(&self) -> &CertifiedKey {
411
12774
        &self.cert_key
412
12774
    }
413

            
414
    /// Return the ed25519 key that signed this certificate.
415
13890
    pub fn signing_key(&self) -> Option<&ed25519::Ed25519Identity> {
416
13890
        self.signed_with.as_ref()
417
13890
    }
418

            
419
    /// Return the type of this certificate.
420
188
    pub fn cert_type(&self) -> CertType {
421
188
        self.cert_type
422
188
    }
423
}
424

            
425
/// A parsed Ed25519 certificate. Maybe it includes its signing key;
426
/// maybe it doesn't.
427
///
428
/// To validate this cert, either it must contain its signing key,
429
/// or the caller must know the signing key.  In the first case, call
430
/// [`should_have_signing_key`](KeyUnknownCert::should_have_signing_key);
431
/// in the latter, call
432
/// [`should_be_signed_with`](KeyUnknownCert::should_be_signed_with).
433
#[derive(Clone, Debug)]
434
pub struct KeyUnknownCert {
435
    /// The certificate whose signing key might not be known.
436
    cert: UncheckedCert,
437
}
438

            
439
impl KeyUnknownCert {
440
    /// Return the certificate type of the underling cert.
441
19654
    pub fn peek_cert_type(&self) -> CertType {
442
19654
        self.cert.cert.cert_type
443
19654
    }
444
    /// Return subject key of the underlying cert.
445
3410
    pub fn peek_subject_key(&self) -> &CertifiedKey {
446
3410
        &self.cert.cert.cert_key
447
3410
    }
448

            
449
    /// Check whether a given pkey is (or might be) a key that has correctly
450
    /// signed this certificate.
451
    ///
452
    /// If pkey is None, this certificate must contain its signing key.
453
    ///
454
    /// On success, we can check whether the certificate is well-signed;
455
    /// otherwise, we can't check the certificate.
456
    #[deprecated(
457
        since = "0.7.1",
458
        note = "Use should_have_signing_key or should_be_signed_with instead."
459
    )]
460
    pub fn check_key(self, pkey: Option<&ed25519::Ed25519Identity>) -> CertResult<UncheckedCert> {
461
        match pkey {
462
            Some(wanted) => self.should_be_signed_with(wanted),
463
            None => self.should_have_signing_key(),
464
        }
465
    }
466

            
467
    /// Declare that this should be a self-contained certificate that contains its own
468
    /// signing key.
469
    ///
470
    /// On success, this certificate did indeed turn out to be self-contained, and so
471
    /// we can validate it.
472
    /// On failure, this certificate was not self-contained.
473
15810
    pub fn should_have_signing_key(self) -> CertResult<UncheckedCert> {
474
15810
        let real_key = match &self.cert.cert.signed_with {
475
15686
            Some(a) => *a,
476
124
            None => return Err(CertError::MissingPubKey),
477
        };
478

            
479
15686
        Ok(UncheckedCert {
480
15686
            cert: Ed25519Cert {
481
15686
                signed_with: Some(real_key),
482
15686
                ..self.cert.cert
483
15686
            },
484
15686
            ..self.cert
485
15686
        })
486
15810
    }
487

            
488
    /// Declare that this should be a certificate signed with a given key.
489
    ///
490
    /// On success, this certificate either listed the provided key, or did not
491
    /// list any key: in either case, we can validate it.
492
    /// On failure, this certificate claims to be signed with a different key.
493
3784
    pub fn should_be_signed_with(
494
3784
        self,
495
3784
        pkey: &ed25519::Ed25519Identity,
496
3784
    ) -> CertResult<UncheckedCert> {
497
3722
        let real_key = match &self.cert.cert.signed_with {
498
124
            Some(a) if a == pkey => *pkey,
499
3660
            None => *pkey,
500
62
            Some(_) => return Err(CertError::KeyMismatch),
501
        };
502

            
503
3722
        Ok(UncheckedCert {
504
3722
            cert: Ed25519Cert {
505
3722
                signed_with: Some(real_key),
506
3722
                ..self.cert.cert
507
3722
            },
508
3722
            ..self.cert
509
3722
        })
510
3784
    }
511
}
512

            
513
/// A certificate that has been parsed, but whose signature and
514
/// timeliness have not been checked.
515
#[derive(Debug, Clone)]
516
pub struct UncheckedCert {
517
    /// The parsed certificate, possibly modified by inserting an externally
518
    /// supplied key as its signing key.
519
    cert: Ed25519Cert,
520

            
521
    /// The signed text of the certificate. (Checking ed25519 signatures
522
    /// forces us to store this.
523
    // TODO(nickm)  It would be better to store a hash here, but we
524
    // don't have the right Ed25519 API.
525
    text: Vec<u8>,
526

            
527
    /// The alleged signature
528
    signature: ed25519::Signature,
529
}
530

            
531
/// A certificate that has been parsed and signature-checked, but whose
532
/// timeliness has not been checked.
533
pub struct SigCheckedCert {
534
    /// The certificate that might or might not be timely
535
    cert: Ed25519Cert,
536
}
537

            
538
impl UncheckedCert {
539
    /// Split this unchecked cert into a component that assumes it has
540
    /// been checked, and a signature to validate.
541
18414
    pub fn dangerously_split(
542
18414
        self,
543
18414
    ) -> CertResult<(SigCheckedCert, ed25519::ValidatableEd25519Signature)> {
544
        use tor_checkable::SelfSigned;
545
18414
        let signing_key = self.cert.signed_with.ok_or(CertError::MissingPubKey)?;
546
18414
        let signing_key = signing_key
547
18414
            .try_into()
548
18414
            .map_err(|_| CertError::BadSignature)?;
549
18414
        let signature =
550
18414
            ed25519::ValidatableEd25519Signature::new(signing_key, self.signature, &self.text[..]);
551
18414
        Ok((self.dangerously_assume_wellsigned(), signature))
552
18414
    }
553

            
554
    /// Return subject key of the underlying cert.
555
4464
    pub fn peek_subject_key(&self) -> &CertifiedKey {
556
4464
        &self.cert.cert_key
557
4464
    }
558
    /// Return signing key of the underlying cert.
559
9548
    pub fn peek_signing_key(&self) -> &ed25519::Ed25519Identity {
560
9548
        self.cert
561
9548
            .signed_with
562
9548
            .as_ref()
563
9548
            .expect("Made an UncheckedCert without a signing key")
564
9548
    }
565
}
566

            
567
impl tor_checkable::SelfSigned<SigCheckedCert> for UncheckedCert {
568
    type Error = CertError;
569

            
570
188
    fn is_well_signed(&self) -> CertResult<()> {
571
188
        let pubkey = &self.cert.signed_with.ok_or(CertError::MissingPubKey)?;
572
188
        let pubkey: ed25519::PublicKey = pubkey.try_into().map_err(|_| CertError::BadSignature)?;
573

            
574
188
        pubkey
575
188
            .verify(&self.text[..], &self.signature)
576
188
            .map_err(|_| CertError::BadSignature)?;
577

            
578
188
        Ok(())
579
188
    }
580

            
581
18664
    fn dangerously_assume_wellsigned(self) -> SigCheckedCert {
582
18664
        SigCheckedCert { cert: self.cert }
583
18664
    }
584
}
585

            
586
impl tor_checkable::Timebound<Ed25519Cert> for Ed25519Cert {
587
    type Error = tor_checkable::TimeValidityError;
588

            
589
1304
    fn is_valid_at(&self, t: &time::SystemTime) -> Result<(), Self::Error> {
590
1304
        if self.is_expired_at(*t) {
591
62
            let expiry = self.expiry();
592
62
            Err(Self::Error::Expired(
593
62
                t.duration_since(expiry)
594
62
                    .expect("certificate expiry time inconsistent"),
595
62
            ))
596
        } else {
597
1242
            Ok(())
598
        }
599
1304
    }
600

            
601
18602
    fn dangerously_assume_timely(self) -> Ed25519Cert {
602
18602
        self
603
18602
    }
604
}
605

            
606
impl tor_checkable::Timebound<Ed25519Cert> for SigCheckedCert {
607
    type Error = tor_checkable::TimeValidityError;
608
1304
    fn is_valid_at(&self, t: &time::SystemTime) -> std::result::Result<(), Self::Error> {
609
1304
        self.cert.is_valid_at(t)
610
1304
    }
611

            
612
18602
    fn dangerously_assume_timely(self) -> Ed25519Cert {
613
18602
        self.cert.dangerously_assume_timely()
614
18602
    }
615
}
616

            
617
#[cfg(test)]
618
mod test {
619
    // @@ begin test lint list maintained by maint/add_warning @@
620
    #![allow(clippy::bool_assert_comparison)]
621
    #![allow(clippy::clone_on_copy)]
622
    #![allow(clippy::dbg_macro)]
623
    #![allow(clippy::mixed_attributes_style)]
624
    #![allow(clippy::print_stderr)]
625
    #![allow(clippy::print_stdout)]
626
    #![allow(clippy::single_char_pattern)]
627
    #![allow(clippy::unwrap_used)]
628
    #![allow(clippy::unchecked_duration_subtraction)]
629
    #![allow(clippy::useless_vec)]
630
    #![allow(clippy::needless_pass_by_value)]
631
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
632
    use super::*;
633
    use hex_literal::hex;
634

            
635
    #[test]
636
    fn parse_unrecognized_ext() -> BytesResult<()> {
637
        // case one: a flag is set but we don't know it
638
        let b = hex!("0009 99 10 657874656e73696f6e");
639
        let mut r = Reader::from_slice(&b);
640
        let e: CertExt = r.extract()?;
641
        r.should_be_exhausted()?;
642

            
643
        assert_eq!(e.ext_id(), 0x99.into());
644

            
645
        // case two: we've been told to ignore the cert if we can't
646
        // handle the extension.
647
        let b = hex!("0009 99 11 657874656e73696f6e");
648
        let mut r = Reader::from_slice(&b);
649
        let e: Result<CertExt, BytesError> = r.extract();
650
        assert!(e.is_err());
651
        assert_eq!(
652
            e.err().unwrap(),
653
            BytesError::InvalidMessage(
654
                "unrecognized certificate extension, with 'affects_validation' flag set.".into()
655
            )
656
        );
657

            
658
        Ok(())
659
    }
660

            
661
    #[test]
662
    fn certified_key() -> BytesResult<()> {
663
        let b =
664
            hex!("4c27616d6f757220756e6974206365757820717527656e636861c3ae6e616974206c6520666572");
665
        let mut r = Reader::from_slice(&b);
666

            
667
        let ck = CertifiedKey::from_reader(KeyType::SHA256_OF_RSA, &mut r)?;
668
        assert_eq!(ck.as_bytes(), &b[..32]);
669
        assert_eq!(ck.key_type(), KeyType::SHA256_OF_RSA);
670
        assert_eq!(r.remaining(), 7);
671

            
672
        let mut r = Reader::from_slice(&b);
673
        let ck = CertifiedKey::from_reader(42.into(), &mut r)?;
674
        assert_eq!(ck.as_bytes(), &b[..32]);
675
        assert_eq!(ck.key_type(), 42.into());
676
        assert_eq!(r.remaining(), 7);
677

            
678
        Ok(())
679
    }
680
}