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
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
45

            
46
mod err;
47
pub mod rsa;
48

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

            
54
use std::time;
55

            
56
pub use err::CertError;
57

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
577
188
        Ok(())
578
188
    }
579

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

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

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

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

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

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

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

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

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

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

            
657
        Ok(())
658
    }
659

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

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

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

            
677
        Ok(())
678
    }
679
}