1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
//! Transport layer security and signing based on OpenSSL.
//!
//! This module wraps some of the lower-level TLS constructs to provide a reasonably safe-to-use API
//! surface for the rest of the application. It also fixes the security parameters of the TLS level
//! in a central place.
//!
//! Features include
//!
//! * a fixed set of chosen encryption parameters
//!   ([`SIGNATURE_ALGORITHM`](constant.SIGNATURE_ALGORITHM.html),
//!   [`SIGNATURE_CURVE`](constant.SIGNATURE_CURVE.html),
//!   [`SIGNATURE_DIGEST`](constant.SIGNATURE_DIGEST.html)),
//! * construction of TLS acceptors for listening TCP sockets
//!   ([`create_tls_acceptor`](fn.create_tls_acceptor.html)),
//! * construction of TLS connectors for outgoing TCP connections
//!   ([`create_tls_connector`](fn.create_tls_connector.html)),
//! * creation and validation of self-signed certificates
//!   ([`generate_node_cert`](fn.generate_node_cert.html)),
//! * signing and verification of arbitrary values using keys from certificates
//!   ([`Signature`](struct.Signature.html), [`Signed`](struct.Signed.html)), and
//! * `serde` support for certificates ([`x509_serde`](x509_serde/index.html))

use std::{
    cmp::Ordering,
    convert::TryInto,
    fmt::{self, Debug, Display, Formatter},
    hash::Hash,
    marker::PhantomData,
    path::Path,
    str,
    time::{SystemTime, UNIX_EPOCH},
};

use anyhow::Context;
use datasize::DataSize;
use hex_fmt::HexFmt;
use nid::Nid;
use openssl::{
    asn1::{Asn1Integer, Asn1IntegerRef, Asn1Time},
    bn::{BigNum, BigNumContext},
    ec,
    error::ErrorStack,
    hash::{DigestBytes, MessageDigest},
    nid,
    pkey::{PKey, PKeyRef, Private},
    sha,
    ssl::{SslAcceptor, SslConnector, SslContextBuilder, SslMethod, SslVerifyMode, SslVersion},
    x509::{X509Builder, X509Name, X509NameBuilder, X509NameRef, X509Ref, X509},
};
#[cfg(test)]
use rand::{
    distributions::{Distribution, Standard},
    Rng,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use thiserror::Error;

use crate::utils::{read_file, write_file};

// This is inside a private module so that the generated `BigArray` does not form part of this
// crate's public API, and hence also doesn't appear in the rustdocs.
mod big_array {
    use serde_big_array::big_array;

    big_array! { BigArray; }
}

/// The chosen signature algorithm (**ECDSA  with SHA512**).
const SIGNATURE_ALGORITHM: Nid = Nid::ECDSA_WITH_SHA512;

/// The underlying elliptic curve (**P-521**).
const SIGNATURE_CURVE: Nid = Nid::SECP521R1;

/// The chosen signature algorithm (**SHA512**).
const SIGNATURE_DIGEST: Nid = Nid::SHA512;

/// OpenSSL result type alias.
///
/// Many functions rely solely on `openssl` functions and return this kind of result.
type SslResult<T> = Result<T, ErrorStack>;

/// SHA512 hash.
#[derive(Copy, Clone, DataSize, Deserialize, Serialize)]
struct Sha512(#[serde(with = "big_array::BigArray")] [u8; Sha512::SIZE]);

impl Sha512 {
    /// Size of digest in bytes.
    const SIZE: usize = 64;

    /// OpenSSL NID.
    const NID: Nid = Nid::SHA512;

    /// Create a new Sha512 by hashing a slice.
    fn new<B: AsRef<[u8]>>(data: B) -> Self {
        let mut openssl_sha = sha::Sha512::new();
        openssl_sha.update(data.as_ref());
        Sha512(openssl_sha.finish())
    }

    /// Returns bytestring of the hash, with length `Self::SIZE`.
    fn bytes(&self) -> &[u8] {
        let bs = &self.0[..];

        debug_assert_eq!(bs.len(), Self::SIZE);
        bs
    }

    /// Converts an OpenSSL digest into an `Sha512`.
    fn from_openssl_digest(digest: &DigestBytes) -> Self {
        let digest_bytes = digest.as_ref();

        debug_assert_eq!(
            digest_bytes.len(),
            Self::SIZE,
            "digest is not the right size - check constants in `tls.rs`"
        );

        let mut buf = [0; Self::SIZE];
        buf.copy_from_slice(&digest_bytes[0..Self::SIZE]);

        Sha512(buf)
    }

    /// Returns a new OpenSSL `MessageDigest` set to SHA-512.
    fn create_message_digest() -> MessageDigest {
        // This can only fail if we specify a `Nid` that does not exist, which cannot happen unless
        // there is something wrong with `Self::NID`.
        MessageDigest::from_nid(Self::NID).expect("Sha512::NID is invalid")
    }
}

/// Certificate fingerprint.
#[derive(Copy, Clone, DataSize, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub(crate) struct CertFingerprint(Sha512);

impl Debug for CertFingerprint {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "CertFingerprint({:10})", HexFmt(self.0.bytes()))
    }
}

