Skip to content

Additional attestation validation #792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion crates/core/src/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ use crate::{
merkle::MerkleTree,
presentation::PresentationBuilder,
signing::{Signature, VerifyingKey},
transcript::{encoding::EncodingCommitment, hash::PlaintextHash},
transcript::{
encoding::{EncoderSecret, EncodingCommitment},
hash::PlaintextHash,
},
CryptoProvider,
};

Expand Down Expand Up @@ -167,6 +170,13 @@ impl Body {
&self.verifying_key.data
}

/// Returns the encoder secret.
pub fn encoder_secret(&self) -> Option<&EncoderSecret> {
self.encoding_commitment
.as_ref()
.map(|field| &field.data.secret)
}

/// Computes the Merkle root of the attestation fields.
///
/// This is only used when building an attestation.
Expand Down
4 changes: 4 additions & 0 deletions crates/core/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ impl Request {
"encoding commitment root does not match".to_string(),
));
}
} else if attestation.body.encoding_commitment().is_some() {
return Err(InconsistentAttestation(
"encoding commitment is present even though it was not requested".to_string(),
));
}

// TODO: improve the O(M*N) complexity of this check.
Expand Down
66 changes: 63 additions & 3 deletions crates/prover/src/notarize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ use serio::{stream::IoStreamExt as _, SinkExt as _};
use tlsn_common::encoding;
use tlsn_core::{
attestation::Attestation,
connection::TranscriptLength,
request::{Request, RequestConfig},
transcript::{encoding::EncodingTree, Transcript, TranscriptCommitConfig},
transcript::{
encoding::{new_encoder, Encoder, EncoderSecret, EncodingProvider, EncodingTree},
Direction, Idx, Transcript, TranscriptCommitConfig,
},
Secrets,
};
use tracing::{debug, instrument};
Expand Down Expand Up @@ -71,9 +75,9 @@ impl Prover<Notarize> {
builder
.server_name(self.config.server_name().clone())
.server_cert_data(server_cert_data)
.transcript(transcript);
.transcript(transcript.clone());

if let Some(config) = transcript_commit_config {
if let Some(ref config) = transcript_commit_config {
if config.has_encoding() {
builder.encoding_tree(
EncodingTree::new(
Expand Down Expand Up @@ -112,6 +116,62 @@ impl Prover<Notarize> {
.validate(&attestation)
.map_err(ProverError::attestation)?;

if let Some(config) = transcript_commit_config {
if config.has_encoding() {
validate_encoder_secret(
attestation
.body
.encoder_secret()
.expect("attestation contains encoder secret"),
&transcript,
&encoding_provider,
)?;
}
}

Ok((attestation, secrets))
}
}

// Validates that the encoder `secret` is consistent with the encoding
// `provider` for the given `transcript`.
fn validate_encoder_secret(
secret: &EncoderSecret,
transcript: &Transcript,
provider: &impl EncodingProvider,
) -> Result<(), ProverError> {
let encoder = new_encoder(secret);
let TranscriptLength { sent, received } = transcript.length();
let sent_idx = Idx::new(0..sent as usize);
let recv_idx = Idx::new(0..received as usize);

// The transcript encoding produced by the `encoder` and the `provider`
// must match.
if provider
.provide_encoding(Direction::Sent, &sent_idx)
.expect("index is valid")
!= encoder.encode_subsequence(
Direction::Sent,
&transcript
.get(Direction::Sent, &sent_idx)
.expect("index is valid"),
)
{
return Err(ProverError::attestation("Incosistent encoder secret"));
}

if provider
.provide_encoding(Direction::Received, &recv_idx)
.expect("index is valid")
!= encoder.encode_subsequence(
Direction::Received,
&transcript
.get(Direction::Received, &recv_idx)
.expect("index is valid"),
)
{
return Err(ProverError::attestation("Incosistent encoder secret"));
}

Ok(())
}
Loading