Commit Graph

6187 Commits

Author SHA1 Message Date
parazyd
55ee919906 net: Perform full p2p code cleanup and improve certain pieces.
Notable changes:

* Rewritten transport protocols into Dialer and Listener (Nym is TODO)

  This simplifies using the transports a lot, as can be seen for example
  in src/rpc, and generally around the p2p library. It also defines features
  for each transport (all of which are enabled by default). We drop the
  socks client for Tor and Nym and use first-class support with the Arti Tor
  library, and nym-sphinx/nym-websockets (to be used with nym-client).

* Outbound session healing

  The outbound session will now poll and try to fill all the requested
  slots more efficiently, and if needed, will activate peer discovery to
  find more peers if we can't connect to any known ones. Also if we're
  unable to connect to any, we shall drop them from our set.

  Additionally, transport mixing is enabled by default, so when we're
  allowing transport mixing, and we use Tor, we will also be able to connect
  to other transports that Tor can connect to (e.g. tcp://).

* Unix socket transport dropped

  We haven't been using this, and it seems we're not going down this path,
  so the code has been obsoleted and removed.

* TLS session verification

  We fully verify server and client TLS certificates upon connection so
  we're able to perform TLS1.3 with forward secrecy.

* lilith pruning

  lilith now periodically prunes known peers from its sets if it's unable
  to connect to them.
2023-06-29 13:13:15 +02:00
parazyd
d070b7792b wallet: Replace sqlx with rusqlite. 2023-06-29 13:06:54 +02:00
parazyd
cbbfcef832 raft: Remove entire raft module.
This code is not needed anymore.
2023-06-29 13:06:54 +02:00
parazyd
761f3d508d rpc: Remove websockets client. 2023-06-29 13:06:54 +02:00
parazyd
9102fbf33c util/ringbuffer: Implement back() method. 2023-06-29 13:06:54 +02:00
parazyd
0ac5d6026b util/cli: Make -v show the [INFO] log target, and -vv to actually debug.
Also disable file logging by default.
This needs to be done through config files.
2023-06-29 13:06:54 +02:00
parazyd
1699d8e8d6 lilith: Clean up and implement periodic hosts purging.
The purging is done by attempting connections and removing the host
from the set if lilith is unable to connect and/or perform the handshake.
2023-06-29 13:06:54 +02:00
parazyd
ee2cc0e0b2 script/research: Remove arti-exp 2023-06-29 13:06:54 +02:00
parazyd
a065f0dae4 serial: Implement semver crate serialization. 2023-06-29 13:06:54 +02:00
parazyd
949b0bb1e9 net/hosts: Add onion note about Arti. 2023-06-29 13:06:54 +02:00
parazyd
672185cf44 net/tls: Implement client certificate verification.
This the same way like the previous commit 4751d2f81681230d90568610f415e0c56c3ace92
2023-06-29 13:06:54 +02:00
parazyd
ee62ec7bd2 net/tls: Implement server certificate verification.
The system works such that the server creates a new TLS certificate
from an ed25519 keypair. The public key is also encoded with base32
and placed into the altName of the certificate so it can easily be
used with other things.

The server certificate verification will parse the certificate, then
look for the altName extension, attempt to parse the public key from
there, make sure that it is the same as the actual certificate pubkey,
and finally it will verify the certificate signature.

We also remove "pem" dependencies and use binary DER encoding where
applicable.

This is a breaking change for existing deployments.

diff --git a/Cargo.lock b/Cargo.lock
index ff543ddedd..893bfa2380 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -177,6 +177,45 @@ version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8868f09ff8cea88b079da74ae569d9b8c62a23c68c746240b704ee6f7525c89c"

+[[package]]
+name = "asn1-rs"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0"
+dependencies = [
+ "asn1-rs-derive",
+ "asn1-rs-impl",
+ "displaydoc",
+ "nom",
+ "num-traits",
+ "rusticata-macros",
+ "thiserror",
+ "time 0.3.22",
+]
+
+[[package]]
+name = "asn1-rs-derive"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "synstructure",
+]
+
+[[package]]
+name = "asn1-rs-impl"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "async-attributes"
 version = "1.1.2"
@@ -1332,6 +1371,7 @@ dependencies = [
  "wasmer",
  "wasmer-compiler-singlepass",
  "wasmer-middlewares",
+ "x509-parser",
 ]

 [[package]]
@@ -1735,6 +1775,20 @@ dependencies = [
  "url",
 ]

+[[package]]
+name = "der-parser"
+version = "8.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e"
+dependencies = [
+ "asn1-rs",
+ "displaydoc",
+ "nom",
+ "num-bigint",
+ "num-traits",
+ "rusticata-macros",
+]
+
 [[package]]
 name = "derivative"
 version = "2.2.0"
