Skip to content

Commit d0d7cb1

Browse files
Merge pull request #2 from cohere-ai/nvidia-tdx-attestation
feat(api-server-rest): add additional evidence endpoint
2 parents ab95914 + b56070c commit d0d7cb1

6 files changed

Lines changed: 150 additions & 6 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api-server-rest/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ async-trait.workspace = true
1111
base64.workspace = true
1212
clap = { workspace = true, features = ["derive"] }
1313
form_urlencoded = "1.2.2"
14+
hex.workspace = true
1415
hyper = { version = "0.14.27", features = ["server", "http1", "runtime"] }
1516
serde.workspace = true
1617
serde_json.workspace = true

api-server-rest/build.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ fn _token() {}
3131
get,
3232
path = "/aa/evidence",
3333
params(
34-
("runtime_data" = String, Query, description = "Runtime Data")
34+
("runtime_data" = String, Query, description = "Runtime Data"),
35+
("encoding" = Option<String>, Query, description = "Encoding of runtime_data: 'hex', 'base64', or omit for raw UTF-8 string")
3536
),
3637
responses(
3738
(status = 200, description = "success response",
@@ -46,6 +47,26 @@ fn _token() {}
4647
)]
4748
fn _evidence() {}
4849

50+
#[utoipa::path(
51+
get,
52+
path = "/aa/additional_evidence",
53+
params(
54+
("runtime_data" = String, Query, description = "Runtime Data"),
55+
("encoding" = Option<String>, Query, description = "Encoding of runtime_data: 'hex', 'base64', or omit for raw UTF-8 string")
56+
),
57+
responses(
58+
(status = 200, description = "success response",
59+
content_type = "application/octet-stream",
60+
body = String,
61+
example = json!({"svn":"1","report_data":"eHh4eA=="})),
62+
(status = 400, description = "bad request for invalid query param"),
63+
(status = 403, description = "forbid external access"),
64+
(status = 404, description = "resource not found"),
65+
(status = 405, description = "only Get method allowed")
66+
)
67+
)]
68+
fn _additional_evidence() {}
69+
4970
#[derive(ToSchema)]
5071
pub struct AaelEvent {
5172
/// Attestation Agent Event Log Domain
@@ -127,7 +148,7 @@ fn generate_openapi_document() -> std::io::Result<()> {
127148
(url = "http://127.0.0.1:8006", description = "CoCo RESTful API")
128149
),
129150
130-
paths(_token, _evidence, _aael, _resource, _version)
151+
paths(_token, _evidence, _additional_evidence, _aael, _resource, _version)
131152
)]
132153
struct ApiDoc;
133154
let mut file = File::create("openapi/api.json")?;

