@@ -20,7 +20,10 @@ use serde::{Deserialize, Serialize};
2020
2121use tlsn_core:: hash:: HashAlgId ;
2222
23- use crate :: { Attestation , Extension , connection:: ServerCertCommitment , signing:: SignatureAlgId } ;
23+ use crate :: {
24+ Attestation , CryptoProvider , Extension , connection:: ServerCertCommitment ,
25+ serialize:: CanonicalSerialize , signing:: SignatureAlgId ,
26+ } ;
2427
2528pub use builder:: { RequestBuilder , RequestBuilderError } ;
2629pub use config:: { RequestConfig , RequestConfigBuilder , RequestConfigBuilderError } ;
@@ -41,44 +44,102 @@ impl Request {
4144 }
4245
4346 /// Validates the content of the attestation against this request.
44- pub fn validate ( & self , attestation : & Attestation ) -> Result < ( ) , InconsistentAttestation > {
47+ pub fn validate (
48+ & self ,
49+ attestation : & Attestation ,
50+ provider : & CryptoProvider ,
51+ ) -> Result < ( ) , AttestationValidationError > {
4552 if attestation. signature . alg != self . signature_alg {
46- return Err ( InconsistentAttestation ( format ! (
53+ return Err ( AttestationValidationError :: inconsistent ( format ! (
4754 "signature algorithm: expected {:?}, got {:?}" ,
4855 self . signature_alg, attestation. signature. alg
4956 ) ) ) ;
5057 }
5158
5259 if attestation. header . root . alg != self . hash_alg {
53- return Err ( InconsistentAttestation ( format ! (
60+ return Err ( AttestationValidationError :: inconsistent ( format ! (
5461 "hash algorithm: expected {:?}, got {:?}" ,
5562 self . hash_alg, attestation. header. root. alg
5663 ) ) ) ;
5764 }
5865
5966 if attestation. body . cert_commitment ( ) != & self . server_cert_commitment {
60- return Err ( InconsistentAttestation (
61- "server certificate commitment does not match" . to_string ( ) ,
67+ return Err ( AttestationValidationError :: inconsistent (
68+ "server certificate commitment does not match" ,
6269 ) ) ;
6370 }
6471
6572 // TODO: improve the O(M*N) complexity of this check.
6673 for extension in & self . extensions {
6774 if !attestation. body . extensions ( ) . any ( |e| e == extension) {
68- return Err ( InconsistentAttestation (
69- "extension is missing from the attestation" . to_string ( ) ,
75+ return Err ( AttestationValidationError :: inconsistent (
76+ "extension is missing from the attestation" ,
7077 ) ) ;
7178 }
7279 }
7380
81+ let verifier = provider
82+ . signature
83+ . get ( & attestation. signature . alg )
84+ . map_err ( |_| {
85+ AttestationValidationError :: provider ( format ! (
86+ "provider not configured for signature algorithm id {:?}" ,
87+ attestation. signature. alg,
88+ ) )
89+ } ) ?;
90+
91+ verifier
92+ . verify (
93+ & attestation. body . verifying_key . data ,
94+ & CanonicalSerialize :: serialize ( & attestation. header ) ,
95+ & attestation. signature . data ,
96+ )
97+ . map_err ( |_| {
98+ AttestationValidationError :: inconsistent ( "failed to verify the signature" )
99+ } ) ?;
100+
74101 Ok ( ( ) )
75102 }
76103}
77104
78105/// Error for [`Request::validate`].
79106#[ derive( Debug , thiserror:: Error ) ]
80- #[ error( "inconsistent attestation: {0}" ) ]
81- pub struct InconsistentAttestation ( String ) ;
107+ #[ error( "attestation validation error: {kind}: {message}" ) ]
108+ pub struct AttestationValidationError {
109+ kind : ErrorKind ,
110+ message : String ,
111+ }
112+
113+ impl AttestationValidationError {
114+ fn inconsistent ( msg : impl Into < String > ) -> Self {
115+ Self {
116+ kind : ErrorKind :: Inconsistent ,
117+ message : msg. into ( ) ,
118+ }
119+ }
120+
121+ fn provider ( msg : impl Into < String > ) -> Self {
122+ Self {
123+ kind : ErrorKind :: Provider ,
124+ message : msg. into ( ) ,
125+ }
126+ }
127+ }
128+
129+ #[ derive( Debug ) ]
130+ enum ErrorKind {
131+ Inconsistent ,
132+ Provider ,
133+ }
134+
135+ impl std:: fmt:: Display for ErrorKind {
136+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
137+ match self {
138+ ErrorKind :: Inconsistent => write ! ( f, "inconsistent" ) ,
139+ ErrorKind :: Provider => write ! ( f, "provider" ) ,
140+ }
141+ }
142+ }
82143
83144#[ cfg( test) ]
84145mod test {
@@ -93,7 +154,8 @@ mod test {
93154 use crate :: {
94155 CryptoProvider ,
95156 connection:: ServerCertOpening ,
96- fixtures:: { RequestFixture , attestation_fixture, request_fixture} ,
157+ fixtures:: { RequestFixture , attestation_fixture, custom_provider_fixture, request_fixture} ,
158+ request:: { AttestationValidationError , ErrorKind } ,
97159 signing:: SignatureAlgId ,
98160 } ;
99161
@@ -113,7 +175,9 @@ mod test {
113175 let attestation =
114176 attestation_fixture ( request. clone ( ) , connection, SignatureAlgId :: SECP256K1 , & [ ] ) ;
115177
116- assert ! ( request. validate( & attestation) . is_ok( ) )
178+ let provider = CryptoProvider :: default ( ) ;
179+
180+ assert ! ( request. validate( & attestation, & provider) . is_ok( ) )
117181 }
118182
119183 #[ test]
@@ -134,7 +198,9 @@ mod test {
134198
135199 request. signature_alg = SignatureAlgId :: SECP256R1 ;
136200
137- let res = request. validate ( & attestation) ;
201+ let provider = CryptoProvider :: default ( ) ;
202+
203+ let res = request. validate ( & attestation, & provider) ;
138204 assert ! ( res. is_err( ) ) ;
139205 }
140206
@@ -156,7 +222,9 @@ mod test {
156222
157223 request. hash_alg = HashAlgId :: SHA256 ;
158224
159- let res = request. validate ( & attestation) ;
225+ let provider = CryptoProvider :: default ( ) ;
226+
227+ let res = request. validate ( & attestation, & provider) ;
160228 assert ! ( res. is_err( ) )
161229 }
162230
@@ -184,11 +252,62 @@ mod test {
184252 } ) ;
185253 let opening = ServerCertOpening :: new ( server_cert_data) ;
186254
187- let crypto_provider = CryptoProvider :: default ( ) ;
255+ let provider = CryptoProvider :: default ( ) ;
188256 request. server_cert_commitment =
189- opening. commit ( crypto_provider . hash . get ( & HashAlgId :: BLAKE3 ) . unwrap ( ) ) ;
257+ opening. commit ( provider . hash . get ( & HashAlgId :: BLAKE3 ) . unwrap ( ) ) ;
190258
191- let res = request. validate ( & attestation) ;
259+ let res = request. validate ( & attestation, & provider ) ;
192260 assert ! ( res. is_err( ) )
193261 }
262+
263+ #[ test]
264+ fn test_wrong_sig ( ) {
265+ let transcript = Transcript :: new ( GET_WITH_HEADER , OK_JSON ) ;
266+ let connection = ConnectionFixture :: tlsnotary ( transcript. length ( ) ) ;
267+
268+ let RequestFixture { request, .. } = request_fixture (
269+ transcript,
270+ encoding_provider ( GET_WITH_HEADER , OK_JSON ) ,
271+ connection. clone ( ) ,
272+ Blake3 :: default ( ) ,
273+ Vec :: new ( ) ,
274+ ) ;
275+
276+ let mut attestation =
277+ attestation_fixture ( request. clone ( ) , connection, SignatureAlgId :: SECP256K1 , & [ ] ) ;
278+
279+ // Corrupt the signature.
280+ attestation. signature . data [ 1 ] = attestation. signature . data [ 1 ] . wrapping_add ( 1 ) ;
281+
282+ let provider = CryptoProvider :: default ( ) ;
283+
284+ assert ! ( request. validate( & attestation, & provider) . is_err( ) )
285+ }
286+
287+ #[ test]
288+ fn test_wrong_provider ( ) {
289+ let transcript = Transcript :: new ( GET_WITH_HEADER , OK_JSON ) ;
290+ let connection = ConnectionFixture :: tlsnotary ( transcript. length ( ) ) ;
291+
292+ let RequestFixture { request, .. } = request_fixture (
293+ transcript,
294+ encoding_provider ( GET_WITH_HEADER , OK_JSON ) ,
295+ connection. clone ( ) ,
296+ Blake3 :: default ( ) ,
297+ Vec :: new ( ) ,
298+ ) ;
299+
300+ let attestation =
301+ attestation_fixture ( request. clone ( ) , connection, SignatureAlgId :: SECP256K1 , & [ ] ) ;
302+
303+ let provider = custom_provider_fixture ( ) ;
304+
305+ assert ! ( matches!(
306+ request. validate( & attestation, & provider) ,
307+ Err ( AttestationValidationError {
308+ kind: ErrorKind :: Provider ,
309+ ..
310+ } )
311+ ) )
312+ }
194313}
0 commit comments