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

            
44
mod err;
45
pub mod rsa;
46

            
47
use caret::caret_int;
48
use tor_bytes::{Error as BytesError, Result as BytesResult};
49
use tor_bytes::{Readable, Reader};
50
use tor_llcrypto::pk::ed25519::Verifier as _;
51
use tor_llcrypto::pk::*;
52

            
53
use std::time;
54

            
55
pub use err::CertError;
56

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
211
impl CertifiedKey {
212
    /// Return the byte that identifies the type of this key.
213
26832
    pub fn key_type(&self) -> KeyType {
214
26832
        match self {
215
26777
            CertifiedKey::Ed25519(_) => KeyType::ED25519_KEY,
216
2
            CertifiedKey::RsaSha256Digest(_) => KeyType::SHA256_OF_RSA,
217
51
            CertifiedKey::X509Sha256Digest(_) => KeyType::SHA256_OF_X509,
218

            
219
2
            CertifiedKey::Unrecognized(u) => u.key_type,
220
        }
221
26832
    }
222
    /// Return the bytes that are used for the body of this certified
223
    /// key or object.
224
27291
    pub fn as_bytes(&self) -> &[u8] {
225
27291
        match self {
226
26726
            CertifiedKey::Ed25519(k) => k.as_bytes(),
227
2
            CertifiedKey::RsaSha256Digest(k) => &k[..],
228
561
            CertifiedKey::X509Sha256Digest(k) => &k[..],
229
2
            CertifiedKey::Unrecognized(u) => &u.key_digest[..],
230
        }
231
27291
    }
232
    /// If this is an Ed25519 public key, return Some(key).
233
    /// Otherwise, return None.
234
15249
    pub fn as_ed25519(&self) -> Option<&ed25519::Ed25519Identity> {
235
15249
        match self {
236
15147
            CertifiedKey::Ed25519(k) => Some(k),
237
102
            _ => None,
238
        }
239
15249
    }
240
    /// Try to extract a CertifiedKey from a Reader, given that we have
241
    /// already read its type as `key_type`.
242
15306
    fn from_reader(key_type: KeyType, r: &mut Reader<'_>) -> BytesResult<Self> {
243
15306
        Ok(match key_type {
244
14690
            KeyType::ED25519_KEY => CertifiedKey::Ed25519(r.extract()?),
245
2
            KeyType::SHA256_OF_RSA => CertifiedKey::RsaSha256Digest(r.extract()?),
246
612
            KeyType::SHA256_OF_X509 => CertifiedKey::X509Sha256Digest(r.extract()?),
247
            _ => CertifiedKey::Unrecognized(UnrecognizedKey {
248
2
                key_type,
249
2
                key_digest: r.extract()?,
250
            }),
251
        })
252
15306
    }
253
}
254

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

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

            
277
impl CertExt {
278
    /// Return the identifier code for this Extension.
279
12140
    fn ext_id(&self) -> ExtType {
280
12140
        match self {
281
12138
            CertExt::SignedWithEd25519(_) => ExtType::SIGNED_WITH_ED25519_KEY,
282
2
            CertExt::Unrecognized(u) => u.ext_type,
283
        }
284
12140
    }
285
}
286

            
287
/// Extension indicating that a key that signed a given certificate.
288
#[derive(Debug, Clone)]
289
struct SignedWithEd25519Ext {
290
    /// The key that signed the certificate including this extension.
291
    pk: ed25519::Ed25519Identity,
292
}
293

            
294
impl Readable for CertExt {
295
12246
    fn take_from(b: &mut Reader<'_>) -> BytesResult<Self> {
296
12246
        let len = b.take_u16()?;
297
12246
        let ext_type: ExtType = b.take_u8()?.into();
298
12246
        let flags = b.take_u8()?;
299
12246
        let body = b.take(len as usize)?;
300

            
301
12246
        Ok(match ext_type {
302
            ExtType::SIGNED_WITH_ED25519_KEY => CertExt::SignedWithEd25519(SignedWithEd25519Ext {
303
12190
                pk: ed25519::Ed25519Identity::from_bytes(body).ok_or_else(|| {
304
51
                    BytesError::InvalidMessage("wrong length on Ed25519 key".into())
305
12190
                })?,
306
            }),
307
            _ => {
308
57
                if (flags & 1) != 0 {
309
53
                    return Err(BytesError::InvalidMessage(
310
53
                        "unrecognized certificate extension, with 'affects_validation' flag set."
311
53
                            .into(),
312
53
                    ));
313
4
                }
314
4
                CertExt::Unrecognized(UnrecognizedExt {
315
4
                    affects_validation: false,
316
4
                    ext_type,
317
4
                    body: body.into(),
318
4
                })
319
            }
320
        })
321
12246
    }
322
}
323

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

            
347
15302
        // This is a workaround for a tor bug: the key type is
