diff --git a/book/api/metrics-generated.md b/book/api/metrics-generated.md
index 373a001e289..19c48e2142e 100644
--- a/book/api/metrics-generated.md
+++ b/book/api/metrics-generated.md
@@ -1219,10 +1219,9 @@
| event_events_acked | counter | The total number of events acknowledged by the event service |
| event_bytes_written | counter | The total number of bytes written to the event service |
| event_bytes_read | counter | The total number of bytes read from the event service |
-| event_auth_fail | counter | The total number of authentication failures with the event service |
| event_invalid_msg | counter | The total number of malformed messages received from the event service |
| event_connect_attempts | counter | The total number of connection attempts to the event service |
-| event_handshake_timeouts | counter | The total number of authentication handshake timeouts with the event service |
+| event_handshake_timeouts | counter | The total number of handshake timeouts with the event service |
diff --git a/contrib/event-test-server/Cargo.toml b/contrib/event-test-server/Cargo.toml
index 1f8882c4a62..1a34069b701 100644
--- a/contrib/event-test-server/Cargo.toml
+++ b/contrib/event-test-server/Cargo.toml
@@ -4,16 +4,15 @@ version = "0.1.0"
edition = "2021"
[dependencies]
-tonic = "0.14"
+async-stream = "0.3"
+tonic = { version = "0.14", features = ["tls-ring"] }
prost = "0.14"
tonic-prost = "0.14"
-tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
+tokio = { version = "1.0", features = ["macros", "net", "rt", "sync"] }
+tokio-rustls = { version = "0.26", default-features = false, features = ["ring"] }
tokio-stream = "0.1"
hex = "0.4"
-tower-http = { version = "0.6", features = ["trace"] }
-tracing = "0.1"
-tracing-subscriber = "0.3"
[build-dependencies]
-tonic-build = "0.14.2"
-tonic-prost-build = "0.14.2"
+tonic-build = "0.14"
+tonic-prost-build = "0.14"
diff --git a/contrib/event-test-server/build.rs b/contrib/event-test-server/build.rs
index 49bd22f9287..fdf42d9d026 100644
--- a/contrib/event-test-server/build.rs
+++ b/contrib/event-test-server/build.rs
@@ -1,6 +1,9 @@
fn main() -> Result<(), Box> {
tonic_prost_build::configure()
.build_server(true)
- .compile_protos(&["../../src/disco/events/schema/event.proto"], &["../../src/disco/events/schema"])?;
+ .compile_protos(
+ &["../../src/disco/events/schema/event.proto"],
+ &["../../src/disco/events/schema"],
+ )?;
Ok(())
}
diff --git a/contrib/event-test-server/src/main.rs b/contrib/event-test-server/src/main.rs
index a905872cfc7..213bd51fb74 100644
--- a/contrib/event-test-server/src/main.rs
+++ b/contrib/event-test-server/src/main.rs
@@ -1,18 +1,70 @@
+use std::sync::Arc;
+
+use async_stream::try_stream;
+use tokio::net::TcpListener;
use tokio::sync::mpsc;
+use tokio_rustls::rustls::client::danger::HandshakeSignatureValid;
+use tokio_rustls::rustls::crypto::ring;
+use tokio_rustls::rustls::pki_types::{
+ CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, SubjectPublicKeyInfoDer, UnixTime,
+};
+use tokio_rustls::rustls::server::danger::{ClientCertVerified, ClientCertVerifier};
+use tokio_rustls::rustls::{
+ version, DigitallySignedStruct, Error as TlsError, ServerConfig, SignatureScheme,
+};
+use tokio_rustls::TlsAcceptor;
use tokio_stream::wrappers::ReceiverStream;
-use tonic::{transport::Server, Request, Response, Status};
+use tonic::{
+ transport::server::{TcpConnectInfo, TlsConnectInfo},
+ transport::Server,
+ Request, Response, Status,
+};
pub mod events {
tonic::include_proto!("events.v1");
}
-use events::event_service_server::{EventService, EventServiceServer};
-use events::{
- StreamEventsRequest, StreamEventsResponse,
- AuthenticateRequest, AuthenticateResponse,
- ConfirmAuthChallengeRequest, ConfirmAuthChallengeResponse,
-};
use events::event::Event;
+use events::event_service_server::{EventService, EventServiceServer};
+use events::{HelloRequest, HelloResponse, StreamEventsRequest, StreamEventsResponse};
+
+const ALPN_H2: &[u8] = b"h2";
+const ED25519_SPKI_PREFIX: &[u8] = &[
+ 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
+];
+
+const SERVER_CERT_DER: &[u8] = &[
+ 0x30, 0x82, 0x01, 0x4f, 0x30, 0x82, 0x01, 0x01, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x72,
+ 0xe9, 0x82, 0x60, 0xef, 0x3b, 0xa1, 0x19, 0xd3, 0x9c, 0x24, 0x06, 0x7e, 0x63, 0xf0, 0x8f, 0x45,
+ 0x6b, 0x1f, 0x48, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x30, 0x1c, 0x31, 0x1a, 0x30, 0x18,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x65, 0x73,
+ 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x36,
+ 0x30, 0x31, 0x30, 0x31, 0x30, 0x34, 0x34, 0x31, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32, 0x36, 0x30,
+ 0x35, 0x30, 0x38, 0x30, 0x31, 0x30, 0x34, 0x34, 0x31, 0x5a, 0x30, 0x1c, 0x31, 0x1a, 0x30, 0x18,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x65, 0x73,
+ 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
+ 0x70, 0x03, 0x21, 0x00, 0x23, 0x8b, 0xc4, 0xee, 0x4d, 0xa9, 0x3f, 0x52, 0x43, 0x3e, 0xe3, 0x23,
+ 0xb7, 0x0d, 0xfe, 0xb7, 0xa3, 0x0c, 0x21, 0xd3, 0xb3, 0x23, 0x05, 0x6c, 0x6e, 0xa7, 0xd3, 0x17,
+ 0xbf, 0xfc, 0xe1, 0xa1, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+ 0x16, 0x04, 0x14, 0x79, 0x03, 0xc0, 0xd9, 0x41, 0x63, 0x05, 0xbe, 0xca, 0x8c, 0xeb, 0x6b, 0x2b,
+ 0x69, 0xb1, 0xd9, 0xc0, 0x22, 0x59, 0x2a, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+ 0x30, 0x16, 0x80, 0x14, 0x79, 0x03, 0xc0, 0xd9, 0x41, 0x63, 0x05, 0xbe, 0xca, 0x8c, 0xeb, 0x6b,
+ 0x2b, 0x69, 0xb1, 0xd9, 0xc0, 0x22, 0x59, 0x2a, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+ 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
+ 0x03, 0x41, 0x00, 0x9d, 0xbe, 0x72, 0xd7, 0xcb, 0x17, 0xb6, 0x61, 0x3d, 0x9f, 0x68, 0xc3, 0x07,
+ 0xb1, 0x6a, 0x3a, 0x69, 0xd7, 0xc8, 0xc3, 0xcd, 0x20, 0xc4, 0x43, 0x8b, 0x87, 0xa2, 0xb3, 0x44,
+ 0x83, 0xca, 0x7f, 0xb7, 0xbf, 0x11, 0x11, 0x11, 0x26, 0xd1, 0x44, 0xf0, 0x74, 0x99, 0xe2, 0xcf,
+ 0x1d, 0x19, 0xb7, 0xf0, 0xc9, 0x6d, 0xb5, 0x0d, 0x58, 0x12, 0x54, 0x10, 0x87, 0xcd, 0x65, 0x3b,
+ 0xa1, 0x68, 0x01,
+];
+
+// This key is plaintext intentionally -- this file is only used for
+// testing.
+const SERVER_KEY_DER: &[u8] = &[
+ 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20,
+ 0x22, 0xe8, 0xff, 0xec, 0xd8, 0x12, 0x17, 0xc1, 0x60, 0xe2, 0xf6, 0xe7, 0xf4, 0x87, 0x6d, 0xdb,
+ 0x7d, 0xf4, 0x9b, 0x55, 0x83, 0x5f, 0x37, 0xb3, 0xe4, 0x50, 0x33, 0x8b, 0x6e, 0x33, 0xaf, 0xb9,
+];
fn event_kind_name(event: &Option) -> &'static str {
match event.as_ref().and_then(|e| e.event.as_ref()) {
@@ -22,6 +74,119 @@ fn event_kind_name(event: &Option) -> &'static str {
}
}
+fn client_public_key(request: &Request>) -> Option<[u8; 32]> {
+ let connect_info = request
+ .extensions()
+ .get::>()?;
+ let certs = connect_info.peer_certs()?;
+ let spki = certs.first()?.as_ref();
+ spki.strip_prefix(ED25519_SPKI_PREFIX)?.try_into().ok()
+}
+
+#[derive(Debug)]
+struct AnyRpkVerifier {
+ supported_algs: tokio_rustls::rustls::crypto::WebPkiSupportedAlgorithms,
+}
+
+impl AnyRpkVerifier {
+ fn new() -> Self {
+ Self {
+ supported_algs: ring::default_provider().signature_verification_algorithms,
+ }
+ }
+
+ fn is_ed25519_subject_public_key_info(spki: &[u8]) -> bool {
+ spki.len() == ED25519_SPKI_PREFIX.len() + 32 && spki.starts_with(ED25519_SPKI_PREFIX)
+ }
+}
+
+impl ClientCertVerifier for AnyRpkVerifier {
+ fn root_hint_subjects(&self) -> &[tokio_rustls::rustls::DistinguishedName] {
+ &[]
+ }
+
+ fn verify_client_cert(
+ &self,
+ end_entity: &CertificateDer<'_>,
+ intermediates: &[CertificateDer<'_>],
+ _now: UnixTime,
+ ) -> Result {
+ if !intermediates.is_empty() {
+ return Err(TlsError::General(
+ "client raw public key must not include intermediates".into(),
+ ));
+ }
+ if !Self::is_ed25519_subject_public_key_info(end_entity.as_ref()) {
+ return Err(TlsError::General(
+ "client raw public key must be Ed25519 SubjectPublicKeyInfo".into(),
+ ));
+ }
+ Ok(ClientCertVerified::assertion())
+ }
+
+ fn verify_tls12_signature(
+ &self,
+ _message: &[u8],
+ _cert: &CertificateDer<'_>,
+ _dss: &DigitallySignedStruct,
+ ) -> Result {
+ Err(TlsError::General(
+ "raw public key client authentication requires TLS 1.3".into(),
+ ))
+ }
+
+ fn verify_tls13_signature(
+ &self,
+ message: &[u8],
+ cert: &CertificateDer<'_>,
+ dss: &DigitallySignedStruct,
+ ) -> Result {
+ let spki = SubjectPublicKeyInfoDer::from(cert.as_ref());
+ tokio_rustls::rustls::crypto::verify_tls13_signature_with_raw_key(
+ message,
+ &spki,
+ dss,
+ &self.supported_algs,
+ )
+ }
+
+ fn supported_verify_schemes(&self) -> Vec {
+ vec![SignatureScheme::ED25519]
+ }
+
+ fn requires_raw_public_keys(&self) -> bool {
+ true
+ }
+}
+
+fn tls_config() -> Result> {
+ let cert = CertificateDer::from(SERVER_CERT_DER.to_vec());
+ let key = PrivateKeyDer::from(PrivatePkcs8KeyDer::from(SERVER_KEY_DER.to_vec()));
+ let verifier = Arc::new(AnyRpkVerifier::new());
+ let mut config = ServerConfig::builder_with_protocol_versions(&[&version::TLS13])
+ .with_client_cert_verifier(verifier)
+ .with_single_cert(vec![cert], key)?;
+ config.alpn_protocols.push(ALPN_H2.to_vec());
+ Ok(config)
+}
+
+fn tls_incoming(
+ listener: TcpListener,
+ acceptor: TlsAcceptor,
+) -> impl tokio_stream::Stream<
+ Item = Result, std::io::Error>,
+> {
+ try_stream! {
+ loop {
+ let (stream, peer_addr) = listener.accept().await?;
+ match acceptor.accept(stream).await {
+ Ok(tls_stream) => yield tls_stream,
+ Err(err) => eprintln!("TLS handshake failed from {peer_addr}: {err}"),
+ }
+ }
+ }
+}
+
#[derive(Debug, Default)]
pub struct MyEventService;
@@ -29,30 +194,22 @@ pub struct MyEventService;
impl EventService for MyEventService {
type StreamEventsStream = ReceiverStream>;
- async fn authenticate(
- &self,
- request: Request,
- ) -> Result, Status> {
- println!("Received authenticate request from identity: {:?}",
- hex::encode(&request.get_ref().identity_pubkey));
- let challenge = vec![0u8; 32];
- Ok(Response::new(AuthenticateResponse { challenge }))
- }
-
- async fn confirm_auth_challenge(
+ async fn hello(
&self,
- request: Request,
- ) -> Result, Status> {
- println!("Received confirm_auth_challenge with signed challenge: {:?}",
- hex::encode(&request.get_ref().signed_challenge));
- Ok(Response::new(ConfirmAuthChallengeResponse {}))
+ _request: Request,
+ ) -> Result, Status> {
+ println!("Received hello request");
+ Ok(Response::new(HelloResponse {}))
}
async fn stream_events(
&self,
request: Request>,
) -> Result, Status> {
- println!("Client connected");
+ match client_public_key(&request) {
+ Some(public_key) => println!("Client connected: public_key={}", hex::encode(public_key)),
+ None => println!("Client connected: public_key="),
+ }
let mut stream = request.into_inner();
let (tx, rx) = mpsc::channel(128);
@@ -61,9 +218,15 @@ impl EventService for MyEventService {
loop {
match stream.message().await {
Ok(Some(event_tx)) => {
- println!("Received event: nonce={}, event_id={}, kind={}",
- event_tx.nonce, event_tx.event_id, event_kind_name(&event_tx.event));
- let ack = StreamEventsResponse { nonce: event_tx.nonce };
+ println!(
+ "Received event: nonce={}, event_id={}, kind={}",
+ event_tx.nonce,
+ event_tx.event_id,
+ event_kind_name(&event_tx.event)
+ );
+ let ack = StreamEventsResponse {
+ nonce: event_tx.nonce,
+ };
if tx.send(Ok(ack)).await.is_err() {
eprintln!("Failed to send ack, client disconnected");
break;
@@ -85,14 +248,16 @@ impl EventService for MyEventService {
}
}
-#[tokio::main]
+#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box> {
- let addr = "127.0.0.1:7878".parse()?;
- println!("Listening on {}", addr);
+ let addr = "127.0.0.1:7878";
+ let listener = TcpListener::bind(addr).await?;
+ let acceptor = TlsAcceptor::from(Arc::new(tls_config()?));
+ println!("Listening on https://{}", addr);
Server::builder()
.add_service(EventServiceServer::new(MyEventService))
- .serve(addr)
+ .serve_with_incoming(tls_incoming(listener, acceptor))
.await?;
Ok(())
diff --git a/src/app/firedancer-dev/main.h b/src/app/firedancer-dev/main.h
index a1d6e96af67..e6a9c20a0ef 100644
--- a/src/app/firedancer-dev/main.h
+++ b/src/app/firedancer-dev/main.h
@@ -122,7 +122,9 @@ fd_topo_run_tile_t * TILES[] = {
&fd_tile_shred,
&fd_tile_sign,
&fd_tile_metric,
+# if FD_HAS_OPENSSL
&fd_tile_event,
+# endif
&fd_tile_diag,
&fd_tile_gui,
&fd_tile_rpc,
diff --git a/src/app/firedancer/config/default.toml b/src/app/firedancer/config/default.toml
index e73a8f1e9a7..c80f5ac50c4 100644
--- a/src/app/firedancer/config/default.toml
+++ b/src/app/firedancer/config/default.toml
@@ -1463,7 +1463,12 @@ telemetry = true
# If no URL is provided, event reporting is disabled, although
# it is suggested to leave the default URL in place and set
# `telemetry` to false to disable event reporting.
- url = "http://events-in.firedancer.io"
+ url = "https://events-in.firedancer.io"
+
+ # By default, the TLS certificate of the event server is
+ # verified against the CA certs in /etc/ssl/certs. To disable
+ # certificate verification, set this option to 'false'.
+ tls_cert_verify = true
# The gui tile receives data from the validator and serves an HTTP
# endpoint to clients to view it.
diff --git a/src/app/firedancer/main.c b/src/app/firedancer/main.c
index 877f735eb8e..c7ac76cc882 100644
--- a/src/app/firedancer/main.c
+++ b/src/app/firedancer/main.c
@@ -107,7 +107,9 @@ fd_topo_run_tile_t * TILES[] = {
&fd_tile_shred,
&fd_tile_sign,
&fd_tile_metric,
+# if FD_HAS_OPENSSL
&fd_tile_event,
+# endif
&fd_tile_diag,
&fd_tile_gui,
&fd_tile_rpc,
diff --git a/src/app/firedancer/topology.c b/src/app/firedancer/topology.c
index 14eb97e562b..14ac30cbdb1 100644
--- a/src/app/firedancer/topology.c
+++ b/src/app/firedancer/topology.c
@@ -746,11 +746,12 @@ fd_topo_initialize( config_t * config ) {
FOR(shred_tile_cnt) fd_topob_tile_in ( topo, "shred", i, "metric_in", "tower_out", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
FOR(shred_tile_cnt) fd_topob_tile_out( topo, "shred", i, "shred_net", i );
+# if FD_HAS_OPENSSL
if( FD_LIKELY( telemetry_enabled ) ) {
fd_topob_wksp( topo, "event" );
fd_topob_wksp( topo, "event_sign" );
fd_topob_wksp( topo, "sign_event" );
- fd_topob_link( topo, "event_sign", "event_sign", 128UL, 32UL, 1UL );
+ fd_topob_link( topo, "event_sign", "event_sign", 128UL, 162UL, 1UL );
fd_topob_link( topo, "sign_event", "sign_event", 128UL, 64UL, 1UL );
fd_topob_tile( topo, "event", "event", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1, 0 );
fd_topob_tile_in( topo, "event", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
@@ -772,6 +773,9 @@ fd_topo_initialize( config_t * config ) {
fd_topob_tile_in( topo, "event", 0UL, "metric_in", "sign_event", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
fd_topob_tile_out( topo, "sign", 0UL, "sign_event", 0UL );
}
+# else /* no OpenSSL */
+ if( telemetry_enabled ) FD_LOG_WARNING(( "ignoring [telemetry] = true: this build of Firedancer is missing OpenSSL" ));
+# endif /* FD_HAS_OPENSSL */
if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
fd_topob_wksp( topo, "bundle_verif" );
@@ -1119,6 +1123,7 @@ fd_topo_configure_tile( fd_topo_tile_t * tile,
fd_cstr_ncpy( tile->event.identity_key_path, config->paths.identity_key, sizeof(tile->event.identity_key_path) );
fd_cstr_ncpy( tile->event.url, config->tiles.event.url, sizeof(tile->event.url) );
fd_cstr_ncpy( tile->event.action, config->action, sizeof(tile->event.action) );
+ tile->event.tls_cert_verify = !!config->tiles.event.tls_cert_verify;
} else if( FD_UNLIKELY( !strcmp( tile->name, "net" ) || !strcmp( tile->name, "sock" ) ) ) {
diff --git a/src/app/shared/commands/watch/watch.c b/src/app/shared/commands/watch/watch.c
index 1d1d2b0e884..04af105a461 100644
--- a/src/app/shared/commands/watch/watch.c
+++ b/src/app/shared/commands/watch/watch.c
@@ -608,12 +608,11 @@ write_event( config_t const * config,
ulong connection_state = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, CONNECTION_STATE ) ];
char const * connection_state_str;
switch( connection_state ) {
- case 0UL: connection_state_str = "disconnected"; break;
- case 1UL: connection_state_str = "connecting"; break;
- case 2UL: connection_state_str = "authenticating"; break;
- case 3UL: connection_state_str = "confirming_auth"; break;
- case 4UL: connection_state_str = "connected"; break;
- default: connection_state_str = "unknown"; break;
+ case 0UL: connection_state_str = "disconnected"; break;
+ case 1UL: connection_state_str = "connecting"; break;
+ case 2UL: connection_state_str = "registering"; break;
+ case 3UL: connection_state_str = "connected"; break;
+ default: connection_state_str = "unknown"; break;
}
ulong event_queue_count = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, EVENT_QUEUE_COUNT ) ];
diff --git a/src/app/shared/fd_config.h b/src/app/shared/fd_config.h
index da9d9e76e36..20b4698fb9c 100644
--- a/src/app/shared/fd_config.h
+++ b/src/app/shared/fd_config.h
@@ -455,6 +455,7 @@ struct fd_config {
struct {
char url[ 256 ];
+ int tls_cert_verify;
} event;
struct {
diff --git a/src/app/shared/fd_config_parse.c b/src/app/shared/fd_config_parse.c
index 8c22914015b..00f12782a6a 100644
--- a/src/app/shared/fd_config_parse.c
+++ b/src/app/shared/fd_config_parse.c
@@ -244,6 +244,7 @@ fd_config_extract_pod( uchar * pod,
CFG_POP ( ushort, tiles.metric.prometheus_listen_port );
CFG_POP ( cstr, tiles.event.url );
+ CFG_POP ( bool, tiles.event.tls_cert_verify );
CFG_POP ( bool, tiles.gui.enabled );
CFG_POP ( cstr, tiles.gui.gui_listen_address );
diff --git a/src/disco/events/Local.mk b/src/disco/events/Local.mk
index 9fa1b7775c3..8b19f9d9e45 100644
--- a/src/disco/events/Local.mk
+++ b/src/disco/events/Local.mk
@@ -1,10 +1,12 @@
-ifdef FD_HAS_HOSTED
$(call add-hdrs,fd_circq.h)
-$(call add-objs,fd_circq fd_event_client,fd_disco)
-ifdef FD_HAS_ALLOCA
-$(call add-objs,fd_event_tile,fd_disco)
-endif
-
+$(call add-objs,fd_circq,fd_disco)
$(call make-unit-test,test_circq,test_circq,fd_disco fd_flamenco fd_tango fd_util)
$(call run-unit-test,test_circq)
-endif
+ifdef FD_HAS_HOSTED
+ifdef FD_HAS_OPENSSL
+$(call add-objs,fd_event_auth fd_event_client,fd_disco)
+ifdef FD_HAS_ALLOCA
+$(call add-objs,fd_event_tile,fd_disco)
+endif # FD_HAS_ALLOCA
+endif # FD_HAS_OPENSSL
+endif # FD_HAS_HOSTED
diff --git a/src/disco/events/fd_event_auth.c b/src/disco/events/fd_event_auth.c
new file mode 100644
index 00000000000..520539bdff7
--- /dev/null
+++ b/src/disco/events/fd_event_auth.c
@@ -0,0 +1,424 @@
+#define _GNU_SOURCE
+#include "fd_event_auth.h"
+
+#if !FD_HAS_OPENSSL
+#error "Building fd_event_auth requires FD_HAS_OPENSSL"
+#endif
+
+#include "../keyguard/fd_keyguard.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#define FD_EVENT_RPK_PROVIDER_NAME "fd_event_rpk"
+#define FD_EVENT_RPK_KEYGUARD_PARAM "fd-keyguard"
+
+typedef struct fd_event_rpk_key {
+ uchar pubkey[ 32UL ];
+ fd_keyguard_client_t * keyguard_client;
+ int has_public;
+ int has_private;
+} fd_event_rpk_key_t;
+
+typedef struct fd_event_rpk_sig_ctx {
+ fd_event_rpk_key_t * key;
+ uchar msg[ FD_KEYGUARD_SIGN_REQ_MTU ];
+ ulong msg_sz;
+} fd_event_rpk_sig_ctx_t;
+
+static void *
+fd_event_rpk_keymgmt_new( void * provctx FD_PARAM_UNUSED ) {
+ return OPENSSL_zalloc( sizeof(fd_event_rpk_key_t) );
+}
+
+static void
+fd_event_rpk_keymgmt_free( void * keydata ) {
+ OPENSSL_free( keydata );
+}
+
+static void *
+fd_event_rpk_keymgmt_dup( void const * keydata_from,
+ int selection FD_PARAM_UNUSED ) {
+ fd_event_rpk_key_t const * from = keydata_from;
+ fd_event_rpk_key_t * to = OPENSSL_malloc( sizeof(fd_event_rpk_key_t) );
+ if( FD_UNLIKELY( !to ) ) return NULL;
+ *to = *from;
+ return to;
+}
+
+static int
+fd_event_rpk_keymgmt_import( void * keydata,
+ int selection,
+ OSSL_PARAM const * params ) {
+ fd_event_rpk_key_t * key = keydata;
+
+ if( selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY ) {
+ OSSL_PARAM const * pub = OSSL_PARAM_locate_const( params, OSSL_PKEY_PARAM_PUB_KEY );
+ if( FD_UNLIKELY( !pub || pub->data_size!=32UL ) ) return 0;
+ fd_memcpy( key->pubkey, pub->data, 32UL );
+ key->has_public = 1;
+ }
+
+ if( selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ) {
+ OSSL_PARAM const * kg = OSSL_PARAM_locate_const( params, FD_EVENT_RPK_KEYGUARD_PARAM );
+ ulong keyguard_ptr = 0UL;
+ if( FD_UNLIKELY(
+ !kg ||
+ !OSSL_PARAM_get_ulong( kg, &keyguard_ptr ) ||
+ !keyguard_ptr ) ) {
+ return 0;
+ }
+ key->keyguard_client = (fd_keyguard_client_t *)(uintptr_t)keyguard_ptr;
+ key->has_private = 1;
+ }
+
+ return 1;
+}
+
+static OSSL_PARAM const *
+fd_event_rpk_keymgmt_import_types( int selection FD_PARAM_UNUSED ) {
+ static OSSL_PARAM const import_types[] = {
+ OSSL_PARAM_octet_string( OSSL_PKEY_PARAM_PUB_KEY, NULL, 0 ),
+ OSSL_PARAM_ulong ( FD_EVENT_RPK_KEYGUARD_PARAM, NULL ),
+ OSSL_PARAM_END
+ };
+ return import_types;
+}
+
+static OSSL_PARAM const *
+fd_event_rpk_keymgmt_import_types_ex( void * provctx FD_PARAM_UNUSED,
+ int selection FD_PARAM_UNUSED ) {
+ return fd_event_rpk_keymgmt_import_types( selection );
+}
+
+static int
+fd_event_rpk_keymgmt_export( void const * keydata,
+ int selection,
+ OSSL_CALLBACK * param_cb,
+ void * cbarg ) {
+ fd_event_rpk_key_t const * key = keydata;
+ if( FD_UNLIKELY( selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ) ) return 0;
+ if( FD_UNLIKELY( (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) && !key->has_public ) ) return 0;
+
+ OSSL_PARAM params[] = {
+ OSSL_PARAM_construct_octet_string( OSSL_PKEY_PARAM_PUB_KEY, (void *)key->pubkey, 32UL ),
+ OSSL_PARAM_END
+ };
+ return param_cb( params, cbarg );
+}
+
+static OSSL_PARAM const *
+fd_event_rpk_keymgmt_export_types( int selection FD_PARAM_UNUSED ) {
+ static OSSL_PARAM const export_types[] = {
+ OSSL_PARAM_octet_string( OSSL_PKEY_PARAM_PUB_KEY, NULL, 0 ),
+ OSSL_PARAM_END
+ };
+ return export_types;
+}
+
+static OSSL_PARAM const *
+fd_event_rpk_keymgmt_export_types_ex( void * provctx FD_PARAM_UNUSED,
+ int selection FD_PARAM_UNUSED ) {
+ return fd_event_rpk_keymgmt_export_types( selection );
+}
+
+static int
+fd_event_rpk_keymgmt_get_params( void * keydata,
+ OSSL_PARAM params[] ) {
+ fd_event_rpk_key_t * key = keydata;
+
+ OSSL_PARAM * p = OSSL_PARAM_locate( params, OSSL_PKEY_PARAM_BITS );
+ if( p && FD_UNLIKELY( !OSSL_PARAM_set_int( p, 256 ) ) ) return 0;
+ p = OSSL_PARAM_locate( params, OSSL_PKEY_PARAM_SECURITY_BITS );
+ if( p && FD_UNLIKELY( !OSSL_PARAM_set_int( p, 128 ) ) ) return 0;
+ p = OSSL_PARAM_locate( params, OSSL_PKEY_PARAM_MAX_SIZE );
+ if( p && FD_UNLIKELY( !OSSL_PARAM_set_int( p, 64 ) ) ) return 0;
+ p = OSSL_PARAM_locate( params, OSSL_PKEY_PARAM_MANDATORY_DIGEST );
+ if( p && FD_UNLIKELY( !OSSL_PARAM_set_utf8_string( p, "" ) ) ) return 0;
+ p = OSSL_PARAM_locate( params, OSSL_PKEY_PARAM_PUB_KEY );
+ if( p && FD_UNLIKELY( !key->has_public || !OSSL_PARAM_set_octet_string( p, key->pubkey, 32UL ) ) ) return 0;
+ return 1;
+}
+
+static OSSL_PARAM const *
+fd_event_rpk_keymgmt_gettable_params( void * provctx FD_PARAM_UNUSED ) {
+ static OSSL_PARAM const gettable[] = {
+ OSSL_PARAM_int ( OSSL_PKEY_PARAM_BITS, NULL ),
+ OSSL_PARAM_int ( OSSL_PKEY_PARAM_SECURITY_BITS, NULL ),
+ OSSL_PARAM_int ( OSSL_PKEY_PARAM_MAX_SIZE, NULL ),
+ OSSL_PARAM_utf8_string ( OSSL_PKEY_PARAM_MANDATORY_DIGEST, NULL, 0 ),
+ OSSL_PARAM_octet_string( OSSL_PKEY_PARAM_PUB_KEY, NULL, 0 ),
+ OSSL_PARAM_END
+ };
+ return gettable;
+}
+
+static int
+fd_event_rpk_keymgmt_has( void const * keydata,
+ int selection ) {
+ fd_event_rpk_key_t const * key = keydata;
+ if( (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY ) && !key->has_public ) return 0;
+ if( (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) && !key->has_private ) return 0;
+ return 1;
+}
+
+static int
+fd_event_rpk_keymgmt_validate( void const * keydata,
+ int selection,
+ int checktype FD_PARAM_UNUSED ) {
+ return fd_event_rpk_keymgmt_has( keydata, selection );
+}
+
+static int
+fd_event_rpk_keymgmt_match( void const * keydata1,
+ void const * keydata2,
+ int selection ) {
+ fd_event_rpk_key_t const * key1 = keydata1;
+ fd_event_rpk_key_t const * key2 = keydata2;
+ if( selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY ) {
+ return key1->has_public && key2->has_public && !memcmp( key1->pubkey, key2->pubkey, 32UL );
+ }
+ return 1;
+}
+
+static char const *
+fd_event_rpk_keymgmt_query_operation_name( int operation_id ) {
+ return operation_id==OSSL_OP_SIGNATURE ? "ED25519" : NULL;
+}
+
+static void *
+fd_event_rpk_signature_newctx( void * provctx FD_PARAM_UNUSED,
+ char const * propq FD_PARAM_UNUSED ) {
+ return OPENSSL_zalloc( sizeof(fd_event_rpk_sig_ctx_t) );
+}
+
+static void
+fd_event_rpk_signature_freectx( void * ctx ) {
+ OPENSSL_free( ctx );
+}
+
+static int
+fd_event_rpk_signature_digest_sign_init( void * ctx,
+ char const * mdname,
+ void * provkey,
+ OSSL_PARAM const * params FD_PARAM_UNUSED ) {
+ fd_event_rpk_sig_ctx_t * sig_ctx = ctx;
+ if( FD_UNLIKELY( mdname && mdname[0] ) ) return 0;
+ sig_ctx->key = provkey;
+ sig_ctx->msg_sz = 0UL;
+ return !!sig_ctx->key;
+}
+
+static int
+fd_event_rpk_signature_sign_init( void * ctx,
+ void * provkey,
+ OSSL_PARAM const * params ) {
+ return fd_event_rpk_signature_digest_sign_init( ctx, NULL, provkey, params );
+}
+
+static int
+fd_event_rpk_signature_sign( void * ctx,
+ uchar * sig,
+ size_t * siglen,
+ size_t sigsize,
+ uchar const * tbs,
+ size_t tbslen ) {
+ fd_event_rpk_sig_ctx_t * sig_ctx = ctx;
+ if( FD_UNLIKELY( !sig_ctx->key || !sig_ctx->key->keyguard_client ) ) return 0;
+ if( !sig ) {
+ *siglen = 64UL;
+ return 1;
+ }
+ if( FD_UNLIKELY( sigsize<64UL || tbslen>FD_KEYGUARD_SIGN_REQ_MTU ) ) return 0;
+
+ fd_keyguard_client_sign( sig_ctx->key->keyguard_client,
+ sig,
+ tbs,
+ (ulong)tbslen,
+ FD_KEYGUARD_SIGN_TYPE_ED25519 );
+ *siglen = 64UL;
+ return 1;
+}
+
+static int
+fd_event_rpk_signature_digest_sign( void * ctx,
+ uchar * sigret,
+ size_t * siglen,
+ size_t sigsize,
+ uchar const * tbs,
+ size_t tbslen ) {
+ return fd_event_rpk_signature_sign( ctx, sigret, siglen, sigsize, tbs, tbslen );
+}
+
+static int
+fd_event_rpk_signature_digest_sign_update( void * ctx,
+ uchar const * data,
+ size_t datalen ) {
+ fd_event_rpk_sig_ctx_t * sig_ctx = ctx;
+ if( FD_UNLIKELY( datalen>FD_KEYGUARD_SIGN_REQ_MTU-sig_ctx->msg_sz ) ) return 0;
+ fd_memcpy( sig_ctx->msg+sig_ctx->msg_sz, data, datalen );
+ sig_ctx->msg_sz += datalen;
+ return 1;
+}
+
+static int
+fd_event_rpk_signature_digest_sign_final( void * ctx,
+ uchar * sig,
+ size_t * siglen,
+ size_t sigsize ) {
+ fd_event_rpk_sig_ctx_t * sig_ctx = ctx;
+ return fd_event_rpk_signature_sign( ctx, sig, siglen, sigsize, sig_ctx->msg, sig_ctx->msg_sz );
+}
+
+static int
+fd_event_rpk_signature_get_ctx_params( void * ctx FD_PARAM_UNUSED,
+ OSSL_PARAM params[] ) {
+ OSSL_PARAM * p = OSSL_PARAM_locate( params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID );
+ if( p ) {
+ static uchar const ed25519_alg_id[] = { 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70 };
+ if( FD_UNLIKELY( !OSSL_PARAM_set_octet_string( p, ed25519_alg_id, sizeof(ed25519_alg_id) ) ) ) return 0;
+ }
+ return 1;
+}
+
+static OSSL_PARAM const *
+fd_event_rpk_signature_gettable_ctx_params( void * ctx FD_PARAM_UNUSED,
+ void * provctx FD_PARAM_UNUSED ) {
+ static OSSL_PARAM const gettable[] = {
+ OSSL_PARAM_octet_string( OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0 ),
+ OSSL_PARAM_END
+ };
+ return gettable;
+}
+
+static OSSL_DISPATCH const fd_event_rpk_keymgmt_fns[] = {
+ { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))fd_event_rpk_keymgmt_new },
+ { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))fd_event_rpk_keymgmt_free },
+ { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))fd_event_rpk_keymgmt_dup },
+ { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))fd_event_rpk_keymgmt_import },
+ { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))fd_event_rpk_keymgmt_import_types },
+ { OSSL_FUNC_KEYMGMT_IMPORT_TYPES_EX, (void (*)(void))fd_event_rpk_keymgmt_import_types_ex },
+ { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))fd_event_rpk_keymgmt_export },
+ { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))fd_event_rpk_keymgmt_export_types },
+ { OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX, (void (*)(void))fd_event_rpk_keymgmt_export_types_ex },
+ { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))fd_event_rpk_keymgmt_get_params },
+ { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))fd_event_rpk_keymgmt_gettable_params },
+ { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))fd_event_rpk_keymgmt_has },
+ { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))fd_event_rpk_keymgmt_validate },
+ { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))fd_event_rpk_keymgmt_match },
+ { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))fd_event_rpk_keymgmt_query_operation_name },
+ OSSL_DISPATCH_END
+};
+
+static OSSL_DISPATCH const fd_event_rpk_signature_fns[] = {
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))fd_event_rpk_signature_newctx },
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))fd_event_rpk_signature_freectx },
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))fd_event_rpk_signature_sign_init },
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))fd_event_rpk_signature_sign },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))fd_event_rpk_signature_digest_sign_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void))fd_event_rpk_signature_digest_sign },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))fd_event_rpk_signature_digest_sign_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))fd_event_rpk_signature_digest_sign_final },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))fd_event_rpk_signature_get_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void))fd_event_rpk_signature_gettable_ctx_params },
+ OSSL_DISPATCH_END
+};
+
+static OSSL_ALGORITHM const fd_event_rpk_keymgmt_algs[] = {
+ { "ED25519:1.3.101.112", "provider=" FD_EVENT_RPK_PROVIDER_NAME, fd_event_rpk_keymgmt_fns, "Firedancer event Ed25519 keyguard keymgmt" },
+ { NULL, NULL, NULL, NULL }
+};
+
+static OSSL_ALGORITHM const fd_event_rpk_signature_algs[] = {
+ { "ED25519:1.3.101.112", "provider=" FD_EVENT_RPK_PROVIDER_NAME, fd_event_rpk_signature_fns, "Firedancer event Ed25519 keyguard signature" },
+ { NULL, NULL, NULL, NULL }
+};
+
+static OSSL_ALGORITHM const *
+fd_event_rpk_provider_query( void * provctx FD_PARAM_UNUSED,
+ int operation_id,
+ int * no_cache ) {
+ *no_cache = 0;
+ switch( operation_id ) {
+ case OSSL_OP_KEYMGMT: return fd_event_rpk_keymgmt_algs;
+ case OSSL_OP_SIGNATURE: return fd_event_rpk_signature_algs;
+ default: return NULL;
+ }
+}
+
+static OSSL_DISPATCH const fd_event_rpk_provider_fns[] = {
+ { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))fd_event_rpk_provider_query },
+ OSSL_DISPATCH_END
+};
+
+static int
+fd_event_rpk_provider_init( OSSL_CORE_HANDLE const * handle FD_PARAM_UNUSED,
+ OSSL_DISPATCH const * in FD_PARAM_UNUSED,
+ OSSL_DISPATCH const ** out,
+ void ** provctx ) {
+ *provctx = NULL;
+ *out = fd_event_rpk_provider_fns;
+ return 1;
+}
+
+static void
+fd_event_rpk_provider_ensure_loaded( void ) {
+ static OSSL_PROVIDER * provider;
+ FD_ONCE_BEGIN {
+ if( FD_UNLIKELY( !OSSL_PROVIDER_add_builtin( NULL, FD_EVENT_RPK_PROVIDER_NAME, fd_event_rpk_provider_init ) ) ) {
+ FD_LOG_ERR(( "OSSL_PROVIDER_add_builtin(" FD_EVENT_RPK_PROVIDER_NAME ") failed" ));
+ }
+ provider = OSSL_PROVIDER_load( NULL, FD_EVENT_RPK_PROVIDER_NAME );
+ if( FD_UNLIKELY( !provider ) ) {
+ FD_LOG_ERR(( "OSSL_PROVIDER_load(" FD_EVENT_RPK_PROVIDER_NAME ") failed" ));
+ }
+ } FD_ONCE_END;
+}
+
+static EVP_PKEY *
+fd_event_rpk_pkey_new( uchar const * identity_pubkey,
+ fd_keyguard_client_t * keyguard_client ) {
+ fd_event_rpk_provider_ensure_loaded();
+
+ EVP_PKEY_CTX * pkey_ctx = EVP_PKEY_CTX_new_from_name( NULL, "ED25519", "provider=" FD_EVENT_RPK_PROVIDER_NAME );
+ if( FD_UNLIKELY( !pkey_ctx ) ) return NULL;
+ if( FD_UNLIKELY( EVP_PKEY_fromdata_init( pkey_ctx )<=0 ) ) {
+ EVP_PKEY_CTX_free( pkey_ctx );
+ return NULL;
+ }
+
+ ulong keyguard_ptr = (ulong)(uintptr_t)keyguard_client;
+ OSSL_PARAM params[] = {
+ OSSL_PARAM_construct_octet_string( OSSL_PKEY_PARAM_PUB_KEY, (void *)identity_pubkey, 32UL ),
+ OSSL_PARAM_construct_ulong ( FD_EVENT_RPK_KEYGUARD_PARAM, &keyguard_ptr ),
+ OSSL_PARAM_END
+ };
+
+ EVP_PKEY * pkey = NULL;
+ int const ok = EVP_PKEY_fromdata( pkey_ctx, &pkey, OSSL_KEYMGMT_SELECT_KEYPAIR, params );
+ EVP_PKEY_CTX_free( pkey_ctx );
+ return ok>0 ? pkey : NULL;
+}
+
+int
+fd_event_auth_set_identity( SSL * ssl,
+ uchar const * identity_pubkey,
+ fd_keyguard_client_t * keyguard_client ) {
+ uchar client_cert_type = TLSEXT_cert_type_rpk;
+ if( FD_UNLIKELY( !SSL_set1_client_cert_type( ssl, &client_cert_type, 1UL ) ) ) return 0;
+
+ EVP_PKEY * rpk = fd_event_rpk_pkey_new( identity_pubkey, keyguard_client );
+ if( FD_UNLIKELY( !rpk ) ) return 0;
+
+ int const ok = SSL_use_PrivateKey( ssl, rpk );
+ EVP_PKEY_free( rpk );
+ return ok;
+}
diff --git a/src/disco/events/fd_event_auth.h b/src/disco/events/fd_event_auth.h
new file mode 100644
index 00000000000..9be28582dab
--- /dev/null
+++ b/src/disco/events/fd_event_auth.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_fd_src_disco_events_fd_event_auth_h
+#define HEADER_fd_src_disco_events_fd_event_auth_h
+
+/* fd_event_auth.h provides OpenSSL glue code to authenticate the
+ event client with the validator's identity key.
+
+ This is done securely via 'remote' (IPC) signing via the sign tile.
+ The identity key is only used to sign TLS 1.3 CertificateVerify
+ messages. */
+
+#include "../keyguard/fd_keyguard_client.h"
+#include
+
+FD_PROTOTYPES_BEGIN
+
+/* fd_event_auth_set_identity configures an SSL connection to use RFC
+ 7250 RawPublicKey client authentication using the validator
+ identity Ed25519 public key.
+
+ Signing is delegated to the sign tile via the provided keyguard
+ client object. (Retains mutable borrow on keyguard_client until the
+ SSL object is destroyed.) */
+
+int
+fd_event_auth_set_identity( SSL * ssl,
+ uchar const * identity_pubkey,
+ fd_keyguard_client_t * keyguard_client );
+
+FD_PROTOTYPES_END
+
+#endif /* HEADER_fd_src_disco_events_fd_event_auth_h */
diff --git a/src/disco/events/fd_event_client.c b/src/disco/events/fd_event_client.c
index ae69ab62f58..41142cf9fa2 100644
--- a/src/disco/events/fd_event_client.c
+++ b/src/disco/events/fd_event_client.c
@@ -1,5 +1,10 @@
#define _GNU_SOURCE
#include "fd_event_client.h"
+#include "fd_event_auth.h"
+
+#if !FD_HAS_OPENSSL
+#error "Building fd_event_client requires FD_HAS_OPENSSL"
+#endif
#include "../../waltz/resolv/fd_netdb.h"
#include "../../waltz/http/fd_url.h"
@@ -9,13 +14,8 @@
#include "../../ballet/pb/fd_pb_encode.h"
#include "../../util/net/fd_ip4.h"
#include "../../util/log/fd_log.h"
-#include "../keyguard/fd_keyguard.h"
-
-#if FD_HAS_OPENSSL
#include "../../waltz/openssl/fd_openssl.h"
#include
-#include
-#endif
#include
#include
@@ -30,12 +30,10 @@
#define DISCONNECT_REASON_TRANSPORT_FAILED (4)
#define DISCONNECT_REASON_PEER_CLOSED (5)
#define DISCONNECT_REASON_INVALID_CURSOR (6)
-#define DISCONNECT_REASON_AUTH_FAILED (7)
-#define DISCONNECT_REASON_INVALID_PROTOBUF (8)
+#define DISCONNECT_REASON_INVALID_PROTOBUF (7)
-#define FD_EVENT_CLIENT_REQ_CTX_AUTHENTICATE (1UL)
-#define FD_EVENT_CLIENT_REQ_CTX_CONFIRM_AUTH (2UL)
-#define FD_EVENT_CLIENT_REQ_CTX_STREAM_EVENTS (3UL)
+#define FD_EVENT_CLIENT_REQ_CTX_HELLO (1UL)
+#define FD_EVENT_CLIENT_REQ_CTX_STREAM_EVENTS (2UL)
struct fd_event_client {
fd_grpc_client_t * grpc_client;
@@ -79,15 +77,13 @@ struct fd_event_client {
int so_sndbuf;
int sockfd;
- int use_tls;
-#if FD_HAS_OPENSSL
SSL_CTX * ssl_ctx;
SSL * ssl;
-#endif
+ int tls_cert_verify;
- /* wallclock deadline for auth handshake, LONG_MAX if not
+ /* wallclock deadline for hello handshake, LONG_MAX if not
authenticating. */
- long auth_deadline;
+ long hello_deadline;
char server_fqdn[ 256 ]; /* cstr */
ulong server_fqdn_len;
@@ -129,8 +125,8 @@ fd_event_client_new( void * shmem,
ulong boot_id,
ulong machine_id,
ulong buf_max,
- int use_tls,
- void * ssl_ctx ) {
+ void * ssl_ctx,
+ int tls_cert_verify ) {
if( FD_UNLIKELY( !shmem ) ) {
FD_LOG_WARNING(( "NULL shmem" ));
return NULL;
@@ -145,6 +141,8 @@ fd_event_client_new( void * shmem,
fd_event_client_t * client = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_event_client_t), sizeof(fd_event_client_t) );
void * grpc_client_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_grpc_client_align(), fd_grpc_client_footprint( buf_max ) );
+ memset( client, 0, sizeof(fd_event_client_t) );
+
fd_url_t url[1];
_Bool _is_ssl = 0;
if( FD_UNLIKELY( fd_url_parse_endpoint( url,
@@ -177,18 +175,10 @@ fd_event_client_new( void * shmem,
client->so_sndbuf = so_sndbuf;
client->sockfd = -1;
- client->use_tls = use_tls;
-#if FD_HAS_OPENSSL
client->ssl_ctx = (SSL_CTX *)ssl_ctx;
client->ssl = NULL;
-#else
- (void)ssl_ctx;
- if( FD_UNLIKELY( use_tls ) ) {
- FD_LOG_ERR(( "TLS requested for event service but this build does not include OpenSSL. "
- "To install OpenSSL, re-run ./deps.sh and do a clean rebuild." ));
- }
-#endif
- client->auth_deadline = LONG_MAX;
+ client->hello_deadline = LONG_MAX;
+ client->tls_cert_verify = !!tls_cert_verify;
client->state = FD_EVENT_CLIENT_STATE_DISCONNECTED;
client->disconnected.reconnect_deadline = 0L;
@@ -275,19 +265,18 @@ disconnect( fd_event_client_t * client,
int reason,
int err,
int _backoff ) {
-#if FD_HAS_OPENSSL
+ client->event_stream = NULL;
if( FD_UNLIKELY( client->ssl ) ) {
SSL_free( client->ssl );
client->ssl = NULL;
}
-#endif
if( FD_LIKELY( -1!=client->sockfd ) ) {
if( FD_UNLIKELY( -1==close( client->sockfd ) ) ) FD_LOG_ERR(( "close() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
client->sockfd = -1;
- client->state = FD_EVENT_CLIENT_STATE_DISCONNECTED;
- fd_circq_reset_cursor( client->circq );
}
- client->auth_deadline = LONG_MAX;
+ client->hello_deadline = LONG_MAX;
+ client->state = FD_EVENT_CLIENT_STATE_DISCONNECTED;
+ fd_circq_reset_cursor( client->circq );
switch( reason ) {
case DISCONNECT_REASON_IDENTITY_CHANGED:
@@ -317,10 +306,6 @@ disconnect( fd_event_client_t * client,
FD_LOG_WARNING(( "disconnected: invalid cursor" ));
client->metrics.transport_fail_cnt++;
break;
- case DISCONNECT_REASON_AUTH_FAILED:
- FD_LOG_WARNING(( "disconnected: authentication failed" ));
- client->metrics.transport_fail_cnt++;
- break;
case DISCONNECT_REASON_INVALID_PROTOBUF:
FD_LOG_WARNING(( "disconnected: invalid protobuf message received" ));
client->metrics.transport_fail_cnt++;
@@ -352,7 +337,7 @@ reconnect( fd_event_client_t * client,
*charge_busy = 1;
client->metrics.connect_attempt_cnt++;
- FD_LOG_INFO(( "connecting to event server %s://%.*s:%u", client->use_tls ? "https" : "http", (int)client->server_fqdn_len, client->server_fqdn, client->server_tcp_port ));
+ FD_LOG_INFO(( "connecting to event server https://%.*s:%u", (int)client->server_fqdn_len, client->server_fqdn, client->server_tcp_port ));
/* FIXME IPv6 support */
fd_addrinfo_t hints = {0};
@@ -392,43 +377,46 @@ reconnect( fd_event_client_t * client,
return;
}
-# if FD_HAS_OPENSSL
- if( client->use_tls ) {
- BIO * bio = fd_openssl_bio_new_socket( client->sockfd, BIO_NOCLOSE );
- if( FD_UNLIKELY( !bio ) ) {
- FD_LOG_WARNING(( "fd_openssl_bio_new_socket failed" ));
- disconnect( client, DISCONNECT_REASON_CONNECT_FAILED, 0, 1 );
- return;
- }
+ BIO * bio = fd_openssl_bio_new_socket( client->sockfd, BIO_NOCLOSE );
+ if( FD_UNLIKELY( !bio ) ) {
+ FD_LOG_WARNING(( "fd_openssl_bio_new_socket failed" ));
+ disconnect( client, DISCONNECT_REASON_CONNECT_FAILED, 0, 1 );
+ return;
+ }
- SSL * ssl = SSL_new( client->ssl_ctx );
- if( FD_UNLIKELY( !ssl ) ) {
- FD_LOG_WARNING(( "SSL_new failed" ));
- BIO_free( bio );
- disconnect( client, DISCONNECT_REASON_CONNECT_FAILED, 0, 1 );
- return;
- }
+ SSL * ssl = SSL_new( client->ssl_ctx );
+ if( FD_UNLIKELY( !ssl ) ) {
+ FD_LOG_WARNING(( "SSL_new failed" ));
+ BIO_free( bio );
+ disconnect( client, DISCONNECT_REASON_CONNECT_FAILED, 0, 1 );
+ return;
+ }
- SSL_set_bio( ssl, bio, bio ); /* moves ownership of bio */
- SSL_set_connect_state( ssl );
+ SSL_set_bio( ssl, bio, bio ); /* moves ownership of bio */
+ SSL_set_connect_state( ssl );
- /* SNI and hostname verification */
- if( FD_UNLIKELY( !SSL_set_tlsext_host_name( ssl, client->server_fqdn ) ) ) {
- FD_LOG_WARNING(( "SSL_set_tlsext_host_name failed" ));
- SSL_free( ssl );
- disconnect( client, DISCONNECT_REASON_CONNECT_FAILED, 0, 1 );
- return;
- }
- if( FD_UNLIKELY( !SSL_set1_host( ssl, client->server_fqdn ) ) ) {
- FD_LOG_WARNING(( "SSL_set1_host failed" ));
- SSL_free( ssl );
- disconnect( client, DISCONNECT_REASON_CONNECT_FAILED, 0, 1 );
- return;
- }
+ if( FD_UNLIKELY( !fd_event_auth_set_identity( ssl, client->identity_pubkey, client->keyguard_client ) ) ) {
+ FD_LOG_WARNING(( "fd_event_auth_set_identity failed" ));
+ SSL_free( ssl );
+ disconnect( client, DISCONNECT_REASON_CONNECT_FAILED, 0, 1 );
+ return;
+ }
- client->ssl = ssl;
+ /* SNI and hostname verification */
+ if( FD_UNLIKELY( !SSL_set_tlsext_host_name( ssl, client->server_fqdn ) ) ) {
+ FD_LOG_WARNING(( "SSL_set_tlsext_host_name failed" ));
+ SSL_free( ssl );
+ disconnect( client, DISCONNECT_REASON_CONNECT_FAILED, 0, 1 );
+ return;
}
-# endif /* FD_HAS_OPENSSL */
+ if( FD_UNLIKELY( client->tls_cert_verify && !SSL_set1_host( ssl, client->server_fqdn ) ) ) {
+ FD_LOG_WARNING(( "SSL_set1_host failed" ));
+ SSL_free( ssl );
+ disconnect( client, DISCONNECT_REASON_CONNECT_FAILED, 0, 1 );
+ return;
+ }
+
+ client->ssl = ssl;
fd_grpc_client_reset( client->grpc_client );
@@ -440,6 +428,11 @@ static void
fd_event_client_grpc_conn_established( void * app_ctx ) {
fd_event_client_t * client = app_ctx;
+ client->event_stream = NULL;
+ client->metrics.transport_success_cnt++;
+ client->state = FD_EVENT_CLIENT_STATE_CONNECTED;
+ client->connected.connected_timestamp = fd_log_wallclock();
+
fd_pb_encoder_t auth_req[1];
uchar buffer[ 256UL ];
fd_pb_encoder_init( auth_req, buffer, sizeof(buffer) );
@@ -455,14 +448,14 @@ fd_event_client_grpc_conn_established( void * app_ctx ) {
fd_grpc_h2_stream_t * stream = fd_grpc_client_request_start1(
client->grpc_client,
- "/events.v1.EventService/Authenticate", strlen("/events.v1.EventService/Authenticate"),
- FD_EVENT_CLIENT_REQ_CTX_AUTHENTICATE,
+ "/events.v1.EventService/Hello", strlen("/events.v1.EventService/Hello"),
+ FD_EVENT_CLIENT_REQ_CTX_HELLO,
buffer, fd_pb_encoder_out_sz( auth_req ),
NULL, 0UL,
0 /* not streaming */ );
if( FD_UNLIKELY( !stream ) ) {
- FD_LOG_WARNING(( "Failed to start Authenticate request" ));
+ FD_LOG_WARNING(( "Failed to start Hello request" ));
return;
}
@@ -470,109 +463,22 @@ fd_event_client_grpc_conn_established( void * app_ctx ) {
fd_grpc_client_deadline_set( stream, FD_GRPC_DEADLINE_HEADER, now+(long)5e9 /* 5s */ );
fd_grpc_client_deadline_set( stream, FD_GRPC_DEADLINE_RX_END, now+(long)5e9 /* 5s */ );
- client->state = FD_EVENT_CLIENT_STATE_AUTHENTICATING;
- client->auth_deadline = now + (long)5e9; /* 5s */
+ client->state = FD_EVENT_CLIENT_STATE_REGISTERING;
+ client->hello_deadline = now + (long)5e9; /* 5s */
FD_LOG_INFO(( "Requesting auth challenge from event server " FD_IP4_ADDR_FMT ":%u (%.*s)",
FD_IP4_ADDR_FMT_ARGS( client->server_ip4_addr ), client->server_tcp_port,
(int)client->server_fqdn_len, client->server_fqdn ));
}
static void
-fd_event_client_handle_auth_challenge_resp( fd_event_client_t * client,
- void const * protobuf,
- ulong protobuf_sz ) {
- fd_pb_inbuf_t inbuf[1];
- fd_pb_inbuf_init( inbuf, protobuf, protobuf_sz );
-
- if( FD_UNLIKELY( protobuf_sz==0UL ) ) {
- FD_LOG_WARNING(( "Empty auth challenge response" ));
- client->defer_disconnect = DISCONNECT_REASON_AUTH_FAILED;
- return;
- }
-
- fd_pb_tlv_t challenge_tlv;
- if( FD_UNLIKELY( !fd_pb_read_tlv( inbuf, &challenge_tlv ) ) ) {
- FD_LOG_WARNING(( "Failed to parse auth challenge response" ));
- client->defer_disconnect = DISCONNECT_REASON_AUTH_FAILED;
- return;
- }
-
- if( FD_UNLIKELY( challenge_tlv.field_id!=1U || challenge_tlv.wire_type!=FD_PB_WIRE_TYPE_LEN ) ) {
- FD_LOG_WARNING(( "Unexpected field in auth challenge response" ));
- client->defer_disconnect = DISCONNECT_REASON_AUTH_FAILED;
- return;
- }
-
- ulong challenge_len = challenge_tlv.len;
- if( FD_UNLIKELY( challenge_len!=32UL ) ) {
- FD_LOG_WARNING(( "Invalid challenge size: %lu bytes", challenge_len ));
- client->defer_disconnect = DISCONNECT_REASON_AUTH_FAILED;
- return;
- }
-
- if( FD_UNLIKELY( fd_pb_inbuf_sz( inbuf )defer_disconnect = DISCONNECT_REASON_AUTH_FAILED;
- return;
- }
-
- uchar const * challenge_data = inbuf->cur;
- inbuf->cur += challenge_len;
-
- if( FD_UNLIKELY( fd_pb_inbuf_sz( inbuf ) ) ) {
- FD_LOG_WARNING(( "Trailing data in auth challenge response" ));
- client->defer_disconnect = DISCONNECT_REASON_AUTH_FAILED;
- return;
- }
-
- uchar signed_challenge[ 64UL ];
- fd_keyguard_client_sign( client->keyguard_client,
- signed_challenge,
- challenge_data,
- 32UL,
- FD_KEYGUARD_SIGN_TYPE_FD_EVENTS_AUTH_CONCAT_ED25519 );
-
- fd_pb_encoder_t confirm_req[1];
- uchar buffer[ 128UL ];
- fd_pb_encoder_init( confirm_req, buffer, sizeof(buffer) );
- fd_pb_push_bytes( confirm_req, 1U, signed_challenge, 64UL );
-
- fd_grpc_h2_stream_t * stream = fd_grpc_client_request_start1(
- client->grpc_client,
- "/events.v1.EventService/ConfirmAuthChallenge", strlen("/events.v1.EventService/ConfirmAuthChallenge"),
- FD_EVENT_CLIENT_REQ_CTX_CONFIRM_AUTH,
- buffer, fd_pb_encoder_out_sz( confirm_req ),
- NULL, 0UL,
- 0 /* not streaming */ );
-
- if( FD_UNLIKELY( !stream ) ) {
- FD_LOG_WARNING(( "Failed to start ConfirmAuthChallenge request" ));
- client->defer_disconnect = DISCONNECT_REASON_AUTH_FAILED;
- return;
- }
-
- long now = fd_log_wallclock();
- fd_grpc_client_deadline_set( stream, FD_GRPC_DEADLINE_HEADER, now+(long)5e9 /* 5s */ );
- fd_grpc_client_deadline_set( stream, FD_GRPC_DEADLINE_RX_END, now+(long)5e9 /* 5s */ );
-
- client->state = FD_EVENT_CLIENT_STATE_CONFIRMING_AUTH;
- FD_LOG_DEBUG(( "Sent signed auth challenge" ));
-}
-
-static void
-fd_event_client_handle_confirm_auth_resp( fd_event_client_t * client,
- void const * protobuf,
- ulong protobuf_sz ) {
- (void)protobuf;
- (void)protobuf_sz;
-
- client->event_stream = NULL;
- client->metrics.transport_success_cnt++;
+fd_env_client_handle_hello_resp( fd_event_client_t * client,
+ void const * protobuf,
+ ulong protobuf_sz ) {
+ (void)protobuf; (void)protobuf_sz;
client->state = FD_EVENT_CLIENT_STATE_CONNECTED;
- client->connected.connected_timestamp = fd_log_wallclock();
FD_LOG_NOTICE(( "connected to event server " FD_IP4_ADDR_FMT ":%u (%.*s)",
- FD_IP4_ADDR_FMT_ARGS( client->server_ip4_addr ), client->server_tcp_port,
- (int)client->server_fqdn_len, client->server_fqdn ));
+ FD_IP4_ADDR_FMT_ARGS( client->server_ip4_addr ), client->server_tcp_port,
+ (int)client->server_fqdn_len, client->server_fqdn ));
}
static void
@@ -642,11 +548,8 @@ fd_event_client_grpc_rx_msg( void * app_ctx,
fd_event_client_t * client = app_ctx;
switch( request_ctx ) {
- case FD_EVENT_CLIENT_REQ_CTX_AUTHENTICATE:
- fd_event_client_handle_auth_challenge_resp( client, protobuf, protobuf_sz );
- break;
- case FD_EVENT_CLIENT_REQ_CTX_CONFIRM_AUTH:
- fd_event_client_handle_confirm_auth_resp( client, protobuf, protobuf_sz );
+ case FD_EVENT_CLIENT_REQ_CTX_HELLO:
+ fd_env_client_handle_hello_resp( client, protobuf, protobuf_sz );
break;
case FD_EVENT_CLIENT_REQ_CTX_STREAM_EVENTS:
fd_event_client_handle_stream_events_resp( client, protobuf, protobuf_sz );
@@ -678,12 +581,11 @@ fd_event_client_grpc_rx_end( void * app_ctx,
if( FD_UNLIKELY( resp->grpc_status!=FD_GRPC_STATUS_OK ) ) {
switch( request_ctx ) {
- case FD_EVENT_CLIENT_REQ_CTX_AUTHENTICATE:
- case FD_EVENT_CLIENT_REQ_CTX_CONFIRM_AUTH:
- FD_LOG_WARNING(( "Event authentication failed (gRPC status %u-%s): %.*s",
+ case FD_EVENT_CLIENT_REQ_CTX_HELLO:
+ FD_LOG_WARNING(( "Hello request failed (gRPC status %u-%s): %.*s",
resp->grpc_status, fd_grpc_status_cstr( resp->grpc_status ),
(int)resp->grpc_msg_len, resp->grpc_msg ));
- client->defer_disconnect = DISCONNECT_REASON_AUTH_FAILED;
+ client->defer_disconnect = DISCONNECT_REASON_PEER_CLOSED;
return;
case FD_EVENT_CLIENT_REQ_CTX_STREAM_EVENTS:
FD_LOG_WARNING(( "Event stream failed (gRPC status %u-%s): %.*s",
@@ -719,7 +621,7 @@ fd_event_client_grpc_rx_timeout( void * app_ctx,
static void
fd_event_client_grpc_ping_ack( void * app_ctx ) {
(void)app_ctx;
- FD_LOG_WARNING(( "Event gRPC ping ack" ));
+ FD_LOG_DEBUG(( "Event gRPC ping ack" ));
}
static void
@@ -767,21 +669,15 @@ fd_event_client_poll( fd_event_client_t * client,
return;
}
}
- /* Check auth handshake timeout */
- if( FD_UNLIKELY( (client->state==FD_EVENT_CLIENT_STATE_AUTHENTICATING || client->state==FD_EVENT_CLIENT_STATE_CONFIRMING_AUTH) && now>client->auth_deadline ) ) {
- FD_LOG_WARNING(( "auth handshake timed out" ));
+ /* Check hello timeout */
+ if( FD_UNLIKELY( client->state==FD_EVENT_CLIENT_STATE_REGISTERING && now>client->hello_deadline ) ) {
+ FD_LOG_WARNING(( "hello request timed out" ));
client->metrics.handshake_timeout_cnt++;
disconnect( client, DISCONNECT_REASON_TIMEOUT, 0, 1 );
return;
}
if( FD_LIKELY( client->state!=FD_EVENT_CLIENT_STATE_DISCONNECTED ) ) {
- int rxtx_err;
-# if FD_HAS_OPENSSL
- if( client->use_tls )
- rxtx_err = fd_grpc_client_rxtx_ossl( client->grpc_client, client->ssl, charge_busy );
- else
-# endif
- rxtx_err = fd_grpc_client_rxtx_socket( client->grpc_client, client->sockfd, charge_busy );
+ int rxtx_err = fd_grpc_client_rxtx_ossl( client->grpc_client, client->ssl, charge_busy );
if( FD_UNLIKELY( -1==rxtx_err ) ) {
disconnect( client, DISCONNECT_REASON_TRANSPORT_FAILED, errno, 1 );
return;
@@ -791,7 +687,6 @@ fd_event_client_poll( fd_event_client_t * client,
if( FD_UNLIKELY( client->defer_disconnect!=INT_MAX ) ) {
int reason = client->defer_disconnect;
client->defer_disconnect = INT_MAX;
- if( reason==DISCONNECT_REASON_AUTH_FAILED ) client->metrics.auth_fail_cnt++;
if( reason==DISCONNECT_REASON_INVALID_PROTOBUF ) client->metrics.invalid_msg_cnt++;
disconnect( client, reason, 0, 1 );
return;
diff --git a/src/disco/events/fd_event_client.h b/src/disco/events/fd_event_client.h
index 116b08d2c83..5929678b856 100644
--- a/src/disco/events/fd_event_client.h
+++ b/src/disco/events/fd_event_client.h
@@ -4,16 +4,12 @@
#include "fd_circq.h"
#include "../keyguard/fd_keyguard_client.h"
#include "../../discof/genesis/fd_genesi_tile.h"
-
-#if FD_HAS_OPENSSL
#include
-#endif
-#define FD_EVENT_CLIENT_STATE_DISCONNECTED (0)
-#define FD_EVENT_CLIENT_STATE_CONNECTING (1)
-#define FD_EVENT_CLIENT_STATE_AUTHENTICATING (2)
-#define FD_EVENT_CLIENT_STATE_CONFIRMING_AUTH (3)
-#define FD_EVENT_CLIENT_STATE_CONNECTED (4)
+#define FD_EVENT_CLIENT_STATE_DISCONNECTED (0)
+#define FD_EVENT_CLIENT_STATE_CONNECTING (1)
+#define FD_EVENT_CLIENT_STATE_REGISTERING (2)
+#define FD_EVENT_CLIENT_STATE_CONNECTED (3)
struct fd_event_client;
typedef struct fd_event_client fd_event_client_t;
@@ -25,7 +21,6 @@ struct fd_event_client_metrics {
ulong events_acked;
ulong bytes_written;
ulong bytes_read;
- ulong auth_fail_cnt;
ulong invalid_msg_cnt;
ulong connect_attempt_cnt;
ulong handshake_timeout_cnt;
@@ -55,8 +50,8 @@ fd_event_client_new( void * shmem,
ulong boot_id,
ulong machine_id,
ulong buf_max,
- int use_tls,
- void * ssl_ctx );
+ void * ssl_ctx,
+ int tls_cert_verify );
fd_event_client_t *
fd_event_client_join( void * shec );
diff --git a/src/disco/events/fd_event_tile.c b/src/disco/events/fd_event_tile.c
index 234e2d56e7e..c1854257132 100644
--- a/src/disco/events/fd_event_tile.c
+++ b/src/disco/events/fd_event_tile.c
@@ -2,6 +2,10 @@
#include "fd_circq.h"
#include "fd_event_client.h"
+#if !FD_HAS_OPENSSL
+#error "Building fd_event_tile requires FD_HAS_OPENSSL"
+#endif
+
#include "../fd_txn_m.h"
#include "../metrics/fd_metrics.h"
#include "../net/fd_net_tile.h"
@@ -15,13 +19,10 @@
#include "../../ballet/lthash/fd_lthash.h"
#include "../../ballet/pb/fd_pb_encode.h"
#include "../../tango/tempo/fd_tempo.h"
-
-#if FD_HAS_OPENSSL
#include "../../util/alloc/fd_alloc.h"
#include "../../waltz/openssl/fd_openssl.h"
#include "../../waltz/openssl/fd_openssl_tile.h"
#include
-#endif
#include
#include
@@ -81,10 +82,7 @@ struct fd_event_tile {
uchar identity_pubkey[ 32UL ];
- int use_tls;
-#if FD_HAS_OPENSSL
SSL_CTX * ssl_ctx;
-#endif
fd_keyguard_client_t keyguard_client[1];
fd_rng_t rng[1];
@@ -107,9 +105,7 @@ scratch_align( void ) {
ulong a = alignof( fd_event_tile_t );
a = fd_ulong_max( a, fd_event_client_align() );
a = fd_ulong_max( a, fd_circq_align() );
-# if FD_HAS_OPENSSL
a = fd_ulong_max( a, fd_alloc_align() );
-# endif
return a;
}
@@ -121,20 +117,16 @@ scratch_footprint( fd_topo_tile_t const * tile ) {
l = FD_LAYOUT_APPEND( l, alignof(fd_event_tile_t), sizeof(fd_event_tile_t) );
l = FD_LAYOUT_APPEND( l, fd_event_client_align(), fd_event_client_footprint( GRPC_BUF_MAX ) );
l = FD_LAYOUT_APPEND( l, fd_circq_align(), fd_circq_footprint( 1UL<<30UL ) ); /* 1GiB circq for events */
-# if FD_HAS_OPENSSL
- l = FD_LAYOUT_APPEND( l, fd_alloc_align(), fd_alloc_footprint() );
-# endif
+ l = FD_LAYOUT_APPEND( l, fd_alloc_align(), fd_alloc_footprint() );
return FD_LAYOUT_FINI( l, scratch_align() );
}
-# if FD_HAS_OPENSSL
FD_FN_CONST static inline ulong
loose_footprint( fd_topo_tile_t const * tile ) {
(void)tile;
/* Extra workspace memory for OpenSSL dynamic allocations */
return 1UL<<26UL; /* 64 MiB */
}
-# endif
static inline void
metrics_write( fd_event_tile_t * ctx ) {
@@ -144,16 +136,15 @@ metrics_write( fd_event_tile_t * ctx ) {
FD_MGAUGE_SET( EVENT, EVENT_QUEUE_BYTES_CAPACITY, ctx->circq->size );
fd_event_client_metrics_t const * metrics = fd_event_client_metrics( ctx->client );
- FD_MCNT_SET( EVENT, EVENTS_SENT, metrics->events_sent );
- FD_MCNT_SET( EVENT, EVENTS_ACKED, metrics->events_acked );
- FD_MCNT_SET( EVENT, BYTES_WRITTEN, metrics->bytes_written );
- FD_MCNT_SET( EVENT, BYTES_READ, metrics->bytes_read );
- FD_MCNT_SET( EVENT, AUTH_FAIL, metrics->auth_fail_cnt );
- FD_MCNT_SET( EVENT, INVALID_MSG, metrics->invalid_msg_cnt );
- FD_MCNT_SET( EVENT, CONNECT_ATTEMPTS, metrics->connect_attempt_cnt );
- FD_MCNT_SET( EVENT, HANDSHAKE_TIMEOUTS, metrics->handshake_timeout_cnt );
-
- FD_MGAUGE_SET( EVENT, CONNECTION_STATE, fd_event_client_state( ctx->client ) );
+ FD_MCNT_SET( EVENT, EVENTS_SENT, metrics->events_sent );
+ FD_MCNT_SET( EVENT, EVENTS_ACKED, metrics->events_acked );
+ FD_MCNT_SET( EVENT, BYTES_WRITTEN, metrics->bytes_written );
+ FD_MCNT_SET( EVENT, BYTES_READ, metrics->bytes_read );
+ FD_MCNT_SET( EVENT, INVALID_MSG, metrics->invalid_msg_cnt );
+ FD_MCNT_SET( EVENT, CONNECT_ATTEMPTS, metrics->connect_attempt_cnt );
+ FD_MCNT_SET( EVENT, HANDSHAKE_TIMEOUTS, metrics->handshake_timeout_cnt );
+
+ FD_MGAUGE_SET( EVENT, CONNECTION_STATE, fd_event_client_state( ctx->client ) );
}
static void
@@ -339,10 +330,7 @@ privileged_init( fd_topo_t * topo,
fd_event_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_event_tile_t), sizeof(fd_event_tile_t) );
FD_SCRATCH_ALLOC_APPEND( l, fd_event_client_align(), fd_event_client_footprint( GRPC_BUF_MAX ) );
FD_SCRATCH_ALLOC_APPEND( l, fd_circq_align(), fd_circq_footprint( 1UL<<30UL ) );
-# if FD_HAS_OPENSSL
void * alloc_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_alloc_align(), fd_alloc_footprint() );
- (void)alloc_mem;
-# endif
ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
@@ -384,37 +372,34 @@ privileged_init( fd_topo_t * topo,
if( FD_UNLIKELY( fd_url_parse_endpoint( url, tile->event.url, strlen( tile->event.url ), &port, &is_ssl, "[tiles.event.url]" ) ) ) {
FD_LOG_ERR(( "Could not parse [tiles.event.url]" ));
}
- ctx->use_tls = is_ssl;
+ if( FD_UNLIKELY( !is_ssl ) ) {
+ FD_LOG_ERR(( "[tiles.event.url] must start with \"https://\"" ));
+ }
-# if FD_HAS_OPENSSL
ctx->ssl_ctx = NULL;
- if( ctx->use_tls ) {
- fd_alloc_t * alloc = fd_alloc_join( fd_alloc_new( alloc_mem, 1UL ), tile->kind_id );
- if( FD_UNLIKELY( !alloc ) ) FD_LOG_ERR(( "fd_alloc_new failed" ));
- fd_ossl_tile_init( alloc );
+ fd_alloc_t * alloc = fd_alloc_join( fd_alloc_new( alloc_mem, 1UL ), tile->kind_id );
+ if( FD_UNLIKELY( !alloc ) ) FD_LOG_ERR(( "fd_alloc_new failed" ));
+ fd_ossl_tile_init( alloc );
- SSL_CTX * ssl_ctx = SSL_CTX_new( TLS_client_method() );
- if( FD_UNLIKELY( !ssl_ctx ) ) FD_LOG_ERR(( "SSL_CTX_new failed" ));
+ SSL_CTX * ssl_ctx = SSL_CTX_new( TLS_client_method() );
+ if( FD_UNLIKELY( !ssl_ctx ) ) FD_LOG_ERR(( "SSL_CTX_new failed" ));
- if( FD_UNLIKELY( !SSL_CTX_set_mode( ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_AUTO_RETRY ) ) )
- FD_LOG_ERR(( "SSL_CTX_set_mode failed" ));
+ if( FD_UNLIKELY( !SSL_CTX_set_mode( ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_AUTO_RETRY ) ) )
+ FD_LOG_ERR(( "SSL_CTX_set_mode failed" ));
- if( FD_UNLIKELY( !SSL_CTX_set_min_proto_version( ssl_ctx, TLS1_3_VERSION ) ) )
- FD_LOG_ERR(( "SSL_CTX_set_min_proto_version(ssl_ctx,TLS1_3_VERSION) failed" ));
+ if( FD_UNLIKELY( !SSL_CTX_set_min_proto_version( ssl_ctx, TLS1_3_VERSION ) ) )
+ FD_LOG_ERR(( "SSL_CTX_set_min_proto_version(ssl_ctx,TLS1_3_VERSION) failed" ));
- if( FD_UNLIKELY( 0!=SSL_CTX_set_alpn_protos( ssl_ctx, (uchar const *)"\x02h2", 3 ) ) )
- FD_LOG_ERR(( "SSL_CTX_set_alpn_protos failed" ));
+ if( FD_UNLIKELY( 0!=SSL_CTX_set_alpn_protos( ssl_ctx, (uchar const *)"\x02h2", 3 ) ) )
+ FD_LOG_ERR(( "SSL_CTX_set_alpn_protos failed" ));
+ if( tile->event.tls_cert_verify ) {
fd_ossl_load_certs( ssl_ctx ); /* also sets SSL_VERIFY_PEER */
-
- ctx->ssl_ctx = ssl_ctx;
+ } else {
+ SSL_CTX_set_verify( ssl_ctx, SSL_VERIFY_NONE, NULL );
}
-# else
- if( FD_UNLIKELY( ctx->use_tls ) ) {
- FD_LOG_ERR(( "TLS requested for event service (https:// URL) but this build "
- "does not include OpenSSL. Re-run ./deps.sh and do a clean rebuild." ));
- }
-# endif
+
+ ctx->ssl_ctx = ssl_ctx;
}
static void
@@ -426,9 +411,7 @@ unprivileged_init( fd_topo_t * topo,
fd_event_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_event_tile_t), sizeof(fd_event_tile_t) );
void * _event_client = FD_SCRATCH_ALLOC_APPEND( l, fd_event_client_align(), fd_event_client_footprint( GRPC_BUF_MAX ) );
void * _circq = FD_SCRATCH_ALLOC_APPEND( l, fd_circq_align(), fd_circq_footprint( 1UL<<30UL ) );
-# if FD_HAS_OPENSSL
FD_SCRATCH_ALLOC_APPEND( l, fd_alloc_align(), fd_alloc_footprint() );
-# endif
ulong sign_in_idx = fd_topo_find_tile_in_link ( topo, tile, "sign_event", tile->kind_id );
ulong sign_out_idx = fd_topo_find_tile_out_link( topo, tile, "event_sign", tile->kind_id );
@@ -452,10 +435,7 @@ unprivileged_init( fd_topo_t * topo,
ctx->circq = fd_circq_join( fd_circq_new( _circq, 1UL<<30UL /* 1GiB */ ) );
FD_TEST( ctx->circq );
- void * ssl_ctx_ptr = NULL;
-# if FD_HAS_OPENSSL
- ssl_ctx_ptr = ctx->ssl_ctx;
-# endif
+ void * ssl_ctx_ptr = ctx->ssl_ctx;
/* Rewrite the URL to hardcode port 7878 regardless of the port in
the configured URL. */
@@ -484,8 +464,8 @@ unprivileged_init( fd_topo_t * topo,
ctx->boot_id,
ctx->machine_id,
GRPC_BUF_MAX,
- ctx->use_tls,
- ssl_ctx_ptr ) );
+ ssl_ctx_ptr,
+ tile->event.tls_cert_verify ) );
FD_TEST( ctx->client );
ctx->topo = topo;
@@ -596,9 +576,7 @@ fd_topo_run_tile_t fd_tile_event = {
.populate_allowed_fds = populate_allowed_fds,
.scratch_align = scratch_align,
.scratch_footprint = scratch_footprint,
-# if FD_HAS_OPENSSL
.loose_footprint = loose_footprint,
-# endif
.privileged_init = privileged_init,
.unprivileged_init = unprivileged_init,
.run = stem_run,
diff --git a/src/disco/events/schema/event.proto b/src/disco/events/schema/event.proto
index e703134a859..183b845ea26 100644
--- a/src/disco/events/schema/event.proto
+++ b/src/disco/events/schema/event.proto
@@ -22,8 +22,8 @@ message StreamEventsResponse {
uint64 nonce = 1;
}
-message AuthenticateRequest {
- bytes identity_pubkey = 1;
+message HelloRequest {
+ reserved 1;
string version = 2;
bytes genesis_hash = 3;
uint64 shred_version = 4;
@@ -33,24 +33,14 @@ message AuthenticateRequest {
string action = 8;
}
-message AuthenticateResponse {
- bytes challenge = 1;
-}
-
-message ConfirmAuthChallengeRequest {
- bytes signed_challenge = 1;
-}
-
-message ConfirmAuthChallengeResponse {
+message HelloResponse {
+ reserved 1;
}
// An event server for receiving application reported events
service EventService {
- // Generate an authentication challenge for the client to sign
- rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse) {}
-
- // Confirm the signed authentication challenge from the client
- rpc ConfirmAuthChallenge(ConfirmAuthChallengeRequest) returns (ConfirmAuthChallengeResponse) {}
+ // Send instance metadata on startup
+ rpc Hello(HelloRequest) returns (HelloResponse) {}
// Stream of events from client to server, and acknowledgements from server to client
rpc StreamEvents (stream StreamEventsRequest) returns (stream StreamEventsResponse);
diff --git a/src/disco/keyguard/fd_keyguard.h b/src/disco/keyguard/fd_keyguard.h
index 1f77a40b3bd..e798e96ba22 100644
--- a/src/disco/keyguard/fd_keyguard.h
+++ b/src/disco/keyguard/fd_keyguard.h
@@ -32,11 +32,10 @@ FD_PROTOTYPES_BEGIN
#define FD_KEYGUARD_PAYLOAD_LG_PRUNE ( 2) /* Gossip PruneData */
#define FD_KEYGUARD_PAYLOAD_LG_SHRED ( 3) /* Solana legacy or merkle shred */
#define FD_KEYGUARD_PAYLOAD_LG_TLS_CV ( 4) /* TLS 1.3 certificate verify payload */
-#define FD_KEYGUARD_PAYLOAD_LG_REPAIR ( 6) /* RepairProtocol */
-#define FD_KEYGUARD_PAYLOAD_LG_PING ( 7) /* Gossip ping protocol */
-#define FD_KEYGUARD_PAYLOAD_LG_BUNDLE ( 8) /* Bundle block producer authentication */
-#define FD_KEYGUARD_PAYLOAD_LG_EVENT ( 9) /* Event reporter authentication */
-#define FD_KEYGUARD_PAYLOAD_LG_PONG (10) /* Gossip/Repair ping/pong protocol */
+#define FD_KEYGUARD_PAYLOAD_LG_REPAIR ( 5) /* RepairProtocol */
+#define FD_KEYGUARD_PAYLOAD_LG_PING ( 6) /* Gossip ping protocol */
+#define FD_KEYGUARD_PAYLOAD_LG_BUNDLE ( 7) /* Bundle block producer authentication */
+#define FD_KEYGUARD_PAYLOAD_LG_PONG ( 8) /* Gossip/Repair ping/pong protocol */
#define FD_KEYGUARD_PAYLOAD_TXN (1UL<public_key, &ctx->public_key_base58_sz, (char *)ctx->concat );
ctx->concat[ ctx->public_key_base58_sz ] = '-';
-
- memcpy( ctx->event_auth_concat, "FD_EVENTS_AUTH-", 15UL );
}
static void FD_FN_SENSITIVE
@@ -244,11 +240,6 @@ after_frag_sensitive( void * _ctx,
fd_ed25519_sign( dst, ctx->concat, ctx->public_key_base58_sz+1UL+9UL, ctx->public_key, ctx->private_key, ctx->sha512 );
break;
}
- case FD_KEYGUARD_SIGN_TYPE_FD_EVENTS_AUTH_CONCAT_ED25519: {
- memcpy( ctx->event_auth_concat+15UL, ctx->_data, 32UL );
- fd_ed25519_sign( dst, ctx->event_auth_concat, 15UL+32UL, ctx->public_key, ctx->private_key, ctx->sha512 );
- break;
- }
default:
FD_LOG_EMERG(( "invalid sign type: %d", sign_type ));
}
@@ -385,7 +376,7 @@ unprivileged_init_sensitive( fd_topo_t * topo,
} else if( !strcmp(in_link->name, "event_sign" ) ) {
ctx->in[ i ].role = FD_KEYGUARD_ROLE_EVENT;
FD_TEST( !strcmp( out_link->name, "sign_event" ) );
- FD_TEST( in_link->mtu==32UL );
+ FD_TEST( in_link->mtu==162UL );
FD_TEST( out_link->mtu==64UL );
} else if( !strcmp(in_link->name, "pack_sign" ) ) {
ctx->in[ i ].role = FD_KEYGUARD_ROLE_BUNDLE_CRANK;
diff --git a/src/disco/metrics/generated/fd_metrics_event.c b/src/disco/metrics/generated/fd_metrics_event.c
index 9ba74779226..cdbda10814f 100644
--- a/src/disco/metrics/generated/fd_metrics_event.c
+++ b/src/disco/metrics/generated/fd_metrics_event.c
@@ -11,7 +11,6 @@ const fd_metrics_meta_t FD_METRICS_EVENT[FD_METRICS_EVENT_TOTAL] = {
DECLARE_METRIC( EVENT_EVENTS_ACKED, COUNTER ),
DECLARE_METRIC( EVENT_BYTES_WRITTEN, COUNTER ),
DECLARE_METRIC( EVENT_BYTES_READ, COUNTER ),
- DECLARE_METRIC( EVENT_AUTH_FAIL, COUNTER ),
DECLARE_METRIC( EVENT_INVALID_MSG, COUNTER ),
DECLARE_METRIC( EVENT_CONNECT_ATTEMPTS, COUNTER ),
DECLARE_METRIC( EVENT_HANDSHAKE_TIMEOUTS, COUNTER ),
diff --git a/src/disco/metrics/generated/fd_metrics_event.h b/src/disco/metrics/generated/fd_metrics_event.h
index 3f03c0865cd..67a7403a1ae 100644
--- a/src/disco/metrics/generated/fd_metrics_event.h
+++ b/src/disco/metrics/generated/fd_metrics_event.h
@@ -16,7 +16,6 @@ enum {
FD_METRICS_COUNTER_EVENT_EVENTS_ACKED_OFF,
FD_METRICS_COUNTER_EVENT_BYTES_WRITTEN_OFF,
FD_METRICS_COUNTER_EVENT_BYTES_READ_OFF,
- FD_METRICS_COUNTER_EVENT_AUTH_FAIL_OFF,
FD_METRICS_COUNTER_EVENT_INVALID_MSG_OFF,
FD_METRICS_COUNTER_EVENT_CONNECT_ATTEMPTS_OFF,
FD_METRICS_COUNTER_EVENT_HANDSHAKE_TIMEOUTS_OFF,
@@ -67,11 +66,6 @@ enum {
#define FD_METRICS_COUNTER_EVENT_BYTES_READ_DESC "The total number of bytes read from the event service"
#define FD_METRICS_COUNTER_EVENT_BYTES_READ_CVT (FD_METRICS_CONVERTER_NONE)
-#define FD_METRICS_COUNTER_EVENT_AUTH_FAIL_NAME "event_auth_fail"
-#define FD_METRICS_COUNTER_EVENT_AUTH_FAIL_TYPE (FD_METRICS_TYPE_COUNTER)
-#define FD_METRICS_COUNTER_EVENT_AUTH_FAIL_DESC "The total number of authentication failures with the event service"
-#define FD_METRICS_COUNTER_EVENT_AUTH_FAIL_CVT (FD_METRICS_CONVERTER_NONE)
-
#define FD_METRICS_COUNTER_EVENT_INVALID_MSG_NAME "event_invalid_msg"
#define FD_METRICS_COUNTER_EVENT_INVALID_MSG_TYPE (FD_METRICS_TYPE_COUNTER)
#define FD_METRICS_COUNTER_EVENT_INVALID_MSG_DESC "The total number of malformed messages received from the event service"
@@ -84,10 +78,10 @@ enum {
#define FD_METRICS_COUNTER_EVENT_HANDSHAKE_TIMEOUTS_NAME "event_handshake_timeouts"
#define FD_METRICS_COUNTER_EVENT_HANDSHAKE_TIMEOUTS_TYPE (FD_METRICS_TYPE_COUNTER)
-#define FD_METRICS_COUNTER_EVENT_HANDSHAKE_TIMEOUTS_DESC "The total number of authentication handshake timeouts with the event service"
+#define FD_METRICS_COUNTER_EVENT_HANDSHAKE_TIMEOUTS_DESC "The total number of handshake timeouts with the event service"
#define FD_METRICS_COUNTER_EVENT_HANDSHAKE_TIMEOUTS_CVT (FD_METRICS_CONVERTER_NONE)
-#define FD_METRICS_EVENT_TOTAL (13UL)
+#define FD_METRICS_EVENT_TOTAL (12UL)
extern const fd_metrics_meta_t FD_METRICS_EVENT[FD_METRICS_EVENT_TOTAL];
#endif /* HEADER_fd_src_disco_metrics_generated_fd_metrics_event_h */
diff --git a/src/disco/metrics/metrics.xml b/src/disco/metrics/metrics.xml
index 70791b476e8..0ffd664ce57 100644
--- a/src/disco/metrics/metrics.xml
+++ b/src/disco/metrics/metrics.xml
@@ -1443,10 +1443,9 @@ metric introduced.
-
-
+
diff --git a/src/disco/topo/fd_topo.h b/src/disco/topo/fd_topo.h
index efed347137f..85350377203 100644
--- a/src/disco/topo/fd_topo.h
+++ b/src/disco/topo/fd_topo.h
@@ -288,6 +288,7 @@ struct fd_topo_tile {
char url[ 256 ];
char identity_key_path[ PATH_MAX ];
char action[ 16 ];
+ uchar tls_cert_verify : 1;
} event;
struct {