@@ -1829,6 +1883,17 @@ dependencies = [
  "winapi",
 ]

+[[package]]
+name = "displaydoc"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.18",
+]
+
 [[package]]
 name = "dlib"
 version = "0.5.2"
@@ -3372,6 +3437,15 @@ dependencies = [
  "cc",
 ]

+[[package]]
+name = "oid-registry"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff"
+dependencies = [
+ "asn1-rs",
+]
+
 [[package]]
 name = "once_cell"
 version = "1.18.0"
@@ -4097,6 +4171,15 @@ dependencies = [
  "semver 0.11.0",
 ]

+[[package]]
+name = "rusticata-macros"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
+dependencies = [
+ "nom",
+]
+
 [[package]]
 name = "rustix"
 version = "0.37.20"
@@ -4734,6 +4817,18 @@ dependencies = [
  "unicode-ident",
 ]

+[[package]]
+name = "synstructure"
+version = "0.12.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "unicode-xid",
+]
+
 [[package]]
 name = "tabbycat"
 version = "0.1.2"
@@ -5163,6 +5258,12 @@ version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"

+[[package]]
+name = "unicode-xid"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+
 [[package]]
 name = "unicode_categories"
 version = "0.1.1"
@@ -5877,6 +5978,24 @@ dependencies = [
  "zeroize",
 ]

+[[package]]
+name = "x509-parser"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bab0c2f54ae1d92f4fcb99c0b7ccf0b1e3451cbd395e5f115ccbdbcb18d4f634"
+dependencies = [
+ "asn1-rs",
+ "data-encoding",
+ "der-parser",
+ "lazy_static",
+ "nom",
+ "oid-registry",
+ "ring",
+ "rusticata-macros",
+ "thiserror",
+ "time 0.3.22",
+]
+
 [[package]]
 name = "xsalsa20poly1305"
 version = "0.9.1"
diff --git a/Cargo.toml b/Cargo.toml
index 1aaf3c1641..4fb39d2603 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -77,9 +77,10 @@ ipnet = {version = "2.7.2", optional = true}
 socket2 = {version = "0.5.3", optional = true, features = ["all"]}

 # TLS cert utilities
-ed25519-compact = {version = "2.0.4", features = ["pem"], optional = true}
-rcgen = {version = "0.10.0", features = ["pem"], optional = true}
+ed25519-compact = {version = "2.0.4", optional = true}
+rcgen = {version = "0.10.0", optional = true}
 rustls-pemfile = {version = "1.0.2", optional = true}
+x509-parser = {version = "0.15.0", features = ["validate", "verify"], optional = true}

 # Encoding
 bs58 = {version = "0.5.0", optional = true}
@@ -213,6 +214,7 @@ net = [
     "rand",
     "rcgen",
     "rustls-pemfile",
+    "x509-parser",
     "serde",
     "serde_json",
     "socket2",
diff --git a/src/net/transport/upgrade_tls.rs b/src/net/transport/upgrade_tls.rs
index 570d5d3b01..8674c25938 100644
--- a/src/net/transport/upgrade_tls.rs
+++ b/src/net/transport/upgrade_tls.rs
@@ -31,9 +31,16 @@ use futures_rustls::{
     },
     TlsAcceptor, TlsConnector, TlsStream,
 };
+use log::error;
 use rustls_pemfile::pkcs8_private_keys;
+use x509_parser::{
+    extensions::{GeneralName, ParsedExtension},
+    parse_x509_certificate,
+    prelude::FromDer,
+    x509::SubjectPublicKeyInfo,
+};

-use crate::Result;
+use crate::{util::encoding::base32, Result};

 const CIPHER_SUITE: &str = "TLS13_CHACHA20_POLY1305_SHA256";

