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

            
49
mod err;
50
pub mod rsa;
51

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

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

            
60
use web_time_compat as time;
61

            
62
pub use err::CertError;
63

            
64
mod encode;
65
pub use encode::{EncodedCert, EncodedEd25519Cert};
66
pub use err::CertEncodeError;
67

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

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

            
91
        /// Identity verifying a signing key, directly.
92
        IDENTITY_V_SIGNING = 0x04,
93

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

            
97
        /// Signing key verifying a link authentication key.
98
        SIGNING_V_LINK_AUTH = 0x06,
99

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
374
24980
        let cert_key = CertifiedKey::from_reader(cert_key_type, &mut r)?;
375
24980
        let n_exts = r.take_u8()?;
376
24980
        let mut extensions = Vec::new();
377
24980
        for _ in 0..n_exts {
378
21114
            let e: CertExt = r.extract()?;
379
20976
            extensions.push(e);
380
        }
381

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

            
387
24842
        let keyext = extensions
388
24842
            .iter()
389
25146
            .find(|e| e.ext_id() == ExtType::SIGNED_WITH_ED25519_KEY);
390

            
391
24842
        let included_pkey = match keyext {
392
20976
            Some(CertExt::SignedWithEd25519(s)) => Some(s.pk),
393
3866
            _ => None,
394
        };
395

            
396
24842
        Ok(KeyUnknownCert {
397
24842
            cert: UncheckedCert {
398
24842
                cert: Ed25519Cert {
399
24842
                    exp_hours,
400
24842
                    cert_type,
401
24842
                    cert_key,
402
24842
                    extensions,
403
24842

            
404
24842
                    signed_with: included_pkey,
405
24842
                },
406
24842
                text: cert[0..sig_offset].into(),
407
24842
                signature,
408
24842
            },
409
24842
        })
410
25187
    }
411

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

            
417
    /// Return true iff this certificate will be expired at the time `when`.
418
1382
    pub fn is_expired_at(&self, when: std::time::SystemTime) -> bool {
419
1382
        when >= self.expiry()
420
1382
    }
421

            
422
    /// Return the signed key or object that is authenticated by this
423
    /// certificate.
424
16976
    pub fn subject_key(&self) -> &CertifiedKey {
425
16976
        &self.cert_key
426
16976
    }
427

            
428
    /// Return the ed25519 key that signed this certificate.
429
19322
    pub fn signing_key(&self) -> Option<&ed25519::Ed25519Identity> {
430
19322
        self.signed_with.as_ref()
431
19322
    }
432

            
433
    /// Return the type of this certificate.
434
347
    pub fn cert_type(&self) -> CertType {
435
347
        self.cert_type
436
347
    }
437
}
438

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

            
453
impl KeyUnknownCert {
454
    /// Return the certificate type of the underling cert.
455
24426
    pub fn peek_cert_type(&self) -> CertType {
456
24426
        self.cert.cert.cert_type
457
24426
    }
458
    /// Return subject key of the underlying cert.
459
3795
    pub fn peek_subject_key(&self) -> &CertifiedKey {
460
3795
        &self.cert.cert.cert_key
461
3795
    }
462

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

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

            
493
20493
        Ok(UncheckedCert {
494
20493
            cert: Ed25519Cert {
495
20493
                signed_with: Some(real_key),
496
20493
                ..self.cert.cert
497
20493
            },
498
20493
            ..self.cert
499
20493
        })
500
20631
    }
501

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

            
517
3935
        Ok(UncheckedCert {
518
3935
            cert: Ed25519Cert {
519
3935
                signed_with: Some(real_key),
520
3935
                ..self.cert.cert
521
3935
            },
522
3935
            ..self.cert
523
3935
        })
524
4004
    }
525
}
526

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

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

            
541
    /// The alleged signature
542
    signature: ed25519::Signature,
543
}
544

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

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

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

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

            
601
impl tor_checkable::SelfSigned<SigCheckedCert> for UncheckedCert {
602
    type Error = CertError;
603

            
604
416
    fn is_well_signed(&self) -> CertResult<()> {
605
416
        let pubkey = &self.cert.signed_with.ok_or(CertError::MissingPubKey)?;
606
416
        let pubkey: ed25519::PublicKey = pubkey.try_into().map_err(|_| CertError::BadSignature)?;
607

            
608
416
        pubkey
609
416
            .verify(&self.text[..], &self.signature)
610
416
            .map_err(|_| CertError::BadSignature)?;
611

            
612
416
        Ok(())
613
416
    }
614

            
615
23600
    fn dangerously_assume_wellsigned(self) -> SigCheckedCert {
616
23600
        SigCheckedCert { cert: self.cert }
617
23600
    }
618
}
619

            
620
impl tor_checkable::Timebound<Ed25519Cert> for Ed25519Cert {
621
    type Error = tor_checkable::TimeValidityError;
622

            
623
1382
    fn is_valid_at(&self, t: &time::SystemTime) -> Result<(), Self::Error> {
624
1382
        if self.is_expired_at(*t) {
625
69
            let expiry = self.expiry();
626
69
            Err(Self::Error::Expired(
627
69
                t.duration_since(expiry)
628
69
                    .expect("certificate expiry time inconsistent"),
629
69
            ))
630
        } else {
631
1313
            Ok(())
632
        }
633
1382
    }
634

            
635
23531
    fn dangerously_assume_timely(self) -> Ed25519Cert {
636
23531
        self
637
23531
    }
638
}
639

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

            
646
23531
    fn dangerously_assume_timely(self) -> Ed25519Cert {
647
23531
        self.cert.dangerously_assume_timely()
648
23531
    }
649
}
650

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

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

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

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

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

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

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

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

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

            
726
        assert_eq!(e.ext_id(), 0x99.into());
727

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

            
741
        Ok(())
742
    }
743

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

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

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

            
761
        Ok(())
762
    }
763

            
764
    #[test]
765
    fn expiry_hours_ceil() {
766
        use std::time::{Duration, SystemTime};
767

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

            
775
            exp += Duration::from_secs(1);
776
        }
777
    }
778
}