348
15302
        // wrong. It was fixed in tor#40124, which got merged into Tor
349
15302
        // 0.4.5.x and later.
350
15302
        if cert_type == CertType::SIGNING_V_TLS_CERT && cert_key_type == KeyType::ED25519_KEY {
351
            cert_key_type = KeyType::SHA256_OF_X509;
352
15302
        }
353

            
354
15302
        let cert_key = CertifiedKey::from_reader(cert_key_type, &mut r)?;
355
15302
        let n_exts = r.take_u8()?;
356
15302
        let mut extensions = Vec::new();
357
15302
        for _ in 0..n_exts {
358
12240
            let e: CertExt = r.extract()?;
359
12138
            extensions.push(e);
360
        }
361

            
362
15200
        let sig_offset = r.consumed();
363
15200
        let signature: ed25519::Signature = r.extract()?;
364
15200
        r.should_be_exhausted()?;
365

            
366
15200
        let keyext = extensions
367
15200
            .iter()
368
15438
            .find(|e| e.ext_id() == ExtType::SIGNED_WITH_ED25519_KEY);
369

            
370
15200
        let included_pkey = match keyext {
371
12138
            Some(CertExt::SignedWithEd25519(s)) => Some(s.pk),
372
3062
            _ => None,
373
        };
374

            
375
15200
        Ok(KeyUnknownCert {
376
15200
            cert: UncheckedCert {
377
15200
                cert: Ed25519Cert {
378
15200
                    exp_hours,
379
15200
                    cert_type,
380
15200
                    cert_key,
381
15200
                    extensions,
382
15200

            
383
15200
                    signed_with: included_pkey,
384
15200
                },
385
15200
                text: cert[0..sig_offset].into(),
386
15200
                signature,
387
15200
            },
388
15200
        })
389
15455
    }
390

            
391
    /// Return the time at which this certificate becomes expired
392
15047
    pub fn expiry(&self) -> std::time::SystemTime {
393
15047
        let d = std::time::Duration::new(u64::from(self.exp_hours) * 3600, 0);
394
15047
        std::time::SystemTime::UNIX_EPOCH + d
395
15047
    }
396

            
397
    /// Return true iff this certificate will be expired at the time `when`.
398
1073
    pub fn is_expired_at(&self, when: std::time::SystemTime) -> bool {
399
1073
        when >= self.expiry()
400
1073
    }
401

            
402
    /// Return the signed key or object that is authenticated by this
403
    /// certificate.
404
9641
    pub fn subject_key(&self) -> &CertifiedKey {
405
9641
        &self.cert_key
406
9641
    }
407

            
408
    /// Return the ed25519 key that signed this certificate.
409
10559
    pub fn signing_key(&self) -> Option<&ed25519::Ed25519Identity> {
410
10559
        self.signed_with.as_ref()
411
10559
    }
412

            
413
    /// Return the type of this certificate.
414
104
    pub fn cert_type(&self) -> CertType {
415
104
        self.cert_type
416
104
    }
417
}
418

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

            
433
impl KeyUnknownCert {
434
    /// Return the certificate type of the underling cert.
435
15147
    pub fn peek_cert_type(&self) -> CertType {
436
15147
        self.cert.cert.cert_type
437
15147
    }
438
    /// Return subject key of the underlying cert.
439
2652
    pub fn peek_subject_key(&self) -> &CertifiedKey {
440
2652
        &self.cert.cert.cert_key
441
2652
    }
442

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

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

            
473
11934
        Ok(UncheckedCert {
474
11934
            cert: Ed25519Cert {
475
11934
                signed_with: Some(real_key),
476
11934
                ..self.cert.cert
477
11934
            },
478
11934
            ..self.cert
479
11934
        })
480
12036
    }
