casper_node/
tls.rs

1//! Transport layer security and signing based on OpenSSL.
2//!
3//! This module wraps some of the lower-level TLS constructs to provide a reasonably safe-to-use API
4//! surface for the rest of the application. It also fixes the security parameters of the TLS level
5//! in a central place.
6//!
7//! Features include
8//!
9//! * a fixed set of chosen encryption parameters
10//!   ([`SIGNATURE_ALGORITHM`](constant.SIGNATURE_ALGORITHM.html),
11//!   [`SIGNATURE_CURVE`](constant.SIGNATURE_CURVE.html),
12//!   [`SIGNATURE_DIGEST`](constant.SIGNATURE_DIGEST.html)),
13//! * construction of TLS acceptors for listening TCP sockets
14//!   ([`create_tls_acceptor`](fn.create_tls_acceptor.html)),
15//! * construction of TLS connectors for outgoing TCP connections
16//!   ([`create_tls_connector`](fn.create_tls_connector.html)),
17//! * creation and validation of self-signed certificates
18//!   ([`generate_node_cert`](fn.generate_node_cert.html)),
19//! * signing and verification of arbitrary values using keys from certificates
20//!   ([`Signature`](struct.Signature.html), [`Signed`](struct.Signed.html)), and
21//! * `serde` support for certificates ([`x509_serde`](x509_serde/index.html))
22
23use std::{
24    cmp::Ordering,
25    convert::TryInto,
26    fmt::{self, Debug, Display, Formatter},
27    hash::Hash,
28    marker::PhantomData,
29    path::Path,
30    str,
31    time::{SystemTime, UNIX_EPOCH},
32};
33
34use casper_types::file_utils::{read_file, ReadFileError};
35use datasize::DataSize;
36use hex_fmt::HexFmt;
37use nid::Nid;
38use openssl::{
39    asn1::{Asn1Integer, Asn1IntegerRef, Asn1Time},
40    bn::{BigNum, BigNumContext},
41    ec::{self, EcKey},
42    error::ErrorStack,
43    hash::{DigestBytes, MessageDigest},
44    nid,
45    pkey::{PKey, PKeyRef, Private, Public},
46    sha,
47    ssl::{SslAcceptor, SslConnector, SslContextBuilder, SslMethod, SslVerifyMode, SslVersion},
48    x509::{X509Builder, X509Name, X509NameBuilder, X509NameRef, X509Ref, X509},
49};
50#[cfg(test)]
51use rand::{
52    distributions::{Distribution, Standard},
53    Rng,
54};
55use serde::{Deserialize, Serialize};
56use thiserror::Error;
57
58// This is inside a private module so that the generated `BigArray` does not form part of this
59// crate's public API, and hence also doesn't appear in the rustdocs.
60mod big_array {
61    use serde_big_array::big_array;
62
63    big_array! { BigArray; }
64}
65
66/// The chosen signature algorithm (**ECDSA with SHA512**).
67const SIGNATURE_ALGORITHM: Nid = Nid::ECDSA_WITH_SHA512;
68
69/// The underlying elliptic curve (**P-521**).
70const SIGNATURE_CURVE: Nid = Nid::SECP521R1;
71
72/// The chosen signature algorithm (**SHA512**).
73const SIGNATURE_DIGEST: Nid = Nid::SHA512;
74
75/// OpenSSL result type alias.
76///
77/// Many functions rely solely on `openssl` functions and return this kind of result.
78type SslResult<T> = Result<T, ErrorStack>;
79
80/// SHA512 hash.
81#[derive(Copy, Clone, DataSize, Deserialize, Serialize)]
82pub struct Sha512(#[serde(with = "big_array::BigArray")] [u8; Sha512::SIZE]);
83
84impl Sha512 {
85    /// Size of digest in bytes.
86    const SIZE: usize = 64;
87
88    /// OpenSSL NID.
89    const NID: Nid = Nid::SHA512;
90
91    /// Create a new Sha512 by hashing a slice.
92    pub fn new<B: AsRef<[u8]>>(data: B) -> Self {
93        let mut openssl_sha = sha::Sha512::new();
94        openssl_sha.update(data.as_ref());
95        Sha512(openssl_sha.finish())
96    }
97
98    /// Returns bytestring of the hash, with length `Self::SIZE`.
99    fn bytes(&self) -> &[u8] {
100        let bs = &self.0[..];
101
102        debug_assert_eq!(bs.len(), Self::SIZE);
103        bs
104    }
105
106    /// Converts an OpenSSL digest into an `Sha512`.
107    fn from_openssl_digest(digest: &DigestBytes) -> Self {
108        let digest_bytes = digest.as_ref();
109
110        debug_assert_eq!(
111            digest_bytes.len(),
112            Self::SIZE,
113            "digest is not the right size - check constants in `tls.rs`"
114        );
115
116        let mut buf = [0; Self::SIZE];
117        buf.copy_from_slice(&digest_bytes[0..Self::SIZE]);
118
119        Sha512(buf)
120    }
121
122    /// Returns a new OpenSSL `MessageDigest` set to SHA-512.
123    fn create_message_digest() -> MessageDigest {
124        // This can only fail if we specify a `Nid` that does not exist, which cannot happen unless
125        // there is something wrong with `Self::NID`.
126        MessageDigest::from_nid(Self::NID).expect("Sha512::NID is invalid")
127    }
128}
129
130/// Certificate fingerprint.
131#[derive(Copy, Clone, DataSize, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
132pub(crate) struct CertFingerprint(Sha512);
133
134impl Debug for CertFingerprint {
135    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
136        write!(f, "CertFingerprint({:10})", HexFmt(self.0.bytes()))
137    }
138}
139
140/// Public key fingerprint.
141#[derive(Copy, Clone, DataSize, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
142pub struct KeyFingerprint(Sha512);
143
144impl KeyFingerprint {
145    /// Size of digest in bytes.
146    pub const LENGTH: usize = Sha512::SIZE;
147}
148
149impl AsRef<[u8]> for KeyFingerprint {
150    fn as_ref(&self) -> &[u8] {
151        self.0.bytes()
152    }
153}
154
155impl Debug for KeyFingerprint {
156    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
157        write!(f, "KeyFingerprint({:10})", HexFmt(self.0.bytes()))
158    }
159}
160
161impl From<[u8; KeyFingerprint::LENGTH]> for KeyFingerprint {
162    fn from(raw_bytes: [u8; KeyFingerprint::LENGTH]) -> Self {
163        KeyFingerprint(Sha512(raw_bytes))
164    }
165}
166
167impl From<Sha512> for KeyFingerprint {
168    fn from(hash: Sha512) -> Self {
169        Self(hash)
170    }
171}
172
173#[cfg(test)]
174impl Distribution<KeyFingerprint> for Standard {
175    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> KeyFingerprint {
176        let mut bytes = [0u8; Sha512::SIZE];
177        rng.fill(&mut bytes[..]);
178        bytes.into()
179    }
180}
181
182/// Cryptographic signature.
183#[derive(Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
184struct Signature(Vec<u8>);
185
186impl Debug for Signature {
187    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
188        write!(f, "Signature({:10})", HexFmt(&self.0))
189    }
190}
191
192/// TLS certificate.
193///
194/// Thin wrapper around `X509` enabling things like Serde serialization and fingerprint caching.
195#[derive(Clone, DataSize)]
196pub struct TlsCert {
197    /// The wrapped x509 certificate.
198    #[data_size(skip)] // Skip OpenSSL type.
199    x509: X509,
200
201    /// Cached certificate fingerprint.
202    cert_fingerprint: CertFingerprint,
203
204    /// Cached public key fingerprint.
205    key_fingerprint: KeyFingerprint,
206}
207
208impl TlsCert {
209    /// Returns the certificate's fingerprint.
210    ///
211    /// In contrast to the `public_key_fingerprint`, this fingerprint also contains the certificate
212    /// information.
213    pub(crate) fn fingerprint(&self) -> CertFingerprint {
214        self.cert_fingerprint
215    }
216
217    /// Returns the public key fingerprint.
218    pub(crate) fn public_key_fingerprint(&self) -> KeyFingerprint {
219        self.key_fingerprint
220    }
221
222    /// Returns a reference to the inner x509 certificate.
223    pub(crate) fn as_x509(&self) -> &X509 {
224        &self.x509
225    }
226}
227
228impl Debug for TlsCert {
229    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
230        write!(f, "TlsCert({:?})", self.fingerprint())
231    }
232}
233
234impl Hash for TlsCert {
235    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
236        self.fingerprint().hash(state);
237    }
238}
239
240impl PartialEq for TlsCert {
241    fn eq(&self, other: &Self) -> bool {
242        self.fingerprint() == other.fingerprint()
243    }
244}
245
246impl Eq for TlsCert {}
247
248/// Error during loading a x509 certificate.
249#[derive(Debug, Error, Serialize)]
250pub enum LoadCertError {
251    #[error("could not load certificate file: {0}")]
252    ReadFile(
253        #[serde(skip_serializing)]
254        #[source]
255        ReadFileError,
256    ),
257    #[error("unable to load x509 certificate {0:?}")]
258    X509CertFromPem(
259        #[serde(skip_serializing)]
260        #[source]
261        ErrorStack,
262    ),
263}
264
265/// Load a certificate from a file.
266pub(crate) fn load_cert<P: AsRef<Path>>(src: P) -> Result<X509, LoadCertError> {
267    let pem = read_file(src.as_ref()).map_err(LoadCertError::ReadFile)?;
268    X509::from_pem(&pem).map_err(LoadCertError::X509CertFromPem)
269}
270
271/// Error during loading a secret key.
272#[derive(Debug, Error, Serialize)]
273pub(crate) enum LoadSecretKeyError {
274    #[error("could not load secret key file: {0}")]
275    ReadFile(
276        #[serde(skip_serializing)]
277        #[source]
278        ReadFileError,
279    ),
280    #[error("unable to load private key from pem {0:?}")]
281    PrivateKeyFromPem(
282        #[serde(skip_serializing)]
283        #[source]
284        ErrorStack,
285    ),
286}
287
288pub(crate) fn load_secret_key<P: AsRef<Path>>(src: P) -> Result<PKey<Private>, LoadSecretKeyError> {
289    let pem = read_file(src.as_ref()).map_err(LoadSecretKeyError::ReadFile)?;
290    PKey::private_key_from_pem(&pem).map_err(LoadSecretKeyError::PrivateKeyFromPem)
291}
292
293/// A signed value.
294///
295/// Combines a value `V` with a `Signature` and a signature scheme. The signature scheme involves
296/// serializing the value to bytes and signing the result.
297#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
298pub struct Signed<V> {
299    data: Vec<u8>,
300    signature: Signature,
301    _phantom: PhantomData<V>,
302}
303
304/// Generates a self-signed (key, certificate) pair suitable for TLS and signing.
305///
306/// The common name of the certificate will be "casper-node".
307pub fn generate_node_cert() -> SslResult<(X509, PKey<Private>)> {
308    let private_key = generate_private_key()?;
309    let cert = generate_cert(&private_key, "casper-node")?;
310
311    Ok((cert, private_key))
312}
313
314/// Creates a TLS acceptor for a server.
315///
316/// The acceptor will restrict TLS parameters to secure one defined in this crate that are
317/// compatible with connectors built with `create_tls_connector`.
318///
319/// Incoming certificates must still be validated using `validate_cert`.
320pub(crate) fn create_tls_acceptor(
321    cert: &X509Ref,
322    private_key: &PKeyRef<Private>,
323) -> SslResult<SslAcceptor> {
324    let mut builder = SslAcceptor::mozilla_modern_v5(SslMethod::tls_server())?;
325    set_context_options(&mut builder, cert, private_key)?;
326
327    Ok(builder.build())
328}
329
330/// Creates a TLS acceptor for a client.
331///
332/// A connector compatible with the acceptor created using `create_tls_acceptor`. Server
333/// certificates must always be validated using `validate_cert` after connecting.
334pub(crate) fn create_tls_connector(
335    cert: &X509Ref,
336    private_key: &PKeyRef<Private>,
337) -> SslResult<SslConnector> {
338    let mut builder = SslConnector::builder(SslMethod::tls_client())?;
339    set_context_options(&mut builder, cert, private_key)?;
340
341    Ok(builder.build())
342}
343
344/// Sets common options of both acceptor and connector on TLS context.
345///
346/// Used internally to set various TLS parameters.
347fn set_context_options(
348    ctx: &mut SslContextBuilder,
349    cert: &X509Ref,
350    private_key: &PKeyRef<Private>,
351) -> SslResult<()> {
352    ctx.set_min_proto_version(Some(SslVersion::TLS1_3))?;
353
354    ctx.set_certificate(cert)?;
355    ctx.set_private_key(private_key)?;
356    ctx.check_private_key()?;
357
358    // Note that this does not seem to work as one might naively expect; the client can still send
359    // no certificate and there will be no error from OpenSSL. For this reason, we pass set `PEER`
360    // (causing the request of a cert), but pass all of them through and verify them after the
361    // handshake has completed.
362    ctx.set_verify_callback(SslVerifyMode::PEER, |_, _| true);
363
364    Ok(())
365}
366
367/// Error during certificate validation.
368#[derive(Debug, Error, Serialize)]
369pub enum ValidationError {
370    /// Failed to read public key from certificate.
371    #[error("error reading public key from certificate: {0:?}")]
372    CannotReadPublicKey(
373        #[serde(skip_serializing)]
374        #[source]
375        ErrorStack,
376    ),
377    /// Failed to read subject or issuer name.
378    #[error("error reading subject or issuer name: {0:?}")]
379    CorruptSubjectOrIssuer(
380        #[serde(skip_serializing)]
381        #[source]
382        ErrorStack,
383    ),
384    /// Wrong signature scheme.
385    #[error("wrong signature scheme")]
386    WrongSignatureAlgorithm,
387    /// Failed to read or convert times.
388    #[error("there was an issue reading or converting times: {0:?}")]
389    TimeIssue(
390        #[serde(skip_serializing)]
391        #[source]
392        ErrorStack,
393    ),
394    /// Certificate not yet valid.
395    #[error("the certificate is not yet valid")]
396    NotYetValid,
397    /// Certificate expired.
398    #[error("the certificate expired")]
399    Expired,
400    /// Serial number could not be compared to the reference.
401    #[error("the serial number could not be compared to the reference: {0:?}")]
402    InvalidSerialNumber(
403        #[serde(skip_serializing)]
404        #[source]
405        ErrorStack,
406    ),
407    /// Wrong serial number.
408    #[error("wrong serial number")]
409    WrongSerialNumber,
410    /// No valid elliptic curve key could be extracted from certificate.
411    #[error("no valid elliptic curve key could be extracted from certificate: {0:?}")]
412    CouldNotExtractEcKey(
413        #[serde(skip_serializing)]
414        #[source]
415        ErrorStack,
416    ),
417    /// Public key failed sanity check.
418    #[error("the given public key fails basic sanity checks: {0:?}")]
419    KeyFailsCheck(
420        #[serde(skip_serializing)]
421        #[source]
422        ErrorStack,
423    ),
424    /// Wrong elliptic curve.
425    #[error("underlying elliptic curve is wrong")]
426    WrongCurve,
427    /// Certificate not self-signed.
428    #[error("certificate is not self-signed")]
429    NotSelfSigned,
430    /// Failed to validate signature.
431    #[error("the signature could not be validated")]
432    FailedToValidateSignature(
433        #[serde(skip_serializing)]
434        #[source]
435        ErrorStack,
436    ),
437    /// Invalid signature.
438    #[error("the signature is invalid")]
439    InvalidSignature,
440    /// Invalid fingerprint.
441    #[error("failed to read fingerprint")]
442    InvalidFingerprint(
443        #[serde(skip_serializing)]
444        #[source]
445        ErrorStack,
446    ),
447    /// Failed to create a big num context.
448    #[error("could not create a big num context")]
449    BigNumContextNotAvailable(
450        #[serde(skip_serializing)]
451        #[source]
452        ErrorStack,
453    ),
454    /// Failed to encode public key.
455    #[error("could not encode public key as bytes")]
456    PublicKeyEncodingFailed(
457        #[serde(skip_serializing)]
458        #[source]
459        ErrorStack,
460    ),
461    /// Wrong certificate authority.
462    #[error("the certificate is not signed by provided certificate authority")]
463    WrongCertificateAuthority,
464    /// Failed to read public key from certificate.
465    #[error("error reading public key from ca certificate: {0:?}")]
466    CannotReadCAPublicKey(
467        #[serde(skip_serializing)]
468        #[source]
469        ErrorStack,
470    ),
471}
472
473/// Checks that the certificate is signed by a provided certificate authority and returns the
474/// fingerprint of the public key.
475pub(crate) fn validate_cert_with_authority(
476    cert: X509,
477    ca: &X509,
478) -> Result<TlsCert, ValidationError> {
479    let authority_key = ca
480        .public_key()
481        .map_err(ValidationError::CannotReadCAPublicKey)?;
482
483    validate_cert_expiration_date(&cert)?;
484
485    if !cert
486        .verify(authority_key.as_ref())
487        .map_err(ValidationError::FailedToValidateSignature)?
488    {
489        return Err(ValidationError::WrongCertificateAuthority);
490    }
491
492    // Ensure that the key is using the correct curve parameters.
493    tls_cert_from_x509(cert)
494}
495
496/// Checks that the cryptographic parameters on a certificate are correct and returns the
497/// fingerprint of the public key.
498///
499/// At the very least this ensures that no weaker ciphers have been used to forge a certificate.
500pub(crate) fn validate_self_signed_cert(cert: X509) -> Result<TlsCert, ValidationError> {
501    if cert.signature_algorithm().object().nid() != SIGNATURE_ALGORITHM {
502        // The signature algorithm is not of the exact kind we are using to generate our
503        // certificates, an attacker could have used a weaker one to generate colliding keys.
504        return Err(ValidationError::WrongSignatureAlgorithm);
505    }
506    // TODO: Lock down extensions on the certificate --- if we manage to lock down the whole cert in
507    //       a way that no additional bytes can be added (all fields are either known or of fixed
508    //       length) we would have an additional hurdle for preimage attacks to clear.
509
510    let subject =
511        name_to_string(cert.subject_name()).map_err(ValidationError::CorruptSubjectOrIssuer)?;
512    let issuer =
513        name_to_string(cert.issuer_name()).map_err(ValidationError::CorruptSubjectOrIssuer)?;
514    if subject != issuer {
515        // All of our certificates are self-signed, so it cannot hurt to check.
516        return Err(ValidationError::NotSelfSigned);
517    }
518
519    // All our certificates have serial number 1.
520    if !num_eq(cert.serial_number(), 1).map_err(ValidationError::InvalidSerialNumber)? {
521        return Err(ValidationError::WrongSerialNumber);
522    }
523
524    // Check expiration times against current time.
525    validate_cert_expiration_date(&cert)?;
526
527    // Ensure that the key is using the correct curve parameters.
528    let (public_key, ec_key) = validate_cert_ec_key(&cert)?;
529    if ec_key.group().curve_name() != Some(SIGNATURE_CURVE) {
530        // The underlying curve is not the one we chose.
531        return Err(ValidationError::WrongCurve);
532    }
533
534    // Finally we can check the actual signature.
535    if !cert
536        .verify(&public_key)
537        .map_err(ValidationError::FailedToValidateSignature)?
538    {
539        return Err(ValidationError::InvalidSignature);
540    }
541
542    tls_cert_from_x509_and_key(cert, ec_key)
543}
544
545/// Creates a [`TlsCert`] instance from [`X509`] cert instance.
546///
547/// This function only ensures that the cert contains EC public key, and is suitable for quickly
548/// validating certs signed by CA.
549pub(crate) fn tls_cert_from_x509(cert: X509) -> Result<TlsCert, ValidationError> {
550    let (_public_key, ec_key) = validate_cert_ec_key(&cert)?;
551    tls_cert_from_x509_and_key(cert, ec_key)
552}
553
554fn tls_cert_from_x509_and_key(
555    cert: X509,
556    ec_key: EcKey<Public>,
557) -> Result<TlsCert, ValidationError> {
558    let cert_fingerprint = cert_fingerprint(&cert)?;
559    let key_fingerprint = key_fingerprint(&ec_key)?;
560    Ok(TlsCert {
561        x509: cert,
562        cert_fingerprint,
563        key_fingerprint,
564    })
565}
566
567/// Calculate a fingerprint for the X509 certificate.
568pub(crate) fn cert_fingerprint(cert: &X509) -> Result<CertFingerprint, ValidationError> {
569    assert_eq!(Sha512::NID, SIGNATURE_DIGEST);
570    let digest = &cert
571        .digest(Sha512::create_message_digest())
572        .map_err(ValidationError::InvalidFingerprint)?;
573    let cert_fingerprint = CertFingerprint(Sha512::from_openssl_digest(digest));
574    Ok(cert_fingerprint)
575}
576
577/// Calculate a fingerprint for the public EC key.
578pub(crate) fn key_fingerprint(ec_key: &EcKey<Public>) -> Result<KeyFingerprint, ValidationError> {
579    let mut big_num_context =
580        BigNumContext::new().map_err(ValidationError::BigNumContextNotAvailable)?;
581    let buf = ec_key
582        .public_key()
583        .to_bytes(
584            ec::EcGroup::from_curve_name(SIGNATURE_CURVE)
585                .expect("broken constant SIGNATURE_CURVE")
586                .as_ref(),
587            ec::PointConversionForm::COMPRESSED,
588            &mut big_num_context,
589        )
590        .map_err(ValidationError::PublicKeyEncodingFailed)?;
591    let key_fingerprint = KeyFingerprint(Sha512::new(buf));
592    Ok(key_fingerprint)
593}
594
595/// Validate cert's public key, and it's EC key parameters.
596fn validate_cert_ec_key(cert: &X509) -> Result<(PKey<Public>, EcKey<Public>), ValidationError> {
597    let public_key = cert
598        .public_key()
599        .map_err(ValidationError::CannotReadPublicKey)?;
600    let ec_key = public_key
601        .ec_key()
602        .map_err(ValidationError::CouldNotExtractEcKey)?;
603    ec_key.check_key().map_err(ValidationError::KeyFailsCheck)?;
604    Ok((public_key, ec_key))
605}
606
607/// Check cert's expiration times against current time.
608fn validate_cert_expiration_date(cert: &X509) -> Result<(), ValidationError> {
609    let asn1_now = Asn1Time::from_unix(now()).map_err(ValidationError::TimeIssue)?;
610    if asn1_now
611        .compare(cert.not_before())
612        .map_err(ValidationError::TimeIssue)?
613        != Ordering::Greater
614    {
615        return Err(ValidationError::NotYetValid);
616    }
617
618    if asn1_now
619        .compare(cert.not_after())
620        .map_err(ValidationError::TimeIssue)?
621        != Ordering::Less
622    {
623        return Err(ValidationError::Expired);
624    }
625
626    Ok(())
627}
628
629/// Returns an OpenSSL compatible timestamp.
630fn now() -> i64 {
631    // Note: We could do the timing dance a little better going straight to the UNIX time functions,
632    //       but this saves us having to bring in `libc` as a dependency.
633    let now = SystemTime::now();
634    let ts: i64 = now
635        .duration_since(UNIX_EPOCH)
636        // This should work unless the clock is set to before 1970.
637        .expect("Great Scott! Your clock is horribly broken, Marty.")
638        .as_secs()
639        // This will fail past year 2038 on 32 bit systems and very far into the future, both cases
640        // we consider out of scope.
641        .try_into()
642        .expect("32-bit systems and far future are not supported");
643
644    ts
645}
646
647/// Creates an ASN1 integer from a `u32`.
648fn mknum(n: u32) -> Result<Asn1Integer, ErrorStack> {
649    let bn = BigNum::from_u32(n)?;
650
651    bn.to_asn1_integer()
652}
653
654/// Creates an ASN1 name from string components.
655///
656/// If `c` or `o` are empty string, they are omitted from the result.
657fn mkname(c: &str, o: &str, cn: &str) -> Result<X509Name, ErrorStack> {
658    let mut builder = X509NameBuilder::new()?;
659
660    if !c.is_empty() {
661        builder.append_entry_by_text("C", c)?;
662    }
663
664    if !o.is_empty() {
665        builder.append_entry_by_text("O", o)?;
666    }
667
668    builder.append_entry_by_text("CN", cn)?;
669    Ok(builder.build())
670}
671
672/// Converts an `X509NameRef` to a human readable string.
673fn name_to_string(name: &X509NameRef) -> SslResult<String> {
674    let mut output = String::new();
675
676    for entry in name.entries() {
677        output.push_str(entry.object().nid().long_name()?);
678        output.push('=');
679        output.push_str(entry.data().as_utf8()?.as_ref());
680        output.push(' ');
681    }
682
683    Ok(output)
684}
685
686/// Checks if an `Asn1IntegerRef` is equal to a given u32.
687fn num_eq(num: &Asn1IntegerRef, other: u32) -> SslResult<bool> {
688    let l = num.to_bn()?;
689    let r = BigNum::from_u32(other)?;
690
691    // The `BigNum` API seems to be really lacking here.
692    Ok(l.is_negative() == r.is_negative() && l.ucmp(r.as_ref()) == Ordering::Equal)
693}
694
695/// Generates a secret key suitable for TLS encryption.
696fn generate_private_key() -> SslResult<PKey<Private>> {
697    // We do not care about browser-compliance, so we're free to use elliptic curves that are more
698    // likely to hold up under pressure than the NIST ones. We want to go with ED25519 because djb
699    // knows best: PKey::generate_ed25519()
700    //
701    // However the following bug currently prevents us from doing so:
702    // https://mta.openssl.org/pipermail/openssl-users/2018-July/008362.html (The same error occurs
703    // when trying to sign the cert inside the builder)
704
705    // Our second choice is 2^521-1, which is slow but a "nice prime".
706    // http://blog.cr.yp.to/20140323-ecdsa.html
707
708    // An alternative is https://en.bitcoin.it/wiki/Secp256k1, which puts us at level of bitcoin.
709
710    // TODO: Please verify this for accuracy!
711
712    let ec_group = ec::EcGroup::from_curve_name(SIGNATURE_CURVE)?;
713    let ec_key = EcKey::generate(ec_group.as_ref())?;
714
715    PKey::from_ec_key(ec_key)
716}
717
718/// Generates a self-signed certificate based on `private_key` with given CN.
719fn generate_cert(private_key: &PKey<Private>, cn: &str) -> SslResult<X509> {
720    let mut builder = X509Builder::new()?;
721
722    // x509 v3 commonly used, the version is 0-indexed, thus 2 == v3.
723    builder.set_version(2)?;
724
725    // The serial number is always one, since we are issuing only one cert.
726    builder.set_serial_number(mknum(1)?.as_ref())?;
727
728    let issuer = mkname("US", "Casper Blockchain", cn)?;
729
730    // Set the issuer, subject names, putting the "self" in "self-signed".
731    builder.set_issuer_name(issuer.as_ref())?;
732    builder.set_subject_name(issuer.as_ref())?;
733
734    let ts = now();
735    // We set valid-from to one minute into the past to allow some clock-skew.
736    builder.set_not_before(Asn1Time::from_unix(ts - 60)?.as_ref())?;
737
738    // Valid-until is a little under 10 years, missing at least 2 leap days.
739    builder.set_not_after(Asn1Time::from_unix(ts + 10 * 365 * 24 * 60 * 60)?.as_ref())?;
740
741    // Set the public key and sign.
742    builder.set_pubkey(private_key.as_ref())?;
743    assert_eq!(Sha512::NID, SIGNATURE_DIGEST);
744    builder.sign(private_key.as_ref(), Sha512::create_message_digest())?;
745
746    let cert = builder.build();
747
748    // Cheap sanity check.
749    assert!(
750        validate_self_signed_cert(cert.clone()).is_ok(),
751        "newly generated cert does not pass our own validity check"
752    );
753
754    Ok(cert)
755}
756
757// Below are trait implementations for signatures and fingerprints. Both implement the full set of
758// traits that are required to stick into either a `HashMap` or `BTreeMap`.
759impl PartialEq for Sha512 {
760    #[inline]
761    fn eq(&self, other: &Self) -> bool {
762        self.bytes() == other.bytes()
763    }
764}
765
766impl Eq for Sha512 {}
767
768impl Ord for Sha512 {
769    #[inline]
770    fn cmp(&self, other: &Self) -> Ordering {
771        Ord::cmp(self.bytes(), other.bytes())
772    }
773}
774
775impl PartialOrd for Sha512 {
776    #[inline]
777    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
778        Some(Ord::cmp(self, other))
779    }
780}
781
782impl Debug for Sha512 {
783    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
784        write!(f, "{}", base16::encode_lower(&self.0[..]))
785    }
786}
787
788impl Display for Sha512 {
789    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
790        write!(f, "{:10}", HexFmt(&self.0[..]))
791    }
792}
793
794impl Display for CertFingerprint {
795    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
796        Display::fmt(&self.0, f)
797    }
798}
799
800impl Display for KeyFingerprint {
801    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
802        write!(f, "{:10}", HexFmt(self.0.bytes()))
803    }
804}
805
806impl Display for Signature {
807    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
808        write!(f, "{:10}", HexFmt(&self.0[..]))
809    }
810}
811
812impl<T> Display for Signed<T>
813where
814    T: Display + for<'de> Deserialize<'de>,
815{
816    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
817        // Decode the data here, even if it is expensive.
818        match bincode::deserialize::<T>(self.data.as_slice()) {
819            Ok(item) => write!(f, "signed[{}]<{} bytes>", self.signature, item),
820            Err(_err) => write!(f, "signed[{}]<CORRUPT>", self.signature),
821        }
822    }
823}
824
825// Since all `Sha512`s are already hashes, we provide a very cheap hashing function that uses
826// bytes from the fingerprint as input, cutting the number of bytes to be hashed to 1/16th.
827
828// If this is ever a performance bottleneck, a custom hasher can be added that passes these bytes
829// through unchanged.
830impl Hash for Sha512 {
831    #[inline]
832    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
833        // Use the first eight bytes when hashing, giving 64 bits pure entropy.
834        let mut chunk = [0u8; 8];
835
836        // TODO: Benchmark if this is really worthwhile over the automatic derivation.
837        chunk.copy_from_slice(&self.bytes()[0..8]);
838
839        state.write_u64(u64::from_le_bytes(chunk));
840    }
841}
842
843#[cfg(test)]
844mod tests {
845    use super::*;
846
847    #[test]
848    fn simple_name_to_string() {
849        let name = mkname("sc", "some_org", "some_cn").expect("could not create name");
850
851        assert_eq!(
852            name_to_string(name.as_ref()).expect("name to string failed"),
853            "countryName=sc organizationName=some_org commonName=some_cn "
854        );
855    }
856
857    #[test]
858    fn test_validate_self_signed_cert() {
859        let (cert, private_key) = generate_node_cert().expect("failed to generate key, cert pair");
860
861        // Validates self signed cert
862        let _tls_cert =
863            validate_self_signed_cert(cert).expect("generated self signed cert is not valid");
864
865        // Cert signed by a CA does not validate as self signed
866        let ca_private_key = generate_private_key().expect("failed to generate private key");
867        let ca_signed_cert = make_ca_signed_cert(private_key, ca_private_key);
868
869        let error = validate_self_signed_cert(ca_signed_cert)
870            .expect_err("should not validate ca signed cert as self signed");
871        assert!(
872            matches!(error, ValidationError::InvalidSignature),
873            "{:?}",
874            error
875        );
876    }
877
878    #[test]
879    fn test_validate_cert_with_authority() {
880        let (ca_cert, ca_private_key) =
881            generate_node_cert().expect("failed to generate key, cert pair");
882
883        let (different_ca_cert, _ca_private_key) =
884            generate_node_cert().expect("failed to generate key, cert pair");
885
886        let node_private_key = generate_private_key().expect("failed to generate private key");
887
888        let node_cert = make_ca_signed_cert(node_private_key, ca_private_key);
889
890        validate_self_signed_cert(node_cert.clone())
891            .expect_err("should not validate CA signed cert as self signed");
892
893        let _node_tls_cert = validate_cert_with_authority(node_cert.clone(), &ca_cert)
894            .expect("should validate with ca cert");
895
896        let validation_error = validate_cert_with_authority(node_cert, &different_ca_cert)
897            .expect_err("should not validate cert against different CA");
898
899        assert!(
900            matches!(validation_error, ValidationError::WrongCertificateAuthority),
901            "{:?}",
902            validation_error
903        );
904    }
905
906    fn make_ca_signed_cert(private_key: PKey<Private>, ca_private_key: PKey<Private>) -> X509 {
907        let mut builder = X509Builder::new().unwrap();
908        builder.set_version(2).unwrap();
909        builder
910            .set_serial_number(mknum(1).unwrap().as_ref())
911            .unwrap();
912        let issuer = mkname("US", "Casper Blockchain", "Casper Network").unwrap();
913        builder.set_issuer_name(issuer.as_ref()).unwrap();
914        builder.set_subject_name(issuer.as_ref()).unwrap();
915        let ts = now();
916        builder
917            .set_not_before(Asn1Time::from_unix(ts - 60).unwrap().as_ref())
918            .unwrap();
919        builder
920            .set_not_after(
921                Asn1Time::from_unix(ts + 10 * 365 * 24 * 60 * 60)
922                    .unwrap()
923                    .as_ref(),
924            )
925            .unwrap();
926        builder.set_pubkey(private_key.as_ref()).unwrap();
927        assert_eq!(Sha512::NID, SIGNATURE_DIGEST);
928        builder
929            .sign(ca_private_key.as_ref(), Sha512::create_message_digest())
930            .unwrap();
931        builder.build()
932    }
933}