@@ -53,14 +60,82 @@ struct ServerCertificateVerifier;
 impl ServerCertVerifier for ServerCertificateVerifier {
     fn verify_server_cert(
         &self,
-        _end_entity: &Certificate,
+        end_entity: &Certificate,
         _intermediates: &[Certificate],
         _server_name: &ServerName,
         _scrs: &mut dyn Iterator<Item = &[u8]>,
         _ocsp_response: &[u8],
         _now: SystemTime,
     ) -> std::result::Result<ServerCertVerified, rustls::Error> {
-        // TODO: upsycle
+        // Parse the actual end_entity certificate
+        let Ok((_, cert)) = parse_x509_certificate(&end_entity.0) else {
+            error!(target: "net::tls", "Failed parsing server TLS certificate");
+            return Err(rustls::CertificateError::BadEncoding.into())
+        };
+
+        // We keep a public key in the altName, so we need to grab it.
+        // We compare that the actual public key of the certificate is
+        // the same as that one, and we then verify the signature of the
+        // provided certificate.
+        #[rustfmt::skip]
+        let oid = x509_parser::oid_registry::asn1_rs::oid!(2.5.29.17);
+        let Ok(Some(extension)) = cert.get_extension_unique(&oid) else {
+            error!(target: "net::tls", "Could not find OID extension for subjectAltName");
+            return Err(rustls::CertificateError::BadSignature.into())
+        };
+
+        // Parse the actual extension
+        // (ノಠ益ಠ)ノ彡┻━┻
+        let pubkey_bytes = match extension.parsed_extension() {
+            ParsedExtension::SubjectAlternativeName(altname) => {
+                if altname.general_names.len() != 1 {
+                    return Err(rustls::CertificateError::BadEncoding.into())
+                }
+
+                match altname.general_names[0] {
+                    GeneralName::DNSName(a) => base32::decode(a),
+                    _ => return Err(rustls::CertificateError::BadEncoding.into()),
+                }
+            }
+            _ => return Err(rustls::CertificateError::BadEncoding.into()),
+        };
+        let Some(pubkey_bytes) = pubkey_bytes else {
+            error!(target: "net::tls", "Could not decode server pubkey from altName");
+            return Err(rustls::CertificateError::BadSignature.into())
+        };
+        if pubkey_bytes.len() != 32 {
+            error!(target: "net::tls", "Could not decode server pubkey from altName");
+            return Err(rustls::CertificateError::BadSignature.into())
+        }
+        let pubkey_der = ed25519_compact::PublicKey::new(pubkey_bytes.try_into().unwrap()).to_der();
+        let Ok((_, parsed_pubkey)) = SubjectPublicKeyInfo::from_der(&pubkey_der) else {
+            error!(target: "net::tls", "Could not decode server pubkey from altName");
+            return Err(rustls::CertificateError::BadSignature.into())
+        };
+
+        let Ok(parsed_name_pubkey) = parsed_pubkey.parsed() else {
+            error!(target: "net::tls", "Could not parse server altName pubkey");
+            return Err(rustls::CertificateError::BadEncoding.into())
+        };
+
+        let Ok(parsed_cert_pubkey) = cert.public_key().parsed() else {
+            error!(target: "net::tls", "Could not parse server certificate pubkey");
+            return Err(rustls::CertificateError::BadEncoding.into())
+        };
+
+        if parsed_name_pubkey != parsed_cert_pubkey {
+            error!(target: "net::tls", "Server altName pubkey does not match certificate key");
+            return Err(rustls::CertificateError::BadSignature.into())
+        }
+
+        // Finally verify the signature. By passing `None`, it should use
+        // the certificate pubkey, but we also verified that it matches
+        // the one in altNames above.
+        if let Err(e) = cert.verify_signature(None) {
+            error!(target: "net::tls", "Failed verifying server certificate signature: {}", e);
+            return Err(rustls::CertificateError::BadSignature.into())
+        }
+
         Ok(ServerCertVerified::assertion())
     }
 }
