1
1
//! Implementation for Tor certificates
2
//!
3
//! # Overview
4
//!
5
//! The `tor-cert` crate implements the binary certificate types
6
//! documented in Tor's cert-spec.txt, which are used when
7
//! authenticating Tor channels.  (Eventually, support for onion service
8
//! certificate support will get added too.)
9
//!
10
//! This crate is part of
11
//! [Arti](https://gitlab.torproject.org/tpo/core/arti/), a project to
12
//! implement [Tor](https://www.torproject.org/) in Rust.
13
//!
14
//! There are other types of certificate used by Tor as well, and they
15
//! are implemented in other places.  In particular, see
16
//! [`tor-netdoc::doc::authcert`] for the certificate types used by
17
//! authorities in the directory protocol.
18
//!
19
//! ## Design notes
20
//!
21
//! The `tor-cert` code is in its own separate crate because it is
22
//! required by several other higher-level crates that do not depend
23
//! upon each other.  For example, [`tor-netdoc`] parses encoded
24
//! certificates from router descriptors, while [`tor-proto`] uses
25
//! certificates when authenticating relays.
26
//!
27
//! # Examples
28
//!
29
//! Parsing, validating, and inspecting a certificate:
30
//!
31
//! ```
32
//! use base64::decode;
33
//! use tor_cert::*;
34
//! use tor_checkable::*;
35
//! // Taken from a random relay on the Tor network.
36
//! let cert_base64 =
37
//!  "AQQABrntAThPWJ4nFH1L77Ar+emd4GPXZTPUYzIwmR2H6Zod5TvXAQAgBAC+vzqh
38
//!   VFO1SGATubxcrZzrsNr+8hrsdZtyGg/Dde/TqaY1FNbeMqtAPMziWOd6txzShER4
39
//!   qc/haDk5V45Qfk6kjcKw+k7cPwyJeu+UF/azdoqcszHRnUHRXpiPzudPoA4=";
40
//! // Remove the whitespace, so base64 doesn't choke on it.
41
//! let cert_base64: String = cert_base64.split_whitespace().collect();
42
//! // Decode the base64.
43
//! let cert_bin = base64::decode(cert_base64).unwrap();
44
//!
45
//! // Decode the cert and check its signature.
46
//! let cert = Ed25519Cert::decode(&cert_bin).unwrap()
47
//!     .check_key(&None).unwrap()
48
//!     .check_signature().unwrap()
49
//!     .dangerously_assume_timely();
50
//! let signed_key = cert.subject_key();
51
//! ```
52

            
53
#![deny(missing_docs)]
54
#![warn(noop_method_call)]
55
#![deny(unreachable_pub)]
56
#![warn(clippy::all)]
57
#![deny(clippy::await_holding_lock)]
58
#![deny(clippy::cargo_common_metadata)]
59
#![deny(clippy::cast_lossless)]
60
#![deny(clippy::checked_conversions)]
61
#![warn(clippy::cognitive_complexity)]
62
#![deny(clippy::debug_assert_with_mut_call)]
63
#![deny(clippy::exhaustive_enums)]
64
#![deny(clippy::exhaustive_structs)]
65
#![deny(clippy::expl_impl_clone_on_copy)]
66
#![deny(clippy::fallible_impl_from)]
67
#![deny(clippy::implicit_clone)]
68
#![deny(clippy::large_stack_arrays)]
69
#![warn(clippy::manual_ok_or)]
70
#![deny(clippy::missing_docs_in_private_items)]
71
#![deny(clippy::missing_panics_doc)]
72
#![warn(clippy::needless_borrow)]
73
#![warn(clippy::needless_pass_by_value)]
74
#![warn(clippy::option_option)]
75
#![warn(clippy::rc_buffer)]
76
#![deny(clippy::ref_option_ref)]
77
#![warn(clippy::semicolon_if_nothing_returned)]
78
#![warn(clippy::trait_duplication_in_bounds)]
79
#![deny(clippy::unnecessary_wraps)]
80
#![warn(clippy::unseparated_literal_suffix)]
81
#![deny(clippy::unwrap_used)]
82

            
83
pub mod rsa;
84

            
85
use caret::caret_int;
86
use signature::Verifier;
87
use tor_bytes::{Error, Result};
88
use tor_bytes::{Readable, Reader};
89
use tor_llcrypto::pk::*;
90

            
91
use std::time;
92

            
93
caret_int! {
94
    /// Recognized values for Tor's certificate type field.
95
    ///
96
    /// In the names used here, "X_V_Y" means "key X verifying key Y",
97
    /// whereas "X_CC_Y" means "key X cross-certifying key Y".  In both
98
    /// cases, X is the key that is doing the signing, and Y is the key
99
    /// or object that is getting signed.
100
    ///
101
    /// Not every one of these types is valid for an Ed25519
102
    /// certificate.  Some are for X.509 certs in a CERTS cell; some
103
    /// are for RSA->Ed crosscerts in a CERTS cell.
104
    pub struct CertType(u8) {
105
        /// TLS link key, signed with RSA identity. X.509 format. (Obsolete)
106
        TLS_LINK_X509 = 0x01,
107
        /// Self-signed RSA identity certificate. X.509 format. (Legacy)
108
        RSA_ID_X509 = 0x02,
109
        /// RSA lnk authentication key signed with RSA identity
110
        /// key. X.509 format. (Obsolete)
111
        LINK_AUTH_X509 = 0x03,
112

            
113
        /// Identity verifying a signing key, directly.
114
        IDENTITY_V_SIGNING = 0x04,
115

            
116
        /// Signing key verifying a TLS certificate by digest.
117
        SIGNING_V_TLS_CERT = 0x05,
118

            
119
        /// Signing key verifying a link authentication key.
120
        SIGNING_V_LINK_AUTH = 0x06,
121

            
122
        /// RSA identity key certifying an Ed25519 identity key. RSA
123
        /// crosscert format. (Legacy)
124
        RSA_ID_V_IDENTITY = 0x07,
125

            
126
        /// For onion services: short-term signing key authenticated with
127
        /// blinded service identity.
128
        HS_BLINDED_ID_V_SIGNING = 0x08,
129

            
130
        /// For onion services: to be documented.
131
        HS_IP_V_SIGNING = 0x09,
132

            
133
        /// An ntor key converted to a ed25519 key, cross-certifying an
134
        /// identity key.
135
        NTOR_CC_IDENTITY = 0x0A,
136

            
137
        /// For onion services: to be documented.
138
        HS_IP_CC_SIGNING = 0x0B,
139
    }
140
}
141

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

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

            
162
        // 08 through 09 and 0B are used for onion services.  They