/// Public key fingerprint.
#[derive(Copy, Clone, DataSize, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct KeyFingerprint(Sha512);

impl Debug for KeyFingerprint {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "KeyFingerprint({:10})", HexFmt(self.0.bytes()))
    }
}

#[cfg(test)]
impl From<[u8; Sha512::SIZE]> for KeyFingerprint {
    fn from(raw_bytes: [u8; Sha512::SIZE]) -> Self {
        KeyFingerprint(Sha512(raw_bytes))
    }
}

#[cfg(test)]
impl Distribution<KeyFingerprint> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> KeyFingerprint {
        let mut bytes = [0u8; Sha512::SIZE];
        rng.fill(&mut bytes[..]);
        bytes.into()
    }
}

/// Cryptographic signature.
#[derive(Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
struct Signature(Vec<u8>);

impl Debug for Signature {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "Signature({:10})", HexFmt(&self.0))
    }
}

/// TLS certificate.
///
/// Thin wrapper around `X509` enabling things like Serde serialization and fingerprint caching.
#[derive(Clone, DataSize)]
pub struct TlsCert {
    /// The wrapped x509 certificate.
    #[data_size(skip)] // Skip OpenSSL type.
    x509: X509,

    /// Cached certificate fingerprint.
    cert_fingerprint: CertFingerprint,

    /// Cached public key fingerprint.
    key_fingerprint: KeyFingerprint,
}

impl TlsCert {
    /// Returns the certificate's fingerprint.
    ///
    /// In contrast to the `public_key_fingerprint`, this fingerprint also contains the certificate
    /// information.
    pub(crate) fn fingerprint(&self) -> CertFingerprint {
        self.cert_fingerprint
    }

    /// Returns the public key fingerprint.
    pub(crate) fn public_key_fingerprint(&self) -> KeyFingerprint {
        self.key_fingerprint
    }

    /// Returns a reference to the inner x509 certificate.
    pub(crate) fn as_x509(&self) -> &X509 {
        &self.x509
    }
}

impl Debug for TlsCert {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "TlsCert({:?})", self.fingerprint())
    }
}

impl Hash for TlsCert {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.fingerprint().hash(state);
    }
}

impl PartialEq for TlsCert {
    fn eq(&self, other: &Self) -> bool {
        self.fingerprint() == other.fingerprint()
    }
}

impl Eq for TlsCert {}

// Serialization and deserialization happens only via x509, which is checked upon deserialization.
impl<'de> Deserialize<'de> for TlsCert {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        validate_cert(x509_serde::deserialize(deserializer)?).map_err(serde::de::Error::custom)
    }
}