api-server-rest/openapi/api.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,60 @@
4949
}
5050
}
5151
},
52+
"/aa/additional_evidence": {
53+
"get": {
54+
"tags": [],
55+
"operationId": "_additional_evidence",
56+
"parameters": [
57+
{
58+
"name": "runtime_data",
59+
"in": "query",
60+
"description": "Runtime Data",
61+
"required": true,
62+
"schema": {
63+
"type": "string"
64+
}
65+
},
66+
{
67+
"name": "encoding",
68+
"in": "query",
69+
"description": "Encoding of runtime_data: 'hex', 'base64', or omit for raw UTF-8 string",
70+
"required": false,
71+
"schema": {
72+
"type": "string"
73+
}
74+
}
75+
],
76+
"responses": {
77+
"200": {
78+
"description": "success response",
79+
"content": {
80+
"application/octet-stream": {
81+
"schema": {
82+
"type": "string"
83+
},
84+
"example": {
85+
"report_data": "eHh4eA==",
86+
"svn": "1"
87+
}
88+
}
89+
}
90+
},
91+
"400": {
92+
"description": "bad request for invalid query param"
93+
},
94+
"403": {
95+
"description": "forbid external access"
96+
},
97+
"404": {
98+
"description": "resource not found"
99+
},
100+
"405": {
101+
"description": "only Get method allowed"
102+
}
103+
}
104+
}
105+
},
52106
"/aa/evidence": {
53107
"get": {
54108
"tags": [],
@@ -62,6 +116,15 @@
62116
"schema": {
63117
"type": "string"
64118
}
119+
},
120+
{
121+
"name": "encoding",
122+
"in": "query",
123+
"description": "Encoding of runtime_data: 'hex', 'base64', or omit for raw UTF-8 string",
124+
"required": false,
125+
"schema": {
126+
"type": "string"
127+
}
65128
}
66129
],
67130
"responses": {

api-server-rest/src/client/aa.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
use anyhow::*;
77
use protos::ttrpc::aa::attestation_agent::{
8-
ExtendRuntimeMeasurementRequest, GetAdditionalTeesRequest, GetEvidenceRequest,
9-
GetTeeTypeRequest, GetTokenRequest,
8+
ExtendRuntimeMeasurementRequest, GetAdditionalEvidenceRequest, GetAdditionalTeesRequest,
9+
GetEvidenceRequest, GetTeeTypeRequest, GetTokenRequest,
1010
};
1111
use protos::ttrpc::aa::attestation_agent_ttrpc::AttestationAgentServiceClient;
1212
use serde::Deserialize;
@@ -19,6 +19,7 @@ pub const AA_ROOT: &str = "/aa";
1919
/// URL for querying CDH get resource API
2020
pub const AA_TOKEN_URL: &str = "/token";
2121
pub const AA_EVIDENCE_URL: &str = "/evidence";
22+
pub const AA_ADDITIONAL_EVIDENCE_URL: &str = "/additional_evidence";
2223
pub const AA_AAEL_URL: &str = "/aael";
2324

2425
pub struct AAClient {
@@ -66,6 +67,18 @@ impl AAClient {
6667
Ok(res.Evidence)
6768
}
6869

70+
pub async fn get_additional_evidence(&self, runtime_data: &[u8]) -> Result<Vec<u8>> {
71+
let req = GetAdditionalEvidenceRequest {
72+
RuntimeData: runtime_data.to_vec(),
73+
..Default::default()
74+
};
75+
let res = self
76+
.client
77+
.get_additional_evidence(ttrpc::context::with_timeout(TTRPC_TIMEOUT), &req)
78+
.await?;
79+
Ok(res.Evidence)
80+
}
81+
6982
pub async fn extend_aael_entry(
7083
&self,
7184
domain: &str,

api-server-rest/src/router.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,32 @@
44
//
55

66
use anyhow::*;
7+
use base64::Engine;
78
use hyper::body::HttpBody;
89
use hyper::{header, Body, Method, Request, Response, StatusCode};
910
use serde::Serialize;
1011
use std::collections::HashMap;
1112
use std::net::SocketAddr;
1213
use tracing::{debug, info};
1314

15+
fn decode_runtime_data(raw: &str, encoding: Option<&str>) -> Result<Vec<u8>> {
16+
match encoding {
17+
Some("hex") => {
18+
hex::decode(raw).map_err(|e| anyhow!("invalid hex in runtime_data: {e}"))
19+
}
20+
Some("base64") => base64::engine::general_purpose::STANDARD
21+
.decode(raw)
22+
.map_err(|e| anyhow!("invalid base64 in runtime_data: {e}")),
23+
Some(other) => bail!("unsupported encoding: {other} (expected hex, base64, or omit)"),
24+
None => Ok(raw.as_bytes().to_vec()),
25+
}
26+
}
27+
1428
use crate::client::{
15-
aa::{AAClient, AaelEvent, AA_AAEL_URL, AA_EVIDENCE_URL, AA_ROOT, AA_TOKEN_URL},
29+
aa::{
30+
AAClient, AaelEvent, AA_AAEL_URL, AA_ADDITIONAL_EVIDENCE_URL, AA_EVIDENCE_URL, AA_ROOT,
31+
AA_TOKEN_URL,
32+
},
1633
cdh::{CDHClient, CDH_RESOURCE_URL, CDH_ROOT},
1734
};
1835
use crate::utils::split_nth_slash;
@@ -168,8 +185,36 @@ impl Router {
168185
info!("Get evidence");
169186
match params.get("runtime_data") {
170187
Some(runtime_data) => {
188+
let data = match decode_runtime_data(
189+
runtime_data,
190+
params.get("encoding").map(|s| s.as_str()),
191+
) {
192+
std::result::Result::Ok(d) => d,
193+
Err(e) => return self.internal_error(e.to_string()),
194+
};
195+
match client.get_evidence(&data).await {
196+
std::result::Result::Ok(results) => {
197+
return self.octet_stream_response(results)
198+
}
199+
Err(e) => return self.internal_error(e.to_string()),
200+
}
201+
}
202+
None => return self.bad_request(),
203+
}
204+
}
205+
(AA_ADDITIONAL_EVIDENCE_URL, &Method::GET) => {
206+
info!("Get additional evidence");
207+
match params.get("runtime_data") {
208+
Some(runtime_data) => {
209+
let data = match decode_runtime_data(
210+
runtime_data,
211+
params.get("encoding").map(|s| s.as_str()),
212+
) {
213+
std::result::Result::Ok(d) => d,
214+
Err(e) => return self.internal_error(e.to_string()),
215+
};
171216
match client
172-
.get_evidence(&runtime_data.clone().into_bytes())
217+
.get_additional_evidence(&data)
173218
.await
174219
{
175220
std::result::Result::Ok(results) => {

0 commit comments

Comments
 (0)