1
- // Copyright 2022 Contributors to the Veraison project.
1
+ // Copyright 2022-2025 Contributors to the Veraison project.
2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
4
#![ allow( clippy:: multiple_crate_versions) ]
5
5
6
6
use std:: { fs:: File , io:: Read , path:: PathBuf } ;
7
7
8
- use reqwest:: { blocking :: ClientBuilder , Certificate } ;
8
+ use reqwest:: { Certificate , ClientBuilder } ;
9
9
10
10
#[ derive( thiserror:: Error , PartialEq , Eq ) ]
11
11
pub enum Error {
@@ -59,7 +59,8 @@ impl std::fmt::Debug for Error {
59
59
/// The application is passed the session nonce and the list of supported
60
60
/// evidence media types and shall return the computed evidence together with
61
61
/// the selected media type.
62
- type EvidenceCreationCb = fn ( nonce : & [ u8 ] , accepted : & [ String ] ) -> Result < ( Vec < u8 > , String ) , Error > ;
62
+ type EvidenceCreationCb =
63
+ fn ( nonce : & [ u8 ] , accepted : & [ String ] , token : Vec < u8 > ) -> Result < ( Vec < u8 > , String ) , Error > ;
63
64
64
65
/// A builder for ChallengeResponse objects
65
66
pub struct ChallengeResponseBuilder {
@@ -99,7 +100,7 @@ impl ChallengeResponseBuilder {
99
100
. new_session_url
100
101
. ok_or_else ( || Error :: ConfigError ( "missing API endpoint" . to_string ( ) ) ) ?;
101
102
102
- let mut http_client_builder: ClientBuilder = reqwest:: blocking :: ClientBuilder :: new ( ) ;
103
+ let mut http_client_builder: ClientBuilder = reqwest:: ClientBuilder :: new ( ) ;
103
104
104
105
if self . root_certificate . is_some ( ) {
105
106
let mut buf = Vec :: new ( ) ;
@@ -128,7 +129,7 @@ impl Default for ChallengeResponseBuilder {
128
129
/// be run. Always use the [ChallengeResponseBuilder] to instantiate it.
129
130
pub struct ChallengeResponse {
130
131
new_session_url : url:: Url ,
131
- http_client : reqwest:: blocking :: Client ,
132
+ http_client : reqwest:: Client ,
132
133
}
133
134
134
135
/// Nonce configuration: either the size (Size) of the nonce generated by the
@@ -143,19 +144,23 @@ impl ChallengeResponse {
143
144
/// Run a challenge-response verification session using the supplied nonce
144
145
/// configuration and evidence creation callback. Returns the raw attestation results, or an
145
146
/// error on failure.
146
- pub fn run (
147
+ pub async fn run (
147
148
& self ,
148
149
nonce : Nonce ,
149
150
evidence_creation_cb : EvidenceCreationCb ,
151
+ token : Vec < u8 > ,
150
152
) -> Result < String , Error > {
151
153
// create new c/r verification session on the veraison side
152
- let ( session_url, session) = self . new_session ( & nonce) ?;
154
+ let ( session_url, session) = self . new_session ( & nonce) . await ?;
153
155
154
156
// invoke the user-provided evidence builder callback with per-session parameters
155
- let ( evidence, media_type) = ( evidence_creation_cb) ( session. nonce ( ) , session. accept ( ) ) ?;
157
+ let ( evidence, media_type) =
158
+ ( evidence_creation_cb) ( session. nonce ( ) , session. accept ( ) , token) ?;
156
159
157
160
// send evidence for verification to the session endpoint
158
- let attestation_result = self . challenge_response ( & evidence, & media_type, & session_url) ?;
161
+ let attestation_result = self
162
+ . challenge_response ( & evidence, & media_type, & session_url)
163
+ . await ?;
159
164
160
165
// return veraison's attestation results
161
166
Ok ( attestation_result)
@@ -164,9 +169,12 @@ impl ChallengeResponse {
164
169
/// Ask Veraison to create a new challenge/response session using the supplied nonce
165
170
/// configuration. On success, the return value is a tuple of the session URL for subsequent
166
171
/// operations, plus the session data including the nonce and the list of accept types.
167
- pub fn new_session ( & self , nonce : & Nonce ) -> Result < ( String , ChallengeResponseSession ) , Error > {
172
+ pub async fn new_session (
173
+ & self ,
174
+ nonce : & Nonce ,
175
+ ) -> Result < ( String , ChallengeResponseSession ) , Error > {
168
176
// ask veraison for a new session object
169
- let resp = self . new_session_request ( nonce) ?;
177
+ let resp = self . new_session_request ( nonce) . await ?;
170
178
171
179
// expect 201 and a Location header containing the URI of the newly
172
180
// allocated session
@@ -180,7 +188,7 @@ impl ChallengeResponse {
180
188
// middleware that is unaware of the API. We need something
181
189
// more robust here that dispatches based on the Content-Type
182
190
// header.
183
- let pd: ProblemDetails = resp. json ( ) ?;
191
+ let pd: ProblemDetails = resp. json ( ) . await ?;
184
192
185
193
return Err ( Error :: ApiError ( format ! (
186
194
"newSession response has unexpected status: {}. Details: {}" ,
@@ -206,13 +214,13 @@ impl ChallengeResponse {
206
214
. map_err ( |e| Error :: ApiError ( e. to_string ( ) ) ) ?;
207
215
208
216
// decode returned session object
209
- let crs: ChallengeResponseSession = resp. json ( ) ?;
217
+ let crs: ChallengeResponseSession = resp. json ( ) . await ?;
210
218
211
219
Ok ( ( session_url. to_string ( ) , crs) )
212
220
}
213
221
214
222
/// Execute a challenge/response operation with the given evidence.
215
- pub fn challenge_response (
223
+ pub async fn challenge_response (
216
224
& self ,
217
225
evidence : & [ u8 ] ,
218
226
media_type : & str ,
@@ -225,14 +233,15 @@ impl ChallengeResponse {
225
233
. header ( reqwest:: header:: ACCEPT , CRS_MEDIA_TYPE )
226
234
. header ( reqwest:: header:: CONTENT_TYPE , media_type)
227
235
. body ( evidence. to_owned ( ) )
228
- . send ( ) ?;
236
+ . send ( )
237
+ . await ?;
229
238
230
239
let status = resp. status ( ) ;
231
240
232
241
if status. is_success ( ) {
233
242
match status {
234
243
reqwest:: StatusCode :: OK => {
235
- let crs: ChallengeResponseSession = resp. json ( ) ?;
244
+ let crs: ChallengeResponseSession = resp. json ( ) . await ?;
236
245
237
246
if crs. status != "complete" {
238
247
return Err ( Error :: ApiError ( format ! (
@@ -259,7 +268,7 @@ impl ChallengeResponse {
259
268
) ) ) ,
260
269
}
261
270
} else {
262
- let pd: ProblemDetails = resp. json ( ) ?;
271
+ let pd: ProblemDetails = resp. json ( ) . await ?;
263
272
264
273
Err ( Error :: ApiError ( format ! (
265
274
"session response has error status: {}. Details: {}" ,
@@ -268,14 +277,15 @@ impl ChallengeResponse {
268
277
}
269
278
}
270
279
271
- fn new_session_request ( & self , nonce : & Nonce ) -> Result < reqwest:: blocking :: Response , Error > {
280
+ async fn new_session_request ( & self , nonce : & Nonce ) -> Result < reqwest:: Response , Error > {
272
281
let u = self . new_session_request_url ( nonce) ?;
273
282
274
283
let r = self
275
284
. http_client
276
285
. post ( u. as_str ( ) )
277
286
. header ( reqwest:: header:: ACCEPT , CRS_MEDIA_TYPE )
278
- . send ( ) ?;
287
+ . send ( )
288
+ . await ?;
279
289
280
290
Ok ( r)
281
291
}
@@ -403,7 +413,7 @@ impl DiscoveryBuilder {
403
413
. url
404
414
. ok_or_else ( || Error :: ConfigError ( "missing API endpoint" . to_string ( ) ) ) ?;
405
415
406
- let mut http_client_builder: ClientBuilder = reqwest:: blocking :: ClientBuilder :: new ( ) ;
416
+ let mut http_client_builder: ClientBuilder = reqwest:: ClientBuilder :: new ( ) ;
407
417
408
418
if self . root_certificate . is_some ( ) {
409
419
let mut buf = Vec :: new ( ) ;
@@ -508,7 +518,7 @@ impl VerificationApi {
508
518
/// Veraison service instance that you are communicating with.
509
519
pub struct Discovery {
510
520
verification_url : url:: Url ,
511
- http_client : reqwest:: blocking :: Client ,
521
+ http_client : reqwest:: Client ,
512
522
}
513
523
514
524
impl Discovery {
@@ -524,20 +534,21 @@ impl Discovery {
524
534
525
535
Ok ( Discovery {
526
536
verification_url,
527
- http_client : reqwest:: blocking :: Client :: new ( ) ,
537
+ http_client : reqwest:: Client :: new ( ) ,
528
538
} )
529
539
}
530
540
531
541
/// Obtains the capabilities and endpoints of the Veraison verification service.
532
- pub fn get_verification_api ( & self ) -> Result < VerificationApi , Error > {
542
+ pub async fn get_verification_api ( & self ) -> Result < VerificationApi , Error > {
533
543
let response = self
534
544
. http_client
535
545
. get ( self . verification_url . as_str ( ) )
536
546
. header ( reqwest:: header:: ACCEPT , DISCOVERY_MEDIA_TYPE )
537
- . send ( ) ?;
547
+ . send ( )
548
+ . await ?;
538
549
539
550
match response. status ( ) {
540
- reqwest:: StatusCode :: OK => Ok ( response. json :: < VerificationApi > ( ) ?) ,
551
+ reqwest:: StatusCode :: OK => Ok ( response. json :: < VerificationApi > ( ) . await ?) ,
541
552
_ => Err ( Error :: ApiError ( String :: from (
542
553
"Failed to discover verification endpoint information." ,
543
554
) ) ) ,
@@ -630,7 +641,7 @@ mod tests {
630
641
. build ( )
631
642
. unwrap ( ) ;
632
643
633
- let rv = cr. new_session ( & nonce) . expect ( "unexpected failure" ) ;
644
+ let rv = cr. new_session ( & nonce) . await . expect ( "unexpected failure" ) ;
634
645
635
646
// Expect we are given the expected location URL
636
647
assert_eq ! ( rv. 0 , format!( "{}/1234" , mock_server. uri( ) ) ) ;
@@ -672,6 +683,7 @@ mod tests {
672
683
673
684
let rv = cr
674
685
. challenge_response ( & evidence_value, media_type, & session_url)
686
+ . await
675
687
. expect ( "unexpected failure" ) ;
676
688
677
689
// Expect we are given the expected attestation result
@@ -722,6 +734,7 @@ mod tests {
722
734
723
735
let verification_api = discovery
724
736
. get_verification_api ( )
737
+ . await
725
738
. expect ( "Failed to get verification endpoint details." ) ;
726
739
727
740
// Check that we've pulled and deserialized everything that we expect
0 commit comments