impl Serialize for TlsCert {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        x509_serde::serialize(&self.x509, serializer)
    }
}

/// A signed value.
///
/// Combines a value `V` with a `Signature` and a signature scheme. The signature scheme involves
/// serializing the value to bytes and signing the result.
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct Signed<V> {
    data: Vec<u8>,
    signature: Signature,
    _phantom: PhantomData<V>,
}

/// Generates a self-signed (key, certificate) pair suitable for TLS and signing.
///
/// The common name of the certificate will be "casper-node".
pub fn generate_node_cert() -> SslResult<(X509, PKey<Private>)> {
    let private_key = generate_private_key()?;
    let cert = generate_cert(&private_key, "casper-node")?;

    Ok((cert, private_key))
}

/// Creates a TLS acceptor for a server.
///
/// The acceptor will restrict TLS parameters to secure one defined in this crate that are
/// compatible with connectors built with `create_tls_connector`.
///
/// Incoming certificates must still be validated using `validate_cert`.
pub(crate) fn create_tls_acceptor(
    cert: &X509Ref,
    private_key: &PKeyRef<Private>,
) -> SslResult<SslAcceptor> {
    let mut builder = SslAcceptor::mozilla_modern_v5(SslMethod::tls_server())?;
    set_context_options(&mut builder, cert, private_key)?;

    Ok(builder.build())
}

/// Creates a TLS acceptor for a client.
///
/// A connector compatible with the acceptor created using `create_tls_acceptor`. Server
/// certificates must always be validated using `validate_cert` after connecting.
pub(crate) fn create_tls_connector(
    cert: &X509Ref,
    private_key: &PKeyRef<Private>,
) -> SslResult<SslConnector> {
    let mut builder = SslConnector::builder(SslMethod::tls_client())?;
    set_context_options(&mut builder, cert, private_key)?;

    Ok(builder.build())
}

/// Sets common options of both acceptor and connector on TLS context.
///
/// Used internally to set various TLS parameters.
fn set_context_options(
    ctx: &mut SslContextBuilder,
    cert: &X509Ref,
    private_key: &PKeyRef<Private>,
) -> SslResult<()> {
    ctx.set_min_proto_version(Some(SslVersion::TLS1_3))?;

    ctx.set_certificate(cert)?;
    ctx.set_private_key(private_key)?;
    ctx.check_private_key()?;

    // Note that this does not seem to work as one might naively expect; the client can still send
    // no certificate and there will be no error from OpenSSL. For this reason, we pass set `PEER`
    // (causing the request of a cert), but pass all of them through and verify them after the
    // handshake has completed.
    ctx.set_verify_callback(SslVerifyMode::PEER, |_, _| true);

    Ok(())
}