481

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

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

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

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

            
521
    /// The alleged signature
522
    signature: ed25519::Signature,
523
}
524

            
525
/// A certificate that has been parsed and signature-checked, but whose
526
/// timeliness has not been checked.
527
pub struct SigCheckedCert {
528
    /// The certificate that might or might not be timely
529
    cert: Ed25519Cert,
530
}
531

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

            
548
    /// Return subject key of the underlying cert.
549
3621
    pub fn peek_subject_key(&self) -> &CertifiedKey {
550
3621
        &self.cert.cert_key
551
3621
    }
552
    /// Return signing key of the underlying cert.
553
7497
    pub fn peek_signing_key(&self) -> &ed25519::Ed25519Identity {
554
7497
        self.cert
555
7497
            .signed_with
556
7497
            .as_ref()
557
7497
            .expect("Made an UncheckedCert without a signing key")
558
7497
    }
559
}
560

            
561
impl tor_checkable::SelfSigned<SigCheckedCert> for UncheckedCert {
562
    type Error = CertError;
563

            
564
155
    fn is_well_signed(&self) -> CertResult<()> {
565
155
        let pubkey = &self.cert.signed_with.ok_or(CertError::MissingPubKey)?;
566
155
        let pubkey: ed25519::PublicKey = pubkey.try_into().map_err(|_| CertError::BadSignature)?;
567

            
568
155
        pubkey
569
155
            .verify(&self.text[..], &self.signature)
570
155
            .map_err(|_| CertError::BadSignature)?;
571

            
572
155
        Ok(())
573
155
    }
574

            
575
14282
    fn dangerously_assume_wellsigned(self) -> SigCheckedCert {
576
14282
        SigCheckedCert { cert: self.cert }
577
14282
    }
578
}
579

            
580
impl tor_checkable::Timebound<Ed25519Cert> for Ed25519Cert {
581
    type Error = tor_checkable::TimeValidityError;
582

            
583
1073
    fn is_valid_at(&self, t: &time::SystemTime) -> Result<(), Self::Error> {
584
1073
        if self.is_expired_at(*t) {
585
51
            let expiry = self.expiry();
586
51
            Err(Self::Error::Expired(
587
51
                t.duration_since(expiry)
588
51
                    .expect("certificate expiry time inconsistent"),
589
51
            ))
590
        } else {
591
1022
            Ok(())
592
        }
593
1073
    }
594

            
595
14231
    fn dangerously_assume_timely(self) -> Ed25519Cert {
596
14231
        self
597
14231
    }
598
}
599

            
600
impl tor_checkable::Timebound<Ed25519Cert> for SigCheckedCert {
601
    type Error = tor_checkable::TimeValidityError;
602
1073
    fn is_valid_at(&self, t: &time::SystemTime) -> std::result::Result<(), Self::Error> {
603
1073
        self.cert.is_valid_at(t)
604
1073
    }
605

            
606
14231
    fn dangerously_assume_timely(self) -> Ed25519Cert {
607
14231
        self.cert.dangerously_assume_timely()
608
14231
    }
609
}
610

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

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

            
637
        assert_eq!(e.ext_id(), 0x99.into());
638

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

            
652
        Ok(())
653
    }
654

            
655
    #[test]
656
    fn certified_key() -> BytesResult<()> {
657
        let b =
658
            hex!("4c27616d6f757220756e6974206365757820717527656e636861c3ae6e616974206c6520666572");
659
        let mut r = Reader::from_slice(&b);
660

            
661
        let ck = CertifiedKey::from_reader(KeyType::SHA256_OF_RSA, &mut r)?;
662
        assert_eq!(ck.as_bytes(), &b[..32]);
663
        assert_eq!(ck.key_type(), KeyType::SHA256_OF_RSA);
664
        assert_eq!(r.remaining(), 7);
665

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

            
672
        Ok(())
673
    }
674
}