mirror of
https://github.com/tlsnotary/tlsn.git
synced 2026-01-09 14:48:13 -05:00
feat: add protocol configuration negotiation (#513)
* Add configuration check. * Fix naming and comments. * Fix clippy. * Fix clippy using latest rust. * Adapt new method to send message. * Add config validator. * Split max transcript size. * Remove unused dependencies and redundant declarations. * Move protocol_config out of verifier config. * Implement default for configs. * Apply fmt. * Correct dependency format. * Add ignored flag to integration test. * Change from String to Version, more debugging. * Use getter instead of pub. * Move ot estimate methods to ProtocolConfig. --------- Co-authored-by: yuroitaki <> Co-authored-by: sinu.eth <65924192+sinui0@users.noreply.github.com>
This commit is contained in:
@@ -14,6 +14,7 @@ members = [
|
||||
"crates/formats",
|
||||
"crates/notary/client",
|
||||
"crates/notary/server",
|
||||
"crates/notary/tests-integration",
|
||||
"crates/prover",
|
||||
"crates/server-fixture",
|
||||
"crates/tests-integration",
|
||||
|
||||
@@ -10,6 +10,7 @@ charming = { version = "0.3.1", features = ["ssr"] }
|
||||
csv = "1.3.0"
|
||||
futures = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tlsn-common = { workspace = true }
|
||||
tlsn-core = { workspace = true }
|
||||
tlsn-prover = { workspace = true }
|
||||
tlsn-server-fixture = { workspace = true }
|
||||
|
||||
@@ -15,6 +15,7 @@ use tlsn_benches::{
|
||||
set_interface, PROVER_INTERFACE,
|
||||
};
|
||||
|
||||
use tlsn_common::config::ProtocolConfig;
|
||||
use tlsn_core::Direction;
|
||||
use tlsn_server_fixture::{CA_CERT_DER, SERVER_DOMAIN};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
@@ -115,13 +116,18 @@ async fn run_instance<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>
|
||||
|
||||
let start_time = Instant::now();
|
||||
|
||||
let protocol_config = ProtocolConfig::builder()
|
||||
.max_sent_data(upload_size + 256)
|
||||
.max_recv_data(download_size + 256)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let prover = Prover::new(
|
||||
ProverConfig::builder()
|
||||
.id("test")
|
||||
.server_dns(SERVER_DOMAIN)
|
||||
.root_cert_store(root_store())
|
||||
.max_sent_data(upload_size + 256)
|
||||
.max_recv_data(download_size + 256)
|
||||
.protocol_config(protocol_config)
|
||||
.build()
|
||||
.context("invalid prover config")?,
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ use tlsn_benches::{
|
||||
config::{BenchInstance, Config},
|
||||
set_interface, VERIFIER_INTERFACE,
|
||||
};
|
||||
use tlsn_common::config::ProtocolConfigValidator;
|
||||
use tlsn_server_fixture::CA_CERT_DER;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_util::compat::TokioAsyncReadCompatExt;
|
||||
@@ -63,12 +64,17 @@ async fn run_instance<S: AsyncWrite + AsyncRead + Send + Sync + Unpin + 'static>
|
||||
|
||||
set_interface(VERIFIER_INTERFACE, download, 1, download_delay)?;
|
||||
|
||||
let config_validator = ProtocolConfigValidator::builder()
|
||||
.max_sent_data(upload_size + 256)
|
||||
.max_recv_data(download_size + 256)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let verifier = Verifier::new(
|
||||
VerifierConfig::builder()
|
||||
.id("test")
|
||||
.cert_verifier(cert_verifier())
|
||||
.max_sent_data(upload_size + 256)
|
||||
.max_recv_data(download_size + 256)
|
||||
.protocol_config_validator(config_validator)
|
||||
.build()?,
|
||||
);
|
||||
|
||||
|
||||
@@ -12,7 +12,16 @@ mpz-common = { workspace = true }
|
||||
mpz-garble = { workspace = true }
|
||||
mpz-ot = { workspace = true }
|
||||
|
||||
derive_builder = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serio = { workspace = true, features = ["codec", "bincode"] }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
uid-mux = { workspace = true, features = ["serio"] }
|
||||
uid-mux = { workspace = true, features = ["serio"] }
|
||||
|
||||
semver = { version = "1.0", features = ["serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = { workspace = true }
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
//! TLSNotary protocol config and config utilities.
|
||||
use core::fmt;
|
||||
use once_cell::sync::Lazy;
|
||||
use semver::Version;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::error::Error;
|
||||
|
||||
use crate::Role;
|
||||
|
||||
@@ -13,6 +18,195 @@ const OTS_PER_BYTE_SENT: usize = 8;
|
||||
// Without deferred decryption we use 16, with it we use 8.
|
||||
const OTS_PER_BYTE_RECV: usize = 16;
|
||||
|
||||
// Current version that is running.
|
||||
static VERSION: Lazy<Version> = Lazy::new(|| {
|
||||
Version::parse(env!("CARGO_PKG_VERSION"))
|
||||
.map_err(|err| ProtocolConfigError::new(ErrorKind::Version, err))
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
/// Protocol configuration to be setup initially by prover and verifier.
|
||||
#[derive(derive_builder::Builder, Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct ProtocolConfig {
|
||||
/// Maximum number of bytes that can be sent.
|
||||
#[builder(default = "DEFAULT_MAX_SENT_LIMIT")]
|
||||
max_sent_data: usize,
|
||||
/// Maximum number of bytes that can be received.
|
||||
#[builder(default = "DEFAULT_MAX_RECV_LIMIT")]
|
||||
max_recv_data: usize,
|
||||
/// Version that is being run by prover/verifier.
|
||||
#[builder(setter(skip), default = "VERSION.clone()")]
|
||||
version: Version,
|
||||
}
|
||||
|
||||
impl Default for ProtocolConfig {
|
||||
fn default() -> Self {
|
||||
Self::builder().build().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolConfig {
|
||||
/// Creates a new builder for `ProtocolConfig`.
|
||||
pub fn builder() -> ProtocolConfigBuilder {
|
||||
ProtocolConfigBuilder::default()
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be sent.
|
||||
pub fn max_sent_data(&self) -> usize {
|
||||
self.max_sent_data
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be received.
|
||||
pub fn max_recv_data(&self) -> usize {
|
||||
self.max_recv_data
|
||||
}
|
||||
|
||||
/// Returns OT sender setup count.
|
||||
pub fn ot_sender_setup_count(&self, role: Role) -> usize {
|
||||
ot_send_estimate(role, self.max_sent_data, self.max_recv_data)
|
||||
}
|
||||
|
||||
/// Returns OT receiver setup count.
|
||||
pub fn ot_receiver_setup_count(&self, role: Role) -> usize {
|
||||
ot_recv_estimate(role, self.max_sent_data, self.max_recv_data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Protocol configuration validator used by checker (i.e. verifier) to perform compatibility check
|
||||
/// with the peer (i.e. prover)'s configuration.
|
||||
#[derive(derive_builder::Builder, Clone, Debug)]
|
||||
pub struct ProtocolConfigValidator {
|
||||
/// Maximum number of bytes that can be sent.
|
||||
#[builder(default = "DEFAULT_MAX_SENT_LIMIT")]
|
||||
max_sent_data: usize,
|
||||
/// Maximum number of bytes that can be received.
|
||||
#[builder(default = "DEFAULT_MAX_RECV_LIMIT")]
|
||||
max_recv_data: usize,
|
||||
/// Version that is being run by checker.
|
||||
#[builder(setter(skip), default = "VERSION.clone()")]
|
||||
version: Version,
|
||||
}
|
||||
|
||||
impl Default for ProtocolConfigValidator {
|
||||
fn default() -> Self {
|
||||
Self::builder().build().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolConfigValidator {
|
||||
/// Creates a new builder for `ProtocolConfigValidator`.
|
||||
pub fn builder() -> ProtocolConfigValidatorBuilder {
|
||||
ProtocolConfigValidatorBuilder::default()
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be sent.
|
||||
pub fn max_sent_data(&self) -> usize {
|
||||
self.max_sent_data
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be received.
|
||||
pub fn max_recv_data(&self) -> usize {
|
||||
self.max_recv_data
|
||||
}
|
||||
|
||||
/// Performs compatibility check of the protocol configuration between prover and verifier.
|
||||
pub fn validate(&self, config: &ProtocolConfig) -> Result<(), ProtocolConfigError> {
|
||||
self.check_max_transcript_size(config.max_sent_data, config.max_recv_data)?;
|
||||
self.check_version(&config.version)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Checks if both the sent and recv data are within limits.
|
||||
fn check_max_transcript_size(
|
||||
&self,
|
||||
max_sent_data: usize,
|
||||
max_recv_data: usize,
|
||||
) -> Result<(), ProtocolConfigError> {
|
||||
if max_sent_data > self.max_sent_data {
|
||||
return Err(ProtocolConfigError::max_transcript_size(format!(
|
||||
"max_sent_data {:?} is greater than the configured limit {:?}",
|
||||
max_sent_data, self.max_sent_data,
|
||||
)));
|
||||
}
|
||||
|
||||
if max_recv_data > self.max_recv_data {
|
||||
return Err(ProtocolConfigError::max_transcript_size(format!(
|
||||
"max_recv_data {:?} is greater than the configured limit {:?}",
|
||||
max_recv_data, self.max_recv_data,
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Checks if both versions are the same (might support check for different but compatible versions in the future).
|
||||
fn check_version(&self, peer_version: &Version) -> Result<(), ProtocolConfigError> {
|
||||
if *peer_version != self.version {
|
||||
return Err(ProtocolConfigError::version(format!(
|
||||
"prover's version {:?} is different from verifier's version {:?}",
|
||||
peer_version, self.version
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A ProtocolConfig error.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub struct ProtocolConfigError {
|
||||
kind: ErrorKind,
|
||||
#[source]
|
||||
source: Option<Box<dyn Error + Send + Sync>>,
|
||||
}
|
||||
|
||||
impl ProtocolConfigError {
|
||||
fn new<E>(kind: ErrorKind, source: E) -> Self
|
||||
where
|
||||
E: Into<Box<dyn Error + Send + Sync>>,
|
||||
{
|
||||
Self {
|
||||
kind,
|
||||
source: Some(source.into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn max_transcript_size(msg: impl Into<String>) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::MaxTranscriptSize,
|
||||
source: Some(msg.into().into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn version(msg: impl Into<String>) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::Version,
|
||||
source: Some(msg.into().into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ProtocolConfigError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.kind {
|
||||
ErrorKind::MaxTranscriptSize => write!(f, "max transcript size error")?,
|
||||
ErrorKind::Version => write!(f, "version error")?,
|
||||
}
|
||||
|
||||
if let Some(ref source) = self.source {
|
||||
write!(f, " caused by: {}", source)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ErrorKind {
|
||||
MaxTranscriptSize,
|
||||
Version,
|
||||
}
|
||||
|
||||
/// Returns an estimate of the number of OTs that will be sent.
|
||||
pub fn ot_send_estimate(role: Role, max_sent_data: usize, max_recv_data: usize) -> usize {
|
||||
match role {
|
||||
@@ -32,3 +226,52 @@ pub fn ot_recv_estimate(role: Role, max_sent_data: usize, max_recv_data: usize)
|
||||
Role::Verifier => EXTRA_OTS,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use rstest::{fixture, rstest};
|
||||
|
||||
#[fixture]
|
||||
#[once]
|
||||
fn config_validator() -> ProtocolConfigValidator {
|
||||
ProtocolConfigValidator::builder().build().unwrap()
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::same_max_sent_recv_data(DEFAULT_MAX_SENT_LIMIT, DEFAULT_MAX_RECV_LIMIT)]
|
||||
#[case::smaller_max_sent_data(1 << 11, DEFAULT_MAX_RECV_LIMIT)]
|
||||
#[case::smaller_max_recv_data(DEFAULT_MAX_SENT_LIMIT, 1 << 13)]
|
||||
#[case::smaller_max_sent_recv_data(1 << 7, 1 << 9)]
|
||||
fn test_check_success(
|
||||
config_validator: &ProtocolConfigValidator,
|
||||
#[case] max_sent_data: usize,
|
||||
#[case] max_recv_data: usize,
|
||||
) {
|
||||
let peer_config = ProtocolConfig::builder()
|
||||
.max_sent_data(max_sent_data)
|
||||
.max_recv_data(max_recv_data)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
assert!(config_validator.validate(&peer_config).is_ok())
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::bigger_max_sent_data(1 << 13, DEFAULT_MAX_RECV_LIMIT)]
|
||||
#[case::bigger_max_recv_data(1 << 10, 1 << 16)]
|
||||
#[case::bigger_max_sent_recv_data(1 << 14, 1 << 21)]
|
||||
fn test_check_fail(
|
||||
config_validator: &ProtocolConfigValidator,
|
||||
#[case] max_sent_data: usize,
|
||||
#[case] max_recv_data: usize,
|
||||
) {
|
||||
let peer_config = ProtocolConfig::builder()
|
||||
.max_sent_data(max_sent_data)
|
||||
.max_recv_data(max_recv_data)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
assert!(config_validator.validate(&peer_config).is_err())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ version = "0.0.0"
|
||||
|
||||
[dependencies]
|
||||
notary-client = { workspace = true }
|
||||
tlsn-common = { workspace = true }
|
||||
tlsn-core = { workspace = true }
|
||||
tlsn-prover = { workspace = true }
|
||||
tlsn-verifier = { workspace = true }
|
||||
|
||||
@@ -7,6 +7,7 @@ use hyper::{body::Bytes, Request, StatusCode};
|
||||
use hyper_util::rt::TokioIo;
|
||||
use notary_client::{Accepted, NotarizationRequest, NotaryClient};
|
||||
use std::{env, ops::Range, str};
|
||||
use tlsn_common::config::ProtocolConfig;
|
||||
use tlsn_core::proof::TlsProof;
|
||||
use tlsn_prover::tls::{Prover, ProverConfig};
|
||||
use tokio::io::AsyncWriteExt as _;
|
||||
@@ -65,12 +66,18 @@ async fn main() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Setup protocol configuration for prover.
|
||||
let protocol_config = ProtocolConfig::builder()
|
||||
.max_sent_data(MAX_SENT_DATA)
|
||||
.max_recv_data(MAX_RECV_DATA)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Configure a new prover with the unique session id returned from notary client.
|
||||
let prover_config = ProverConfig::builder()
|
||||
.id(session_id)
|
||||
.server_dns(SERVER_DOMAIN)
|
||||
.max_sent_data(MAX_SENT_DATA)
|
||||
.max_recv_data(MAX_RECV_DATA)
|
||||
.protocol_config(protocol_config)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ version = "0.1.0-alpha.6"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
notary-server = { workspace = true }
|
||||
tlsn-common = { workspace = true }
|
||||
|
||||
derive_builder = { workspace = true }
|
||||
@@ -11,7 +12,6 @@ futures = { workspace = true }
|
||||
http-body-util = { workspace = true }
|
||||
hyper = { workspace = true, features = ["client", "http1"] }
|
||||
hyper-util = { workspace = true, features = ["full"] }
|
||||
notary-server = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tokio = { workspace = true, features = [
|
||||
|
||||
@@ -4,6 +4,7 @@ version = "0.1.0-alpha.6"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tlsn-common = { workspace = true }
|
||||
tlsn-verifier = { workspace = true }
|
||||
|
||||
async-trait = { workspace = true }
|
||||
|
||||
@@ -109,7 +109,7 @@ To perform a notarization, some parameters need to be configured by the prover a
|
||||
To streamline this process, a single HTTP endpoint (`/session`) is used by both TCP and WebSocket clients.
|
||||
|
||||
#### Notarization
|
||||
After calling the configuration endpoint above, the prover can proceed to start the notarization. For a TCP client, that means calling the `/notarize` endpoint using HTTP (`https`), while a WebSocket client should call the same endpoint but using WebSocket (`wss`). Example implementations of these clients can be found in the [integration test](../tests-integration/tests/notary.rs).
|
||||
After calling the configuration endpoint above, the prover can proceed to start the notarization. For a TCP client, that means calling the `/notarize` endpoint using HTTP (`https`), while a WebSocket client should call the same endpoint but using WebSocket (`wss`). Example implementations of these clients can be found in the [integration test](../notary-tests-integration/tests/notary.rs).
|
||||
|
||||
#### Signatures
|
||||
Currently, both the private key (and cert) used to establish a TLS connection with the prover, and the private key used by the notary server to sign the notarized transcript, are hardcoded PEM keys stored in this repository. Though the paths of these keys can be changed in the config (`notary-key` field) to use different keys instead.
|
||||
|
||||
@@ -12,7 +12,8 @@ server:
|
||||
<a href="/healthcheck">health check</a> - <a href="/info">info</a><br/>
|
||||
|
||||
notarization:
|
||||
max-transcript-size: 20480
|
||||
max-sent-data: 4096
|
||||
max-recv-data: 16384
|
||||
|
||||
tls:
|
||||
enabled: true
|
||||
|
||||
@@ -29,8 +29,10 @@ pub struct AuthorizationProperties {
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct NotarizationProperties {
|
||||
/// Global limit for maximum transcript size in bytes
|
||||
pub max_transcript_size: usize,
|
||||
/// Global limit for maximum number of bytes that can be sent
|
||||
pub max_sent_data: usize,
|
||||
/// Global limit for maximum number of bytes that can be received
|
||||
pub max_recv_data: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
|
||||
@@ -43,20 +43,13 @@ pub enum ClientType {
|
||||
Websocket,
|
||||
}
|
||||
|
||||
/// Session configuration data to be stored in temporary storage
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SessionData {
|
||||
pub max_sent_data: Option<usize>,
|
||||
pub max_recv_data: Option<usize>,
|
||||
}
|
||||
|
||||
/// Global data that needs to be shared with the axum handlers
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NotaryGlobals {
|
||||
pub notary_signing_key: SigningKey,
|
||||
pub notarization_config: NotarizationProperties,
|
||||
/// A temporary storage to store configuration data, mainly used for WebSocket client
|
||||
pub store: Arc<Mutex<HashMap<String, SessionData>>>,
|
||||
/// A temporary storage to store session_id
|
||||
pub store: Arc<Mutex<HashMap<String, ()>>>,
|
||||
/// Whitelist of API keys for authorization purpose
|
||||
pub authorization_whitelist: Option<Arc<Mutex<HashMap<String, AuthorizationWhitelistRecord>>>>,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use axum::http::StatusCode;
|
||||
use axum_core::response::{IntoResponse as AxumCoreIntoResponse, Response};
|
||||
use eyre::Report;
|
||||
use std::error::Error;
|
||||
use tlsn_common::config::ProtocolConfigValidatorBuilderError;
|
||||
|
||||
use tlsn_verifier::tls::{VerifierConfigBuilderError, VerifierError};
|
||||
|
||||
@@ -31,6 +32,12 @@ impl From<VerifierConfigBuilderError> for NotaryServerError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProtocolConfigValidatorBuilderError> for NotaryServerError {
|
||||
fn from(error: ProtocolConfigValidatorBuilderError) -> Self {
|
||||
Self::Notarization(Box::new(error))
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait implementation to convert this error into an axum http response
|
||||
impl AxumCoreIntoResponse for NotaryServerError {
|
||||
fn into_response(self) -> Response {
|
||||
|
||||
@@ -10,6 +10,7 @@ use axum::{
|
||||
};
|
||||
use axum_macros::debug_handler;
|
||||
use p256::ecdsa::{Signature, SigningKey};
|
||||
use tlsn_common::config::ProtocolConfigValidator;
|
||||
use tlsn_verifier::tls::{Verifier, VerifierConfig};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_util::compat::TokioAsyncReadCompatExt;
|
||||
@@ -19,7 +20,7 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
domain::notary::{
|
||||
NotarizationRequestQuery, NotarizationSessionRequest, NotarizationSessionResponse,
|
||||
NotaryGlobals, SessionData,
|
||||
NotaryGlobals,
|
||||
},
|
||||
error::NotaryServerError,
|
||||
service::{
|
||||
@@ -74,37 +75,26 @@ pub async fn upgrade_protocol(
|
||||
) -> Response {
|
||||
info!("Received upgrade protocol request");
|
||||
let session_id = params.session_id;
|
||||
// Fetch the configuration data from the store using the session_id
|
||||
// This also removes the configuration data from the store as each session_id can only be used once
|
||||
let (max_sent_data, max_recv_data) =
|
||||
match notary_globals.store.lock().unwrap().remove(&session_id) {
|
||||
Some(data) => (data.max_sent_data, data.max_recv_data),
|
||||
None => {
|
||||
let err_msg = format!("Session id {} does not exist", session_id);
|
||||
error!(err_msg);
|
||||
return NotaryServerError::BadProverRequest(err_msg).into_response();
|
||||
}
|
||||
};
|
||||
// Check if session_id exists in the store, this also removes session_id from the store as each session_id can only be used once
|
||||
if notary_globals
|
||||
.store
|
||||
.lock()
|
||||
.unwrap()
|
||||
.remove(&session_id)
|
||||
.is_none()
|
||||
{
|
||||
let err_msg = format!("Session id {} does not exist", session_id);
|
||||
error!(err_msg);
|
||||
return NotaryServerError::BadProverRequest(err_msg).into_response();
|
||||
};
|
||||
// This completes the HTTP Upgrade request and returns a successful response to the client, meanwhile initiating the websocket or tcp connection
|
||||
match protocol_upgrade {
|
||||
ProtocolUpgrade::Ws(ws) => ws.on_upgrade(move |socket| {
|
||||
websocket_notarize(
|
||||
socket,
|
||||
notary_globals,
|
||||
session_id,
|
||||
max_sent_data,
|
||||
max_recv_data,
|
||||
)
|
||||
}),
|
||||
ProtocolUpgrade::Tcp(tcp) => tcp.on_upgrade(move |stream| {
|
||||
tcp_notarize(
|
||||
stream,
|
||||
notary_globals,
|
||||
session_id,
|
||||
max_sent_data,
|
||||
max_recv_data,
|
||||
)
|
||||
}),
|
||||
ProtocolUpgrade::Ws(ws) => {
|
||||
ws.on_upgrade(move |socket| websocket_notarize(socket, notary_globals, session_id))
|
||||
}
|
||||
ProtocolUpgrade::Tcp(tcp) => {
|
||||
tcp.on_upgrade(move |stream| tcp_notarize(stream, notary_globals, session_id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,17 +118,31 @@ pub async fn initialize(
|
||||
}
|
||||
};
|
||||
|
||||
// Ensure that the max_transcript_size submitted is not larger than the global max limit configured in notary server
|
||||
// Ensure that the max_sent_data, max_recv_data submitted is not larger than the global max limits configured in notary server
|
||||
if payload.max_sent_data.is_some() || payload.max_recv_data.is_some() {
|
||||
let requested_transcript_size =
|
||||
payload.max_sent_data.unwrap_or_default() + payload.max_recv_data.unwrap_or_default();
|
||||
if requested_transcript_size > notary_globals.notarization_config.max_transcript_size {
|
||||
if payload.max_sent_data.unwrap_or_default()
|
||||
> notary_globals.notarization_config.max_sent_data
|
||||
{
|
||||
error!(
|
||||
"Max transcript size requested {:?} exceeds the maximum threshold {:?}",
|
||||
requested_transcript_size, notary_globals.notarization_config.max_transcript_size
|
||||
"Max sent data requested {:?} exceeds the global maximum threshold {:?}",
|
||||
payload.max_sent_data.unwrap_or_default(),
|
||||
notary_globals.notarization_config.max_sent_data
|
||||
);
|
||||
return NotaryServerError::BadProverRequest(
|
||||
"Max transcript size requested exceeds the maximum threshold".to_string(),
|
||||
"Max sent data requested exceeds the global maximum threshold".to_string(),
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
if payload.max_recv_data.unwrap_or_default()
|
||||
> notary_globals.notarization_config.max_recv_data
|
||||
{
|
||||
error!(
|
||||
"Max recv data requested {:?} exceeds the global maximum threshold {:?}",
|
||||
payload.max_recv_data.unwrap_or_default(),
|
||||
notary_globals.notarization_config.max_recv_data
|
||||
);
|
||||
return NotaryServerError::BadProverRequest(
|
||||
"Max recv data requested exceeds the global maximum threshold".to_string(),
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
@@ -147,13 +151,11 @@ pub async fn initialize(
|
||||
let prover_session_id = Uuid::new_v4().to_string();
|
||||
|
||||
// Store the configuration data in a temporary store
|
||||
notary_globals.store.lock().unwrap().insert(
|
||||
prover_session_id.clone(),
|
||||
SessionData {
|
||||
max_sent_data: payload.max_sent_data,
|
||||
max_recv_data: payload.max_recv_data,
|
||||
},
|
||||
);
|
||||
notary_globals
|
||||
.store
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(prover_session_id.clone(), ());
|
||||
|
||||
trace!("Latest store state: {:?}", notary_globals.store);
|
||||
|
||||
@@ -172,24 +174,20 @@ pub async fn notary_service<T: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
socket: T,
|
||||
signing_key: &SigningKey,
|
||||
session_id: &str,
|
||||
max_sent_data: Option<usize>,
|
||||
max_recv_data: Option<usize>,
|
||||
max_sent_data: usize,
|
||||
max_recv_data: usize,
|
||||
) -> Result<(), NotaryServerError> {
|
||||
debug!(?session_id, "Starting notarization...");
|
||||
|
||||
let mut config_builder = VerifierConfig::builder();
|
||||
let config_validator = ProtocolConfigValidator::builder()
|
||||
.max_sent_data(max_sent_data)
|
||||
.max_recv_data(max_recv_data)
|
||||
.build()?;
|
||||
|
||||
config_builder = config_builder.id(session_id);
|
||||
|
||||
if let Some(max_sent_data) = max_sent_data {
|
||||
config_builder = config_builder.max_sent_data(max_sent_data);
|
||||
}
|
||||
|
||||
if let Some(max_recv_data) = max_recv_data {
|
||||
config_builder = config_builder.max_recv_data(max_recv_data);
|
||||
}
|
||||
|
||||
let config = config_builder.build()?;
|
||||
let config = VerifierConfig::builder()
|
||||
.id(session_id)
|
||||
.protocol_config_validator(config_validator)
|
||||
.build()?;
|
||||
|
||||
Verifier::new(config)
|
||||
.notarize::<_, Signature>(socket.compat(), signing_key)
|
||||
|
||||
@@ -83,16 +83,14 @@ pub async fn tcp_notarize(
|
||||
stream: TokioIo<Upgraded>,
|
||||
notary_globals: NotaryGlobals,
|
||||
session_id: String,
|
||||
max_sent_data: Option<usize>,
|
||||
max_recv_data: Option<usize>,
|
||||
) {
|
||||
debug!(?session_id, "Upgraded to tcp connection");
|
||||
match notary_service(
|
||||
stream,
|
||||
¬ary_globals.notary_signing_key,
|
||||
&session_id,
|
||||
max_sent_data,
|
||||
max_recv_data,
|
||||
notary_globals.notarization_config.max_sent_data,
|
||||
notary_globals.notarization_config.max_recv_data,
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
||||
@@ -11,8 +11,6 @@ pub async fn websocket_notarize(
|
||||
socket: WebSocket,
|
||||
notary_globals: NotaryGlobals,
|
||||
session_id: String,
|
||||
max_sent_data: Option<usize>,
|
||||
max_recv_data: Option<usize>,
|
||||
) {
|
||||
debug!(?session_id, "Upgraded to websocket connection");
|
||||
// Wrap the websocket in WsStream so that we have AsyncRead and AsyncWrite implemented
|
||||
@@ -21,8 +19,8 @@ pub async fn websocket_notarize(
|
||||
stream,
|
||||
¬ary_globals.notary_signing_key,
|
||||
&session_id,
|
||||
max_sent_data,
|
||||
max_recv_data,
|
||||
notary_globals.notarization_config.max_sent_data,
|
||||
notary_globals.notarization_config.max_recv_data,
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
[package]
|
||||
name = "tests-integration"
|
||||
name = "notary-tests-integration"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dev-dependencies]
|
||||
notary-client = { workspace = true }
|
||||
notary-server = { workspace = true }
|
||||
tls-server-fixture = { workspace = true }
|
||||
tlsn-common = { workspace = true }
|
||||
tlsn-prover = { workspace = true }
|
||||
tlsn-tls-core = { workspace = true }
|
||||
|
||||
async-tungstenite = { workspace = true, features = ["tokio-native-tls"] }
|
||||
@@ -14,13 +18,10 @@ http-body-util = { workspace = true }
|
||||
hyper = { workspace = true, features = ["client", "http1", "server"] }
|
||||
hyper-tls = { version = "0.6", features = ["vendored"] } # specify vendored feature to use statically linked copy of OpenSSL
|
||||
hyper-util = { workspace = true, features = ["full"] }
|
||||
notary-client = { workspace = true }
|
||||
notary-server = { workspace = true }
|
||||
rstest = { workspace = true }
|
||||
rustls = { workspace = true }
|
||||
rustls-pemfile = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tlsn-prover = { workspace = true }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tokio-native-tls = { version = "0.3.1", features = ["vendored"] }
|
||||
tokio-util = { workspace = true, features = ["compat"] }
|
||||
|
||||
@@ -13,6 +13,7 @@ use rstest::rstest;
|
||||
use rustls::{Certificate, RootCertStore};
|
||||
use std::{string::String, time::Duration};
|
||||
use tls_server_fixture::{bind_test_server_hyper, CA_CERT_DER, SERVER_DOMAIN};
|
||||
use tlsn_common::config::ProtocolConfig;
|
||||
use tlsn_prover::tls::{Prover, ProverConfig};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt};
|
||||
@@ -43,7 +44,8 @@ fn get_server_config(port: u16, tls_enabled: bool, auth_enabled: bool) -> Notary
|
||||
html_info: "example html response".to_string(),
|
||||
},
|
||||
notarization: NotarizationProperties {
|
||||
max_transcript_size: 1 << 14,
|
||||
max_sent_data: 1 << 13,
|
||||
max_recv_data: 1 << 14,
|
||||
},
|
||||
tls: TLSProperties {
|
||||
enabled: tls_enabled,
|
||||
@@ -163,6 +165,7 @@ async fn tls_prover(notary_config: NotaryServerProperties) -> (NotaryConnection,
|
||||
)]
|
||||
#[awt]
|
||||
#[tokio::test]
|
||||
#[ignore = "expensive"]
|
||||
async fn test_tcp_prover<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
#[future]
|
||||
#[case]
|
||||
@@ -175,12 +178,17 @@ async fn test_tcp_prover<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
.add(&tls_core::key::Certificate(CA_CERT_DER.to_vec()))
|
||||
.unwrap();
|
||||
|
||||
let protocol_config = ProtocolConfig::builder()
|
||||
.max_sent_data(MAX_SENT_DATA)
|
||||
.max_recv_data(MAX_RECV_DATA)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Prover config using the session_id returned from calling /session endpoint in notary client.
|
||||
let prover_config = ProverConfig::builder()
|
||||
.id(session_id)
|
||||
.server_dns(SERVER_DOMAIN)
|
||||
.max_sent_data(MAX_SENT_DATA)
|
||||
.max_recv_data(MAX_RECV_DATA)
|
||||
.protocol_config(protocol_config)
|
||||
.root_cert_store(root_cert_store)
|
||||
.build()
|
||||
.unwrap();
|
||||
@@ -245,6 +253,7 @@ async fn test_tcp_prover<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "expensive"]
|
||||
async fn test_websocket_prover() {
|
||||
// Notary server configuration setup
|
||||
let notary_config = setup_config_and_server(100, 7050, true, false).await;
|
||||
@@ -350,13 +359,18 @@ async fn test_websocket_prover() {
|
||||
.add(&tls_core::key::Certificate(CA_CERT_DER.to_vec()))
|
||||
.unwrap();
|
||||
|
||||
let protocol_config = ProtocolConfig::builder()
|
||||
.max_sent_data(MAX_SENT_DATA)
|
||||
.max_recv_data(MAX_RECV_DATA)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Basic default prover config — use the responded session id from notary server
|
||||
let prover_config = ProverConfig::builder()
|
||||
.id(notarization_response.session_id)
|
||||
.server_dns(SERVER_DOMAIN)
|
||||
.root_cert_store(root_store)
|
||||
.max_sent_data(MAX_SENT_DATA)
|
||||
.max_recv_data(MAX_RECV_DATA)
|
||||
.protocol_config(protocol_config)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use mpz_ot::{chou_orlandi, kos};
|
||||
use tls_client::RootCertStore;
|
||||
use tls_mpc::{MpcTlsCommonConfig, MpcTlsLeaderConfig, TranscriptConfig};
|
||||
use tlsn_common::{
|
||||
config::{ot_recv_estimate, ot_send_estimate, DEFAULT_MAX_RECV_LIMIT, DEFAULT_MAX_SENT_LIMIT},
|
||||
Role,
|
||||
};
|
||||
use tlsn_common::config::ProtocolConfig;
|
||||
|
||||
/// Configuration for the prover
|
||||
#[derive(Debug, Clone, derive_builder::Builder)]
|
||||
@@ -18,12 +15,9 @@ pub struct ProverConfig {
|
||||
/// TLS root certificate store.
|
||||
#[builder(setter(strip_option), default = "default_root_store()")]
|
||||
pub(crate) root_cert_store: RootCertStore,
|
||||
/// Maximum number of bytes that can be sent.
|
||||
#[builder(default = "DEFAULT_MAX_SENT_LIMIT")]
|
||||
max_sent_data: usize,
|
||||
/// Maximum number of bytes that can be received.
|
||||
#[builder(default = "DEFAULT_MAX_RECV_LIMIT")]
|
||||
max_recv_data: usize,
|
||||
/// Protocol configuration to be checked with the verifier.
|
||||
#[builder(default)]
|
||||
protocol_config: ProtocolConfig,
|
||||
}
|
||||
|
||||
impl ProverConfig {
|
||||
@@ -37,21 +31,16 @@ impl ProverConfig {
|
||||
&self.id
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be sent.
|
||||
pub fn max_sent_data(&self) -> usize {
|
||||
self.max_sent_data
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be received.
|
||||
pub fn max_recv_data(&self) -> usize {
|
||||
self.max_recv_data
|
||||
}
|
||||
|
||||
/// Returns the server DNS name.
|
||||
pub fn server_dns(&self) -> &str {
|
||||
&self.server_dns
|
||||
}
|
||||
|
||||
/// Returns the protocol configuration.
|
||||
pub fn protocol_config(&self) -> &ProtocolConfig {
|
||||
&self.protocol_config
|
||||
}
|
||||
|
||||
pub(crate) fn build_mpc_tls_config(&self) -> MpcTlsLeaderConfig {
|
||||
MpcTlsLeaderConfig::builder()
|
||||
.common(
|
||||
@@ -59,13 +48,13 @@ impl ProverConfig {
|
||||
.id(format!("{}/mpc_tls", &self.id))
|
||||
.tx_config(
|
||||
TranscriptConfig::default_tx()
|
||||
.max_size(self.max_sent_data)
|
||||
.max_size(self.protocol_config.max_sent_data())
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.rx_config(
|
||||
TranscriptConfig::default_rx()
|
||||
.max_size(self.max_recv_data)
|
||||
.max_size(self.protocol_config.max_recv_data())
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -98,14 +87,6 @@ impl ProverConfig {
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn ot_sender_setup_count(&self) -> usize {
|
||||
ot_send_estimate(Role::Prover, self.max_sent_data, self.max_recv_data)
|
||||
}
|
||||
|
||||
pub(crate) fn ot_receiver_setup_count(&self) -> usize {
|
||||
ot_recv_estimate(Role::Prover, self.max_sent_data, self.max_recv_data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Default root store using mozilla certs.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::error::Error;
|
||||
use tls_mpc::MpcTlsError;
|
||||
use tlsn_common::config::ProtocolConfigError;
|
||||
use tlsn_core::commitment::TranscriptCommitmentBuilderError;
|
||||
|
||||
/// An error that can occur during proving.
|
||||
@@ -26,6 +27,8 @@ pub enum ProverError {
|
||||
CommitmentError(#[from] CommitmentError),
|
||||
#[error("Range exceeds transcript length")]
|
||||
InvalidRange,
|
||||
#[error(transparent)]
|
||||
ProtocolConfigError(#[from] ProtocolConfigError),
|
||||
}
|
||||
|
||||
impl From<uid_mux::yamux::ConnectionError> for ProverError {
|
||||
|
||||
@@ -23,7 +23,7 @@ use mpz_common::Allocate;
|
||||
use mpz_garble::config::Role as DEAPRole;
|
||||
use mpz_ot::{chou_orlandi, kos};
|
||||
use rand::Rng;
|
||||
use serio::StreamExt;
|
||||
use serio::{SinkExt, StreamExt};
|
||||
use std::sync::Arc;
|
||||
use tls_client::{ClientConnection, ServerName as TlsServerName};
|
||||
use tls_client_async::{bind_client, ClosedConnection, TlsConnection};
|
||||
@@ -78,6 +78,22 @@ impl Prover<state::Initialized> {
|
||||
) -> Result<Prover<state::Setup>, ProverError> {
|
||||
let (mut mux_fut, mux_ctrl) = attach_mux(socket, Role::Prover);
|
||||
|
||||
let mut io = mux_fut
|
||||
.poll_with(
|
||||
mux_ctrl
|
||||
.open_framed(b"tlsnotary")
|
||||
.map_err(ProverError::from),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Sends protocol configuration to verifier for compatibility check
|
||||
mux_fut
|
||||
.poll_with(async {
|
||||
io.send(self.config.protocol_config().clone()).await?;
|
||||
Ok::<_, ProverError>(())
|
||||
})
|
||||
.await?;
|
||||
|
||||
// Maximum thread forking concurrency of 8.
|
||||
// TODO: Determine the optimal number of threads.
|
||||
let mut exec = Executor::new(mux_ctrl.clone(), 8);
|
||||
@@ -86,14 +102,6 @@ impl Prover<state::Initialized> {
|
||||
.poll_with(setup_mpc_backend(&self.config, &mux_ctrl, &mut exec))
|
||||
.await?;
|
||||
|
||||
let io = mux_fut
|
||||
.poll_with(
|
||||
mux_ctrl
|
||||
.open_framed(b"tlsnotary")
|
||||
.map_err(ProverError::from),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let ctx = mux_fut
|
||||
.poll_with(exec.new_thread().map_err(ProverError::from))
|
||||
.await?;
|
||||
@@ -259,13 +267,17 @@ async fn setup_mpc_backend(
|
||||
config.build_ot_sender_config(),
|
||||
chou_orlandi::Receiver::new(config.build_base_ot_receiver_config()),
|
||||
);
|
||||
ot_sender.alloc(config.ot_sender_setup_count());
|
||||
ot_sender.alloc(config.protocol_config().ot_sender_setup_count(Role::Prover));
|
||||
|
||||
let mut ot_receiver = kos::Receiver::new(
|
||||
config.build_ot_receiver_config(),
|
||||
chou_orlandi::Sender::new(config.build_base_ot_sender_config()),
|
||||
);
|
||||
ot_receiver.alloc(config.ot_receiver_setup_count());
|
||||
ot_receiver.alloc(
|
||||
config
|
||||
.protocol_config()
|
||||
.ot_receiver_setup_count(Role::Prover),
|
||||
);
|
||||
|
||||
let ot_sender = OTSender::new(ot_sender);
|
||||
let ot_receiver = OTReceiver::new(ot_receiver);
|
||||
|
||||
@@ -2,10 +2,7 @@ use mpz_ot::{chou_orlandi, kos};
|
||||
use std::fmt::{Debug, Formatter, Result};
|
||||
use tls_core::verify::{ServerCertVerifier, WebPkiVerifier};
|
||||
use tls_mpc::{MpcTlsCommonConfig, MpcTlsFollowerConfig, TranscriptConfig};
|
||||
use tlsn_common::{
|
||||
config::{ot_recv_estimate, ot_send_estimate, DEFAULT_MAX_RECV_LIMIT, DEFAULT_MAX_SENT_LIMIT},
|
||||
Role,
|
||||
};
|
||||
use tlsn_common::config::{ProtocolConfig, ProtocolConfigValidator};
|
||||
use tlsn_core::proof::default_cert_verifier;
|
||||
|
||||
/// Configuration for the [`Verifier`](crate::tls::Verifier).
|
||||
@@ -15,12 +12,8 @@ use tlsn_core::proof::default_cert_verifier;
|
||||
pub struct VerifierConfig {
|
||||
#[builder(setter(into))]
|
||||
id: String,
|
||||
/// Maximum number of bytes that can be sent.
|
||||
#[builder(default = "DEFAULT_MAX_SENT_LIMIT")]
|
||||
max_sent_data: usize,
|
||||
/// Maximum number of bytes that can be received.
|
||||
#[builder(default = "DEFAULT_MAX_RECV_LIMIT")]
|
||||
max_recv_data: usize,
|
||||
#[builder(default)]
|
||||
protocol_config_validator: ProtocolConfigValidator,
|
||||
#[builder(
|
||||
pattern = "owned",
|
||||
setter(strip_option),
|
||||
@@ -33,8 +26,14 @@ impl Debug for VerifierConfig {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
f.debug_struct("VerifierConfig")
|
||||
.field("id", &self.id)
|
||||
.field("max_sent_data", &self.max_sent_data)
|
||||
.field("max_recv_data", &self.max_recv_data)
|
||||
.field(
|
||||
"max_sent_data",
|
||||
&self.protocol_config_validator.max_sent_data(),
|
||||
)
|
||||
.field(
|
||||
"max_recv_data",
|
||||
&self.protocol_config_validator.max_recv_data(),
|
||||
)
|
||||
.field("cert_verifier", &"_")
|
||||
.finish()
|
||||
}
|
||||
@@ -51,14 +50,9 @@ impl VerifierConfig {
|
||||
&self.id
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be sent.
|
||||
pub fn max_sent_data(&self) -> usize {
|
||||
self.max_sent_data
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be received.
|
||||
pub fn max_recv_data(&self) -> usize {
|
||||
self.max_recv_data
|
||||
/// Returns the protocol configuration validator.
|
||||
pub fn protocol_config_validator(&self) -> &ProtocolConfigValidator {
|
||||
&self.protocol_config_validator
|
||||
}
|
||||
|
||||
/// Returns the certificate verifier.
|
||||
@@ -90,20 +84,23 @@ impl VerifierConfig {
|
||||
kos::ReceiverConfig::default()
|
||||
}
|
||||
|
||||
pub(crate) fn build_mpc_tls_config(&self) -> MpcTlsFollowerConfig {
|
||||
pub(crate) fn build_mpc_tls_config(
|
||||
&self,
|
||||
protocol_config: &ProtocolConfig,
|
||||
) -> MpcTlsFollowerConfig {
|
||||
MpcTlsFollowerConfig::builder()
|
||||
.common(
|
||||
MpcTlsCommonConfig::builder()
|
||||
.id(format!("{}/mpc_tls", &self.id))
|
||||
.tx_config(
|
||||
TranscriptConfig::default_tx()
|
||||
.max_size(self.max_sent_data)
|
||||
.max_size(protocol_config.max_sent_data())
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.rx_config(
|
||||
TranscriptConfig::default_rx()
|
||||
.max_size(self.max_recv_data)
|
||||
.max_size(protocol_config.max_recv_data())
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -114,12 +111,4 @@ impl VerifierConfig {
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn ot_sender_setup_count(&self) -> usize {
|
||||
ot_send_estimate(Role::Verifier, self.max_sent_data, self.max_recv_data)
|
||||
}
|
||||
|
||||
pub(crate) fn ot_receiver_setup_count(&self) -> usize {
|
||||
ot_recv_estimate(Role::Verifier, self.max_sent_data, self.max_recv_data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::error::Error;
|
||||
use tls_mpc::MpcTlsError;
|
||||
use tlsn_common::config::ProtocolConfigError;
|
||||
|
||||
/// An error that can occur during TLS verification.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
@@ -13,6 +14,8 @@ pub enum VerifierError {
|
||||
MpcError(Box<dyn Error + Send + Sync + 'static>),
|
||||
#[error("Range exceeds transcript length")]
|
||||
InvalidRange,
|
||||
#[error(transparent)]
|
||||
ProtocolConfigError(#[from] ProtocolConfigError),
|
||||
}
|
||||
|
||||
impl From<uid_mux::yamux::ConnectionError> for VerifierError {
|
||||
|
||||
@@ -9,7 +9,7 @@ mod verify;
|
||||
pub use config::{VerifierConfig, VerifierConfigBuilder, VerifierConfigBuilderError};
|
||||
pub use error::VerifierError;
|
||||
use mpz_common::Allocate;
|
||||
use serio::StreamExt;
|
||||
use serio::{stream::IoStreamExt, StreamExt};
|
||||
use uid_mux::FramedUidMux;
|
||||
|
||||
use web_time::{SystemTime, UNIX_EPOCH};
|
||||
@@ -22,6 +22,7 @@ use signature::Signer;
|
||||
use state::{Notarize, Verify};
|
||||
use tls_mpc::{build_components, MpcTlsFollower, MpcTlsFollowerData, TlsRole};
|
||||
use tlsn_common::{
|
||||
config::ProtocolConfig,
|
||||
mux::{attach_mux, MuxControl},
|
||||
DEAPThread, Executor, OTReceiver, OTSender, Role,
|
||||
};
|
||||
@@ -65,6 +66,26 @@ impl Verifier<state::Initialized> {
|
||||
// TODO: Determine the optimal number of threads.
|
||||
let mut exec = Executor::new(mux_ctrl.clone(), 8);
|
||||
|
||||
let mut io = mux_fut
|
||||
.poll_with(
|
||||
mux_ctrl
|
||||
.open_framed(b"tlsnotary")
|
||||
.map_err(VerifierError::from),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Receives protocol configuration from prover to perform compatibility check
|
||||
let protocol_config = mux_fut
|
||||
.poll_with(async {
|
||||
let peer_configuration: ProtocolConfig = io.expect_next().await?;
|
||||
self.config
|
||||
.protocol_config_validator()
|
||||
.validate(&peer_configuration)?;
|
||||
|
||||
Ok::<_, VerifierError>(peer_configuration)
|
||||
})
|
||||
.await?;
|
||||
|
||||
let encoder_seed: [u8; 32] = rand::rngs::OsRng.gen();
|
||||
let (mpc_tls, vm, ot_send) = mux_fut
|
||||
.poll_with(setup_mpc_backend(
|
||||
@@ -72,17 +93,10 @@ impl Verifier<state::Initialized> {
|
||||
&mux_ctrl,
|
||||
&mut exec,
|
||||
encoder_seed,
|
||||
protocol_config,
|
||||
))
|
||||
.await?;
|
||||
|
||||
let io = mux_fut
|
||||
.poll_with(
|
||||
mux_ctrl
|
||||
.open_framed(b"tlsnotary")
|
||||
.map_err(VerifierError::from),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let ctx = mux_fut
|
||||
.poll_with(exec.new_thread().map_err(VerifierError::from))
|
||||
.await?;
|
||||
@@ -237,6 +251,7 @@ async fn setup_mpc_backend(
|
||||
mux: &MuxControl,
|
||||
exec: &mut Executor,
|
||||
encoder_seed: [u8; 32],
|
||||
protocol_config: ProtocolConfig,
|
||||
) -> Result<(MpcTlsFollower, DEAPThread, OTSender), VerifierError> {
|
||||
debug!("starting MPC backend setup");
|
||||
|
||||
@@ -244,13 +259,13 @@ async fn setup_mpc_backend(
|
||||
config.build_ot_sender_config(),
|
||||
chou_orlandi::Receiver::new(config.build_base_ot_receiver_config()),
|
||||
);
|
||||
ot_sender.alloc(config.ot_sender_setup_count());
|
||||
ot_sender.alloc(protocol_config.ot_sender_setup_count(Role::Verifier));
|
||||
|
||||
let mut ot_receiver = kos::Receiver::new(
|
||||
config.build_ot_receiver_config(),
|
||||
chou_orlandi::Sender::new(config.build_base_ot_sender_config()),
|
||||
);
|
||||
ot_receiver.alloc(config.ot_receiver_setup_count());
|
||||
ot_receiver.alloc(protocol_config.ot_receiver_setup_count(Role::Verifier));
|
||||
|
||||
let ot_sender = OTSender::new(ot_sender);
|
||||
let ot_receiver = OTReceiver::new(ot_receiver);
|
||||
@@ -293,7 +308,7 @@ async fn setup_mpc_backend(
|
||||
ot_receiver.clone(),
|
||||
);
|
||||
|
||||
let mpc_tls_config = config.build_mpc_tls_config();
|
||||
let mpc_tls_config = config.build_mpc_tls_config(&protocol_config);
|
||||
let (ke, prf, encrypter, decrypter) = build_components(
|
||||
TlsRole::Follower,
|
||||
mpc_tls_config.common(),
|
||||
|
||||
@@ -5,6 +5,7 @@ edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
tlsn-common = { workspace = true }
|
||||
tlsn-core = { workspace = true }
|
||||
tlsn-prover = { workspace = true }
|
||||
tlsn-server-fixture = { workspace = true }
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::{env, net::IpAddr};
|
||||
use anyhow::Result;
|
||||
use futures::{AsyncReadExt, AsyncWriteExt, Future};
|
||||
use tls_core::{anchors::RootCertStore, verify::WebPkiVerifier};
|
||||
use tlsn_common::config::{ProtocolConfig, ProtocolConfigValidator};
|
||||
use tlsn_core::Direction;
|
||||
use tlsn_prover::tls::{Prover, ProverConfig};
|
||||
use tlsn_server_fixture::{CA_CERT_DER, SERVER_DOMAIN};
|
||||
@@ -70,10 +71,15 @@ async fn handle_verifier(io: TcpStream) -> Result<()> {
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let config = VerifierConfig::builder()
|
||||
.id("test")
|
||||
let config_validator = ProtocolConfigValidator::builder()
|
||||
.max_sent_data(1024)
|
||||
.max_recv_data(1024)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let config = VerifierConfig::builder()
|
||||
.id("test")
|
||||
.protocol_config_validator(config_validator)
|
||||
.cert_verifier(WebPkiVerifier::new(root_store, None))
|
||||
.build()
|
||||
.unwrap();
|
||||
@@ -87,13 +93,18 @@ async fn handle_verifier(io: TcpStream) -> Result<()> {
|
||||
|
||||
#[instrument(level = "debug", skip_all, err)]
|
||||
async fn handle_notary(io: TcpStream) -> Result<()> {
|
||||
let config = VerifierConfig::builder()
|
||||
.id("test")
|
||||
let config_validator = ProtocolConfigValidator::builder()
|
||||
.max_sent_data(1024)
|
||||
.max_recv_data(1024)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let config = VerifierConfig::builder()
|
||||
.id("test")
|
||||
.protocol_config_validator(config_validator)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let verifier = Verifier::new(config);
|
||||
let signing_key = p256::ecdsa::SigningKey::random(&mut rand::thread_rng());
|
||||
|
||||
@@ -111,12 +122,17 @@ async fn handle_prover(io: TcpStream) -> Result<()> {
|
||||
.add(&tls_core::key::Certificate(CA_CERT_DER.to_vec()))
|
||||
.unwrap();
|
||||
|
||||
let protocol_config = ProtocolConfig::builder()
|
||||
.max_sent_data(1024)
|
||||
.max_recv_data(1024)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let prover = Prover::new(
|
||||
ProverConfig::builder()
|
||||
.id("test")
|
||||
.server_dns(SERVER_DOMAIN)
|
||||
.max_sent_data(1024)
|
||||
.max_recv_data(1024)
|
||||
.protocol_config(protocol_config)
|
||||
.root_cert_store(root_store)
|
||||
.build()
|
||||
.unwrap(),
|
||||
|
||||
@@ -19,6 +19,7 @@ test = []
|
||||
no-bundler = ["wasm-bindgen-rayon/no-bundler"]
|
||||
|
||||
[dependencies]
|
||||
tlsn-common = { path = "../common" }
|
||||
tlsn-core = { path = "../core" }
|
||||
tlsn-prover = { path = "../prover" }
|
||||
tlsn-tls-client-async = { path = "../tls/client-async" }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use serde::Deserialize;
|
||||
use tlsn_common::config::ProtocolConfig;
|
||||
use tsify_next::Tsify;
|
||||
|
||||
#[derive(Debug, Tsify, Deserialize)]
|
||||
@@ -12,9 +13,7 @@ pub struct ProverConfig {
|
||||
|
||||
impl From<ProverConfig> for tlsn_prover::tls::ProverConfig {
|
||||
fn from(value: ProverConfig) -> Self {
|
||||
let mut builder = tlsn_prover::tls::ProverConfig::builder();
|
||||
builder.id(value.id);
|
||||
builder.server_dns(value.server_dns);
|
||||
let mut builder = ProtocolConfig::builder();
|
||||
|
||||
if let Some(value) = value.max_sent_data {
|
||||
builder.max_sent_data(value);
|
||||
@@ -24,6 +23,13 @@ impl From<ProverConfig> for tlsn_prover::tls::ProverConfig {
|
||||
builder.max_recv_data(value);
|
||||
}
|
||||
|
||||
builder.build().unwrap()
|
||||
let protocol_config = builder.build().unwrap();
|
||||
|
||||
tlsn_prover::tls::ProverConfig::builder()
|
||||
.id(value.id)
|
||||
.server_dns(value.server_dns)
|
||||
.protocol_config(protocol_config)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use tls_core::verify::WebPkiVerifier;
|
||||
use tlsn_common::config::{ProtocolConfig, ProtocolConfigValidator};
|
||||
use tlsn_prover::tls::{Prover, ProverConfig};
|
||||
use tlsn_verifier::tls::{Verifier, VerifierConfig};
|
||||
use wasm_bindgen::prelude::*;
|
||||
@@ -23,13 +24,18 @@ pub async fn test_prove() -> Result<(), JsValue> {
|
||||
.add(&tls_core::key::Certificate(CA_CERT_DER.to_vec()))
|
||||
.unwrap();
|
||||
|
||||
let protocol_config = ProtocolConfig::builder()
|
||||
.max_sent_data(1024)
|
||||
.max_recv_data(1024)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let prover = Prover::new(
|
||||
ProverConfig::builder()
|
||||
.id("test")
|
||||
.server_dns(SERVER_DOMAIN)
|
||||
.root_cert_store(root_store)
|
||||
.max_sent_data(1024)
|
||||
.max_recv_data(1024)
|
||||
.protocol_config(protocol_config)
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
@@ -71,13 +77,18 @@ pub async fn test_notarize() -> Result<(), JsValue> {
|
||||
.add(&tls_core::key::Certificate(CA_CERT_DER.to_vec()))
|
||||
.unwrap();
|
||||
|
||||
let protocol_config = ProtocolConfig::builder()
|
||||
.max_sent_data(1024)
|
||||
.max_recv_data(1024)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let prover = Prover::new(
|
||||
ProverConfig::builder()
|
||||
.id("test")
|
||||
.server_dns(SERVER_DOMAIN)
|
||||
.root_cert_store(root_store)
|
||||
.max_sent_data(1024)
|
||||
.max_recv_data(1024)
|
||||
.protocol_config(protocol_config)
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
@@ -121,10 +132,15 @@ pub async fn test_verifier() -> Result<(), JsValue> {
|
||||
.add(&tls_core::key::Certificate(CA_CERT_DER.to_vec()))
|
||||
.unwrap();
|
||||
|
||||
let config = VerifierConfig::builder()
|
||||
.id("test")
|
||||
let config_validator = ProtocolConfigValidator::builder()
|
||||
.max_sent_data(1024)
|
||||
.max_recv_data(1024)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let config = VerifierConfig::builder()
|
||||
.id("test")
|
||||
.protocol_config_validator(config_validator)
|
||||
.cert_verifier(WebPkiVerifier::new(root_store, None))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use serde::Deserialize;
|
||||
use tlsn_common::config::ProtocolConfigValidator;
|
||||
use tsify_next::Tsify;
|
||||
|
||||
#[derive(Debug, Tsify, Deserialize)]
|
||||
@@ -11,16 +12,22 @@ pub struct VerifierConfig {
|
||||
|
||||
impl From<VerifierConfig> for tlsn_verifier::tls::VerifierConfig {
|
||||
fn from(value: VerifierConfig) -> Self {
|
||||
let mut builder = tlsn_verifier::tls::VerifierConfig::builder();
|
||||
let mut builder = ProtocolConfigValidator::builder();
|
||||
|
||||
if let Some(value) = value.max_sent_data {
|
||||
builder = builder.max_sent_data(value);
|
||||
builder.max_sent_data(value);
|
||||
}
|
||||
|
||||
if let Some(value) = value.max_received_data {
|
||||
builder = builder.max_recv_data(value);
|
||||
builder.max_recv_data(value);
|
||||
}
|
||||
|
||||
builder.id(value.id).build().unwrap()
|
||||
let config_validator = builder.build().unwrap();
|
||||
|
||||
tlsn_verifier::tls::VerifierConfig::builder()
|
||||
.id(value.id)
|
||||
.protocol_config_validator(config_validator)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user