/// Error during certificate validation.
#[derive(Debug, Error)]
pub enum ValidationError {
    /// Failed to read public key from certificate.
    #[error("error reading public key from certificate: {0:?}")]
    CannotReadPublicKey(#[source] ErrorStack),
    /// Failed to read subject or issuer name.
    #[error("error reading subject or issuer name: {0:?}")]
    CorruptSubjectOrIssuer(#[source] ErrorStack),
    /// Wrong signature scheme.
    #[error("wrong signature scheme")]
    WrongSignatureAlgorithm,
    /// Failed to read or convert times.
    #[error("there was an issue reading or converting times: {0:?}")]
    TimeIssue(#[source] ErrorStack),
    /// Certificate not yet valid.
    #[error("the certificate is not yet valid")]
    NotYetValid,
    /// Certificate expired.
    #[error("the certificate expired")]
    Expired,
    /// Serial number could not be compared to the reference.
    #[error("the serial number could not be compared to the reference: {0:?}")]
    InvalidSerialNumber(#[source] ErrorStack),
    /// Wrong serial number.
    #[error("wrong serial number")]
    WrongSerialNumber,
    /// No valid elliptic curve key could be extracted from certificate.
    #[error("no valid elliptic curve key could be extracted from certificate: {0:?}")]
    CouldNotExtractEcKey(#[source] ErrorStack),
    /// Public key failed sanity check.
    #[error("the given public key fails basic sanity checks: {0:?}")]
    KeyFailsCheck(#[source] ErrorStack),
    /// Wrong elliptic curve.
    #[error("underlying elliptic curve is wrong")]
    WrongCurve,
    /// Certificate not self-signed.
    #[error("certificate is not self-signed")]
    NotSelfSigned,
    /// Failed to validate signature.
    #[error("the signature could not be validated")]
    FailedToValidateSignature(#[source] ErrorStack),
    /// Invalid signature.
    #[error("the signature is invalid")]
    InvalidSignature,
    /// Invalid fingerprint.
    #[error("failed to read fingerprint")]
    InvalidFingerprint(#[source] ErrorStack),
    /// Failed to create a big num context.
    #[error("could not create a big num context")]
    BigNumContextNotAvailable(#[source] ErrorStack),
    /// Failed to encode public key.
    #[error("could not encode public key as bytes")]
    PublicKeyEncodingFailed(#[source] ErrorStack),
}

/// Checks that the cryptographic parameters on a certificate are correct and returns the
/// fingerprint of the public key.
///
/// At the very least this ensures that no weaker ciphers have been used to forge a certificate.
pub(crate) fn validate_cert(cert: X509) -> Result<TlsCert, ValidationError> {
    if cert.signature_algorithm().object().nid() != SIGNATURE_ALGORITHM {
        // The signature algorithm is not of the exact kind we are using to generate our
        // certificates, an attacker could have used a weaker one to generate colliding keys.
        return Err(ValidationError::WrongSignatureAlgorithm);
    }
    // TODO: Lock down extensions on the certificate --- if we manage to lock down the whole cert in
    //       a way that no additional bytes can be added (all fields are either known or of fixed
    //       length) we would have an additional hurdle for preimage attacks to clear.

    let subject =
        name_to_string(cert.subject_name()).map_err(ValidationError::CorruptSubjectOrIssuer)?;
    let issuer =
        name_to_string(cert.issuer_name()).map_err(ValidationError::CorruptSubjectOrIssuer)?;
    if subject != issuer {
        // All of our certificates are self-signed, so it cannot hurt to check.
        return Err(ValidationError::NotSelfSigned);
    }

    // All our certificates have serial number 1.
    if !num_eq(cert.serial_number(), 1).map_err(ValidationError::InvalidSerialNumber)? {
        return Err(ValidationError::WrongSerialNumber);
    }

    // Check expiration times against current time.
    let asn1_now = Asn1Time::from_unix(now()).map_err(ValidationError::TimeIssue)?;
    if asn1_now
        .compare(cert.not_before())
        .map_err(ValidationError::TimeIssue)?
        != Ordering::Greater
    {
        return Err(ValidationError::NotYetValid);
    }

    if asn1_now
        .compare(cert.not_after())
        .map_err(ValidationError::TimeIssue)?
        != Ordering::Less
    {
        return Err(ValidationError::Expired);
    }

    // Ensure that the key is using the correct curve parameters.
    let public_key = cert
        .public_key()
        .map_err(ValidationError::CannotReadPublicKey)?;

    let ec_key = public_key
        .ec_key()
        .map_err(ValidationError::CouldNotExtractEcKey)?;

    ec_key.check_key().map_err(ValidationError::KeyFailsCheck)?;
    if ec_key.group().curve_name() != Some(SIGNATURE_CURVE) {
        // The underlying curve is not the one we chose.
        return Err(ValidationError::WrongCurve);
    }

    // Finally we can check the actual signature.
    if !cert
        .verify(&public_key)
        .map_err(ValidationError::FailedToValidateSignature)?
    {
        return Err(ValidationError::InvalidSignature);
    }

    // We now have a valid certificate and can extract the fingerprint.
    assert_eq!(Sha512::NID, SIGNATURE_DIGEST);
    let digest = &cert
        .digest(Sha512::create_message_digest())
        .map_err(ValidationError::InvalidFingerprint)?;
    let cert_fingerprint = CertFingerprint(Sha512::from_openssl_digest(digest));

    // Additionally we can calculate a fingerprint for the public key:
    let mut big_num_context =
        BigNumContext::new().map_err(ValidationError::BigNumContextNotAvailable)?;

    let buf = ec_key
        .public_key()
        .to_bytes(
            ec::EcGroup::from_curve_name(SIGNATURE_CURVE)
                .expect("broken constant SIGNATURE_CURVE")
                .as_ref(),
            ec::PointConversionForm::COMPRESSED,
            &mut big_num_context,
        )
        .map_err(ValidationError::PublicKeyEncodingFailed)?;

    let key_fingerprint = KeyFingerprint(Sha512::new(&buf));

    Ok(TlsCert {
        x509: cert,
        cert_fingerprint,
        key_fingerprint,
    })
}

/// Loads a certificate from a file.
pub(crate) fn load_cert<P: AsRef<Path>>(src: P) -> anyhow::Result<X509> {
    let pem = read_file(src.as_ref()).with_context(|| "failed to load certificate")?;

    Ok(X509::from_pem(&pem).context("parsing certificate")?)
}

/// Loads a private key from a file.
pub(crate) fn load_private_key<P: AsRef<Path>>(src: P) -> anyhow::Result<PKey<Private>> {
    let pem = read_file(src.as_ref()).with_context(|| "failed to load private key")?;

    // TODO: It might be that we need to call `PKey::private_key_from_pkcs8` instead.
    Ok(PKey::private_key_from_pem(&pem).context("parsing private key")?)
}

/// Saves a certificate to a file.
pub fn save_cert<P: AsRef<Path>>(cert: &X509Ref, dest: P) -> anyhow::Result<()> {
    let pem = cert.to_pem().context("converting certificate to PEM")?;

    write_file(dest, pem).with_context(|| "failed to write certificate")?;
    Ok(())
}

/// Saves a private key to a file.
pub fn save_private_key<P: AsRef<Path>>(key: &PKeyRef<Private>, dest: P) -> anyhow::Result<()> {
    let pem = key
        .private_key_to_pem_pkcs8()
        .context("converting private key to PEM")?;

    write_file(dest, pem).with_context(|| "failed to write private key")?;
    Ok(())
}

/// Returns an OpenSSL compatible timestamp.
fn now() -> i64 {
    // Note: We could do the timing dance a little better going straight to the UNIX time functions,
    //       but this saves us having to bring in `libc` as a dependency.
    let now = SystemTime::now();
    let ts: i64 = now
        .duration_since(UNIX_EPOCH)
        // This should work unless the clock is set to before 1970.
        .expect("Great Scott! Your clock is horribly broken, Marty.")
        .as_secs()
        // This will fail past year 2038 on 32 bit systems and very far into the future, both cases
        // we consider out of scope.
        .try_into()
        .expect("32-bit systems and far future are not supported");

    ts
}

/// Creates an ASN1 integer from a `u32`.
fn mknum(n: u32) -> Result<Asn1Integer, ErrorStack> {
    let bn = BigNum::from_u32(n)?;

    bn.to_asn1_integer()
}

/// Creates an ASN1 name from string components.
///
/// If `c` or `o` are empty string, they are omitted from the result.
fn mkname(c: &str, o: &str, cn: &str) -> Result<X509Name, ErrorStack> {
    let mut builder = X509NameBuilder::new()?;

    if !c.is_empty() {
        builder.append_entry_by_text("C", c)?;
    }

    if !o.is_empty() {
        builder.append_entry_by_text("O", o)?;
    }

    builder.append_entry_by_text("CN", cn)?;
    Ok(builder.build())
}

/// Converts an `X509NameRef` to a human readable string.
fn name_to_string(name: &X509NameRef) -> SslResult<String> {
    let mut output = String::new();

    for entry in name.entries() {
        output.push_str(entry.object().nid().long_name()?);
        output.push_str("=");
        output.push_str(entry.data().as_utf8()?.as_ref());
        output.push_str(" ");
    }

    Ok(output)
}

/// Checks if an `Asn1IntegerRef` is equal to a given u32.
fn num_eq(num: &Asn1IntegerRef, other: u32) -> SslResult<bool> {
    let l = num.to_bn()?;
    let r = BigNum::from_u32(other)?;

    // The `BigNum` API seems to be really lacking here.
    Ok(l.is_negative() == r.is_negative() && l.ucmp(&r.as_ref()) == Ordering::Equal)
}

/// Generates a secret key suitable for TLS encryption.
fn generate_private_key() -> SslResult<PKey<Private>> {
    // We do not care about browser-compliance, so we're free to use elliptic curves that are more
    // likely to hold up under pressure than the NIST ones. We want to go with ED25519 because djb
    // knows best: PKey::generate_ed25519()
    //
    // However the following bug currently prevents us from doing so:
    // https://mta.openssl.org/pipermail/openssl-users/2018-July/008362.html (The same error occurs
    // when trying to sign the cert inside the builder)

    // Our second choice is 2^521-1, which is slow but a "nice prime".
    // http://blog.cr.yp.to/20140323-ecdsa.html

    // An alternative is https://en.bitcoin.it/wiki/Secp256k1, which puts us at level of bitcoin.

    // TODO: Please verify this for accuracy!

    let ec_group = ec::EcGroup::from_curve_name(SIGNATURE_CURVE)?;
    let ec_key = ec::EcKey::generate(ec_group.as_ref())?;

    PKey::from_ec_key(ec_key)
}

/// Generates a self-signed certificate based on `private_key` with given CN.
fn generate_cert(private_key: &PKey<Private>, cn: &str) -> SslResult<X509> {
    let mut builder = X509Builder::new()?;

    // x509 v3 commonly used, the version is 0-indexed, thus 2 == v3.
    builder.set_version(2)?;

    // The serial number is always one, since we are issuing only one cert.
    builder.set_serial_number(mknum(1)?.as_ref())?;

    let issuer = mkname("US", "Casper Blockchain", cn)?;

    // Set the issuer, subject names, putting the "self" in "self-signed".
    builder.set_issuer_name(issuer.as_ref())?;
    builder.set_subject_name(issuer.as_ref())?;

    let ts = now();
    // We set valid-from to one minute into the past to allow some clock-skew.
    builder.set_not_before(Asn1Time::from_unix(ts - 60)?.as_ref())?;

    // Valid-until is a little under 10 years, missing at least 2 leap days.
    builder.set_not_after(Asn1Time::from_unix(ts + 10 * 365 * 24 * 60 * 60)?.as_ref())?;

    // Set the public key and sign.
    builder.set_pubkey(private_key.as_ref())?;
    assert_eq!(Sha512::NID, SIGNATURE_DIGEST);
    builder.sign(private_key.as_ref(), Sha512::create_message_digest())?;

    let cert = builder.build();

    // Cheap sanity check.
    assert!(
        validate_cert(cert.clone()).is_ok(),
        "newly generated cert does not pass our own validity check"
    );

    Ok(cert)
}

/// Serde support for `openx509::X509` certificates.
///
/// Will also check if certificates are valid according to `validate_cert` when deserializing.
mod x509_serde {
    use std::str;

    use openssl::x509::X509;
    use serde::{Deserialize, Deserializer, Serializer};

    use super::validate_cert;

    /// Serde-compatible serialization for X509 certificates.
    pub(super) fn serialize<S>(value: &X509, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let encoded = value.to_pem().map_err(serde::ser::Error::custom)?;

        // We don't expect encoding to fail, since PEMs are ASCII, but pass the error just in case.
        serializer.serialize_str(str::from_utf8(&encoded).map_err(serde::ser::Error::custom)?)
    }

    /// Serde-compatible deserialization for X509 certificates.
    pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<X509, D::Error>
    where
        D: Deserializer<'de>,
    {
        // Create an extra copy for simplicity here. If this becomes a bottleneck, feel free to try
        // to leverage Cow<str> here, or implement a custom visitor that handles both cases.
        let s: String = Deserialize::deserialize(deserializer)?;
        let x509 = X509::from_pem(s.as_bytes()).map_err(serde::de::Error::custom)?;

        validate_cert(x509)
            .map_err(serde::de::Error::custom)
            .map(|tc| tc.x509)
    }
}

// Below are trait implementations for signatures and fingerprints. Both implement the full set of
// traits that are required to stick into either a `HashMap` or `BTreeMap`.
impl PartialEq for Sha512 {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.bytes() == other.bytes()
    }
}

impl Eq for Sha512 {}

impl Ord for Sha512 {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        Ord::cmp(self.bytes(), other.bytes())
    }
}

impl PartialOrd for Sha512 {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(Ord::cmp(self, other))
    }
}

impl Debug for Sha512 {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}", HexFmt(&self.0[..]))
    }
}

impl Display for Sha512 {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{:10}", HexFmt(&self.0[..]))
    }
}

impl Display for CertFingerprint {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl Display for KeyFingerprint {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{:10}", HexFmt(self.0.bytes()))
    }
}

impl Display for Signature {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{:10}", HexFmt(&self.0[..]))
    }
}

impl<T> Display for Signed<T>
where
    T: Display + for<'de> Deserialize<'de>,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        // Decode the data here, even if it is expensive.
        match bincode::deserialize::<T>(self.data.as_slice()) {
            Ok(item) => write!(f, "signed[{}]<{} bytes>", self.signature, item),
            Err(_err) => write!(f, "signed[{}]<CORRUPT>", self.signature),
        }
    }
}

// Since all `Sha512`s are already hashes, we provide a very cheap hashing function that uses
// bytes from the fingerprint as input, cutting the number of bytes to be hashed to 1/16th.

// If this is ever a performance bottleneck, a custom hasher can be added that passes these bytes
// through unchanged.
impl Hash for Sha512 {
    #[inline]
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        // Use the first eight bytes when hashing, giving 64 bits pure entropy.
        let mut chunk = [0u8; 8];