@@ -92,11 +167,13 @@ pub struct TlsUpgrade {
 impl TlsUpgrade {
     pub fn new() -> Self {
         // On each instantiation, generate a new keypair and certificate.
-        let keypair_pem = ed25519_compact::KeyPair::generate().to_pem();
+        let keypair = ed25519_compact::KeyPair::generate();
+        let keypair_pem = keypair.to_pem();
         let secret_key = pkcs8_private_keys(&mut keypair_pem.as_bytes()).unwrap();
         let secret_key = rustls::PrivateKey(secret_key[0].clone());

-        let altnames = vec![String::from("dark.fi")];
+        let altname = base32::encode(false, keypair.pk.as_slice()).to_ascii_lowercase();
+        let altnames = vec![altname];
         let mut cert_params = rcgen::CertificateParams::new(altnames);
         cert_params.alg = &rcgen::PKCS_ED25519;
         cert_params.key_pair = Some(rcgen::KeyPair::from_pem(&keypair_pem).unwrap());
2023-06-29 13:06:54 +02:00
parazyd
cb4354e127 tests/network_transports: Avoid TLS EOF panic. 2023-06-29 13:06:54 +02:00
aggstam
c77ed67df1 validator: decoupled verification functions so we can chain them using same overlay 2023-06-28 20:52:29 +03:00
aggstam
97445fca25 blockchain: cleanup 2023-06-28 18:29:46 +03:00
aggstam
800adf21d9 blockchain/contract_store: added missing functions so transaction verification now operates purelly over an overlay 2023-06-28 16:04:01 +03:00
aggstam
feabf5a67a blockchain: rewrite completed
Attention: this commit breaks darkfid/faucetd network functionalities, so nodes can't sync or participate in the protocol. Wait for their rewrite(TM)
2023-06-28 14:42:14 +03:00
aggstam
f37e05e0ec validator/blockchain: added rest overlays needed for validations 2023-06-27 19:23:45 +03:00
aggstam
44be02f528 validator/blockchain/contract_store: unused import removed 2023-06-27 16:18:00 +03:00
ertosns
2e2aff3919 [reesarch/lotterysim] pool zero advantage demonestration 2023-06-27 13:56:22 +03:00
aggstam
6318c2bd76 script/research/lotterysim: .gitignore added 2023-06-27 12:20:28 +02:00
aggstam
9617331dde validator/blockchain/contract_store: reverted ContractStateStore::remove() since drop_tree() doesn't work in an atomic transaction 2023-06-27 12:20:28 +02:00
aggstam
92b9b339f4 validatro/blockchain/contract_store: make ContractStateStore::remove atomic 2023-06-27 12:38:49 +03:00
Dastan-glitch
64abd7db65 bin/tau: show info on one id instead of listing it 2023-06-27 05:28:31 +03:00
Dastan-glitch
5ec6f86e07 book: update tau doc 2023-06-27 05:12:56 +03:00
Dastan-glitch
8363c4c891 bin/tau: update cli help message 2023-06-27 05:11:05 +03:00
Dastan-glitch
d08c45045d bin/tau: change assign usage from key:value to @value 2023-06-27 04:48:14 +03:00
Dastan-glitch
64f3978280 bin/darkirc: minor test script rename contact 2023-06-27 04:24:02 +03:00
Dastan-glitch
194cd2e1ff book: update event_graph docs 2023-06-27 04:22:39 +03:00
aggstam
7a2f07502c WIP: validator: blockchain rewrite foundation added 2023-06-26 22:02:25 +03:00
aggstam
8401789b06 script/research/blockchain-explorer: updated to latest structs 2023-06-24 18:18:31 +03:00
aggstam
ec97e969c8 sdk: renamed SlotCheckpoint to Slot 2023-06-24 18:18:08 +03:00
aggstam
2e8b956073 contract/consensus/proof/proposal: minor formatting 2023-06-24 16:21:51 +03:00
aggstam
7deaab24e1 src: moved SlotCheckpoint to sdk so it can be used by contracts 2023-06-24 15:59:45 +03:00
Dastan-glitch
743789de0c bin/ircd: [bots] port as int 2023-06-24 04:40:38 +03:00
aggstam
80acf6baed contract/dao: integrate new validator 2023-06-23 16:44:55 +03:00
aggstam
275b6ac166 event_graph: test cleanup 2023-06-23 16:26:34 +03:00
aggstam
dd45787d8d chore: clippy 2023-06-23 16:19:25 +03:00
aggstam
703986909a contract/consensus: enable proper nullifiers check on stake and unstake 2023-06-23 16:17:25 +03:00
aggstam
0afaf50d65 contract/test-harness: integrate new validator 2023-06-23 16:12:14 +03:00
aggstam
5677bb5966 src/validator/verify_txs(): verifying slot added 2023-06-23 14:28:00 +03:00
aggstam
6ffa0974d5 src/validator: added verify_txs() and receive_slot_checkpoint()
sled-overlay was also updated to v0.0.5
2023-06-23 14:07:33 +03:00
aggstam
a980612ce8 src/validator: get TimeKeeper from upstream 2023-06-23 13:09:48 +03:00
aggstam
dd3d6a15e7 src/validator: set foundation for validator rewrite 2023-06-23 12:49:09 +03:00
lunar-mining
ccff162b11 Merge branch 'dnv-ringbuffer' 2023-06-23 01:17:25 +02:00
lunar-mining
d38e27d4f0 dnetview: deserialize log to RingBuffer
Parse the incoming log as a RingBuffer and stop dnetview from
crashing. This is a partial intergration of the /net upgrade: f3659261dc

There is a bug where message logs are showing as empty.
2023-06-23 00:57:27 +02:00
aggstam
d763fc154f contract/test-harness/consensus_proposal: typo 2023-06-22 16:21:54 +03:00
ertosns
7b1bb391be [research/lotterysim] edit cascade report 2023-06-22 16:13:23 +03:00
lunar-mining
92221ef5bb doc/ircd: rename pubkey to contact_public on ircd Contact specification 2023-06-22 11:57:39 +02:00
lunar-mining
975c7c7daa book: edit development/learn.md
language edit for correctness and readibility
2023-06-22 11:23:46 +02:00