1
#![cfg_attr(docsrs, feature(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_time_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
#![allow(clippy::collapsible_if)] // See arti#2342
46
#![deny(clippy::unused_async)]
47
#![deny(clippy::string_slice)] // See arti#2571
48
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
49

            
50
mod err;
51
pub mod rsa;
52

            
53
#[cfg(feature = "x509")]
54
pub use tor_cert_x509 as x509;
55

            
56
use caret::caret_int;
57
use tor_bytes::{Error as BytesError, Result as BytesResult};
58
use tor_bytes::{Readable, Reader, Writeable, Writer};
59
use tor_llcrypto::pk::*;
60

            
61
use saturating_time::SaturatingTime;
62
use web_time_compat as time;
63

            
64
pub use err::CertError;
65

            
66
mod encode;
67
pub use encode::{EncodedCert, EncodedEd25519Cert};
68
pub use err::CertEncodeError;
69

            
70
/// A Result defined to use CertError
71
type CertResult<T> = std::result::Result<T, CertError>;
72

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

            
93
        /// Identity verifying a signing key, directly.
94
        IDENTITY_V_SIGNING = 0x04,
95

            
96
        /// Signing key verifying a TLS certificate by digest.
97
        SIGNING_V_TLS_CERT = 0x05,
98

            
99
        /// Signing key verifying a link authentication key.
100
        SIGNING_V_LINK_AUTH = 0x06,
101

            
102
        /// RSA identity key certifying an Ed25519 identity key. RSA
103
        /// crosscert format. (Legacy)
104
        RSA_ID_V_IDENTITY = 0x07,
105

            
106
        /// For onion services: short-term descriptor signing key
107
        /// (`KP_hs_desc_sign`), signed with blinded onion service identity
108
        /// (`KP_hs_blind_id`).
109
        HS_BLINDED_ID_V_SIGNING = 0x08,
110

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

            
127
        /// An ntor key converted to a ed25519 key, cross-certifying an
128
        /// identity key.
129
        NTOR_CC_IDENTITY = 0x0A,
130

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

            
141
        /// For relays: family key certifying membership of a relay
142
        /// by signing its identity.
143
        FAMILY_V_IDENTITY = 0x0C,
144
    }
145
}
146

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

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

            
169
/// Structure for an Ed25519-signed certificate as described in Tor's
170
/// cert-spec.txt.
171
#[derive(Debug, Clone, derive_builder::Builder)]
172
#[builder(build_fn(skip))]
173
pub struct Ed25519Cert {
174
    /// How many _hours_ after the epoch will this certificate expire?
175
    #[builder(setter(custom))]
176
    exp_hours: ExpiryHours,
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)] // TODO review CertExt and make it pub, and add a getter
183
    #[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
    #[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, PartialEq, Eq, derive_more::From)]
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
    #[from(skip)]
202
    RsaSha256Digest([u8; 32]),
203
    /// The SHA256 digest of an X.509 certificate.
204
    #[from(skip)]
205
    X509Sha256Digest([u8; 32]),
206
    /// Some unrecognized key type.
207
    #[from(skip)]
208
    Unrecognized(UnrecognizedKey),