        // TODO: Benchmark if this is really worthwhile over the automatic derivation.
        chunk.copy_from_slice(&self.bytes()[0..8]);

        state.write_u64(u64::from_le_bytes(chunk))
    }
}

#[cfg(test)]
mod test {
    use super::{generate_node_cert, mkname, name_to_string, validate_cert, TlsCert};

    #[test]
    fn simple_name_to_string() {
        let name = mkname("sc", "some_org", "some_cn").expect("could not create name");

        assert_eq!(
            name_to_string(name.as_ref()).expect("name to string failed"),
            "countryName=sc organizationName=some_org commonName=some_cn "
        );
    }

    #[test]
    fn test_tls_cert_serde_roundtrip() {
        let (cert, _private_key) = generate_node_cert().expect("failed to generate key, cert pair");

        let tls_cert = validate_cert(cert).expect("generated cert is not valid");

        // There is no `PartialEq` impl for `TlsCert`, so we simply serialize it twice.
        let serialized = bincode::serialize(&tls_cert).expect("could not serialize");
        let deserialized: TlsCert =
            bincode::deserialize(serialized.as_slice()).expect("could not deserialize");
        let serialized_again = bincode::serialize(&deserialized).expect("could not serialize");

        assert_eq!(serialized, serialized_again);
    }
}