mirror of
https://github.com/tlsnotary/tlsn.git
synced 2026-01-06 20:14:00 -05:00
docs: rustfmt wrap_comments (#611)
This commit is contained in:
@@ -29,8 +29,8 @@ static VERSION: Lazy<Version> = Lazy::new(|| {
|
||||
pub struct ProtocolConfig {
|
||||
/// Maximum number of bytes that can be sent.
|
||||
max_sent_data: usize,
|
||||
/// Maximum number of bytes that can be decrypted online, i.e. while the MPC-TLS connection is
|
||||
/// active.
|
||||
/// Maximum number of bytes that can be decrypted online, i.e. while the
|
||||
/// MPC-TLS connection is active.
|
||||
#[builder(default = "0")]
|
||||
max_recv_data_online: usize,
|
||||
/// Maximum number of bytes that can be received.
|
||||
@@ -93,8 +93,8 @@ impl ProtocolConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Protocol configuration validator used by checker (i.e. verifier) to perform compatibility check
|
||||
/// with the peer's (i.e. the prover's) configuration.
|
||||
/// Protocol configuration validator used by checker (i.e. verifier) to perform
|
||||
/// compatibility check with the peer's (i.e. the prover's) configuration.
|
||||
#[derive(derive_builder::Builder, Clone, Debug)]
|
||||
pub struct ProtocolConfigValidator {
|
||||
/// Maximum number of bytes that can be sent.
|
||||
@@ -122,7 +122,8 @@ impl ProtocolConfigValidator {
|
||||
self.max_recv_data
|
||||
}
|
||||
|
||||
/// Performs compatibility check of the protocol configuration between prover and verifier.
|
||||
/// 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)?;
|
||||
@@ -152,7 +153,8 @@ impl ProtocolConfigValidator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Checks if both versions are the same (might support check for different but compatible versions in the future).
|
||||
// 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!(
|
||||
|
||||
@@ -61,7 +61,8 @@ impl Future for MuxFuture {
|
||||
|
||||
/// Attaches a multiplexer to the provided socket.
|
||||
///
|
||||
/// Returns the multiplexer and a controller for creating streams with a codec attached.
|
||||
/// Returns the multiplexer and a controller for creating streams with a codec
|
||||
/// attached.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
||||
@@ -59,8 +59,8 @@ async fn compute_tag_share<C: StreamCipher<Aes128Ctr> + ?Sized, H: UniversalHash
|
||||
|
||||
/// Computes the tag for a ciphertext and additional data.
|
||||
///
|
||||
/// The commit-reveal step is not required for computing a tag sent to the Server, as it
|
||||
/// will be able to detect if the tag is incorrect.
|
||||
/// The commit-reveal step is not required for computing a tag sent to the
|
||||
/// Server, as it will be able to detect if the tag is incorrect.
|
||||
#[instrument(level = "debug", skip_all, err)]
|
||||
pub(crate) async fn compute_tag<
|
||||
Ctx: Context,
|
||||
@@ -89,9 +89,10 @@ pub(crate) async fn compute_tag<
|
||||
|
||||
/// Verifies a purported tag against the ciphertext and additional data.
|
||||
///
|
||||
/// Verifying a tag requires a commit-reveal protocol between the leader and follower.
|
||||
/// Without it, the party which receives the other's tag share first could trivially compute
|
||||
/// a tag share which would cause an invalid message to be accepted.
|
||||
/// Verifying a tag requires a commit-reveal protocol between the leader and
|
||||
/// follower. Without it, the party which receives the other's tag share first
|
||||
/// could trivially compute a tag share which would cause an invalid message to
|
||||
/// be accepted.
|
||||
#[instrument(level = "debug", skip_all, err)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) async fn verify_tag<
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
//! This crate provides implementations of 2PC AEADs for authenticated encryption with
|
||||
//! a shared key.
|
||||
//! This crate provides implementations of 2PC AEADs for authenticated
|
||||
//! encryption with a shared key.
|
||||
//!
|
||||
//! Both parties can work together to encrypt and decrypt messages with different visibility
|
||||
//! configurations. See [`Aead`] for more information on the interface.
|
||||
//! Both parties can work together to encrypt and decrypt messages with
|
||||
//! different visibility configurations. See [`Aead`] for more information on
|
||||
//! the interface.
|
||||
//!
|
||||
//! For example, one party can privately provide the plaintext to encrypt, while both parties
|
||||
//! can see the ciphertext and the tag. Or, both parties can cooperate to decrypt a ciphertext
|
||||
//! and verify the tag, while only one party can see the plaintext.
|
||||
//! For example, one party can privately provide the plaintext to encrypt, while
|
||||
//! both parties can see the ciphertext and the tag. Or, both parties can
|
||||
//! cooperate to decrypt a ciphertext and verify the tag, while only one party
|
||||
//! can see the plaintext.
|
||||
|
||||
#![deny(missing_docs, unreachable_pub, unused_must_use)]
|
||||
#![deny(clippy::all)]
|
||||
@@ -37,14 +39,15 @@ pub trait Aead: Send {
|
||||
/// The AEAD assigns unique identifiers to each byte of plaintext
|
||||
/// during encryption and decryption.
|
||||
///
|
||||
/// For example, if the transcript id is set to `foo`, then the first byte will
|
||||
/// be assigned the id `foo/0`, the second byte `foo/1`, and so on.
|
||||
/// For example, if the transcript id is set to `foo`, then the first byte
|
||||
/// will be assigned the id `foo/0`, the second byte `foo/1`, and so on.
|
||||
///
|
||||
/// Each transcript id has an independent counter.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The state of a transcript counter is preserved between calls to `set_transcript_id`.
|
||||
/// The state of a transcript counter is preserved between calls to
|
||||
/// `set_transcript_id`.
|
||||
fn set_transcript_id(&mut self, id: &str);
|
||||
|
||||
/// Performs any necessary one-time setup for the AEAD.
|
||||
@@ -74,7 +77,8 @@ pub trait Aead: Send {
|
||||
aad: Vec<u8>,
|
||||
) -> Result<Vec<u8>, Self::Error>;
|
||||
|
||||
/// Encrypts a plaintext message, hiding it from the other party, returning the ciphertext and tag.
|
||||
/// Encrypts a plaintext message, hiding it from the other party, returning
|
||||
/// the ciphertext and tag.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -105,7 +109,8 @@ pub trait Aead: Send {
|
||||
|
||||
/// Decrypts a ciphertext message, returning the plaintext to both parties.
|
||||
///
|
||||
/// This method checks the authenticity of the ciphertext, tag and additional data.
|
||||
/// This method checks the authenticity of the ciphertext, tag and
|
||||
/// additional data.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -119,9 +124,11 @@ pub trait Aead: Send {
|
||||
aad: Vec<u8>,
|
||||
) -> Result<Vec<u8>, Self::Error>;
|
||||
|
||||
/// Decrypts a ciphertext message, returning the plaintext only to this party.
|
||||
/// Decrypts a ciphertext message, returning the plaintext only to this
|
||||
/// party.
|
||||
///
|
||||
/// This method checks the authenticity of the ciphertext, tag and additional data.
|
||||
/// This method checks the authenticity of the ciphertext, tag and
|
||||
/// additional data.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -135,9 +142,11 @@ pub trait Aead: Send {
|
||||
aad: Vec<u8>,
|
||||
) -> Result<Vec<u8>, Self::Error>;
|
||||
|
||||
/// Decrypts a ciphertext message, returning the plaintext only to the other party.
|
||||
/// Decrypts a ciphertext message, returning the plaintext only to the other
|
||||
/// party.
|
||||
///
|
||||
/// This method checks the authenticity of the ciphertext, tag and additional data.
|
||||
/// This method checks the authenticity of the ciphertext, tag and
|
||||
/// additional data.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -153,7 +162,8 @@ pub trait Aead: Send {
|
||||
|
||||
/// Verifies the tag of a ciphertext message.
|
||||
///
|
||||
/// This method checks the authenticity of the ciphertext, tag and additional data.
|
||||
/// This method checks the authenticity of the ciphertext, tag and
|
||||
/// additional data.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -167,13 +177,13 @@ pub trait Aead: Send {
|
||||
aad: Vec<u8>,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
/// Locally decrypts the provided ciphertext and then proves in ZK to the other party(s) that the
|
||||
/// plaintext is correct.
|
||||
/// Locally decrypts the provided ciphertext and then proves in ZK to the
|
||||
/// other party(s) that the plaintext is correct.
|
||||
///
|
||||
/// Returns the plaintext.
|
||||
///
|
||||
/// This method requires this party to know the encryption key, which can be achieved by calling
|
||||
/// the `decode_key_private` method.
|
||||
/// This method requires this party to know the encryption key, which can be
|
||||
/// achieved by calling the `decode_key_private` method.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -187,17 +197,18 @@ pub trait Aead: Send {
|
||||
aad: Vec<u8>,
|
||||
) -> Result<Vec<u8>, Self::Error>;
|
||||
|
||||
/// Locally decrypts the provided ciphertext and then proves in ZK to the other party(s) that the
|
||||
/// plaintext is correct.
|
||||
/// Locally decrypts the provided ciphertext and then proves in ZK to the
|
||||
/// other party(s) that the plaintext is correct.
|
||||
///
|
||||
/// Returns the plaintext.
|
||||
///
|
||||
/// This method requires this party to know the encryption key, which can be achieved by calling
|
||||
/// the `decode_key_private` method.
|
||||
/// This method requires this party to know the encryption key, which can be
|
||||
/// achieved by calling the `decode_key_private` method.
|
||||
///
|
||||
/// # WARNING
|
||||
///
|
||||
/// This method does not verify the tag of the ciphertext. Only use this if you know what you're doing.
|
||||
/// This method does not verify the tag of the ciphertext. Only use this if
|
||||
/// you know what you're doing.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -209,7 +220,8 @@ pub trait Aead: Send {
|
||||
ciphertext: Vec<u8>,
|
||||
) -> Result<Vec<u8>, Self::Error>;
|
||||
|
||||
/// Verifies the other party(s) can prove they know a plaintext which encrypts to the given ciphertext.
|
||||
/// Verifies the other party(s) can prove they know a plaintext which
|
||||
/// encrypts to the given ciphertext.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -223,11 +235,13 @@ pub trait Aead: Send {
|
||||
aad: Vec<u8>,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
/// Verifies the other party(s) can prove they know a plaintext which encrypts to the given ciphertext.
|
||||
/// Verifies the other party(s) can prove they know a plaintext which
|
||||
/// encrypts to the given ciphertext.
|
||||
///
|
||||
/// # WARNING
|
||||
///
|
||||
/// This method does not verify the tag of the ciphertext. Only use this if you know what you're doing.
|
||||
/// This method does not verify the tag of the ciphertext. Only use this if
|
||||
/// you know what you're doing.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! This crate provides a 2PC block cipher implementation.
|
||||
//!
|
||||
//! Both parties work together to encrypt or share an encrypted block using a shared key.
|
||||
//! Both parties work together to encrypt or share an encrypted block using a
|
||||
//! shared key.
|
||||
|
||||
#![deny(missing_docs, unreachable_pub, unused_must_use)]
|
||||
#![deny(clippy::all)]
|
||||
|
||||
@@ -80,7 +80,8 @@ pub fn hmac_sha256_partial(key: &[u8]) -> ([u32; 8], [u32; 8]) {
|
||||
|
||||
/// HMAC-SHA256 finalization function.
|
||||
///
|
||||
/// Returns the HMAC-SHA256 digest of the provided message using existing outer and inner states.
|
||||
/// Returns the HMAC-SHA256 digest of the provided message using existing outer
|
||||
/// and inner states.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -103,7 +104,8 @@ pub fn hmac_sha256_finalize_trace<'a>(
|
||||
|
||||
/// Reference implementation of the HMAC-SHA256 finalization function.
|
||||
///
|
||||
/// Returns the HMAC-SHA256 digest of the provided message using existing outer and inner states.
|
||||
/// Returns the HMAC-SHA256 digest of the provided message using existing outer
|
||||
/// and inner states.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
||||
@@ -10,7 +10,8 @@ use crate::prf::{prf, prf_trace};
|
||||
/// Computes verify_data as specified in RFC 5246, Section 7.4.9.
|
||||
///
|
||||
/// verify_data
|
||||
/// PRF(master_secret, finished_label, Hash(handshake_messages))[0..verify_data_length-1];
|
||||
/// PRF(master_secret, finished_label,
|
||||
/// Hash(handshake_messages))[0..verify_data_length-1];
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -31,7 +32,8 @@ pub fn verify_data_trace<'a>(
|
||||
vd.try_into().expect("vd is 12 bytes")
|
||||
}
|
||||
|
||||
/// Reference implementation of verify_data as specified in RFC 5246, Section 7.4.9.
|
||||
/// Reference implementation of verify_data as specified in RFC 5246, Section
|
||||
/// 7.4.9.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
||||
@@ -56,7 +56,8 @@ impl State {
|
||||
|
||||
/// An MPC key exchange protocol.
|
||||
///
|
||||
/// Can be either a leader or a follower depending on the `role` field in [`KeyExchangeConfig`].
|
||||
/// Can be either a leader or a follower depending on the `role` field in
|
||||
/// [`KeyExchangeConfig`].
|
||||
#[derive(Debug)]
|
||||
pub struct MpcKeyExchange<Ctx, C0, C1, E> {
|
||||
ctx: Ctx,
|
||||
@@ -66,7 +67,8 @@ pub struct MpcKeyExchange<Ctx, C0, C1, E> {
|
||||
converter_1: C1,
|
||||
/// MPC executor.
|
||||
executor: E,
|
||||
/// The private key of the party behind this instance, either follower or leader.
|
||||
/// The private key of the party behind this instance, either follower or
|
||||
/// leader.
|
||||
private_key: Option<SecretKey>,
|
||||
/// The public key of the server.
|
||||
server_key: Option<PublicKey>,
|
||||
@@ -419,9 +421,9 @@ async fn compute_pms_shares<
|
||||
) -> Result<(P256, P256), KeyExchangeError> {
|
||||
// Compute the leader's/follower's share of the pre-master secret.
|
||||
//
|
||||
// We need to mimic the [diffie-hellman](p256::ecdh::diffie_hellman) function without the
|
||||
// [SharedSecret](p256::ecdh::SharedSecret) wrapper, because this makes it harder to get
|
||||
// the result as an EC curve point.
|
||||
// We need to mimic the [diffie-hellman](p256::ecdh::diffie_hellman) function
|
||||
// without the [SharedSecret](p256::ecdh::SharedSecret) wrapper, because
|
||||
// this makes it harder to get the result as an EC curve point.
|
||||
let shared_secret = {
|
||||
let public_projective = server_key.to_projective();
|
||||
(public_projective * private_key.to_nonzero_scalar().as_ref()).to_affine()
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
//! # The Key Exchange Protocol
|
||||
//!
|
||||
//! This crate implements a key exchange protocol with 3 parties, namely server, leader and
|
||||
//! follower. The goal is to end up with a shared secret (ECDH) between the server and the client.
|
||||
//! The client in this context is leader and follower combined, which means that each of them will
|
||||
//! end up with a share of the shared secret. The leader will do all the necessary communication
|
||||
//! This crate implements a key exchange protocol with 3 parties, namely server,
|
||||
//! leader and follower. The goal is to end up with a shared secret (ECDH)
|
||||
//! between the server and the client. The client in this context is leader and
|
||||
//! follower combined, which means that each of them will end up with a share of
|
||||
//! the shared secret. The leader will do all the necessary communication
|
||||
//! with the server alone and forward all messages from and to the follower.
|
||||
//!
|
||||
//! A detailed description of this protocol can be found in our documentation
|
||||
@@ -58,8 +59,9 @@ pub trait KeyExchange {
|
||||
|
||||
/// Computes the client's public key.
|
||||
///
|
||||
/// The client's public key in this context is the combined public key (EC point addition) of
|
||||
/// the leader's public key and the follower's public key.
|
||||
/// The client's public key in this context is the combined public key (EC
|
||||
/// point addition) of the leader's public key and the follower's public
|
||||
/// key.
|
||||
async fn client_key(&mut self) -> Result<PublicKey, KeyExchangeError>;
|
||||
|
||||
/// Performs any necessary one-time setup, returning a reference to the PMS.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! This module provides mock types for key exchange leader and follower and a function to create
|
||||
//! such a pair.
|
||||
//! This module provides mock types for key exchange leader and follower and a
|
||||
//! function to create such a pair.
|
||||
|
||||
use crate::{KeyExchangeConfig, MpcKeyExchange, Role};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! This module implements a secure two-party computation protocol for adding two private EC points
|
||||
//! and secret-sharing the resulting x coordinate (the shares are field elements of the field
|
||||
//! underlying the elliptic curve).
|
||||
//! This module implements a secure two-party computation protocol for adding
|
||||
//! two private EC points and secret-sharing the resulting x coordinate (the
|
||||
//! shares are field elements of the field underlying the elliptic curve).
|
||||
//! This protocol has semi-honest security.
|
||||
//!
|
||||
//! The protocol is described in <https://docs.tlsnotary.org/protocol/notarization/key_exchange.html>
|
||||
|
||||
@@ -191,10 +191,11 @@ impl<C: CtrCircuit> KeyStream<C> {
|
||||
}
|
||||
}
|
||||
ExecutionMode::Prove => {
|
||||
// Note that after the circuit execution, the value of `block` can be considered as
|
||||
// implicitly authenticated since `key` and `iv` have already been authenticated earlier
|
||||
// and `nonce_ref` and `ctr_ref` are public.
|
||||
// [Prove::prove] will **not** be called on `block` at any later point.
|
||||
// Note that after the circuit execution, the value of `block` can be considered
|
||||
// as implicitly authenticated since `key` and `iv` have already
|
||||
// been authenticated earlier and `nonce_ref` and `ctr_ref` are
|
||||
// public. [Prove::prove] will **not** be called on `block` at
|
||||
// any later point.
|
||||
thread.commit_prove(&inputs).await?;
|
||||
for (circ, inputs, outputs) in calls {
|
||||
thread.execute_prove(circ, &inputs, &outputs).await?;
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
//! This crate provides a 2PC stream cipher implementation using a block cipher in counter mode.
|
||||
//! This crate provides a 2PC stream cipher implementation using a block cipher
|
||||
//! in counter mode.
|
||||
//!
|
||||
//! Each party plays a specific role, either the `StreamCipherLeader` or the `StreamCipherFollower`.
|
||||
//! Both parties work together to encrypt and decrypt messages using a shared key.
|
||||
//! Each party plays a specific role, either the `StreamCipherLeader` or the
|
||||
//! `StreamCipherFollower`. Both parties work together to encrypt and decrypt
|
||||
//! messages using a shared key.
|
||||
//!
|
||||
//! # Transcript
|
||||
//!
|
||||
//! Using the `record` flag, the `StreamCipherFollower` can optionally use a dedicated stream when
|
||||
//! encoding the plaintext labels, which allows the `StreamCipherLeader` to build a transcript of
|
||||
//! active labels which are pushed to the provided `TranscriptSink`.
|
||||
//! Using the `record` flag, the `StreamCipherFollower` can optionally use a
|
||||
//! dedicated stream when encoding the plaintext labels, which allows the
|
||||
//! `StreamCipherLeader` to build a transcript of active labels which are pushed
|
||||
//! to the provided `TranscriptSink`.
|
||||
//!
|
||||
//! Afterwards, the `StreamCipherLeader` can create commitments to the transcript which can be used in
|
||||
//! a selective disclosure protocol.
|
||||
//! Afterwards, the `StreamCipherLeader` can create commitments to the
|
||||
//! transcript which can be used in a selective disclosure protocol.
|
||||
|
||||
#![deny(missing_docs, unreachable_pub, unused_must_use)]
|
||||
#![deny(clippy::all)]
|
||||
@@ -43,7 +46,8 @@ where
|
||||
/// Decodes the key for the stream cipher, revealing it to this party.
|
||||
async fn decode_key_private(&mut self) -> Result<(), StreamCipherError>;
|
||||
|
||||
/// Decodes the key for the stream cipher, revealing it to the other party(s).
|
||||
/// Decodes the key for the stream cipher, revealing it to the other
|
||||
/// party(s).
|
||||
async fn decode_key_blind(&mut self) -> Result<(), StreamCipherError>;
|
||||
|
||||
/// Sets the transcript id
|
||||
@@ -51,14 +55,15 @@ where
|
||||
/// The stream cipher assigns unique identifiers to each byte of plaintext
|
||||
/// during encryption and decryption.
|
||||
///
|
||||
/// For example, if the transcript id is set to `foo`, then the first byte will
|
||||
/// be assigned the id `foo/0`, the second byte `foo/1`, and so on.
|
||||
/// For example, if the transcript id is set to `foo`, then the first byte
|
||||
/// will be assigned the id `foo/0`, the second byte `foo/1`, and so on.
|
||||
///
|
||||
/// Each transcript id has an independent counter.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The state of a transcript counter is preserved between calls to `set_transcript_id`.
|
||||
/// The state of a transcript counter is preserved between calls to
|
||||
/// `set_transcript_id`.
|
||||
fn set_transcript_id(&mut self, id: &str);
|
||||
|
||||
/// Preprocesses the keystream for the given number of bytes.
|
||||
@@ -141,13 +146,13 @@ where
|
||||
ciphertext: Vec<u8>,
|
||||
) -> Result<(), StreamCipherError>;
|
||||
|
||||
/// Locally decrypts the provided ciphertext and then proves in ZK to the other party(s) that the
|
||||
/// plaintext is correct.
|
||||
/// Locally decrypts the provided ciphertext and then proves in ZK to the
|
||||
/// other party(s) that the plaintext is correct.
|
||||
///
|
||||
/// Returns the plaintext.
|
||||
///
|
||||
/// This method requires this party to know the encryption key, which can be achieved by calling
|
||||
/// the `decode_key_private` method.
|
||||
/// This method requires this party to know the encryption key, which can be
|
||||
/// achieved by calling the `decode_key_private` method.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -159,7 +164,8 @@ where
|
||||
ciphertext: Vec<u8>,
|
||||
) -> Result<Vec<u8>, StreamCipherError>;
|
||||
|
||||
/// Verifies the other party(s) can prove they know a plaintext which encrypts to the given ciphertext.
|
||||
/// Verifies the other party(s) can prove they know a plaintext which
|
||||
/// encrypts to the given ciphertext.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -171,7 +177,8 @@ where
|
||||
ciphertext: Vec<u8>,
|
||||
) -> Result<(), StreamCipherError>;
|
||||
|
||||
/// Returns an additive share of the keystream block for the given explicit nonce and counter.
|
||||
/// Returns an additive share of the keystream block for the given explicit
|
||||
/// nonce and counter.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
||||
@@ -57,8 +57,8 @@ struct KeyAndIv {
|
||||
|
||||
/// A subset of plaintext bytes processed by the stream cipher.
|
||||
///
|
||||
/// Note that `Transcript` does not store the actual bytes. Instead, it provides IDs which are
|
||||
/// assigned to plaintext bytes of the stream cipher.
|
||||
/// Note that `Transcript` does not store the actual bytes. Instead, it provides
|
||||
/// IDs which are assigned to plaintext bytes of the stream cipher.
|
||||
struct Transcript {
|
||||
/// The ID of this transcript.
|
||||
id: String,
|
||||
@@ -74,7 +74,8 @@ impl Transcript {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns unique identifiers for the next plaintext bytes in the transcript.
|
||||
/// Returns unique identifiers for the next plaintext bytes in the
|
||||
/// transcript.
|
||||
fn extend_plaintext(&mut self, len: usize) -> Vec<String> {
|
||||
(0..len)
|
||||
.map(|_| self.plaintext.increment_in_place().to_string())
|
||||
|
||||
@@ -24,8 +24,8 @@ impl GhashCore {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `max_block_count` - Determines the maximum number of 128-bit message blocks we want to
|
||||
/// authenticate. Panics if `max_block_count` is 0.
|
||||
/// * `max_block_count` - Determines the maximum number of 128-bit message
|
||||
/// blocks we want to authenticate. Panics if `max_block_count` is 0.
|
||||
pub(crate) fn new(max_block_count: usize) -> Self {
|
||||
assert!(max_block_count > 0);
|
||||
|
||||
@@ -35,10 +35,11 @@ impl GhashCore {
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms `self` into a `GhashCore<Intermediate>`, holding multiplicative shares of
|
||||
/// powers of `H`.
|
||||
/// Transforms `self` into a `GhashCore<Intermediate>`, holding
|
||||
/// multiplicative shares of powers of `H`.
|
||||
///
|
||||
/// Converts `H` into `H`, `H^3`, `H^5`, ... depending on `self.max_block_count`.
|
||||
/// Converts `H` into `H`, `H^3`, `H^5`, ... depending on
|
||||
/// `self.max_block_count`.
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
pub(crate) fn compute_odd_mul_powers(self, mul_share: Gf2_128) -> GhashCore<Intermediate> {
|
||||
let mut hashkey_powers = vec![mul_share];
|
||||
@@ -63,17 +64,17 @@ impl GhashCore<Intermediate> {
|
||||
/// exists, are not returned.
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
pub(crate) fn odd_mul_shares(&self) -> Vec<Gf2_128> {
|
||||
// If we already have some cached additive sharings, we do not need to compute new powers.
|
||||
// So we compute an offset to ignore them. We divide by 2 because
|
||||
// `self.state.cached_add_shares` contain even and odd powers, while
|
||||
// `self.state.odd_mul_shares` only have odd powers.
|
||||
// If we already have some cached additive sharings, we do not need to compute
|
||||
// new powers. So we compute an offset to ignore them. We divide by 2
|
||||
// because `self.state.cached_add_shares` contain even and odd powers,
|
||||
// while `self.state.odd_mul_shares` only have odd powers.
|
||||
let offset = self.state.cached_add_shares.len() / 2;
|
||||
|
||||
self.state.odd_mul_shares[offset..].to_vec()
|
||||
}
|
||||
|
||||
/// Adds new additive shares of hashkey powers by also computing the even ones
|
||||
/// and transforms `self` into a `GhashCore<Finalized>`.
|
||||
/// Adds new additive shares of hashkey powers by also computing the even
|
||||
/// ones and transforms `self` into a `GhashCore<Finalized>`.
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
pub(crate) fn add_new_add_shares(
|
||||
mut self,
|
||||
@@ -120,8 +121,9 @@ impl GhashCore<Finalized> {
|
||||
|
||||
/// Changes the maximum hashkey power.
|
||||
///
|
||||
/// If we want to create a GHASH output for a new message, which is longer than the old one, we need
|
||||
/// to compute the missing shares of the powers of `H`.
|
||||
/// If we want to create a GHASH output for a new message, which is longer
|
||||
/// than the old one, we need to compute the missing shares of the
|
||||
/// powers of `H`.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn change_max_hashkey(
|
||||
self,
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
//! This module implements the AES-GCM's GHASH function in a secure two-party computation (2PC)
|
||||
//! setting. The parties start with their secret XOR shares of H (the GHASH key) and at the end
|
||||
//! each gets their XOR share of the GHASH output. The method is described here:
|
||||
//! <https://tlsnotary.org/how_it_works#section4>.
|
||||
//! This module implements the AES-GCM's GHASH function in a secure two-party
|
||||
//! computation (2PC) setting. The parties start with their secret XOR shares of
|
||||
//! H (the GHASH key) and at the end each gets their XOR share of the GHASH
|
||||
//! output. The method is described here: <https://tlsnotary.org/how_it_works#section4>.
|
||||
//!
|
||||
//! At first we will convert the XOR (additive) share of `H`, into a multiplicative share. This
|
||||
//! allows us to compute all the necessary powers of `H^n` locally. Note, that it is only required
|
||||
//! to compute the odd multiplicative powers, because of free squaring. Then each of these
|
||||
//! multiplicative shares will be converted back into additive shares. The even additive shares can
|
||||
//! then locally be built by using the odd ones. This way, we can batch nearly all oblivious
|
||||
//! transfers and reduce the round complexity of the protocol.
|
||||
//! At first we will convert the XOR (additive) share of `H`, into a
|
||||
//! multiplicative share. This allows us to compute all the necessary powers of
|
||||
//! `H^n` locally. Note, that it is only required to compute the odd
|
||||
//! multiplicative powers, because of free squaring. Then each of these
|
||||
//! multiplicative shares will be converted back into additive shares. The even
|
||||
//! additive shares can then locally be built by using the odd ones. This way,
|
||||
//! we can batch nearly all oblivious transfers and reduce the round complexity
|
||||
//! of the protocol.
|
||||
//!
|
||||
//! On the whole, we need a single additive-to-multiplicative (A2M) and `n/2`, where `n` is the
|
||||
//! number of blocks of message, multiplicative-to-additive (M2A) conversions. Finally, having
|
||||
//! additive shares of `H^n` for all needed `n`, we can compute an additive share of the GHASH
|
||||
//! output.
|
||||
//! On the whole, we need a single additive-to-multiplicative (A2M) and `n/2`,
|
||||
//! where `n` is the number of blocks of message, multiplicative-to-additive
|
||||
//! (M2A) conversions. Finally, having additive shares of `H^n` for all needed
|
||||
//! `n`, we can compute an additive share of the GHASH output.
|
||||
|
||||
/// Contains the core logic for ghash.
|
||||
mod core;
|
||||
@@ -35,14 +37,16 @@ pub(crate) enum GhashError {
|
||||
|
||||
/// Computes missing odd multiplicative shares of the hashkey powers.
|
||||
///
|
||||
/// Checks if depending on the number of `needed` shares, we need more odd multiplicative shares and
|
||||
/// computes them. Notice that we only need odd multiplicative shares for the OT, because we can
|
||||
/// derive even additive shares from odd additive shares, which we call free squaring.
|
||||
/// Checks if depending on the number of `needed` shares, we need more odd
|
||||
/// multiplicative shares and computes them. Notice that we only need odd
|
||||
/// multiplicative shares for the OT, because we can derive even additive shares
|
||||
/// from odd additive shares, which we call free squaring.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `present_odd_mul_shares` - Multiplicative odd shares already present.
|
||||
/// * `needed` - How many powers we need including odd and even.
|
||||
/// * `needed` - How many powers we need including odd and
|
||||
/// even.
|
||||
#[instrument(level = "trace", skip(present_odd_mul_shares))]
|
||||
fn compute_missing_mul_shares(present_odd_mul_shares: &mut Vec<Gf2_128>, needed: usize) {
|
||||
// Divide by 2 and round up.
|
||||
@@ -59,33 +63,35 @@ fn compute_missing_mul_shares(present_odd_mul_shares: &mut Vec<Gf2_128>, needed:
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes new even (additive) shares from new odd (additive) shares and saves both the new odd shares
|
||||
/// and the new even shares.
|
||||
/// Computes new even (additive) shares from new odd (additive) shares and saves
|
||||
/// both the new odd shares and the new even shares.
|
||||
///
|
||||
/// This function implements the derivation of even additive shares from odd additive shares,
|
||||
/// which we refer to as free squaring. Every additive share of an even power of
|
||||
/// `H` can be computed without an OT interaction by squaring the corresponding additive share
|
||||
/// of an odd power of `H`, e.g. if we have a share of H^3, we can derive the share of H^6 by doing
|
||||
/// (H^3)^2.
|
||||
/// This function implements the derivation of even additive shares from odd
|
||||
/// additive shares, which we refer to as free squaring. Every additive share of
|
||||
/// an even power of `H` can be computed without an OT interaction by squaring
|
||||
/// the corresponding additive share of an odd power of `H`, e.g. if we have a
|
||||
/// share of H^3, we can derive the share of H^6 by doing (H^3)^2.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `new_add_odd_shares` - New odd additive shares we got as a result of doing an OT on odd
|
||||
/// multiplicative shares.
|
||||
/// * `add_shares` - All additive shares (even and odd) we already have. This is a mutable
|
||||
/// reference to cached_add_shares in [crate::ghash::state::Intermediate].
|
||||
/// * `new_add_odd_shares` - New odd additive shares we got as a result of doing
|
||||
/// an OT on odd multiplicative shares.
|
||||
/// * `add_shares` - All additive shares (even and odd) we already have.
|
||||
/// This is a mutable reference to cached_add_shares in
|
||||
/// [crate::ghash::state::Intermediate].
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
fn compute_new_add_shares(new_add_odd_shares: &[Gf2_128], add_shares: &mut Vec<Gf2_128>) {
|
||||
for (odd_share, current_odd_power) in new_add_odd_shares
|
||||
.iter()
|
||||
.zip((add_shares.len() + 1..).step_by(2))
|
||||
{
|
||||
// `add_shares` always have an even number of shares so we simply add the next odd share.
|
||||
// `add_shares` always have an even number of shares so we simply add the next
|
||||
// odd share.
|
||||
add_shares.push(*odd_share);
|
||||
|
||||
// Now we need to compute the next even share and add it.
|
||||
// Note that the n-th index corresponds to the (n+1)-th power, e.g. add_shares[4]
|
||||
// is the share of H^5.
|
||||
// Note that the n-th index corresponds to the (n+1)-th power, e.g.
|
||||
// add_shares[4] is the share of H^5.
|
||||
let mut base_share = add_shares[current_odd_power / 2];
|
||||
base_share = base_share * base_share;
|
||||
add_shares.push(base_share);
|
||||
|
||||
@@ -24,8 +24,8 @@ opaque_debug::implement!(Init);
|
||||
|
||||
/// Intermediate state for Ghash protocol.
|
||||
///
|
||||
/// This is when the additive share has been converted into a multiplicative share and all the
|
||||
/// needed powers have been computed.
|
||||
/// This is when the additive share has been converted into a multiplicative
|
||||
/// share and all the needed powers have been computed.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Intermediate {
|
||||
pub(super) odd_mul_shares: Vec<Gf2_128>,
|
||||
@@ -41,8 +41,8 @@ opaque_debug::implement!(Intermediate);
|
||||
|
||||
/// Final state for Ghash protocol.
|
||||
///
|
||||
/// This is when each party can compute a final share of the ghash output, because both now have
|
||||
/// additive shares of all the powers of `H`.
|
||||
/// This is when each party can compute a final share of the ghash output,
|
||||
/// because both now have additive shares of all the powers of `H`.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Finalized {
|
||||
pub(super) odd_mul_shares: Vec<Gf2_128>,
|
||||
|
||||
@@ -46,8 +46,8 @@ where
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `config` - The configuration for this Ghash instance.
|
||||
/// * `converter` - An instance which allows to convert multiplicative into additive shares
|
||||
/// and vice versa.
|
||||
/// * `converter` - An instance which allows to convert multiplicative
|
||||
/// into additive shares and vice versa.
|
||||
/// * `context` - The context.
|
||||
pub fn new(config: GhashConfig, converter: C, context: Ctx) -> Self {
|
||||
Self {
|
||||
@@ -128,9 +128,9 @@ where
|
||||
|
||||
#[instrument(level = "debug", fields(thread = %self.context.id()), skip_all, err)]
|
||||
async fn setup(&mut self) -> Result<(), UniversalHashError> {
|
||||
// We need only half the number of `max_block_count` M2As because of the free squaring trick
|
||||
// and we need one extra A2M conversion in the beginning. Both M2A and A2M, each require a single
|
||||
// OLE.
|
||||
// We need only half the number of `max_block_count` M2As because of the free
|
||||
// squaring trick and we need one extra A2M conversion in the beginning.
|
||||
// Both M2A and A2M, each require a single OLE.
|
||||
let ole_count = self.config.max_block_count / 2 + 1;
|
||||
self.converter.alloc(ole_count);
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
//! Attestation types.
|
||||
//!
|
||||
//! An attestation is a cryptographically signed document from a Notary who witnessed a TLS
|
||||
//! connection. It contains various fields which can be used to verify statements about the
|
||||
//! connection and the associated application data.
|
||||
//! An attestation is a cryptographically signed document from a Notary who
|
||||
//! witnessed a TLS connection. It contains various fields which can be used to
|
||||
//! verify statements about the connection and the associated application data.
|
||||
//!
|
||||
//! Attestations contain a header and a body. The header is signed by a Notary and it contains
|
||||
//! a merkle root of the body fields. This allows a Prover to disclose only necessary fields
|
||||
//! to a Verifier depending on the statements being made.
|
||||
//! Attestations contain a header and a body. The header is signed by a Notary
|
||||
//! and it contains a merkle root of the body fields. This allows a Prover to
|
||||
//! disclose only necessary fields to a Verifier depending on the statements
|
||||
//! being made.
|
||||
|
||||
mod builder;
|
||||
mod config;
|
||||
@@ -122,10 +123,10 @@ impl_domain_separator!(Header);
|
||||
|
||||
/// Attestation body.
|
||||
///
|
||||
/// An attestation contains a set of fields which are cryptographically signed by
|
||||
/// a Notary via a [`Header`]. These fields include data which can be
|
||||
/// used to verify aspects of a TLS connection, such as the server's identity, and facts
|
||||
/// about the transcript.
|
||||
/// An attestation contains a set of fields which are cryptographically signed
|
||||
/// by a Notary via a [`Header`]. These fields include data which can be
|
||||
/// used to verify aspects of a TLS connection, such as the server's identity,
|
||||
/// and facts about the transcript.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Body {
|
||||
verifying_key: Field<VerifyingKey>,
|
||||
@@ -158,14 +159,16 @@ impl Body {
|
||||
|
||||
/// Returns the fields of the body hashed and sorted by id.
|
||||
///
|
||||
/// Each field is hashed with a domain separator to mitigate type confusion attacks.
|
||||
/// Each field is hashed with a domain separator to mitigate type confusion
|
||||
/// attacks.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The order of fields is not stable across versions.
|
||||
pub(crate) fn hash_fields(&self, hasher: &dyn HashAlgorithm) -> Vec<(FieldId, Hash)> {
|
||||
// CRITICAL: ensure all fields are included! If a new field is added to the struct
|
||||
// without including it here it will not be verified to be included in the attestation.
|
||||
// CRITICAL: ensure all fields are included! If a new field is added to the
|
||||
// struct without including it here it will not be verified to be
|
||||
// included in the attestation.
|
||||
let Self {
|
||||
verifying_key,
|
||||
connection_info: conn_info,
|
||||
|
||||
@@ -2,20 +2,22 @@
|
||||
//!
|
||||
//! ## Commitment
|
||||
//!
|
||||
//! During the TLS handshake the Notary receives the Server's ephemeral public key, and this key
|
||||
//! serves as a binding commitment to the identity of the Server. The ephemeral key itself does not
|
||||
//! reveal the Server's identity, but it is bound to it via a signature created using the Server's
|
||||
//! During the TLS handshake the Notary receives the Server's ephemeral public
|
||||
//! key, and this key serves as a binding commitment to the identity of the
|
||||
//! Server. The ephemeral key itself does not reveal the Server's identity, but
|
||||
//! it is bound to it via a signature created using the Server's
|
||||
//! X.509 certificate.
|
||||
//!
|
||||
//! A Prover can withhold the Server's signature and certificate chain from the Notary to
|
||||
//! improve privacy and censorship resistance.
|
||||
//! A Prover can withhold the Server's signature and certificate chain from the
|
||||
//! Notary to improve privacy and censorship resistance.
|
||||
//!
|
||||
//! ## Proving the Server's identity
|
||||
//!
|
||||
//! A Prover can prove the Server's identity to a Verifier by sending a [`ServerIdentityProof`]. This
|
||||
//! proof contains all the information required to establish the link between the TLS connection
|
||||
//! and the Server's X.509 certificate. A Verifier checks the Server's certificate against their own trust
|
||||
//! anchors, the same way a typical TLS client would.
|
||||
//! A Prover can prove the Server's identity to a Verifier by sending a
|
||||
//! [`ServerIdentityProof`]. This proof contains all the information required to
|
||||
//! establish the link between the TLS connection and the Server's X.509
|
||||
//! certificate. A Verifier checks the Server's certificate against their own
|
||||
//! trust anchors, the same way a typical TLS client would.
|
||||
|
||||
mod commit;
|
||||
mod proof;
|
||||
|
||||
@@ -47,8 +47,8 @@ impl HashProvider {
|
||||
self.algs.insert(id, algorithm);
|
||||
}
|
||||
|
||||
/// Returns the hash algorithm with the given identifier, or an error if the hash algorithm
|
||||
/// does not exist.
|
||||
/// Returns the hash algorithm with the given identifier, or an error if the
|
||||
/// hash algorithm does not exist.
|
||||
pub fn get(
|
||||
&self,
|
||||
id: &HashAlgId,
|
||||
@@ -293,7 +293,8 @@ impl<T> Blinded<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A type with a domain separator which is used during hashing to mitigate type confusion attacks.
|
||||
/// A type with a domain separator which is used during hashing to mitigate type
|
||||
/// confusion attacks.
|
||||
pub(crate) trait DomainSeparator {
|
||||
/// Returns the domain separator for the type.
|
||||
fn domain(&self) -> &[u8];
|
||||
|
||||
@@ -26,7 +26,8 @@ pub(crate) struct MerkleProof {
|
||||
opaque_debug::implement!(MerkleProof);
|
||||
|
||||
impl MerkleProof {
|
||||
/// Checks if indices, hashes and leaves count are valid for the provided root
|
||||
/// Checks if indices, hashes and leaves count are valid for the provided
|
||||
/// root
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@@ -103,7 +104,8 @@ impl MerkleTree {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If the provided hasher is not the same as the one used to create the tree.
|
||||
/// - If the provided hasher is not the same as the one used to create the
|
||||
/// tree.
|
||||
pub(crate) fn insert(&mut self, hasher: &dyn HashAlgorithm, mut leaves: Vec<Hash>) {
|
||||
assert_eq!(self.alg, hasher.id(), "hash algorithm mismatch");
|
||||
|
||||
|
||||
@@ -12,13 +12,16 @@ use crate::{
|
||||
///
|
||||
/// ## Custom Algorithms
|
||||
///
|
||||
/// This is the primary interface for extending cryptographic functionality. The various
|
||||
/// providers can be configured with custom algorithms and implementations.
|
||||
/// This is the primary interface for extending cryptographic functionality. The
|
||||
/// various providers can be configured with custom algorithms and
|
||||
/// implementations.
|
||||
///
|
||||
/// Algorithms are uniquely identified using an 8-bit ID, eg. [`HashAlgId`](crate::hash::HashAlgId),
|
||||
/// half of which is reserved for the officially supported algorithms. If you think that a new
|
||||
/// algorithm should be added to the official set, please open an issue. Beware that other parties
|
||||
/// may assign different algorithms to the same ID as you, and we make no effort to mitigate this.
|
||||
/// Algorithms are uniquely identified using an 8-bit ID, eg.
|
||||
/// [`HashAlgId`](crate::hash::HashAlgId), half of which is reserved for the
|
||||
/// officially supported algorithms. If you think that a new algorithm should be
|
||||
/// added to the official set, please open an issue. Beware that other parties
|
||||
/// may assign different algorithms to the same ID as you, and we make no effort
|
||||
/// to mitigate this.
|
||||
pub struct CryptoProvider {
|
||||
/// Hash provider.
|
||||
pub hash: HashProvider,
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
//! Attestation requests.
|
||||
//!
|
||||
//! After the TLS connection, a Prover can request an attestation from the Notary which contains
|
||||
//! various information about the connection. During this process the Prover has the opportunity
|
||||
//! to configure certain aspects of the attestation, such as which signature algorithm the Notary
|
||||
//! should use to sign the attestation. Or which hash algorithm the Notary should use to merkelize
|
||||
//! After the TLS connection, a Prover can request an attestation from the
|
||||
//! Notary which contains various information about the connection. During this
|
||||
//! process the Prover has the opportunity to configure certain aspects of the
|
||||
//! attestation, such as which signature algorithm the Notary should use to sign
|
||||
//! the attestation. Or which hash algorithm the Notary should use to merkelize
|
||||
//! the fields.
|
||||
//!
|
||||
//! A [`Request`] can be created using a [`RequestBuilder`]. The builder will take both configuration
|
||||
//! via a [`RequestConfig`] as well as the Prover's secret data. The [`Secrets`](crate::Secrets) are of
|
||||
//! course not shared with the Notary but are used to create commitments which are included in the attestation.
|
||||
//! A [`Request`] can be created using a [`RequestBuilder`]. The builder will
|
||||
//! take both configuration via a [`RequestConfig`] as well as the Prover's
|
||||
//! secret data. The [`Secrets`](crate::Secrets) are of course not shared with
|
||||
//! the Notary but are used to create commitments which are included in the
|
||||
//! attestation.
|
||||
|
||||
mod builder;
|
||||
mod config;
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
//! Transcript types.
|
||||
//!
|
||||
//! All application data communicated over a TLS connection is referred to as a [`Transcript`]. A transcript is essentially
|
||||
//! just two vectors of bytes, each corresponding to a [`Direction`].
|
||||
//! All application data communicated over a TLS connection is referred to as a
|
||||
//! [`Transcript`]. A transcript is essentially just two vectors of bytes, each
|
||||
//! corresponding to a [`Direction`].
|
||||
//!
|
||||
//! TLS operates over a bidirectional byte stream, and thus there are no application layer semantics present in the transcript.
|
||||
//! For example, HTTPS is an application layer protocol that runs *over TLS* so there is no concept of "requests" or "responses"
|
||||
//! in the transcript itself. These semantics must be recovered by parsing the application data and relating it to the bytes
|
||||
//! TLS operates over a bidirectional byte stream, and thus there are no
|
||||
//! application layer semantics present in the transcript. For example, HTTPS is
|
||||
//! an application layer protocol that runs *over TLS* so there is no concept of
|
||||
//! "requests" or "responses" in the transcript itself. These semantics must be
|
||||
//! recovered by parsing the application data and relating it to the bytes
|
||||
//! in the transcript.
|
||||
//!
|
||||
//! ## Commitments
|
||||
//!
|
||||
//! During the attestation process a Prover can generate multiple commitments to various parts of the transcript.
|
||||
//! These commitments are inserted into the attestation body and can be used by the Verifier to verify transcript proofs
|
||||
//! During the attestation process a Prover can generate multiple commitments to
|
||||
//! various parts of the transcript. These commitments are inserted into the
|
||||
//! attestation body and can be used by the Verifier to verify transcript proofs
|
||||
//! later.
|
||||
//!
|
||||
//! To configure the transcript commitments, use the [`TranscriptCommitConfigBuilder`].
|
||||
//! To configure the transcript commitments, use the
|
||||
//! [`TranscriptCommitConfigBuilder`].
|
||||
//!
|
||||
//! ## Selective Disclosure
|
||||
//!
|
||||
//! Using a [`TranscriptProof`] a Prover can selectively disclose parts of a transcript to a Verifier
|
||||
//! in the form of a [`PartialTranscript`]. A Verifier always learns the length of the transcript, but sensitive
|
||||
//! data can be withheld.
|
||||
//! Using a [`TranscriptProof`] a Prover can selectively disclose parts of a
|
||||
//! transcript to a Verifier in the form of a [`PartialTranscript`]. A Verifier
|
||||
//! always learns the length of the transcript, but sensitive data can be
|
||||
//! withheld.
|
||||
//!
|
||||
//! To create a proof, use the [`TranscriptProofBuilder`] which is returned by
|
||||
//! [`Secrets::transcript_proof_builder`](crate::Secrets::transcript_proof_builder).
|
||||
@@ -103,8 +109,8 @@ impl Transcript {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the subsequence of the transcript with the provided index, returning `None`
|
||||
/// if the index is out of bounds.
|
||||
/// Returns the subsequence of the transcript with the provided index,
|
||||
/// returning `None` if the index is out of bounds.
|
||||
pub fn get(&self, direction: Direction, idx: &Idx) -> Option<Subsequence> {
|
||||
let data = match direction {
|
||||
Direction::Sent => &self.sent,
|
||||
@@ -154,7 +160,8 @@ impl Transcript {
|
||||
|
||||
/// A partial transcript.
|
||||
///
|
||||
/// A partial transcript is a transcript which may not have all the data authenticated.
|
||||
/// A partial transcript is a transcript which may not have all the data
|
||||
/// authenticated.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(try_from = "validation::PartialTranscriptUnchecked")]
|
||||
pub struct PartialTranscript {
|
||||
@@ -213,7 +220,8 @@ impl PartialTranscript {
|
||||
/// # Warning
|
||||
///
|
||||
/// Not all of the data in the transcript may have been authenticated. See
|
||||
/// [sent_authed](PartialTranscript::sent_authed) for a set of ranges which have been.
|
||||
/// [sent_authed](PartialTranscript::sent_authed) for a set of ranges which
|
||||
/// have been.
|
||||
pub fn sent_unsafe(&self) -> &[u8] {
|
||||
&self.sent
|
||||
}
|
||||
@@ -223,7 +231,8 @@ impl PartialTranscript {
|
||||
/// # Warning
|
||||
///
|
||||
/// Not all of the data in the transcript may have been authenticated. See
|
||||
/// [received_authed](PartialTranscript::received_authed) for a set of ranges which have been.
|
||||
/// [received_authed](PartialTranscript::received_authed) for a set of
|
||||
/// ranges which have been.
|
||||
pub fn received_unsafe(&self) -> &[u8] {
|
||||
&self.received
|
||||
}
|
||||
@@ -329,7 +338,8 @@ impl PartialTranscript {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets all bytes in the transcript which haven't been authenticated within the given range.
|
||||
/// Sets all bytes in the transcript which haven't been authenticated within
|
||||
/// the given range.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -353,8 +363,8 @@ impl PartialTranscript {
|
||||
|
||||
/// The direction of data communicated over a TLS connection.
|
||||
///
|
||||
/// This is used to differentiate between data sent from the Prover to the TLS peer,
|
||||
/// and data received by the Prover from the TLS peer (client or server).
|
||||
/// This is used to differentiate between data sent from the Prover to the TLS
|
||||
/// peer, and data received by the Prover from the TLS peer (client or server).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Direction {
|
||||
/// Sent from the Prover to the TLS peer.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Transcript encoding commitments and proofs.
|
||||
//!
|
||||
//! This is an internal module that is not intended to be used directly by users.
|
||||
//! This is an internal module that is not intended to be used directly by
|
||||
//! users.
|
||||
|
||||
mod encoder;
|
||||
mod proof;
|
||||
@@ -16,11 +17,13 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::hash::{impl_domain_separator, TypedHash};
|
||||
|
||||
/// The maximum allowed total bytelength of all committed data. Used to prevent DoS during verification.
|
||||
/// (this will cause the verifier to hash up to a max of 1GB * 128 = 128GB of plaintext encodings if the
|
||||
/// commitment type is [crate::commitment::Blake3]).
|
||||
/// The maximum allowed total bytelength of all committed data. Used to prevent
|
||||
/// DoS during verification. (this will cause the verifier to hash up to a max
|
||||
/// of 1GB * 128 = 128GB of plaintext encodings if the commitment type is
|
||||
/// [crate::commitment::Blake3]).
|
||||
///
|
||||
/// This value must not exceed bcs's MAX_SEQUENCE_LENGTH limit (which is (1 << 31) - 1 by default)
|
||||
/// This value must not exceed bcs's MAX_SEQUENCE_LENGTH limit (which is (1 <<
|
||||
/// 31) - 1 by default)
|
||||
const MAX_TOTAL_COMMITTED_DATA: usize = 1_000_000_000;
|
||||
|
||||
/// Transcript encoding commitment.
|
||||
|
||||
@@ -169,7 +169,8 @@ impl<'a> TranscriptProofBuilder<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Reveals the given ranges in the transcript using the provided kind of commitment.
|
||||
/// Reveals the given ranges in the transcript using the provided kind of
|
||||
/// commitment.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -252,7 +253,8 @@ impl<'a> TranscriptProofBuilder<'a> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Reveals the given ranges in the transcript using the default kind of commitment.
|
||||
/// Reveals the given ranges in the transcript using the default kind of
|
||||
/// commitment.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Runs a simple Prover which connects to the Notary and notarizes a request/response from
|
||||
// example.com. The Prover then generates a proof and writes it to disk.
|
||||
// Runs a simple Prover which connects to the Notary and notarizes a
|
||||
// request/response from example.com. The Prover then generates a proof and
|
||||
// writes it to disk.
|
||||
|
||||
use http_body_util::Empty;
|
||||
use hyper::{body::Bytes, Request, StatusCode};
|
||||
@@ -56,8 +57,9 @@ async fn main() {
|
||||
.unwrap();
|
||||
|
||||
// Bind the Prover to the server connection.
|
||||
// The returned `mpc_tls_connection` is an MPC TLS connection to the Server: all data written
|
||||
// to/read from it will be encrypted/decrypted using MPC with the Notary.
|
||||
// The returned `mpc_tls_connection` is an MPC TLS connection to the Server: all
|
||||
// data written to/read from it will be encrypted/decrypted using MPC with
|
||||
// the Notary.
|
||||
let (mpc_tls_connection, prover_fut) = prover.connect(client_socket.compat()).await.unwrap();
|
||||
let mpc_tls_connection = TokioIo::new(mpc_tls_connection.compat());
|
||||
|
||||
@@ -178,7 +180,8 @@ async fn build_proof_without_redactions(mut prover: Prover<Notarize>) -> TlsProo
|
||||
}
|
||||
|
||||
async fn build_proof_with_redactions(mut prover: Prover<Notarize>) -> TlsProof {
|
||||
// Identify the ranges in the outbound data which contain data which we want to disclose
|
||||
// Identify the ranges in the outbound data which contain data which we want to
|
||||
// disclose
|
||||
let (sent_public_ranges, _) = find_ranges(
|
||||
prover.sent_transcript().data(),
|
||||
&[
|
||||
@@ -187,7 +190,8 @@ async fn build_proof_with_redactions(mut prover: Prover<Notarize>) -> TlsProof {
|
||||
],
|
||||
);
|
||||
|
||||
// Identify the ranges in the inbound data which contain data which we want to disclose
|
||||
// Identify the ranges in the inbound data which contain data which we want to
|
||||
// disclose
|
||||
let (recv_public_ranges, _) = find_ranges(
|
||||
prover.recv_transcript().data(),
|
||||
&[
|
||||
|
||||
@@ -4,8 +4,8 @@ use elliptic_curve::pkcs8::DecodePublicKey;
|
||||
|
||||
use tlsn_core::proof::{SessionProof, TlsProof};
|
||||
|
||||
/// A simple verifier which reads a proof generated by `simple_prover.rs` from "proof.json", verifies
|
||||
/// it and prints the verified data to the console.
|
||||
/// A simple verifier which reads a proof generated by `simple_prover.rs` from
|
||||
/// "proof.json", verifies it and prints the verified data to the console.
|
||||
fn main() {
|
||||
// Deserialize the proof
|
||||
let proof = std::fs::read_to_string("simple_proof.json").unwrap();
|
||||
@@ -22,14 +22,15 @@ fn main() {
|
||||
|
||||
// Verify the session proof against the Notary's public key
|
||||
//
|
||||
// This verifies the identity of the server using a default certificate verifier which trusts
|
||||
// the root certificates from the `webpki-roots` crate.
|
||||
// This verifies the identity of the server using a default certificate verifier
|
||||
// which trusts the root certificates from the `webpki-roots` crate.
|
||||
session
|
||||
.verify_with_default_cert_verifier(notary_pubkey())
|
||||
.unwrap();
|
||||
|
||||
let SessionProof {
|
||||
// The session header that was signed by the Notary is a succinct commitment to the TLS transcript.
|
||||
// The session header that was signed by the Notary is a succinct commitment to the TLS
|
||||
// transcript.
|
||||
header,
|
||||
// This is the session_info, which contains the server_name, that is checked against the
|
||||
// certificate chain shared in the TLS handshake.
|
||||
|
||||
@@ -17,7 +17,8 @@ use tracing::debug;
|
||||
// Setting of the application server
|
||||
const SERVER_DOMAIN: &str = "discord.com";
|
||||
|
||||
// Setting of the notary server — make sure these are the same with the config in ../../notary/server
|
||||
// Setting of the notary server — make sure these are the same with the config
|
||||
// in ../../notary/server
|
||||
const NOTARY_HOST: &str = "127.0.0.1";
|
||||
const NOTARY_PORT: u16 = 7047;
|
||||
|
||||
@@ -69,7 +70,8 @@ async fn main() {
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Configure a new prover with the unique session id returned from notary client.
|
||||
// Configure a new prover with the unique session id returned from notary
|
||||
// client.
|
||||
let prover_config = ProverConfig::builder()
|
||||
.id(session_id)
|
||||
.server_name(SERVER_DOMAIN)
|
||||
@@ -155,7 +157,8 @@ async fn main() {
|
||||
.map(|range| builder.commit_sent(range).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Commit to the full received transcript in one shot, as we don't need to redact anything
|
||||
// Commit to the full received transcript in one shot, as we don't need to
|
||||
// redact anything
|
||||
commitment_ids.push(builder.commit_recv(&(0..recv_len)).unwrap());
|
||||
|
||||
// Finalize, returning the notarized session
|
||||
|
||||
@@ -4,8 +4,9 @@ use elliptic_curve::pkcs8::DecodePublicKey;
|
||||
|
||||
use tlsn_core::proof::{SessionProof, TlsProof};
|
||||
|
||||
/// A simple verifier which reads a proof generated by `discord_dm.rs` from "discord_dm_proof.json", verifies
|
||||
/// it and prints the verified data to the console.
|
||||
/// A simple verifier which reads a proof generated by `discord_dm.rs` from
|
||||
/// "discord_dm_proof.json", verifies it and prints the verified data to the
|
||||
/// console.
|
||||
fn main() {
|
||||
// Deserialize the proof
|
||||
let proof = std::fs::read_to_string("discord_dm_proof.json").unwrap();
|
||||
@@ -22,14 +23,15 @@ fn main() {
|
||||
|
||||
// Verify the session proof against the Notary's public key
|
||||
//
|
||||
// This verifies the identity of the server using a default certificate verifier which trusts
|
||||
// the root certificates from the `webpki-roots` crate.
|
||||
// This verifies the identity of the server using a default certificate verifier
|
||||
// which trusts the root certificates from the `webpki-roots` crate.
|
||||
session
|
||||
.verify_with_default_cert_verifier(notary_pubkey())
|
||||
.unwrap();
|
||||
|
||||
let SessionProof {
|
||||
// The session header that was signed by the Notary is a succinct commitment to the TLS transcript.
|
||||
// The session header that was signed by the Notary is a succinct commitment to the TLS
|
||||
// transcript.
|
||||
header,
|
||||
// This is the session_info, which contains the server_name, that is checked against the
|
||||
// certificate chain shared in the TLS handshake.
|
||||
|
||||
@@ -80,7 +80,8 @@ impl HttpCommitError {
|
||||
pub trait HttpCommit {
|
||||
/// Commits to an HTTP transcript.
|
||||
///
|
||||
/// The default implementation commits to each request and response in the transcript separately.
|
||||
/// The default implementation commits to each request and response in the
|
||||
/// transcript separately.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -104,8 +105,9 @@ pub trait HttpCommit {
|
||||
|
||||
/// Commits to a request.
|
||||
///
|
||||
/// The default implementation commits to the request excluding the target, headers and body. Additionally,
|
||||
/// it commits to the target, headers and body separately.
|
||||
/// The default implementation commits to the request excluding the target,
|
||||
/// headers and body. Additionally, it commits to the target, headers
|
||||
/// and body separately.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -181,7 +183,8 @@ pub trait HttpCommit {
|
||||
|
||||
/// Commits to a request header.
|
||||
///
|
||||
/// The default implementation commits to the entire header, and the header excluding the value.
|
||||
/// The default implementation commits to the entire header, and the header
|
||||
/// excluding the value.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -224,9 +227,9 @@ pub trait HttpCommit {
|
||||
|
||||
/// Commits to a request body.
|
||||
///
|
||||
/// The default implementation commits using the default implementation for the
|
||||
/// format type of the body. If the format of the body is unknown, it commits to the
|
||||
/// body as a whole.
|
||||
/// The default implementation commits using the default implementation for
|
||||
/// the format type of the body. If the format of the body is unknown,
|
||||
/// it commits to the body as a whole.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -269,8 +272,9 @@ pub trait HttpCommit {
|
||||
|
||||
/// Commits to a response.
|
||||
///
|
||||
/// The default implementation commits to the response excluding the headers and body. Additionally,
|
||||
/// it commits to the headers and body separately.
|
||||
/// The default implementation commits to the response excluding the headers
|
||||
/// and body. Additionally, it commits to the headers and body
|
||||
/// separately.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -316,7 +320,8 @@ pub trait HttpCommit {
|
||||
|
||||
/// Commits to a response header.
|
||||
///
|
||||
/// The default implementation commits to the entire header, and the header excluding the value.
|
||||
/// The default implementation commits to the entire header, and the header
|
||||
/// excluding the value.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -359,9 +364,9 @@ pub trait HttpCommit {
|
||||
|
||||
/// Commits to a response body.
|
||||
///
|
||||
/// The default implementation commits using the default implementation for the
|
||||
/// format type of the body. If the format of the body is unknown, it commits to the
|
||||
/// body as a whole.
|
||||
/// The default implementation commits using the default implementation for
|
||||
/// the format type of the body. If the format of the body is unknown,
|
||||
/// it commits to the body as a whole.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
||||
@@ -76,8 +76,8 @@ pub trait JsonCommit {
|
||||
|
||||
/// Commits to a JSON object.
|
||||
///
|
||||
/// The default implementation commits the object without any of the key-value pairs, then
|
||||
/// commits each key-value pair individually.
|
||||
/// The default implementation commits the object without any of the
|
||||
/// key-value pairs, then commits each key-value pair individually.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -103,8 +103,8 @@ pub trait JsonCommit {
|
||||
|
||||
/// Commits to a JSON key-value pair.
|
||||
///
|
||||
/// The default implementation commits the pair without the value, and then commits the value
|
||||
/// separately.
|
||||
/// The default implementation commits the pair without the value, and then
|
||||
/// commits the value separately.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -131,8 +131,8 @@ pub trait JsonCommit {
|
||||
|
||||
/// Commits to a JSON array.
|
||||
///
|
||||
/// The default implementation commits to the entire array, then commits the array
|
||||
/// excluding all values and separators.
|
||||
/// The default implementation commits to the entire array, then commits the
|
||||
/// array excluding all values and separators.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
//!
|
||||
//! # Warning
|
||||
//!
|
||||
//! This library is not yet ready for production use, and should *NOT* be considered secure.
|
||||
//! This library is not yet ready for production use, and should *NOT* be
|
||||
//! considered secure.
|
||||
//!
|
||||
//! At present, this library does not verify that redacted data does not contain control characters which can
|
||||
//! be used by a malicious prover to cheat.
|
||||
//! At present, this library does not verify that redacted data does not contain
|
||||
//! control characters which can be used by a malicious prover to cheat.
|
||||
|
||||
#![deny(missing_docs, unreachable_pub, unused_must_use)]
|
||||
#![deny(clippy::all)]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Notary client.
|
||||
//!
|
||||
//! This module sets up connection to notary server via TCP or TLS for subsequent requests for notarization.
|
||||
//! This module sets up connection to notary server via TCP or TLS for
|
||||
//! subsequent requests for notarization.
|
||||
|
||||
use http_body_util::{BodyExt as _, Either, Empty, Full};
|
||||
use hyper::{body::Bytes, client::conn::http1::Parts, Request, StatusCode};
|
||||
@@ -107,7 +108,8 @@ impl AsyncWrite for NotaryConnection {
|
||||
/// Client that sets up connection to notary server.
|
||||
#[derive(Debug, Clone, derive_builder::Builder)]
|
||||
pub struct NotaryClient {
|
||||
/// Host of the notary server endpoint, either a DNS name (if TLS is used) or IP address.
|
||||
/// Host of the notary server endpoint, either a DNS name (if TLS is used)
|
||||
/// or IP address.
|
||||
#[builder(setter(into))]
|
||||
host: String,
|
||||
/// Port of the notary server endpoint.
|
||||
@@ -116,10 +118,12 @@ pub struct NotaryClient {
|
||||
/// Flag to turn on/off using TLS with notary server.
|
||||
#[builder(setter(name = "enable_tls"), default = "true")]
|
||||
tls: bool,
|
||||
/// Root certificate store used for establishing TLS connection with notary server.
|
||||
/// Root certificate store used for establishing TLS connection with notary
|
||||
/// server.
|
||||
#[builder(default = "default_root_store()")]
|
||||
root_cert_store: RootCertStore,
|
||||
/// API key used to call notary server endpoints if whitelisting is enabled in notary server.
|
||||
/// API key used to call notary server endpoints if whitelisting is enabled
|
||||
/// in notary server.
|
||||
#[builder(setter(into, strip_option), default)]
|
||||
api_key: Option<String>,
|
||||
}
|
||||
@@ -127,8 +131,9 @@ pub struct NotaryClient {
|
||||
impl NotaryClientBuilder {
|
||||
// Default setter of port.
|
||||
fn default_port(&self) -> u16 {
|
||||
// If port is not specified, set it to 80 if TLS is off, else 443 since TLS is on
|
||||
// (including when self.tls = None, which means it's set to default (true)).
|
||||
// If port is not specified, set it to 80 if TLS is off, else 443 since TLS is
|
||||
// on (including when self.tls = None, which means it's set to default
|
||||
// (true)).
|
||||
if let Some(false) = self.tls {
|
||||
80
|
||||
} else {
|
||||
@@ -143,7 +148,8 @@ impl NotaryClient {
|
||||
NotaryClientBuilder::default()
|
||||
}
|
||||
|
||||
/// Configures and requests a notarization, returning a connection to the notary server if successful.
|
||||
/// Configures and requests a notarization, returning a connection to the
|
||||
/// notary server if successful.
|
||||
pub async fn request_notarization(
|
||||
&self,
|
||||
notarization_request: NotarizationRequest,
|
||||
@@ -202,7 +208,8 @@ impl NotaryClient {
|
||||
) -> Result<(S, String), ClientError> {
|
||||
let http_scheme = if self.tls { "https" } else { "http" };
|
||||
|
||||
// Attach the hyper HTTP client to the notary connection to send request to the /session endpoint to configure notarization and obtain session id.
|
||||
// Attach the hyper HTTP client to the notary connection to send request to the
|
||||
// /session endpoint to configure notarization and obtain session id.
|
||||
let (mut notary_request_sender, notary_connection) =
|
||||
hyper::client::conn::http1::handshake(TokioIo::new(notary_socket))
|
||||
.await
|
||||
@@ -211,7 +218,8 @@ impl NotaryClient {
|
||||
ClientError::new(ErrorKind::Connection, Some(Box::new(err)))
|
||||
})?;
|
||||
|
||||
// Create a future to poll the notary connection to completion before extracting the socket.
|
||||
// Create a future to poll the notary connection to completion before extracting
|
||||
// the socket.
|
||||
let notary_connection_fut = async {
|
||||
// Claim back notary socket after HTTP exchange is done.
|
||||
let Parts {
|
||||
@@ -224,7 +232,8 @@ impl NotaryClient {
|
||||
Ok(notary_socket)
|
||||
};
|
||||
|
||||
// Create a future to send configuration and notarization requests to the notary server using the connection established above.
|
||||
// Create a future to send configuration and notarization requests to the notary
|
||||
// server using the connection established above.
|
||||
let client_requests_fut = async {
|
||||
// Build the HTTP request to configure notarization.
|
||||
let configuration_request_payload =
|
||||
@@ -311,10 +320,12 @@ impl NotaryClient {
|
||||
configuration_response_payload_parsed
|
||||
);
|
||||
|
||||
// Send notarization request via HTTP, where the underlying TCP/TLS connection will be extracted later.
|
||||
// Send notarization request via HTTP, where the underlying TCP/TLS connection
|
||||
// will be extracted later.
|
||||
let notarization_request = Request::builder()
|
||||
// Need to specify the session_id so that notary server knows the right configuration to use
|
||||
// as the configuration is set in the previous HTTP call.
|
||||
// Need to specify the session_id so that notary server knows the right
|
||||
// configuration to use as the configuration is set in the previous
|
||||
// HTTP call.
|
||||
.uri(format!(
|
||||
"{http_scheme}://{}:{}/notarize?sessionId={}",
|
||||
self.host, self.port, &configuration_response_payload_parsed.session_id
|
||||
@@ -322,7 +333,8 @@ impl NotaryClient {
|
||||
.method("GET")
|
||||
.header("Host", &self.host)
|
||||
.header("Connection", "Upgrade")
|
||||
// Need to specify this upgrade header for server to extract TCP/TLS connection later.
|
||||
// Need to specify this upgrade header for server to extract TCP/TLS connection
|
||||
// later.
|
||||
.header("Upgrade", "TCP")
|
||||
.body(Either::Right(Empty::<Bytes>::new()))
|
||||
.map_err(|err| {
|
||||
@@ -358,7 +370,8 @@ impl NotaryClient {
|
||||
Ok(configuration_response_payload_parsed.session_id)
|
||||
};
|
||||
|
||||
// Poll both futures simultaneously to obtain the resulting socket and session_id.
|
||||
// Poll both futures simultaneously to obtain the resulting socket and
|
||||
// session_id.
|
||||
let (notary_socket, session_id) =
|
||||
futures::try_join!(notary_connection_fut, client_requests_fut)?;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Notary client errors.
|
||||
//!
|
||||
//! This module handles errors that might occur during connection setup and notarization requests.
|
||||
//! This module handles errors that might occur during connection setup and
|
||||
//! notarization requests.
|
||||
|
||||
use derive_builder::UninitializedFieldError;
|
||||
use std::{error::Error, fmt};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Notary client library.
|
||||
//!
|
||||
//! A notary client's purpose is to establish a connection to the notary server via TCP or TLS, and
|
||||
//! to configure and request notarization.
|
||||
//! Note that the actual notarization is not performed by the notary client but by the prover of the
|
||||
//! TLSNotary protocol.
|
||||
//! A notary client's purpose is to establish a connection to the notary server
|
||||
//! via TCP or TLS, and to configure and request notarization.
|
||||
//! Note that the actual notarization is not performed by the notary client but
|
||||
//! by the prover of the TLSNotary protocol.
|
||||
#![deny(missing_docs, unreachable_pub, unused_must_use)]
|
||||
#![deny(clippy::all)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
@@ -42,15 +42,18 @@ pub struct ServerProperties {
|
||||
pub name: String,
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
/// Static html response returned from API root endpoint "/". Default html response contains
|
||||
/// placeholder strings that will be replaced with actual values in server.rs, e.g. {version}, {public_key}
|
||||
/// Static html response returned from API root endpoint "/". Default html
|
||||
/// response contains placeholder strings that will be replaced with
|
||||
/// actual values in server.rs, e.g. {version}, {public_key}
|
||||
pub html_info: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct TLSProperties {
|
||||
/// Flag to turn on/off TLS between prover and notary (should always be turned on unless TLS is handled by external setup e.g. reverse proxy, cloud)
|
||||
/// Flag to turn on/off TLS between prover and notary (should always be
|
||||
/// turned on unless TLS is handled by external setup e.g. reverse proxy,
|
||||
/// cloud)
|
||||
pub enabled: bool,
|
||||
pub private_key_pem_path: String,
|
||||
pub certificate_pem_path: String,
|
||||
@@ -66,8 +69,8 @@ pub struct NotarySigningKeyProperties {
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct LoggingProperties {
|
||||
/// Log verbosity level of the default filtering logic, which is notary_server=<level>,tlsn_verifier=<level>,tls_mpc=<level>
|
||||
/// Must be either of <https://docs.rs/tracing/latest/tracing/struct.Level.html#implementations>
|
||||
/// Log verbosity level of the default filtering logic, which is
|
||||
/// notary_server=<level>,tlsn_verifier=<level>,tls_mpc=<level> Must be either of <https://docs.rs/tracing/latest/tracing/struct.Level.html#implementations>
|
||||
pub level: String,
|
||||
/// Custom filtering logic, refer to the syntax here https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax
|
||||
/// This will override the default filtering logic above
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Structure of each whitelisted record of the API key whitelist for authorization purpose
|
||||
/// Structure of each whitelisted record of the API key whitelist for
|
||||
/// authorization purpose
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct AuthorizationWhitelistRecord {
|
||||
@@ -10,7 +11,8 @@ pub struct AuthorizationWhitelistRecord {
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
/// Convert whitelist data structure from vector to hashmap using api_key as the key to speed up lookup
|
||||
/// Convert whitelist data structure from vector to hashmap using api_key as the
|
||||
/// key to speed up lookup
|
||||
pub fn authorization_whitelist_vec_into_hashmap(
|
||||
authorization_whitelist: Vec<AuthorizationWhitelistRecord>,
|
||||
) -> HashMap<String, AuthorizationWhitelistRecord> {
|
||||
|
||||
@@ -39,7 +39,8 @@ pub struct NotarizationRequestQuery {
|
||||
pub enum ClientType {
|
||||
/// Client that has access to the transport layer
|
||||
Tcp,
|
||||
/// Client that cannot directly access transport layer, e.g. browser extension
|
||||
/// Client that cannot directly access transport layer, e.g. browser
|
||||
/// extension
|
||||
Websocket,
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ use crate::{
|
||||
util::parse_csv_file,
|
||||
};
|
||||
|
||||
/// Start a TCP server (with or without TLS) to accept notarization request for both TCP and WebSocket clients
|
||||
/// Start a TCP server (with or without TLS) to accept notarization request for
|
||||
/// both TCP and WebSocket clients
|
||||
#[tracing::instrument(skip(config))]
|
||||
pub async fn run_server(config: &NotaryServerProperties) -> Result<(), NotaryServerError> {
|
||||
// Load the private key for notarized transcript signing
|
||||
@@ -161,7 +162,8 @@ pub async fn run_server(config: &NotaryServerProperties) -> Result<(), NotarySer
|
||||
.with_state(notary_globals);
|
||||
|
||||
loop {
|
||||
// Poll and await for any incoming connection, ensure that all operations inside are infallible to prevent bringing down the server
|
||||
// Poll and await for any incoming connection, ensure that all operations inside
|
||||
// are infallible to prevent bringing down the server
|
||||
let stream = match poll_fn(|cx| Pin::new(&mut listener).poll_accept(cx)).await {
|
||||
Ok((stream, _)) => stream,
|
||||
Err(err) => {
|
||||
@@ -191,8 +193,9 @@ pub async fn run_server(config: &NotaryServerProperties) -> Result<(), NotarySer
|
||||
// Serve different requests using the same hyper protocol and axum router
|
||||
let _ = protocol
|
||||
.serve_connection(io, hyper_service)
|
||||
// use with_upgrades to upgrade connection to websocket for websocket clients
|
||||
// and to extract tcp connection for tcp clients
|
||||
// use with_upgrades to upgrade connection to websocket for websocket
|
||||
// clients and to extract tcp connection for
|
||||
// tcp clients
|
||||
.with_upgrades()
|
||||
.await;
|
||||
}
|
||||
@@ -300,7 +303,8 @@ fn load_authorization_whitelist(
|
||||
|
||||
// Setup a watcher to detect any changes to authorization whitelist
|
||||
// When the list file is modified, the watcher thread will reload the whitelist
|
||||
// The watcher is setup in a separate thread by the notify library which is synchronous
|
||||
// The watcher is setup in a separate thread by the notify library which is
|
||||
// synchronous
|
||||
fn watch_and_reload_authorization_whitelist(
|
||||
config: NotaryServerProperties,
|
||||
authorization_whitelist: Option<Arc<Mutex<HashMap<String, AuthorizationWhitelistRecord>>>>,
|
||||
@@ -308,7 +312,8 @@ fn watch_and_reload_authorization_whitelist(
|
||||
// Only setup the watcher if auth whitelist is loaded
|
||||
let watcher = if let Some(authorization_whitelist) = authorization_whitelist {
|
||||
let cloned_config = config.clone();
|
||||
// Setup watcher by giving it a function that will be triggered when an event is detected
|
||||
// Setup watcher by giving it a function that will be triggered when an event is
|
||||
// detected
|
||||
let mut watcher = RecommendedWatcher::new(
|
||||
move |event: Result<Event, Error>| {
|
||||
match event {
|
||||
@@ -351,7 +356,8 @@ fn watch_and_reload_authorization_whitelist(
|
||||
// Skip setup the watcher if auth whitelist is not loaded
|
||||
None
|
||||
};
|
||||
// Need to return the watcher to parent function, else it will be dropped and stop listening
|
||||
// Need to return the watcher to parent function, else it will be dropped and
|
||||
// stop listening
|
||||
Ok(watcher)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,9 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
/// A wrapper enum to facilitate extracting TCP connection for either WebSocket or TCP clients,
|
||||
/// so that we can use a single endpoint and handler for notarization for both types of clients
|
||||
/// A wrapper enum to facilitate extracting TCP connection for either WebSocket
|
||||
/// or TCP clients, so that we can use a single endpoint and handler for
|
||||
/// notarization for both types of clients
|
||||
pub enum ProtocolUpgrade {
|
||||
Tcp(TcpUpgrade),
|
||||
Ws(WebSocketUpgrade),
|
||||
@@ -67,9 +68,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler to upgrade protocol from http to either websocket or underlying tcp depending on the type of client
|
||||
/// the session_id parameter is also extracted here to fetch the configuration parameters
|
||||
/// that have been submitted in the previous request to /session made by the same client
|
||||
/// Handler to upgrade protocol from http to either websocket or underlying tcp
|
||||
/// depending on the type of client the session_id parameter is also extracted
|
||||
/// here to fetch the configuration parameters that have been submitted in the
|
||||
/// previous request to /session made by the same client
|
||||
pub async fn upgrade_protocol(
|
||||
protocol_upgrade: ProtocolUpgrade,
|
||||
State(notary_globals): State<NotaryGlobals>,
|
||||
@@ -77,7 +79,8 @@ pub async fn upgrade_protocol(
|
||||
) -> Response {
|
||||
info!("Received upgrade protocol request");
|
||||
let session_id = params.session_id;
|
||||
// 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
|
||||
// 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()
|
||||
@@ -89,7 +92,8 @@ pub async fn upgrade_protocol(
|
||||
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
|
||||
// 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))
|
||||
@@ -100,7 +104,8 @@ pub async fn upgrade_protocol(
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler to initialize and configure notarization for both TCP and WebSocket clients
|
||||
/// Handler to initialize and configure notarization for both TCP and WebSocket
|
||||
/// clients
|
||||
#[debug_handler(state = NotaryGlobals)]
|
||||
pub async fn initialize(
|
||||
State(notary_globals): State<NotaryGlobals>,
|
||||
@@ -120,7 +125,8 @@ pub async fn initialize(
|
||||
}
|
||||
};
|
||||
|
||||
// Ensure that the max_sent_data, max_recv_data submitted is not larger than the global max limits 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() {
|
||||
if payload.max_sent_data.unwrap_or_default()
|
||||
> notary_globals.notarization_config.max_sent_data
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
//! where we swapped out tokio_tungstenite (https://docs.rs/tokio-tungstenite/latest/tokio_tungstenite/)
|
||||
//! with async_tungstenite (https://docs.rs/async-tungstenite/latest/async_tungstenite/) so that we can use
|
||||
//! ws_stream_tungstenite (https://docs.rs/ws_stream_tungstenite/latest/ws_stream_tungstenite/index.html)
|
||||
//! to get AsyncRead and AsyncWrite implemented for the WebSocket. Any other modification is commented with the prefix "NOTARY_MODIFICATION:"
|
||||
//! to get AsyncRead and AsyncWrite implemented for the WebSocket. Any other
|
||||
//! modification is commented with the prefix "NOTARY_MODIFICATION:"
|
||||
//!
|
||||
//! The code is under the following license:
|
||||
//!
|
||||
@@ -160,14 +161,15 @@ use tracing::error;
|
||||
/// Extractor for establishing WebSocket connections.
|
||||
///
|
||||
/// Note: This extractor requires the request method to be `GET` so it should
|
||||
/// always be used with [`get`](crate::routing::get). Requests with other methods will be
|
||||
/// rejected.
|
||||
/// always be used with [`get`](crate::routing::get). Requests with other
|
||||
/// methods will be rejected.
|
||||
///
|
||||
/// See the [module docs](self) for an example.
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "ws")))]
|
||||
pub struct WebSocketUpgrade<F = DefaultOnFailedUpgrade> {
|
||||
config: WebSocketConfig,
|
||||
/// The chosen protocol sent in the `Sec-WebSocket-Protocol` header of the response.
|
||||
/// The chosen protocol sent in the `Sec-WebSocket-Protocol` header of the
|
||||
/// response.
|
||||
protocol: Option<HeaderValue>,
|
||||
sec_websocket_key: HeaderValue,
|
||||
on_upgrade: hyper::upgrade::OnUpgrade,
|
||||
@@ -187,31 +189,36 @@ impl<F> std::fmt::Debug for WebSocketUpgrade<F> {
|
||||
}
|
||||
|
||||
impl<F> WebSocketUpgrade<F> {
|
||||
/// The target minimum size of the write buffer to reach before writing the data
|
||||
/// to the underlying stream.
|
||||
/// The target minimum size of the write buffer to reach before writing the
|
||||
/// data to the underlying stream.
|
||||
///
|
||||
/// The default value is 128 KiB.
|
||||
///
|
||||
/// If set to `0` each message will be eagerly written to the underlying stream.
|
||||
/// It is often more optimal to allow them to buffer a little, hence the default value.
|
||||
/// If set to `0` each message will be eagerly written to the underlying
|
||||
/// stream. It is often more optimal to allow them to buffer a little,
|
||||
/// hence the default value.
|
||||
///
|
||||
/// Note: [`flush`](SinkExt::flush) will always fully write the buffer regardless.
|
||||
/// Note: [`flush`](SinkExt::flush) will always fully write the buffer
|
||||
/// regardless.
|
||||
pub fn write_buffer_size(mut self, size: usize) -> Self {
|
||||
self.config.write_buffer_size = size;
|
||||
self
|
||||
}
|
||||
|
||||
/// The max size of the write buffer in bytes. Setting this can provide backpressure
|
||||
/// in the case the write buffer is filling up due to write errors.
|
||||
/// The max size of the write buffer in bytes. Setting this can provide
|
||||
/// backpressure in the case the write buffer is filling up due to write
|
||||
/// errors.
|
||||
///
|
||||
/// The default value is unlimited.
|
||||
///
|
||||
/// Note: The write buffer only builds up past [`write_buffer_size`](Self::write_buffer_size)
|
||||
/// when writes to the underlying stream are failing. So the **write buffer can not
|
||||
/// fill up if you are not observing write errors even if not flushing**.
|
||||
/// Note: The write buffer only builds up past
|
||||
/// [`write_buffer_size`](Self::write_buffer_size) when writes to the
|
||||
/// underlying stream are failing. So the **write buffer can not fill up
|
||||
/// if you are not observing write errors even if not flushing**.
|
||||
///
|
||||
/// Note: Should always be at least [`write_buffer_size + 1 message`](Self::write_buffer_size)
|
||||
/// and probably a little more depending on error handling strategy.
|
||||
/// Note: Should always be at least [`write_buffer_size + 1
|
||||
/// message`](Self::write_buffer_size) and probably a little more
|
||||
/// depending on error handling strategy.
|
||||
pub fn max_write_buffer_size(mut self, max: usize) -> Self {
|
||||
self.config.max_write_buffer_size = max;
|
||||
self
|
||||
@@ -238,12 +245,12 @@ impl<F> WebSocketUpgrade<F> {
|
||||
/// Set the known protocols.
|
||||
///
|
||||
/// If the protocol name specified by `Sec-WebSocket-Protocol` header
|
||||
/// to match any of them, the upgrade response will include `Sec-WebSocket-Protocol` header and
|
||||
/// return the protocol name.
|
||||
/// to match any of them, the upgrade response will include
|
||||
/// `Sec-WebSocket-Protocol` header and return the protocol name.
|
||||
///
|
||||
/// The protocols should be listed in decreasing order of preference: if the client offers
|
||||
/// multiple protocols that the server could support, the server will pick the first one in
|
||||
/// this list.
|
||||
/// The protocols should be listed in decreasing order of preference: if the
|
||||
/// client offers multiple protocols that the server could support, the
|
||||
/// server will pick the first one in this list.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -296,8 +303,8 @@ impl<F> WebSocketUpgrade<F> {
|
||||
|
||||
/// Provide a callback to call if upgrading the connection fails.
|
||||
///
|
||||
/// The connection upgrade is performed in a background task. If that fails this callback
|
||||
/// will be called.
|
||||
/// The connection upgrade is performed in a background task. If that fails
|
||||
/// this callback will be called.
|
||||
///
|
||||
/// By default any errors will be silently ignored.
|
||||
///
|
||||
@@ -359,7 +366,8 @@ impl<F> WebSocketUpgrade<F> {
|
||||
let upgraded = TokioIo::new(upgraded);
|
||||
|
||||
let socket = WebSocketStream::from_raw_socket(
|
||||
// NOTARY_MODIFICATION: Need to use TokioAdapter to wrap Upgraded which doesn't implement futures crate's AsyncRead and AsyncWrite
|
||||
// NOTARY_MODIFICATION: Need to use TokioAdapter to wrap Upgraded which doesn't
|
||||
// implement futures crate's AsyncRead and AsyncWrite
|
||||
TokioAdapter::new(upgraded),
|
||||
protocol::Role::Server,
|
||||
Some(config),
|
||||
@@ -504,7 +512,8 @@ pub struct WebSocket {
|
||||
}
|
||||
|
||||
impl WebSocket {
|
||||
/// NOTARY_MODIFICATION: Consume `self` and get the inner [`async_tungstenite::WebSocketStream`].
|
||||
/// NOTARY_MODIFICATION: Consume `self` and get the inner
|
||||
/// [`async_tungstenite::WebSocketStream`].
|
||||
pub fn into_inner(self) -> WebSocketStream<TokioAdapter<TokioIo<hyper::upgrade::Upgraded>>> {
|
||||
self.inner
|
||||
}
|
||||
@@ -575,7 +584,8 @@ impl Sink<Message> for WebSocket {
|
||||
}
|
||||
}
|
||||
|
||||
/// Status code used to indicate why an endpoint is closing the WebSocket connection.
|
||||
/// Status code used to indicate why an endpoint is closing the WebSocket
|
||||
/// connection.
|
||||
pub type CloseCode = u16;
|
||||
|
||||
/// A struct representing the close command.
|
||||
@@ -620,16 +630,16 @@ pub enum Message {
|
||||
///
|
||||
/// The payload here must have a length less than 125 bytes.
|
||||
///
|
||||
/// Ping messages will be automatically responded to by the server, so you do not have to worry
|
||||
/// about dealing with them yourself.
|
||||
/// Ping messages will be automatically responded to by the server, so you
|
||||
/// do not have to worry about dealing with them yourself.
|
||||
Ping(Vec<u8>),
|
||||
/// A pong message with the specified payload
|
||||
///
|
||||
/// The payload here must have a length less than 125 bytes.
|
||||
///
|
||||
/// Pong messages will be automatically sent to the client if a ping message is received, so
|
||||
/// you do not have to worry about constructing them yourself unless you want to implement a
|
||||
/// [unidirectional heartbeat](https://tools.ietf.org/html/rfc6455#section-5.5.3).
|
||||
/// Pong messages will be automatically sent to the client if a ping message
|
||||
/// is received, so you do not have to worry about constructing them
|
||||
/// yourself unless you want to implement a [unidirectional heartbeat](https://tools.ietf.org/html/rfc6455#section-5.5.3).
|
||||
Pong(Vec<u8>),
|
||||
/// A close message with the optional close frame.
|
||||
Close(Option<CloseFrame<'static>>),
|
||||
@@ -820,20 +830,22 @@ pub mod close_code {
|
||||
//!
|
||||
//! [`CloseCode`]: super::CloseCode
|
||||
|
||||
/// Indicates a normal closure, meaning that the purpose for which the connection was
|
||||
/// established has been fulfilled.
|
||||
/// Indicates a normal closure, meaning that the purpose for which the
|
||||
/// connection was established has been fulfilled.
|
||||
pub const NORMAL: u16 = 1000;
|
||||
|
||||
/// Indicates that an endpoint is "going away", such as a server going down or a browser having
|
||||
/// navigated away from a page.
|
||||
/// Indicates that an endpoint is "going away", such as a server going down
|
||||
/// or a browser having navigated away from a page.
|
||||
pub const AWAY: u16 = 1001;
|
||||
|
||||
/// Indicates that an endpoint is terminating the connection due to a protocol error.
|
||||
/// Indicates that an endpoint is terminating the connection due to a
|
||||
/// protocol error.
|
||||
pub const PROTOCOL: u16 = 1002;
|
||||
|
||||
/// Indicates that an endpoint is terminating the connection because it has received a type of
|
||||
/// data it cannot accept (e.g., an endpoint that understands only text data MAY send this if
|
||||
/// it receives a binary message).
|
||||
/// Indicates that an endpoint is terminating the connection because it has
|
||||
/// received a type of data it cannot accept (e.g., an endpoint that
|
||||
/// understands only text data MAY send this if it receives a binary
|
||||
/// message).
|
||||
pub const UNSUPPORTED: u16 = 1003;
|
||||
|
||||
/// Indicates that no status code was included in a closing frame.
|
||||
@@ -842,38 +854,42 @@ pub mod close_code {
|
||||
/// Indicates an abnormal closure.
|
||||
pub const ABNORMAL: u16 = 1006;
|
||||
|
||||
/// Indicates that an endpoint is terminating the connection because it has received data
|
||||
/// within a message that was not consistent with the type of the message (e.g., non-UTF-8
|
||||
/// RFC3629 data within a text message).
|
||||
/// Indicates that an endpoint is terminating the connection because it has
|
||||
/// received data within a message that was not consistent with the type
|
||||
/// of the message (e.g., non-UTF-8 RFC3629 data within a text message).
|
||||
pub const INVALID: u16 = 1007;
|
||||
|
||||
/// Indicates that an endpoint is terminating the connection because it has received a message
|
||||
/// that violates its policy. This is a generic status code that can be returned when there is
|
||||
/// no other more suitable status code (e.g., `UNSUPPORTED` or `SIZE`) or if there is a need to
|
||||
/// hide specific details about the policy.
|
||||
/// Indicates that an endpoint is terminating the connection because it has
|
||||
/// received a message that violates its policy. This is a generic
|
||||
/// status code that can be returned when there is no other more
|
||||
/// suitable status code (e.g., `UNSUPPORTED` or `SIZE`) or if there is a
|
||||
/// need to hide specific details about the policy.
|
||||
pub const POLICY: u16 = 1008;
|
||||
|
||||
/// Indicates that an endpoint is terminating the connection because it has received a message
|
||||
/// that is too big for it to process.
|
||||
/// Indicates that an endpoint is terminating the connection because it has
|
||||
/// received a message that is too big for it to process.
|
||||
pub const SIZE: u16 = 1009;
|
||||
|
||||
/// Indicates that an endpoint (client) is terminating the connection because it has expected
|
||||
/// the server to negotiate one or more extension, but the server didn't return them in the
|
||||
/// response message of the WebSocket handshake. The list of extensions that are needed should
|
||||
/// be given as the reason for closing. Note that this status code is not used by the server,
|
||||
/// because it can fail the WebSocket handshake instead.
|
||||
/// Indicates that an endpoint (client) is terminating the connection
|
||||
/// because it has expected the server to negotiate one or more
|
||||
/// extension, but the server didn't return them in the response message
|
||||
/// of the WebSocket handshake. The list of extensions that are needed
|
||||
/// should be given as the reason for closing. Note that this status
|
||||
/// code is not used by the server, because it can fail the WebSocket
|
||||
/// handshake instead.
|
||||
pub const EXTENSION: u16 = 1010;
|
||||
|
||||
/// Indicates that a server is terminating the connection because it encountered an unexpected
|
||||
/// condition that prevented it from fulfilling the request.
|
||||
/// Indicates that a server is terminating the connection because it
|
||||
/// encountered an unexpected condition that prevented it from
|
||||
/// fulfilling the request.
|
||||
pub const ERROR: u16 = 1011;
|
||||
|
||||
/// Indicates that the server is restarting.
|
||||
pub const RESTART: u16 = 1012;
|
||||
|
||||
/// Indicates that the server is overloaded and the client should either connect to a different
|
||||
/// IP (when multiple targets exist), or reconnect to the same IP when a user has performed an
|
||||
/// action.
|
||||
/// Indicates that the server is overloaded and the client should either
|
||||
/// connect to a different IP (when multiple targets exist), or
|
||||
/// reconnect to the same IP when a user has performed an action.
|
||||
pub const AGAIN: u16 = 1013;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@ use tracing::{debug, error, info};
|
||||
|
||||
use crate::{domain::notary::NotaryGlobals, service::notary_service, NotaryServerError};
|
||||
|
||||
/// Custom extractor used to extract underlying TCP connection for TCP client — using the same upgrade primitives used by
|
||||
/// the WebSocket implementation where the underlying TCP connection (wrapped in an Upgraded object) only gets polled as an OnUpgrade future
|
||||
/// after the ongoing HTTP request is finished (ref: https://github.com/tokio-rs/axum/blob/a6a849bb5b96a2f641fa077fe76f70ad4d20341c/axum/src/extract/ws.rs#L122)
|
||||
/// Custom extractor used to extract underlying TCP connection for TCP client —
|
||||
/// using the same upgrade primitives used by the WebSocket implementation where
|
||||
/// the underlying TCP connection (wrapped in an Upgraded object) only gets
|
||||
/// polled as an OnUpgrade future after the ongoing HTTP request is finished (ref: https://github.com/tokio-rs/axum/blob/a6a849bb5b96a2f641fa077fe76f70ad4d20341c/axum/src/extract/ws.rs#L122)
|
||||
///
|
||||
/// More info on the upgrade primitives: https://docs.rs/hyper/latest/hyper/upgrade/index.html
|
||||
pub struct TcpUpgrade {
|
||||
@@ -43,8 +44,9 @@ where
|
||||
|
||||
impl TcpUpgrade {
|
||||
/// Utility function to complete the http upgrade protocol by
|
||||
/// (1) Return 101 switching protocol response to client to indicate the switching to TCP
|
||||
/// (2) Spawn a new thread to await on the OnUpgrade object to claim the underlying TCP connection
|
||||
/// (1) Return 101 switching protocol response to client to indicate the
|
||||
/// switching to TCP (2) Spawn a new thread to await on the OnUpgrade
|
||||
/// object to claim the underlying TCP connection
|
||||
pub fn on_upgrade<C, Fut>(self, callback: C) -> Response
|
||||
where
|
||||
C: FnOnce(TokioIo<Upgraded>) -> Fut + Send + 'static,
|
||||
|
||||
@@ -13,7 +13,8 @@ pub async fn websocket_notarize(
|
||||
session_id: String,
|
||||
) {
|
||||
debug!(?session_id, "Upgraded to websocket connection");
|
||||
// Wrap the websocket in WsStream so that we have AsyncRead and AsyncWrite implemented
|
||||
// Wrap the websocket in WsStream so that we have AsyncRead and AsyncWrite
|
||||
// implemented
|
||||
let stream = WsStream::new(socket.into_inner());
|
||||
match notary_service(
|
||||
stream,
|
||||
|
||||
@@ -157,8 +157,8 @@ async fn tls_prover(notary_config: NotaryServerProperties) -> (NotaryConnection,
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
// For `tls_without_auth` test to pass, one needs to add "<NOTARY_HOST> <NOTARY_DNS>" in /etc/hosts so that
|
||||
// this test programme can resolve the self-named NOTARY_DNS to NOTARY_HOST IP successfully.
|
||||
// For `tls_without_auth` test to pass, one needs to add "<NOTARY_HOST> <NOTARY_DNS>" in /etc/hosts
|
||||
// so that this test programme can resolve the self-named NOTARY_DNS to NOTARY_HOST IP successfully.
|
||||
#[case::tls_without_auth(
|
||||
tls_prover(setup_config_and_server(100, 7047, true, false).await)
|
||||
)]
|
||||
@@ -194,7 +194,8 @@ async fn test_tcp_prover<S: AsyncWrite + AsyncRead + Send + Unpin + 'static>(
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Prover config using the session_id returned from calling /session endpoint in notary client.
|
||||
// Prover config using the session_id returned from calling /session endpoint in
|
||||
// notary client.
|
||||
let prover_config = ProverConfig::builder()
|
||||
.server_name(SERVER_DOMAIN)
|
||||
.protocol_config(protocol_config)
|
||||
@@ -279,7 +280,8 @@ async fn test_websocket_prover() {
|
||||
let notary_port = notary_config.server.port;
|
||||
|
||||
// Connect to the notary server via TLS-WebSocket
|
||||
// Try to avoid dealing with transport layer directly to mimic the limitation of a browser extension that uses websocket
|
||||
// Try to avoid dealing with transport layer directly to mimic the limitation of
|
||||
// a browser extension that uses websocket
|
||||
//
|
||||
// Establish TLS setup for connections later
|
||||
let certificate =
|
||||
@@ -336,10 +338,12 @@ async fn test_websocket_prover() {
|
||||
|
||||
// Connect to the Notary via TLS-Websocket
|
||||
//
|
||||
// Note: This will establish a new TLS-TCP connection instead of reusing the previous TCP connection
|
||||
// used in the previous HTTP POST request because we cannot claim back the tcp connection used in hyper
|
||||
// client while using its high level request function — there does not seem to have a crate that can let you
|
||||
// make a request without establishing TCP connection where you can claim the TCP connection later after making the request
|
||||
// Note: This will establish a new TLS-TCP connection instead of reusing the
|
||||
// previous TCP connection used in the previous HTTP POST request because we
|
||||
// cannot claim back the tcp connection used in hyper client while using its
|
||||
// high level request function — there does not seem to have a crate that can
|
||||
// let you make a request without establishing TCP connection where you can
|
||||
// claim the TCP connection later after making the request
|
||||
let request = http::Request::builder()
|
||||
// Need to specify the session_id so that notary server knows the right configuration to use
|
||||
// as the configuration is set in the previous HTTP call
|
||||
@@ -365,7 +369,8 @@ async fn test_websocket_prover() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Wrap the socket with the adapter so that we get AsyncRead and AsyncWrite implemented
|
||||
// Wrap the socket with the adapter so that we get AsyncRead and AsyncWrite
|
||||
// implemented
|
||||
let notary_ws_socket = WsStream::new(notary_ws_stream);
|
||||
|
||||
// Connect to the Server
|
||||
|
||||
@@ -13,8 +13,8 @@ pub struct ProverConfig {
|
||||
server_name: ServerName,
|
||||
/// Protocol configuration to be checked with the verifier.
|
||||
protocol_config: ProtocolConfig,
|
||||
/// Whether the `deferred decryption` feature is toggled on from the start of the MPC-TLS
|
||||
/// connection.
|
||||
/// Whether the `deferred decryption` feature is toggled on from the start
|
||||
/// of the MPC-TLS connection.
|
||||
///
|
||||
/// See `defer_decryption_from_start` in [tls_mpc::MpcTlsLeaderConfig].
|
||||
#[builder(default = "true")]
|
||||
@@ -45,8 +45,8 @@ impl ProverConfig {
|
||||
&self.protocol_config
|
||||
}
|
||||
|
||||
/// Returns whether the `deferred decryption` feature is toggled on from the start of the MPC-TLS
|
||||
/// connection.
|
||||
/// Returns whether the `deferred decryption` feature is toggled on from the
|
||||
/// start of the MPC-TLS connection.
|
||||
pub fn defer_decryption_from_start(&self) -> bool {
|
||||
self.defer_decryption_from_start
|
||||
}
|
||||
|
||||
@@ -117,8 +117,8 @@ impl Prover<state::Initialized> {
|
||||
impl Prover<state::Setup> {
|
||||
/// Connects to the server using the provided socket.
|
||||
///
|
||||
/// Returns a handle to the TLS connection, a future which returns the prover once the connection is
|
||||
/// closed.
|
||||
/// Returns a handle to the TLS connection, a future which returns the
|
||||
/// prover once the connection is closed.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -255,8 +255,9 @@ impl Prover<state::Closed> {
|
||||
|
||||
/// Starts notarization of the TLS session.
|
||||
///
|
||||
/// Used when the TLS verifier is a Notary to transition the prover to the next state
|
||||
/// where it can generate commitments to the transcript prior to finalization.
|
||||
/// Used when the TLS verifier is a Notary to transition the prover to the
|
||||
/// next state where it can generate commitments to the transcript prior
|
||||
/// to finalization.
|
||||
pub fn start_notarize(self) -> Prover<Notarize> {
|
||||
Prover {
|
||||
config: self.config,
|
||||
@@ -267,8 +268,8 @@ impl Prover<state::Closed> {
|
||||
|
||||
/// Starts proving the TLS session.
|
||||
///
|
||||
/// This function transitions the prover into a state where it can prove content of the
|
||||
/// transcript.
|
||||
/// This function transitions the prover into a state where it can prove
|
||||
/// content of the transcript.
|
||||
pub fn start_prove(self) -> Prover<Prove> {
|
||||
Prover {
|
||||
config: self.config,
|
||||
@@ -404,15 +405,17 @@ pub struct ProverControl {
|
||||
}
|
||||
|
||||
impl ProverControl {
|
||||
/// Defers decryption of data from the server until the server has closed the connection.
|
||||
/// Defers decryption of data from the server until the server has closed
|
||||
/// the connection.
|
||||
///
|
||||
/// This is a performance optimization which will significantly reduce the amount of upload bandwidth
|
||||
/// used by the prover.
|
||||
/// This is a performance optimization which will significantly reduce the
|
||||
/// amount of upload bandwidth used by the prover.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// * The prover may need to close the connection to the server in order for it to close the connection
|
||||
/// on its end. If neither the prover or server close the connection this will cause a deadlock.
|
||||
/// * The prover may need to close the connection to the server in order for
|
||||
/// it to close the connection on its end. If neither the prover or server
|
||||
/// close the connection this will cause a deadlock.
|
||||
pub async fn defer_decryption(&self) -> Result<(), ProverError> {
|
||||
self.mpc_ctrl
|
||||
.defer_decryption()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! This module handles the proving phase of the prover.
|
||||
//!
|
||||
//! Here the prover deals with a verifier directly, so there is no notary involved. Instead
|
||||
//! the verifier directly verifies parts of the transcript.
|
||||
//! Here the prover deals with a verifier directly, so there is no notary
|
||||
//! involved. Instead the verifier directly verifies parts of the transcript.
|
||||
|
||||
use super::{state::Prove as ProveState, Prover, ProverError};
|
||||
use mpz_garble::{Memory, Prove};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! This library provides the [Backend] trait to encapsulate the cryptography backend of the TLS
|
||||
//! client.
|
||||
//! This library provides the [Backend] trait to encapsulate the cryptography
|
||||
//! backend of the TLS client.
|
||||
|
||||
#![deny(missing_docs, unreachable_pub, unused_must_use)]
|
||||
#![deny(clippy::all)]
|
||||
@@ -66,8 +66,8 @@ pub enum DecryptMode {
|
||||
Application,
|
||||
}
|
||||
|
||||
/// Core trait which manages crypto operations for the TLS connection such as key exchange, encryption
|
||||
/// and decryption.
|
||||
/// Core trait which manages crypto operations for the TLS connection such as
|
||||
/// key exchange, encryption and decryption.
|
||||
#[async_trait]
|
||||
pub trait Backend: Send {
|
||||
/// Signals selected protocol version to implementor.
|
||||
@@ -120,8 +120,8 @@ pub trait Backend: Send {
|
||||
async fn buffer_incoming(&mut self, msg: OpaqueMessage) -> Result<(), BackendError>;
|
||||
/// Returns next incoming message ready for decryption.
|
||||
async fn next_incoming(&mut self) -> Result<Option<OpaqueMessage>, BackendError>;
|
||||
/// Returns a notification future which resolves when the backend is ready to process
|
||||
/// the next message.
|
||||
/// Returns a notification future which resolves when the backend is ready
|
||||
/// to process the next message.
|
||||
async fn get_notify(&mut self) -> Result<BackendNotify, BackendError> {
|
||||
Ok(BackendNotify::dummy())
|
||||
}
|
||||
|
||||
@@ -19,13 +19,15 @@ type CompatSinkWriter =
|
||||
|
||||
/// A TLS connection to a server.
|
||||
///
|
||||
/// This type implements `AsyncRead` and `AsyncWrite` and can be used to communicate
|
||||
/// with a server using TLS.
|
||||
/// This type implements `AsyncRead` and `AsyncWrite` and can be used to
|
||||
/// communicate with a server using TLS.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This connection is closed on a best-effort basis if this is dropped. To ensure a clean close, you should call
|
||||
/// [`AsyncWriteExt::close`](futures::io::AsyncWriteExt::close) to close the connection.
|
||||
/// This connection is closed on a best-effort basis if this is dropped. To
|
||||
/// ensure a clean close, you should call
|
||||
/// [`AsyncWriteExt::close`](futures::io::AsyncWriteExt::close) to close the
|
||||
/// connection.
|
||||
#[derive(Debug)]
|
||||
pub struct TlsConnection {
|
||||
/// The data to be transmitted to the server is sent to this sink.
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
//! Provides a TLS client which exposes an async socket.
|
||||
//!
|
||||
//! This library provides the [bind_client] function which attaches a TLS client to a socket
|
||||
//! connection and then exposes a [TlsConnection] object, which provides an async socket API for
|
||||
//! reading and writing cleartext. The TLS client will then automatically encrypt and decrypt
|
||||
//! traffic and forward that to the provided socket.
|
||||
//! This library provides the [bind_client] function which attaches a TLS client
|
||||
//! to a socket connection and then exposes a [TlsConnection] object, which
|
||||
//! provides an async socket API for reading and writing cleartext. The TLS
|
||||
//! client will then automatically encrypt and decrypt traffic and forward that
|
||||
//! to the provided socket.
|
||||
|
||||
#![deny(missing_docs, unreachable_pub, unused_must_use)]
|
||||
#![deny(clippy::all)]
|
||||
@@ -71,11 +72,13 @@ impl Future for ConnectionFuture {
|
||||
|
||||
/// Binds a client connection to the provided socket.
|
||||
///
|
||||
/// Returns a connection handle and a future which runs the connection to completion.
|
||||
/// Returns a connection handle and a future which runs the connection to
|
||||
/// completion.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Any connection errors that occur will be returned from the future, not [`TlsConnection`].
|
||||
/// Any connection errors that occur will be returned from the future, not
|
||||
/// [`TlsConnection`].
|
||||
pub fn bind_client<T: AsyncRead + AsyncWrite + Send + Unpin + 'static>(
|
||||
socket: T,
|
||||
mut client: ClientConnection,
|
||||
@@ -138,7 +141,8 @@ pub fn bind_client<T: AsyncRead + AsyncWrite + Send + Unpin + 'static>(
|
||||
#[cfg(feature = "tracing")]
|
||||
debug!("handshake complete");
|
||||
handshake_done = true;
|
||||
// Start reading application data that needs to be transmitted from the `TlsConnection`.
|
||||
// Start reading application data that needs to be transmitted from the
|
||||
// `TlsConnection`.
|
||||
tx_recv_fut = tx_receiver.next().fuse();
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ async fn set_up_tls() -> TlsFixture {
|
||||
}
|
||||
}
|
||||
|
||||
// Expect the async tls client wrapped in `hyper::client` to make a successful request and receive
|
||||
// the expected response
|
||||
// Expect the async tls client wrapped in `hyper::client` to make a successful
|
||||
// request and receive the expected response
|
||||
#[tokio::test]
|
||||
async fn test_hyper_ok() {
|
||||
let (client_socket, server_socket) = tokio::io::duplex(1 << 16);
|
||||
@@ -120,8 +120,8 @@ async fn test_hyper_ok() {
|
||||
assert!(closed_conn.client.received_close_notify());
|
||||
}
|
||||
|
||||
// Expect a clean TLS connection closure when server responds to the client's close_notify but
|
||||
// doesn't close the socket
|
||||
// Expect a clean TLS connection closure when server responds to the client's
|
||||
// close_notify but doesn't close the socket
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_ok_server_no_socket_close(set_up_tls: impl Future<Output = TlsFixture>) {
|
||||
@@ -145,8 +145,8 @@ async fn test_ok_server_no_socket_close(set_up_tls: impl Future<Output = TlsFixt
|
||||
assert!(closed_conn.client.received_close_notify());
|
||||
}
|
||||
|
||||
// Expect a clean TLS connection closure when server responds to the client's close_notify AND
|
||||
// also closes the socket
|
||||
// Expect a clean TLS connection closure when server responds to the client's
|
||||
// close_notify AND also closes the socket
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_ok_server_socket_close(set_up_tls: impl Future<Output = TlsFixture>) {
|
||||
@@ -155,7 +155,8 @@ async fn test_ok_server_socket_close(set_up_tls: impl Future<Output = TlsFixture
|
||||
closed_tls_task,
|
||||
} = set_up_tls.await;
|
||||
|
||||
// instruct the server to send close_notify back to us AND close the socket after 10 ms
|
||||
// instruct the server to send close_notify back to us AND close the socket
|
||||
// after 10 ms
|
||||
client_tls_conn
|
||||
.write_all(&pad("send_close_notify_and_close_socket".to_string()))
|
||||
.await
|
||||
@@ -170,8 +171,8 @@ async fn test_ok_server_socket_close(set_up_tls: impl Future<Output = TlsFixture
|
||||
assert!(closed_conn.client.received_close_notify());
|
||||
}
|
||||
|
||||
// Expect a clean TLS connection closure when server sends close_notify first but doesn't close
|
||||
// the socket
|
||||
// Expect a clean TLS connection closure when server sends close_notify first
|
||||
// but doesn't close the socket
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_ok_server_close_notify(set_up_tls: impl Future<Output = TlsFixture>) {
|
||||
@@ -197,8 +198,8 @@ async fn test_ok_server_close_notify(set_up_tls: impl Future<Output = TlsFixture
|
||||
assert!(closed_conn.client.received_close_notify());
|
||||
}
|
||||
|
||||
// Expect a clean TLS connection closure when server sends close_notify first AND also closes
|
||||
// the socket
|
||||
// Expect a clean TLS connection closure when server sends close_notify first
|
||||
// AND also closes the socket
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_ok_server_close_notify_and_socket_close(
|
||||
@@ -259,7 +260,8 @@ async fn test_ok_read_after_close(set_up_tls: impl Future<Output = TlsFixture>)
|
||||
assert_eq!(std::str::from_utf8(&buf[0..n]).unwrap(), "hello");
|
||||
}
|
||||
|
||||
// Expect there to be no error when server DOES NOT send close_notify but just closes the socket
|
||||
// Expect there to be no error when server DOES NOT send close_notify but just
|
||||
// closes the socket
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_ok_server_no_close_notify(set_up_tls: impl Future<Output = TlsFixture>) {
|
||||
@@ -391,7 +393,8 @@ async fn test_err_alert(set_up_tls: impl Future<Output = TlsFixture>) {
|
||||
);
|
||||
}
|
||||
|
||||
// Expect an error when trying to write data to a connection which server closed abruptly
|
||||
// Expect an error when trying to write data to a connection which server closed
|
||||
// abruptly
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_err_write_after_close(set_up_tls: impl Future<Output = TlsFixture>) {
|
||||
|
||||
@@ -11,14 +11,14 @@ const DEFAULT_TRANSCRIPT_MAX_SIZE: usize = 1 << 14;
|
||||
pub struct TranscriptConfig {
|
||||
/// The transcript id.
|
||||
id: String,
|
||||
/// The "opaque" transcript id, used for parts of the transcript that are not
|
||||
/// part of the application data.
|
||||
/// The "opaque" transcript id, used for parts of the transcript that are
|
||||
/// not part of the application data.
|
||||
opaque_id: String,
|
||||
/// The maximum number of bytes that can be written to the transcript during the **online**
|
||||
/// phase, i.e. while the MPC-TLS connection is active.
|
||||
/// The maximum number of bytes that can be written to the transcript during
|
||||
/// the **online** phase, i.e. while the MPC-TLS connection is active.
|
||||
max_online_size: usize,
|
||||
/// The maximum number of bytes that can be written to the transcript during the **offline**
|
||||
/// phase, i.e. after the MPC-TLS connection was closed.
|
||||
/// The maximum number of bytes that can be written to the transcript during
|
||||
/// the **offline** phase, i.e. after the MPC-TLS connection was closed.
|
||||
max_offline_size: usize,
|
||||
}
|
||||
|
||||
@@ -64,14 +64,16 @@ impl TranscriptConfig {
|
||||
&self.opaque_id
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be written to the transcript during the **online**
|
||||
/// phase, i.e. while the MPC-TLS connection is active.
|
||||
/// Returns the maximum number of bytes that can be written to the
|
||||
/// transcript during the **online** phase, i.e. while the MPC-TLS
|
||||
/// connection is active.
|
||||
pub fn max_online_size(&self) -> usize {
|
||||
self.max_online_size
|
||||
}
|
||||
|
||||
/// Returns the maximum number of bytes that can be written to the transcript during the **offline**
|
||||
/// phase, i.e. after the MPC-TLS connection was closed.
|
||||
/// Returns the maximum number of bytes that can be written to the
|
||||
/// transcript during the **offline** phase, i.e. after the MPC-TLS
|
||||
/// connection was closed.
|
||||
pub fn max_offline_size(&self) -> usize {
|
||||
self.max_offline_size
|
||||
}
|
||||
@@ -126,16 +128,17 @@ impl MpcTlsCommonConfig {
|
||||
#[derive(Debug, Clone, Builder)]
|
||||
pub struct MpcTlsLeaderConfig {
|
||||
common: MpcTlsCommonConfig,
|
||||
/// Whether the `deferred decryption` feature is toggled on from the start of the MPC-TLS
|
||||
/// connection.
|
||||
/// Whether the `deferred decryption` feature is toggled on from the start
|
||||
/// of the MPC-TLS connection.
|
||||
///
|
||||
/// The received data will be decrypted locally without MPC, thus improving
|
||||
/// bandwidth usage and performance.
|
||||
///
|
||||
/// Decryption of the data received while `deferred decryption` is toggled on will be deferred
|
||||
/// until after the MPC-TLS connection is closed.
|
||||
/// If you need to decrypt some subset of data received from the TLS peer while the MPC-TLS
|
||||
/// connection is active, you must toggle `deferred decryption` **off** for that subset of data.
|
||||
/// Decryption of the data received while `deferred decryption` is toggled
|
||||
/// on will be deferred until after the MPC-TLS connection is closed.
|
||||
/// If you need to decrypt some subset of data received from the TLS peer
|
||||
/// while the MPC-TLS connection is active, you must toggle `deferred
|
||||
/// decryption` **off** for that subset of data.
|
||||
#[builder(default = "true")]
|
||||
defer_decryption_from_start: bool,
|
||||
}
|
||||
@@ -151,8 +154,8 @@ impl MpcTlsLeaderConfig {
|
||||
&self.common
|
||||
}
|
||||
|
||||
/// Returns whether the `deferred decryption` feature is toggled on from the start of the MPC-TLS
|
||||
/// connection.
|
||||
/// Returns whether the `deferred decryption` feature is toggled on from the
|
||||
/// start of the MPC-TLS connection.
|
||||
pub fn defer_decryption_from_start(&self) -> bool {
|
||||
self.defer_decryption_from_start
|
||||
}
|
||||
|
||||
@@ -156,7 +156,8 @@ impl MpcTlsFollower {
|
||||
|
||||
/// Runs the follower actor.
|
||||
///
|
||||
/// Returns a control handle and a future that resolves when the actor is stopped.
|
||||
/// Returns a control handle and a future that resolves when the actor is
|
||||
/// stopped.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
@@ -238,8 +239,8 @@ impl MpcTlsFollower {
|
||||
|
||||
/// Returns an error if the follower is not accepting new messages.
|
||||
///
|
||||
/// This can happen if the follower has received a CloseNotify alert or if the leader has
|
||||
/// committed to the transcript.
|
||||
/// This can happen if the follower has received a CloseNotify alert or if
|
||||
/// the leader has committed to the transcript.
|
||||
fn is_accepting_messages(&self) -> Result<(), MpcTlsError> {
|
||||
if self.close_notify {
|
||||
return Err(MpcTlsError::new(
|
||||
@@ -485,9 +486,10 @@ impl MpcTlsFollower {
|
||||
debug!("decrypting message");
|
||||
|
||||
if self.committed {
|
||||
// At this point the AEAD key was revealed to the leader and the leader locally decrypted
|
||||
// the TLS message and now is proving to us that they know the plaintext which encrypts
|
||||
// to the ciphertext of this TLS message.
|
||||
// At this point the AEAD key was revealed to the leader and the leader locally
|
||||
// decrypted the TLS message and now is proving to us that they know
|
||||
// the plaintext which encrypts to the ciphertext of this TLS
|
||||
// message.
|
||||
self.decrypter.verify_plaintext(msg).await?;
|
||||
} else {
|
||||
self.decrypter.decrypt_blind(msg).await?;
|
||||
@@ -519,7 +521,8 @@ impl MpcTlsFollower {
|
||||
|
||||
self.committed = true;
|
||||
|
||||
// Reveal the AEAD key to the leader only if there are TLS messages which need to be decrypted.
|
||||
// Reveal the AEAD key to the leader only if there are TLS messages which need
|
||||
// to be decrypted.
|
||||
if !buffer.is_empty() {
|
||||
self.decrypter.decode_key_blind().await?;
|
||||
}
|
||||
@@ -644,8 +647,9 @@ mod state {
|
||||
pub(super) server_key: PublicKey,
|
||||
/// TLS messages purportedly received by the leader from the server.
|
||||
///
|
||||
/// The follower must verify the authenticity of these messages with AEAD verification
|
||||
/// (i.e. by verifying the authentication tag).
|
||||
/// The follower must verify the authenticity of these messages with
|
||||
/// AEAD verification (i.e. by verifying the authentication
|
||||
/// tag).
|
||||
pub(super) buffer: VecDeque<OpaqueMessage>,
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@ pub struct MpcTlsLeader {
|
||||
encrypter: Encrypter,
|
||||
decrypter: Decrypter,
|
||||
|
||||
/// When set, notifies the backend that there are TLS messages which need to be decrypted.
|
||||
/// When set, notifies the backend that there are TLS messages which need to
|
||||
/// be decrypted.
|
||||
notifier: BackendNotifier,
|
||||
|
||||
/// Whether the backend is ready to decrypt messages.
|
||||
@@ -151,7 +152,8 @@ impl MpcTlsLeader {
|
||||
|
||||
/// Runs the leader actor.
|
||||
///
|
||||
/// Returns a control handle and a future that resolves when the actor is stopped.
|
||||
/// Returns a control handle and a future that resolves when the actor is
|
||||
/// stopped.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
@@ -322,8 +324,9 @@ impl MpcTlsLeader {
|
||||
.await?;
|
||||
|
||||
let msg = if self.committed {
|
||||
// At this point the AEAD key was revealed to us. We will locally decrypt the TLS message
|
||||
// and will prove the knowledge of the plaintext to the follower.
|
||||
// At this point the AEAD key was revealed to us. We will locally decrypt the
|
||||
// TLS message and will prove the knowledge of the plaintext to the
|
||||
// follower.
|
||||
self.decrypter.prove_plaintext(msg).await?
|
||||
} else {
|
||||
self.decrypter.decrypt_private(msg).await?
|
||||
@@ -390,8 +393,8 @@ impl MpcTlsLeader {
|
||||
|
||||
/// Commits the leader to the current transcript.
|
||||
///
|
||||
/// This reveals the AEAD key to the leader and disables sending or receiving
|
||||
/// any further messages.
|
||||
/// This reveals the AEAD key to the leader and disables sending or
|
||||
/// receiving any further messages.
|
||||
#[instrument(name = "finalize", level = "debug", skip_all, err)]
|
||||
#[msg(skip, name = "Commit")]
|
||||
pub async fn commit(&mut self) -> Result<(), MpcTlsError> {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
//! This crate provides tooling for instantiating MPC TLS machinery for leader and follower.
|
||||
//! This crate provides tooling for instantiating MPC TLS machinery for leader
|
||||
//! and follower.
|
||||
|
||||
//! The main API objects are [MpcTlsLeader] and [MpcTlsFollower], which wrap the necessary
|
||||
//! cryptographic machinery and also an [MpcTlsChannel] for communication.
|
||||
//! The main API objects are [MpcTlsLeader] and [MpcTlsFollower], which wrap the
|
||||
//! necessary cryptographic machinery and also an [MpcTlsChannel] for
|
||||
//! communication.
|
||||
|
||||
#![deny(missing_docs, unreachable_pub, unused_must_use)]
|
||||
#![deny(clippy::all)]
|
||||
|
||||
@@ -352,8 +352,9 @@ impl Decrypter {
|
||||
|
||||
/// Proves the plaintext of the message to the other party
|
||||
///
|
||||
/// This verifies the tag of the message and locally decrypts it. Then, this party
|
||||
/// commits to the plaintext and proves it encrypts back to the ciphertext.
|
||||
/// This verifies the tag of the message and locally decrypts it. Then, this
|
||||
/// party commits to the plaintext and proves it encrypts back to the
|
||||
/// ciphertext.
|
||||
pub(crate) async fn prove_plaintext(
|
||||
&mut self,
|
||||
msg: OpaqueMessage,
|
||||
@@ -388,8 +389,9 @@ impl Decrypter {
|
||||
|
||||
/// Verifies the plaintext of the message
|
||||
///
|
||||
/// This verifies the tag of the message then has the other party decrypt it. Then,
|
||||
/// the other party commits to the plaintext and proves it encrypts back to the ciphertext.
|
||||
/// This verifies the tag of the message then has the other party decrypt
|
||||
/// it. Then, the other party commits to the plaintext and proves it
|
||||
/// encrypts back to the ciphertext.
|
||||
pub(crate) async fn verify_plaintext(&mut self, msg: OpaqueMessage) -> Result<(), MpcTlsError> {
|
||||
let OpaqueMessage {
|
||||
typ,
|
||||
|
||||
@@ -93,8 +93,8 @@ pub async fn bind_test_server<
|
||||
let mut read_buf = vec![0u8; APP_RECORD_LENGTH];
|
||||
if conn.read_exact(&mut read_buf).await.is_err() {
|
||||
// EOF reached because client closed its tx part of the socket.
|
||||
// The client's rx part of the socket is still open and waiting for a clean server
|
||||
// shutdown.
|
||||
// The client's rx part of the socket is still open and waiting for a clean
|
||||
// server shutdown.
|
||||
if must_delay_when_closing {
|
||||
// delay closing the socket
|
||||
tokio::time::sleep(std::time::Duration::from_millis(CLOSE_DELAY)).await;
|
||||
@@ -179,8 +179,8 @@ pub async fn bind_test_server<
|
||||
break;
|
||||
}
|
||||
"send_record_with_bad_mac" => {
|
||||
// send a record which a bad MAC which will trigger the `bad_record_mac` alert on
|
||||
// the client side
|
||||
// send a record which a bad MAC which will trigger the `bad_record_mac` alert
|
||||
// on the client side
|
||||
|
||||
let (socket, _tls) = conn.into_inner();
|
||||
|
||||
|
||||
@@ -129,7 +129,8 @@ impl Verifier<state::Initialized> {
|
||||
|
||||
/// Runs the TLS verifier to completion, notarizing the TLS session.
|
||||
///
|
||||
/// This is a convenience method which runs all the steps needed for notarization.
|
||||
/// This is a convenience method which runs all the steps needed for
|
||||
/// notarization.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -152,7 +153,8 @@ impl Verifier<state::Initialized> {
|
||||
|
||||
/// Runs the TLS verifier to completion, verifying the TLS session.
|
||||
///
|
||||
/// This is a convenience method which runs all the steps needed for verification.
|
||||
/// This is a convenience method which runs all the steps needed for
|
||||
/// verification.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@@ -231,8 +233,9 @@ impl Verifier<state::Setup> {
|
||||
impl Verifier<state::Closed> {
|
||||
/// Starts notarization of the TLS session.
|
||||
///
|
||||
/// If the verifier is a Notary, this function will transition the verifier to the next state
|
||||
/// where it can sign the prover's commitments to the transcript.
|
||||
/// If the verifier is a Notary, this function will transition the verifier
|
||||
/// to the next state where it can sign the prover's commitments to the
|
||||
/// transcript.
|
||||
pub fn start_notarize(self) -> Verifier<Notarize> {
|
||||
Verifier {
|
||||
config: self.config,
|
||||
@@ -243,8 +246,8 @@ impl Verifier<state::Closed> {
|
||||
|
||||
/// Starts verification of the TLS session.
|
||||
///
|
||||
/// This function transitions the verifier into a state where it can verify content of the
|
||||
/// transcript.
|
||||
/// This function transitions the verifier into a state where it can verify
|
||||
/// content of the transcript.
|
||||
pub fn start_verify(self) -> Verifier<Verify> {
|
||||
Verifier {
|
||||
config: self.config,
|
||||
|
||||
@@ -19,7 +19,8 @@ impl Verifier<VerifyState> {
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// The content of the received transcripts can not be considered authentic until after finalization.
|
||||
/// The content of the received transcripts can not be considered authentic
|
||||
/// until after finalization.
|
||||
#[instrument(parent = &self.span, level = "info", skip_all, err)]
|
||||
pub async fn receive(&mut self) -> Result<PartialTranscript, VerifierError> {
|
||||
self.state
|
||||
|
||||
@@ -19,8 +19,9 @@ impl<T> FuturesIo<T> {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This wrapper is only safe to use if the inner I/O object does not under any circumstance
|
||||
/// read from the buffer passed to `poll_read` in the `futures::AsyncRead` implementation.
|
||||
/// This wrapper is only safe to use if the inner I/O object does not under
|
||||
/// any circumstance read from the buffer passed to `poll_read` in the
|
||||
/// `futures::AsyncRead` implementation.
|
||||
pub(crate) fn new(inner: T) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
@@ -68,7 +69,8 @@ where
|
||||
cx: &mut Context<'_>,
|
||||
mut buf: hyper::rt::ReadBufCursor<'_>,
|
||||
) -> Poll<Result<(), std::io::Error>> {
|
||||
// Safety: buf_slice should only be written to, so it's safe to convert `&mut [MaybeUninit<u8>]` to `&mut [u8]`.
|
||||
// Safety: buf_slice should only be written to, so it's safe to convert `&mut
|
||||
// [MaybeUninit<u8>]` to `&mut [u8]`.
|
||||
let buf_slice = unsafe {
|
||||
slice::from_raw_parts_mut(buf.as_mut().as_mut_ptr() as *mut u8, buf.as_mut().len())
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
ignore = ["tls-core/", "tls-client/"]
|
||||
ignore = ["crates/tls/core", "crates/tls/client"]
|
||||
|
||||
imports_granularity = "Crate"
|
||||
wrap_comments = true
|
||||
|
||||
Reference in New Issue
Block a user