163
        // probably shouldn't be, but that's what Tor does.
164
    }
165
}
166

            
167
/// Structure for an Ed25519-signed certificate as described in Tor's
168
/// cert-spec.txt.
169
pub struct Ed25519Cert {
170
    /// How many _hours_ after the epoch will this certificate expire?
171
    exp_hours: u32,
172
    /// Type of the certificate; recognized values are in certtype::*
173
    cert_type: CertType,
174
    /// The key or object being certified.
175
    cert_key: CertifiedKey,
176
    /// A list of extensions.
177
    #[allow(unused)]
178
    extensions: Vec<CertExt>,
179
    /// The key that signed this cert.
180
    ///
181
    /// Once the cert has been unwrapped from an KeyUnknownCert, this
182
    /// field will be set.
183
    signed_with: Option<ed25519::PublicKey>,
184
}
185

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

            
199
/// A key whose type we didn't recognize.
200
pub struct UnrecognizedKey {
201
    /// Actual type of the key.
202
    key_type: KeyType,
203
    /// digest of the key, or the key itself.
204
    key_digest: [u8; 32],
205
}
206

            
207
impl CertifiedKey {
208
    /// Return the byte that identifies the type of this key.
209
54
    pub fn key_type(&self) -> KeyType {
210
54
        match self {
211
26
            CertifiedKey::Ed25519(_) => KeyType::ED25519_KEY,
212
1
            CertifiedKey::RsaSha256Digest(_) => KeyType::SHA256_OF_RSA,
213
26
            CertifiedKey::X509Sha256Digest(_) => KeyType::SHA256_OF_X509,
214

            
215
1
            CertifiedKey::Unrecognized(u) => u.key_type,
216
        }
217
54
    }
218
    /// Return the bytes that are used for the body of this certified
219
    /// key or object.
220
262
    pub fn as_bytes(&self) -> &[u8] {
221
262
        match self {
222
            CertifiedKey::Ed25519(k) => k.as_bytes(),
223
1
            CertifiedKey::RsaSha256Digest(k) => &k[..],
224
260
            CertifiedKey::X509Sha256Digest(k) => &k[..],
225
1
            CertifiedKey::Unrecognized(u) => &u.key_digest[..],
226
        }
227
262
    }
228
    /// If this is an Ed25519 public key, return Some(key).
229
    /// Otherwise, return None.
230
624
    pub fn as_ed25519(&self) -> Option<&ed25519::PublicKey> {
231
624
        match self {
232
598
            CertifiedKey::Ed25519(k) => Some(k),
233
26
            _ => None,
234
        }
235
624
    }
236
    /// Try to extract a CertifiedKey from a Reader, given that we have
237
    /// already read its type as `key_type`.
238
990
    fn from_reader(key_type: KeyType, r: &mut Reader<'_>) -> Result<Self> {
239
990
        Ok(match key_type {
240
728
            KeyType::ED25519_KEY => CertifiedKey::Ed25519(r.extract()?),
241
1
            KeyType::SHA256_OF_RSA => CertifiedKey::RsaSha256Digest(r.extract()?),
242
260
            KeyType::SHA256_OF_X509 => CertifiedKey::X509Sha256Digest(r.extract()?),
243
            _ => CertifiedKey::Unrecognized(UnrecognizedKey {
244
1
                key_type,
245
1
                key_digest: r.extract()?,
246
            }),
247
        })
248
990
    }
249
}
250

            
251
/// An extension in a Tor certificate.
252
enum CertExt {
253
    /// Indicates which Ed25519 public key signed this cert.
254
    SignedWithEd25519(SignedWithEd25519Ext),
255
    /// An extension whose identity we don't recognize.
256
    Unrecognized(UnrecognizedExt),
257
}
258

            
259
/// Any unrecognized extension on a Tor certificate.
260
#[allow(unused)]
261
struct UnrecognizedExt {
262
    /// True iff this extension must be understand in order to validate the
263
    /// certificate.
264
    affects_validation: bool,
265
    /// The type of the extension
266
    ext_type: ExtType,
267
    /// The body of the extension.
268
    body: Vec<u8>,
269
}
270

            
271
impl CertExt {
272
    /// Return the identifier code for this Extension.
273
547
    fn ext_id(&self) -> ExtType {
274
547
        match self {
275
546
            CertExt::SignedWithEd25519(_) => ExtType::SIGNED_WITH_ED25519_KEY,
276
1
            CertExt::Unrecognized(u) => u.ext_type,
277
        }
278
547
    }
279
}
280

            
281
/*
282
impl Writeable for CertExt {
283
    fn write_onto<B: Writer + ?Sized>(&self, w: &mut B) {
284
        match self {
285
            CertExt::SignedWithEd25519(pk) => pk.write_onto(w),
286
            CertExt::Unrecognized(u) => u.write_onto(w),
287
        }
288
    }
289
}
290
 */
