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

            
47
mod err;
48
pub mod rsa;
49
#[cfg(feature = "x509")]
50
pub mod x509;
51

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

            
57
use std::time;
58

            
59
pub use err::CertError;
60

            
61
#[cfg(feature = "encode")]
62
mod encode;
63
#[cfg(feature = "encode")]
64
pub use encode::EncodedEd25519Cert;
65
#[cfg(feature = "encode")]
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)]
170
#[cfg_attr(feature = "encode", derive(derive_builder::Builder))]
171
#[cfg_attr(
172
    feature = "encode",
173
    builder(name = "Ed25519CertConstructor", build_fn(skip))
174
)]
175
pub struct Ed25519Cert {
176
    /// How many _hours_ after the epoch will this certificate expire?
177
    #[cfg_attr(feature = "encode", builder(setter(custom)))]
178
    exp_hours: u32,
179
    /// Type of the certificate; recognized values are in certtype::*
180
    cert_type: CertType,
181
    /// The key or object being certified.
182
    cert_key: CertifiedKey,
183
    /// A list of extensions.
184
    #[allow(unused)]
185
    #[cfg_attr(feature = "encode", builder(setter(custom)))]
186
    extensions: Vec<CertExt>,
187
    /// The key that signed this cert.
188
    ///
189
    /// Once the cert has been unwrapped from an KeyUnknownCert, this field will
190
    /// be set.  If there is a `SignedWithEd25519` extension in
191
    /// `self.extensions`, this will match it.
192
    #[cfg_attr(feature = "encode", builder(setter(custom)))]
193
    signed_with: Option<ed25519::Ed25519Identity>,
194
}
195

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

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

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

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

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

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

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

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

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

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

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

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

            
362
21188
        let cert_key = CertifiedKey::from_reader(cert_key_type, &mut r)?;
363
21188
        let n_exts = r.take_u8()?;
364
21188
        let mut extensions = Vec::new();
365
21188
        for _ in 0..n_exts {
366
17160
            let e: CertExt = r.extract()?;
367
17028
            extensions.push(e);
368
        }
369

            
370
21056
        let sig_offset = r.consumed();
371
21056
        let signature: ed25519::Signature = r.extract()?;
372
21056
        r.should_be_exhausted()?;
373

            
374
21056
        let keyext = extensions
375
21056
            .iter()
376
21314
            .find(|e| e.ext_id() == ExtType::SIGNED_WITH_ED25519_KEY);
377

            
378
21056
        let included_pkey = match keyext {
379
17028
            Some(CertExt::SignedWithEd25519(s)) => Some(s.pk),
380
4028
            _ => None,
381
        };
382

            
383
21056
        Ok(KeyUnknownCert {
384
21056
            cert: UncheckedCert {
385
21056
                cert: Ed25519Cert {
386
21056
                    exp_hours,
387
21056
                    cert_type,
388
21056
                    cert_key,
389
21056
                    extensions,
390
21056

            
391
21056
                    signed_with: included_pkey,
392
21056
                },
393
21056
                text: cert[0..sig_offset].into(),
394
21056
                signature,
395
21056
            },
396
21056
        })
397
21386
    }
398

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

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

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

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

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

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

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

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

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

            
481
16698
        Ok(UncheckedCert {
482
16698
            cert: Ed25519Cert {
483
16698
                signed_with: Some(real_key),
484
16698
                ..self.cert.cert
485
16698
            },
486
16698
            ..self.cert
487
16698
        })
488
16830
    }
489

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

            
505
3962
        Ok(UncheckedCert {
506
3962
            cert: Ed25519Cert {
507
3962
                signed_with: Some(real_key),
508
3962
                ..self.cert.cert
509
3962
            },
510
3962
            ..self.cert
511
3962
        })
512
4028
    }
513
}
514

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

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

            
529
    /// The alleged signature
530
    signature: ed25519::Signature,
531
}
532

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

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

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

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

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

            
576
200
        pubkey
577
200
            .verify(&self.text[..], &self.signature)
578
200
            .map_err(|_| CertError::BadSignature)?;
579

            
580
200
        Ok(())
581
200
    }
582

            
583
19868
    fn dangerously_assume_wellsigned(self) -> SigCheckedCert {
584
19868
        SigCheckedCert { cert: self.cert }
585
19868
    }
586
}
587

            
588
impl tor_checkable::Timebound<Ed25519Cert> for Ed25519Cert {
589
    type Error = tor_checkable::TimeValidityError;
590

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

            
603
19802
    fn dangerously_assume_timely(self) -> Ed25519Cert {
604
19802
        self
605
19802
    }
606
}
607

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

            
614
19802
    fn dangerously_assume_timely(self) -> Ed25519Cert {
615
19802
        self.cert.dangerously_assume_timely()
616
19802
    }
617
}
618

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

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

            
645
        assert_eq!(e.ext_id(), 0x99.into());
646

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

            
660
        Ok(())
661
    }
662

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

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

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

            
680
        Ok(())
681
    }
682
}