209
}
210

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

            
220
impl CertifiedKey {
221
    /// Return the byte that identifies the type of this key.
222
39957
    pub fn key_type(&self) -> KeyType {
223
39957
        match self {
224
39470
            CertifiedKey::Ed25519(_) => KeyType::ED25519_KEY,
225
209
            CertifiedKey::RsaSha256Digest(_) => KeyType::SHA256_OF_RSA,
226
276
            CertifiedKey::X509Sha256Digest(_) => KeyType::SHA256_OF_X509,
227

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

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

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

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

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

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

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

            
333
impl Writeable for KeyUnknownCert {
334
4
    fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> Result<(), tor_bytes::EncodeError> {
335
4
        self.cert.write_onto(b)
336
4
    }
337
}
338

            
339
impl Readable for KeyUnknownCert {
340
1449
    fn take_from(r: &mut Reader<'_>) -> BytesResult<KeyUnknownCert> {
341
1449
        let b = r.take_rest();
342
1449
        Ed25519Cert::decode(b)
343
1449
    }
344
}
345

            
346
impl Ed25519Cert {
347
    /// Try to decode a certificate from a byte slice.
348
    ///
349
    /// This function returns an error if the byte slice is not
350
    /// completely exhausted.
351
    ///
352
    /// Note that the resulting KeyUnknownCertificate is not checked
353
    /// for validity at all: you will need to provide it with an expected
354
    /// signing key, then check it for timeliness and well-signedness.
355
27809
    pub fn decode(cert: &[u8]) -> BytesResult<KeyUnknownCert> {
356
27809
        let mut r = Reader::from_slice(cert);
357
27809
        let v = r.take_u8()?;
358
27809
        if v != 1 {
359
            // This would be something other than a "v1" certificate. We don't
360
            // understand those.
361
138
            return Err(BytesError::InvalidMessage(
362
138
                "Unrecognized certificate version".into(),
363
138
            ));
364
27671
        }
365
27671
        let cert_type = r.take_u8()?.into();
366
27671
        let exp_hours = r.extract()?;
367
27602
        let mut cert_key_type = r.take_u8()?.into();
368

            
369
        // This is a workaround for a tor bug: the key type is
370
        // wrong. It was fixed in tor#40124, which got merged into Tor
371
        // 0.4.5.x and later.
372
27602
        if cert_type == CertType::SIGNING_V_TLS_CERT && cert_key_type == KeyType::ED25519_KEY {
373
            cert_key_type = KeyType::SHA256_OF_X509;
374
27602
        }
375

            
376
27602
        let cert_key = CertifiedKey::from_reader(cert_key_type, &mut r)?;
377
27602
        let n_exts = r.take_u8()?;
378
27602
        let mut extensions = Vec::new();
379
27602
        for _ in 0..n_exts {
380
22149
            let e: CertExt = r.extract()?;
381
22011
            extensions.push(e);
382
        }
383

            
384
27464
        let sig_offset = r.consumed();
385
27464
        let signature: ed25519::Signature = r.extract()?;
386
27464
        r.should_be_exhausted()?;
387
        // See comment in `impl Writeable for UncheckedCert`.
388

            
389
27464
        let keyext = extensions
390
27464
            .iter()
391
27783
            .find(|e| e.ext_id() == ExtType::SIGNED_WITH_ED25519_KEY);
392

            
393
27464
        let included_pkey = match keyext {
394
22011
            Some(CertExt::SignedWithEd25519(s)) => Some(s.pk),
395
5453
            _ => None,
396
        };
397

            
398
27464
        Ok(KeyUnknownCert {
399
27464
            cert: UncheckedCert {
400
27464
                cert: Ed25519Cert {
401
27464
                    exp_hours,
402
27464
                    cert_type,
403
27464
                    cert_key,
404
27464
                    extensions,
405
27464

            
406
27464
                    signed_with: included_pkey,
407
27464
                },
408
27464
                text: cert[0..sig_offset].into(),
409
27464
                signature,
410
27464
            },
411
27464
        })
412
27809
    }
413

            
414
    /// Return the time at which this certificate becomes expired
415
26705
    pub fn expiry(&self) -> std::time::SystemTime {
416
26705
        self.exp_hours.into()
417
26705
    }
418

            
419
    /// Return true iff this certificate will be expired at the time `when`.
420
    ///
421
    /// This is inclusive, meaning that `when == self.expiry()` is still valid.
422
2348
    pub fn is_expired_at(&self, when: std::time::SystemTime) -> bool {
423
2348
        when > self.expiry()
424
2348
    }
425

            
426
    /// Return the signed key or object that is authenticated by this
427
    /// certificate.
428
17597
    pub fn subject_key(&self) -> &CertifiedKey {
429
17597
        &self.cert_key
430
17597
    }
431

            
432
    /// Return the ed25519 key that signed this certificate.
433
19667
    pub fn signing_key(&self) -> Option<&ed25519::Ed25519Identity> {
434
19667
        self.signed_with.as_ref()
435
19667
    }
436

            
437
    /// Return the type of this certificate.
438
899
    pub fn cert_type(&self) -> CertType {
439
899
        self.cert_type
440
899
    }
441
}
442

            
443
/// A parsed Ed25519 certificate. Maybe it includes its signing key;
444
/// maybe it doesn't.
445
///
446
/// To validate this cert, either it must contain its signing key,
447
/// or the caller must know the signing key.  In the first case, call
448
/// [`should_have_signing_key`](KeyUnknownCert::should_have_signing_key);
449
/// in the latter, call
450
/// [`should_be_signed_with`](KeyUnknownCert::should_be_signed_with).
451
#[derive(Clone, Debug)]
452
pub struct KeyUnknownCert {
453
    /// The certificate whose signing key might not be known.
454
    cert: UncheckedCert,
455
}
456

            
457
impl KeyUnknownCert {
458
    /// Return the certificate type of the underling cert.
459
25392
    pub fn peek_cert_type(&self) -> CertType {
460
25392
        self.cert.cert.cert_type
461
25392
    }
462
    /// Return subject key of the underlying cert.
463
4416
    pub fn peek_subject_key(&self) -> &CertifiedKey {
464
4416
        &self.cert.cert.cert_key
465
4416
    }
466

            
467
    /// Check whether a given pkey is (or might be) a key that has correctly
468
    /// signed this certificate.
469
    ///
470
    /// If pkey is None, this certificate must contain its signing key.
471
    ///
472
    /// On success, we can check whether the certificate is well-signed;
473
    /// otherwise, we can't check the certificate.
474
    #[deprecated(
475
        since = "0.7.1",
476
        note = "Use should_have_signing_key or should_be_signed_with instead."
477
    )]
478
    pub fn check_key(self, pkey: Option<&ed25519::Ed25519Identity>) -> CertResult<UncheckedCert> {
479
        match pkey {
480
            Some(wanted) => self.should_be_signed_with(wanted),
481
            None => self.should_have_signing_key(),
482
        }
483
    }
484

            
485
    /// Declare that this should be a self-contained certificate that contains its own
486
    /// signing key.
487
    ///
488
    /// On success, this certificate did indeed turn out to be self-contained, and so
489
    /// we can validate it.
490
    /// On failure, this certificate was not self-contained.
491
21597
    pub fn should_have_signing_key(self) -> CertResult<UncheckedCert> {
492
21597
        let real_key = match &self.cert.cert.signed_with {
493
21321
            Some(a) => *a,
494
276
            None => return Err(CertError::MissingPubKey),
495
        };
496

            
497
21321
        Ok(UncheckedCert {
498
21321
            cert: Ed25519Cert {
499
21321
                signed_with: Some(real_key),
500
21321
                ..self.cert.cert
501
21321
            },
502
21321
            ..self.cert
503
21321
        })
504
21597
    }
505

            
506
    /// Declare that this should be a certificate signed with a given key.
507
    ///
508
    /// On success, this certificate either listed the provided key, or did not
509
    /// list any key: in either case, we can validate it.
510
    /// On failure, this certificate claims to be signed with a different key.
511
4487
    pub fn should_be_signed_with(
512
4487
        self,
513
4487
        pkey: &ed25519::Ed25519Identity,
514
4487
    ) -> CertResult<UncheckedCert> {
515
4418
        let real_key = match &self.cert.cert.signed_with {
516
483
            Some(a) if a == pkey => *pkey,
517
4004
            None => *pkey,
518
69
            Some(_) => return Err(CertError::KeyMismatch),
519
        };
520

            
521
4418
        Ok(UncheckedCert {
522
4418
            cert: Ed25519Cert {
523
4418
                signed_with: Some(real_key),
524
4418
                ..self.cert.cert
525
4418
            },
526
4418
            ..self.cert
527
4418
        })
528
4487
    }
529
}
530

            
531
/// A certificate that has been parsed, but whose signature and
532
/// timeliness have not been checked.
533
#[derive(Debug, Clone)]
534
pub struct UncheckedCert {
535
    /// The parsed certificate, possibly modified by inserting an externally
536
    /// supplied key as its signing key.
537
    cert: Ed25519Cert,
538

            
539
    /// The signed text of the certificate. (Checking ed25519 signatures
540
    /// forces us to store this.
541
    // TODO(nickm)  It would be better to store a hash here, but we
542
    // don't have the right Ed25519 API.
543
    text: Vec<u8>,
544

            
545
    /// The alleged signature
546
    signature: ed25519::Signature,
547
}
548

            
549
/// A certificate that has been parsed and signature-checked, but whose
550
/// timeliness has not been checked.
551
#[derive(Debug, Clone)]
552
pub struct SigCheckedCert {
553
    /// The certificate that might or might not be timely
554
    cert: Ed25519Cert,
555
}
556

            
557
impl UncheckedCert {
558
    /// Split this unchecked cert into a component that assumes it has
559
    /// been checked, and a signature to validate.
560
23943
    pub fn dangerously_split(
561
23943
        self,
562
23943
    ) -> CertResult<(SigCheckedCert, ed25519::ValidatableEd25519Signature)> {
563
        use tor_checkable::SelfSigned;
564
23943
        let signing_key = self.cert.signed_with.ok_or(CertError::MissingPubKey)?;
565
23943
        let signing_key = signing_key
566
23943
            .try_into()
567
23943
            .map_err(|_| CertError::BadSignature)?;
568
23943
        let signature =
569
23943
            ed25519::ValidatableEd25519Signature::new(signing_key, self.signature, &self.text[..]);
570
23943
        Ok((self.dangerously_assume_wellsigned(), signature))
571
23943
    }
572

            
573
    /// Return subject key of the underlying cert.
574
5382
    pub fn peek_subject_key(&self) -> &CertifiedKey {
575
5382
        &self.cert.cert_key
576
5382
    }
577
    /// Return signing key of the underlying cert.
578
7245
    pub fn peek_signing_key(&self) -> &ed25519::Ed25519Identity {
579
7245
        self.cert
580
7245
            .signed_with
581
7245
            .as_ref()
582
7245
            .expect("Made an UncheckedCert without a signing key")
583
7245
    }
584
}
585

            
586
impl Writeable for UncheckedCert {
587
    // TODO in some sense this duplicates things in encode.rs.
588
    // However, encode.rs is not useable in type-driven (derive-based) situations,
589
    // because it uses entirely different types for encoding to those for decoding.
590
    //
591
    // Therefore, here we implement tor_bytes's encoding trait for the type which can
592
    // also be decoded.  Perhaps the encode module could be abolished.
593
4
    fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> Result<(), tor_bytes::EncodeError> {
594
        // Ed25519Cert::decode does a lot of work, which finds a lot of fields,
595
        // but also `sig_offset`.  It then splits the incoming byte buffer at `sig_offset`
596
        // into `text` and `signature`, insisting that there is nothing else.
597
        //
598
        // Therefore this is guaranteed to write precisely the input to `decode`.
599
4
        self.text.write_onto(b)?;
600
4
        self.signature.write_onto(b)?;
601
4
        Ok(())
602
4
    }
603
}
604

            
605
impl tor_checkable::SelfSigned<SigCheckedCert> for UncheckedCert {
606
    type Error = CertError;
607

            
608
1106
    fn is_well_signed(&self) -> CertResult<()> {
609
1106
        let pubkey = &self.cert.signed_with.ok_or(CertError::MissingPubKey)?;
610
1106
        let pubkey: ed25519::PublicKey = pubkey.try_into().map_err(|_| CertError::BadSignature)?;
611

            
612
1106
        pubkey
613
1106
            .verify(&self.text[..], &self.signature)
614
1106
            .map_err(|_| CertError::BadSignature)?;
615

            
616
1106
        Ok(())
617
1106
    }
618

            
619
25118
    fn dangerously_assume_wellsigned(self) -> SigCheckedCert {
620
25118
        SigCheckedCert { cert: self.cert }
621
25118
    }
622
}
623

            
624
impl tor_checkable::Timebound<Ed25519Cert> for Ed25519Cert {
625
    type Error = tor_checkable::TimeValidityError;
626

            
627
    #[allow(unstable_name_collisions)]
628
2348
    fn is_valid_at(&self, t: &time::SystemTime) -> Result<(), Self::Error> {
629
2348
        if self.is_expired_at(*t) {
630
207
            let expiry = self.expiry();
631
207
            Err(Self::Error::Expired(t.saturating_duration_since(expiry)))
632
        } else {
633
2141
            Ok(())
634
        }
635
2348
    }
636

            
637
24911
    fn dangerously_assume_timely(self) -> Ed25519Cert {
638
24911
        self
639
24911
    }
640
}
641

            
642
impl tor_checkable::Timebound<Ed25519Cert> for SigCheckedCert {
643
    type Error = tor_checkable::TimeValidityError;
644
2348
    fn is_valid_at(&self, t: &time::SystemTime) -> std::result::Result<(), Self::Error> {
645
2348
        self.cert.is_valid_at(t)
646
2348
    }
647

            
648
24911
    fn dangerously_assume_timely(self) -> Ed25519Cert {
649
24911
        self.cert.dangerously_assume_timely()
650
24911
    }
651
}
652

            
653
/// A certificate expiration time, represented in _hours_ since the unix epoch.
654
#[derive(Debug, Clone, Copy)]
655
struct ExpiryHours(u32);
656

            
657
/// The number of seconds in an hour.
658
const SEC_PER_HOUR: u64 = 3600;
659

            
660
impl From<ExpiryHours> for time::SystemTime {
661
41665
    fn from(value: ExpiryHours) -> Self {
662
        // TODO MSRV 1.91; use from_hours.
663
41665
        let d = std::time::Duration::from_secs(u64::from(value.0) * SEC_PER_HOUR);
664
41665
        std::time::SystemTime::UNIX_EPOCH + d
665
41665
    }
666
}
667

            
668
impl ExpiryHours {
669
    /// Return the earliest possible `ExpiryHours` that is no earlier than `expiry`.
670
47226
    fn try_from_systemtime_ceil(expiry: time::SystemTime) -> Result<Self, CertEncodeError> {
671
47226
        let d = expiry
672
47226
            .duration_since(time::SystemTime::UNIX_EPOCH)
673
47226
            .map_err(|_| CertEncodeError::InvalidExpiration)?;
674
47226
        let sec_ceil = d.as_secs() + if d.subsec_nanos() > 0 { 1 } else { 0 };
675
47226
        let hours = sec_ceil
676
47226
            .div_ceil(SEC_PER_HOUR)
677
47226
            .try_into()
678
47226
            .map_err(|_| CertEncodeError::InvalidExpiration)?;
679
47226
        Ok(ExpiryHours(hours))
680
47226
    }
681

            
682
    /// Return the latest possible ExpiryHours
683
    const fn max() -> Self {
684
        ExpiryHours(u32::MAX)
685
    }
686
}
687

            
688
impl Readable for ExpiryHours {
689
28294
    fn take_from(b: &mut Reader<'_>) -> BytesResult<Self> {
690
28294
        Ok(ExpiryHours(b.take_u32()?))
691
28294
    }
692
}
693

            
694
impl tor_bytes::Writeable for ExpiryHours {
695
40024
    fn write_onto<B: tor_bytes::Writer + ?Sized>(&self, b: &mut B) -> tor_bytes::EncodeResult<()> {
696
40024
        b.write_u32(self.0);
697
40024
        Ok(())
698
40024
    }
699
}
700

            
701
#[cfg(test)]
702
mod test {
703
    // @@ begin test lint list maintained by maint/add_warning @@
704
    #![allow(clippy::bool_assert_comparison)]
705
    #![allow(clippy::clone_on_copy)]
706
    #![allow(clippy::dbg_macro)]
707
    #![allow(clippy::mixed_attributes_style)]
708
    #![allow(clippy::print_stderr)]
709
    #![allow(clippy::print_stdout)]
710
    #![allow(clippy::single_char_pattern)]
711
    #![allow(clippy::unwrap_used)]
712
    #![allow(clippy::unchecked_time_subtraction)]
713
    #![allow(clippy::useless_vec)]
714
    #![allow(clippy::needless_pass_by_value)]
715
    #![allow(clippy::string_slice)] // See arti#2571
716
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
717
    use super::*;
718
    use hex_literal::hex;
719
    use web_time_compat::SystemTimeExt;
720

            
721
    #[test]
722
    fn parse_unrecognized_ext() -> BytesResult<()> {
723
        // case one: a flag is set but we don't know it
724
        let b = hex!("0009 99 10 657874656e73696f6e");
725
        let mut r = Reader::from_slice(&b);
726
        let e: CertExt = r.extract()?;
727
        r.should_be_exhausted()?;
728

            
729
        assert_eq!(e.ext_id(), 0x99.into());
730

            
731
        // case two: we've been told to ignore the cert if we can't
732
        // handle the extension.
733
        let b = hex!("0009 99 11 657874656e73696f6e");
734
        let mut r = Reader::from_slice(&b);
735
        let e: Result<CertExt, BytesError> = r.extract();
736
        assert!(e.is_err());
737
        assert_eq!(
738
            e.err().unwrap(),
739
            BytesError::InvalidMessage(
740
                "unrecognized certificate extension, with 'affects_validation' flag set.".into()
741
            )
742
        );
743

            
744
        Ok(())
745
    }
746

            
747
    #[test]
748
    fn certified_key() -> BytesResult<()> {
749
        let b =
750
            hex!("4c27616d6f757220756e6974206365757820717527656e636861c3ae6e616974206c6520666572");
751
        let mut r = Reader::from_slice(&b);
752

            
753
        let ck = CertifiedKey::from_reader(KeyType::SHA256_OF_RSA, &mut r)?;
754
        assert_eq!(ck.as_bytes(), &b[..32]);
755
        assert_eq!(ck.key_type(), KeyType::SHA256_OF_RSA);
756
        assert_eq!(r.remaining(), 7);
757

            
758
        let mut r = Reader::from_slice(&b);
759
        let ck = CertifiedKey::from_reader(42.into(), &mut r)?;
760
        assert_eq!(ck.as_bytes(), &b[..32]);
761
        assert_eq!(ck.key_type(), 42.into());
762
        assert_eq!(r.remaining(), 7);
763

            
764
        Ok(())
765
    }
766

            
767
    #[test]
768
    fn expiry_hours_ceil() {
769
        use std::time::{Duration, SystemTime};
770

            
771
        let now = SystemTime::get();
772
        let mut exp = now + Duration::from_secs(24 * 60 * 60);
773
        for _ in 0..=3600 {
774
            let eh = ExpiryHours::try_from_systemtime_ceil(exp).unwrap();
775
            assert!(SystemTime::from(eh) >= exp);
776
            assert!(SystemTime::from(eh) < exp + Duration::from_secs(SEC_PER_HOUR));
777

            
778
            exp += Duration::from_secs(1);
779
        }
780
    }
781
}