291

            
292
/// Extension indicating that a key that signed a given certificate.
293
struct SignedWithEd25519Ext {
294
    /// The key that signed the certificate including this extension.
295
    pk: ed25519::PublicKey,
296
}
297

            
298
/*
299
impl Writeable for SignedWithEd25519Ext {
300
    fn write_onto<B: Writer + ?Sized>(&self, w: &mut B) {
301
        // body length
302
        w.write_u16(32);
303
        // Signed-with-ed25519-key-extension
304
        w.write_u8(ExtType::SIGNED_WITH_ED25519_KEY.into());
305
        // flags = 0.
306
        w.write_u8(0);
307
        // body
308
        w.write_all(self.pk.as_bytes());
309
    }
310
}
311
*/
312

            
313
/*
314
impl UnrecognizedExt {
315
    /// Assert that there is no problem with the internal representation
316
    /// of this object.
317
    fn assert_rep_ok(&self) {
318
        assert!(self.body.len() <= std::u16::MAX as usize);
319
    }
320
}
321
*/
322

            
323
/*
324
impl Writeable for UnrecognizedExt {
325
    fn write_onto<B: Writer + ?Sized>(&self, w: &mut B) {
326
        self.assert_rep_ok();
327
        w.write_u16(self.body.len() as u16);
328
        w.write_u8(self.ext_type.into());
329
        let flags = if self.affects_validation { 1 } else { 0 };
330
        w.write_u8(flags);
331
        w.write_all(&self.body[..]);
332
    }
333
}
334
*/
335

            
336
impl Readable for CertExt {
337
600
    fn take_from(b: &mut Reader<'_>) -> Result<Self> {
338
600
        let len = b.take_u16()?;
339
600
        let ext_type: ExtType = b.take_u8()?.into();
340
600
        let flags = b.take_u8()?;
341
600
        let body = b.take(len as usize)?;
342

            
343
600
        Ok(match ext_type {
344
            ExtType::SIGNED_WITH_ED25519_KEY => {
345
572
                if body.len() != 32 {
346
26
                    return Err(Error::BadMessage("wrong length on Ed25519 key"));
347
546
                }
348
546
                CertExt::SignedWithEd25519(SignedWithEd25519Ext {
349
546
                    pk: ed25519::PublicKey::from_bytes(body)
350
546
                        .map_err(|_| Error::BadMessage("invalid Ed25519 public key"))?,
351
                })
352
            }
353
            _ => {
354
28
                if (flags & 1) != 0 {
355
27
                    return Err(Error::BadMessage(
356
27
                        "unrecognized certificate extension, with 'affects_validation' flag set.",
357
27
                    ));
358
1
                }
359
1
                CertExt::Unrecognized(UnrecognizedExt {
360
1
                    affects_validation: false,
361
1
                    ext_type,
362
1
                    body: body.into(),
363
1
                })
364
            }
365
        })
366
574
    }
367
}
368

            
369
impl Ed25519Cert {
370
    /*
371
        /// Helper: Assert that there is nothing wrong with the
372
        /// internal structure of this certificate.
373
        fn assert_rep_ok(&self) {
374
            assert!(self.extensions.len() <= std::u8::MAX as usize);
375
        }
376

            
377
        /// Encode a certificate into a new vector, signing the result
378
        /// with `keypair`.
379
        pub fn encode_and_sign(&self, skey: &ed25519::Keypair) -> Vec<u8> {
380
            self.assert_rep_ok();
381
            let mut w = Vec::new();
382
            w.write_u8(1); // Version
383
            w.write_u8(self.cert_type.into());
384
            w.write_u32(self.exp_hours);
385
            w.write_u8(self.cert_key.key_type().into());
386
            w.write_all(self.cert_key.as_bytes());
387

            
388
            for e in self.extensions.iter() {
389
                w.write(e);
390
            }
391

            
392
            let signature = skey.sign(&w[..]);
393
            w.write(&signature);
394
            w
395
        }
396
    */
397

            
398
    /// Try to decode a certificate from a byte slice.
399
    ///
400
    /// This function returns an error if the byte slice is not
401
    /// completely exhausted.
402
    ///
403
    /// Note that the resulting KeyUnknownCertificate is not checked
404
    /// for validity at all: you will need to provide it with an expected
405
    /// signing key, then check it for timeliness and well-signedness.
406
1040
    pub fn decode(cert: &[u8]) -> Result<KeyUnknownCert> {
407
1040
        let mut r = Reader::from_slice(cert);
408
1040
        let v = r.take_u8()?;
409
1040
        if v != 1 {
410
            // This would be something other than a "v1" certificate. We don't
411
            // understand those.
412
52
            return Err(Error::BadMessage("Unrecognized certificate version"));
413
988
        }
414
988
        let cert_type = r.take_u8()?.into();
415
988
        let exp_hours = r.take_u32()?;
416
988
        let mut cert_key_type = r.take_u8()?.into();
417
988

            
418
988
        // This is a workaround for a tor bug: the key type is
419
988
        // wrong. It was fixed in tor#40124, which got merged into Tor
420
988
        // 0.4.5.x and later.
421
988
        if cert_type == CertType::SIGNING_V_TLS_CERT && cert_key_type == KeyType::ED25519_KEY {
422
            cert_key_type = KeyType::SHA256_OF_X509;
423
988
        }
424

            
425
988
        let cert_key = CertifiedKey::from_reader(cert_key_type, &mut r)?;
426
988
        let n_exts = r.take_u8()?;
427
988
        let mut extensions = Vec::new();
428
988
        for _ in 0..n_exts {
429
598
            let e: CertExt = r.extract()?;
430
546
            extensions.push(e);
431
        }
432

            
433
936
        let sig_offset = r.consumed();
434
936
        let signature: ed25519::Signature = r.extract()?;
435
936
        r.should_be_exhausted()?;
436

            
437
936
        let keyext = extensions
438
936
            .iter()
439
936
            .find(|e| e.ext_id() == ExtType::SIGNED_WITH_ED25519_KEY);
440

            
441
910
        let included_pkey = match keyext {
442
520
            Some(CertExt::SignedWithEd25519(s)) => Some(s.pk),
443
390
            _ => None,
444
        };
445

            
446
910
        Ok(KeyUnknownCert {
447
910
            cert: UncheckedCert {
448
910
                cert: Ed25519Cert {
449
910
                    exp_hours,
450
910
                    cert_type,
451
910
                    cert_key,
452
910
                    extensions,
453
910

            
454
910
                    signed_with: included_pkey,
455
910
                },
456
910
                text: cert[0..sig_offset].into(),
457
910
                signature,
458
910
            },
459
910
        })
460
1014
    }
461

            
462
    /// Return the time at which this certificate becomes expired
463
624
    pub fn expiry(&self) -> std::time::SystemTime {
464
624
        let d = std::time::Duration::new(u64::from(self.exp_hours) * 3600, 0);
465
624
        std::time::SystemTime::UNIX_EPOCH + d
466
624
    }
467

            
468
    /// Return true iff this certificate will be expired at the time `when`.
469
468
    pub fn is_expired_at(&self, when: std::time::SystemTime) -> bool {
470
468
        when >= self.expiry()
471
468
    }
472

            
473
    /// Return the signed key or object that is authenticated by this
474
    /// certificate.
475
546
    pub fn subject_key(&self) -> &CertifiedKey {
476
546
        &self.cert_key
477
546
    }
478

            
479
    /// Return the ed25519 key that signed this certificate.
480
260
    pub fn signing_key(&self) -> Option<&ed25519::PublicKey> {
481
260
        self.signed_with.as_ref()
482
260
    }
483

            
484
    /// Return the type of this certificate.
485
52
    pub fn cert_type(&self) -> CertType {
486
52
        self.cert_type
487
52
    }
488
}
489

            
490
/// A parsed Ed25519 certificate. Maybe it includes its signing key;
491
/// maybe it doesn't.
492
pub struct KeyUnknownCert {
493
    /// The certificate whose signing key might not be known.
494
    cert: UncheckedCert,
495
}
496

            
497
impl KeyUnknownCert {
498
    /// Return the certificate type of the underling cert.
499
884
    pub fn peek_cert_type(&self) -> CertType {
500
884
        self.cert.cert.cert_type
501
884
    }
502
    /// Return subject key of the underlying cert.
503
182
    pub fn peek_subject_key(&self) -> &CertifiedKey {
504
182
        &self.cert.cert.cert_key
505
182
    }
506

            
507
    /// Check whether a given pkey is (or might be) a key that has correctly
508
    /// signed this certificate.
509
    ///
510
    /// On success, we can check whether the certificate is well-signed;
511
    /// otherwise, we can't check the certificate.
512
884
    pub fn check_key(self, pkey: &Option<ed25519::PublicKey>) -> Result<UncheckedCert> {
513
884
        let real_key = match (pkey, self.cert.cert.signed_with) {
514
26
            (Some(a), Some(b)) if a == &b => b,
515
26
            (Some(_), Some(_)) => return Err(Error::BadMessage("Mismatched public key on cert")),
516
390
            (Some(a), None) => *a,
517
468
            (None, Some(b)) => b,
518
26
            (None, None) => return Err(Error::BadMessage("Missing public key on cert")),
519
        };
520
858
        Ok(UncheckedCert {
521
858
            cert: Ed25519Cert {
522
858
                signed_with: Some(real_key),
523
858
                ..self.cert.cert
524
858
            },
525
858
            ..self.cert
526
858
        })
527
910
    }
528
}
529

            
530
/// A certificate that has been parsed, but whose signature and
531
/// timeliness have not been checked.
532
pub struct UncheckedCert {
533
    /// The parsed certificate, possibly modified by inserting an externally
534
    /// supplied key as its signing key.
535
    cert: Ed25519Cert,
536

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

            
543
    /// The alleged signature
544
    signature: ed25519::Signature,
545
}
546

            
547
/// A certificate that has been parsed and signature-checked, but whose
548
/// timeliness has not been checked.
549
pub struct SigCheckedCert {
550
    /// The certificate that might or might not be timely
551
    cert: Ed25519Cert,
552
}
553

            
554
impl UncheckedCert {
555
    /// Split this unchecked cert into a component that assumes it has
556
    /// been checked, and a signature to validate.
557
546
    pub fn dangerously_split(
558
546
        self,
559
546
    ) -> Result<(SigCheckedCert, ed25519::ValidatableEd25519Signature)> {
560
        use tor_checkable::SelfSigned;
561
546
        let signing_key = self
562
546
            .cert
563
546
            .signed_with
564
546
            .ok_or(Error::BadMessage("Missing public key on cert"))?;
565
546
        let signature =
566
546
            ed25519::ValidatableEd25519Signature::new(signing_key, self.signature, &self.text[..]);
567
546
        Ok((self.dangerously_assume_wellsigned(), signature))
568
546
    }
569

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

            
583
impl tor_checkable::SelfSigned<SigCheckedCert> for UncheckedCert {
584
    type Error = Error;
585

            
586
52
    fn is_well_signed(&self) -> Result<()> {
587
52
        let pubkey = &self
588
52
            .cert
589
52
            .signed_with
590
52
            .ok_or(Error::BadMessage("Certificate was not in fact self-signed"))?;
591

            
592
52
        pubkey
593
52
            .verify(&self.text[..], &self.signature)
594
52
            .map_err(|_| Error::BadMessage("Invalid certificate signature"))?;
595

            
596
52
        Ok(())
597
52
    }
598

            
599
624
    fn dangerously_assume_wellsigned(self) -> SigCheckedCert {
600
624
        SigCheckedCert { cert: self.cert }
601
624
    }
602
}
603

            
604
impl tor_checkable::Timebound<Ed25519Cert> for SigCheckedCert {
605
    type Error = tor_checkable::TimeValidityError;
606
468
    fn is_valid_at(&self, t: &time::SystemTime) -> std::result::Result<(), Self::Error> {
607
468
        if self.cert.is_expired_at(*t) {
608
            let expiry = self.cert.expiry();
609
            Err(Self::Error::Expired(
610
                t.duration_since(expiry)
611
                    .expect("certificate expiry time inconsistent"),
612
            ))
613
        } else {
614
468
            Ok(())
615
        }
616
468
    }
617

            
618
572
    fn dangerously_assume_timely(self) -> Ed25519Cert {
619
572
        self.cert
620
572
    }
621
}
622

            
623
#[cfg(test)]
624
mod test {
625
    #![allow(clippy::unwrap_used)]
626
    use super::*;
627
    use hex_literal::hex;
628

            
629
    #[test]
630
    fn parse_unrecognized_ext() -> Result<()> {
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> = r.extract();
644
        assert!(e.is_err());
645
        assert_eq!(
646
            e.err().unwrap(),
647
            Error::BadMessage(
648
                "unrecognized certificate extension, with 'affects_validation' flag set."
649
            )
650
        );
651

            
652
        Ok(())
653
    }
654

            
655
    #[test]
656
    fn certified_key() -> Result<()> {
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
}