Skip to content

Commit 39e6fef

Browse files
committed
aproxy: Use static registrar for backend protocol
Signed-off-by: Tyler Fanelli <[email protected]>
1 parent 14123ff commit 39e6fef

File tree

6 files changed

+81
-58
lines changed

6 files changed

+81
-58
lines changed

Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aproxy/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ reqwest = { version = "0.12.9", features = ["blocking", "cookies", "json"] }
1010
anyhow = "1.0.93"
1111
clap = { version = "4.5", features = ["derive"] }
1212
kbs-types.workspace = true
13+
lazy_static = "1.5.0"
1314
libaproxy.workspace = true
1415
serde.workspace = true
1516
serde_json.workspace = true

aproxy/src/attest.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Author: Stefano Garzarella <[email protected]>
66
// Author: Tyler Fanelli <[email protected]>
77

8-
use crate::backend;
8+
use crate::backend::BACKEND;
99
use anyhow::Context;
1010
use libaproxy::*;
1111
use serde::Serialize;
@@ -17,9 +17,9 @@ use std::{
1717
};
1818

1919
/// Attest an SVSM client session.
20-
pub fn attest(stream: &mut UnixStream, http: &mut backend::HttpClient) -> anyhow::Result<()> {
21-
negotiation(stream, http)?;
22-
attestation(stream, http)?;
20+
pub fn attest(stream: &mut UnixStream) -> anyhow::Result<()> {
21+
negotiation(stream)?;
22+
attestation(stream)?;
2323

2424
Ok(())
2525
}
@@ -29,7 +29,7 @@ pub fn attest(stream: &mut UnixStream, http: &mut backend::HttpClient) -> anyhow
2929
/// server and gather all data required (i.e. a nonce) that should be hashed into the attestation
3030
/// evidence. The proxy will also reply with the type of hash algorithm to use for the negotiation
3131
/// parameters.
32-
fn negotiation(stream: &mut UnixStream, http: &mut backend::HttpClient) -> anyhow::Result<()> {
32+
fn negotiation(stream: &mut UnixStream) -> anyhow::Result<()> {
3333
// Read the negotiation parameters from SVSM.
3434
let request: NegotiationRequest = {
3535
let payload = proxy_read(stream)?;
@@ -39,7 +39,11 @@ fn negotiation(stream: &mut UnixStream, http: &mut backend::HttpClient) -> anyho
3939
};
4040

4141
// Gather negotiation parameters from the attestation server.
42-
let response: NegotiationResponse = http.negotiation(request)?;
42+
let response = {
43+
let backend = BACKEND.lock().unwrap();
44+
45+
backend.clone().unwrap().negotiation(request) // Safe to unwrap.
46+
}?;
4347

4448
// Write the response from the attestation server to SVSM.
4549
proxy_write(stream, response)?;
@@ -50,15 +54,19 @@ fn negotiation(stream: &mut UnixStream, http: &mut backend::HttpClient) -> anyho
5054
/// Attestation phase of SVSM attestation. SVSM will send an attestation request containing the TEE
5155
/// evidence. Proxy will respond with an attestation response containing the status
5256
/// (success/failure) and an optional secret upon successful attestation.
53-
fn attestation(stream: &mut UnixStream, http: &backend::HttpClient) -> anyhow::Result<()> {
57+
fn attestation(stream: &mut UnixStream) -> anyhow::Result<()> {
5458
let request: AttestationRequest = {
5559
let payload = proxy_read(stream)?;
5660
serde_json::from_slice(&payload)
5761
.context("unable to deserialize attestation request from JSON")?
5862
};
5963

6064
// Attest the TEE evidence with the server.
61-
let response: AttestationResponse = http.attestation(request)?;
65+
let response = {
66+
let backend = BACKEND.lock().unwrap();
67+
68+
backend.clone().unwrap().attestation(request) // Safe to unwrap.
69+
}?;
6270

6371
// Write the response from the attestation server to SVSM.
6472
proxy_write(stream, response)?;

aproxy/src/backend/kbs.rs

+10-13
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ impl AttestationProtocol for KbsProtocol {
2222
/// Make this request to /auth, gather the nonce, and return this in the negotiation
2323
/// parameter for SVSM to hash these components in the attestation evidence.
2424
fn negotiation(
25-
&mut self,
26-
http: &mut HttpClient,
25+
cli: &Client,
26+
url: &str,
2727
request: NegotiationRequest,
2828
) -> anyhow::Result<NegotiationResponse> {
2929
let req = Request {
@@ -33,9 +33,8 @@ impl AttestationProtocol for KbsProtocol {
3333
};
3434

3535
// Fetch challenge containing a nonce from the KBS /auth endpoint.
36-
let http_resp = http
37-
.cli
38-
.post(format!("{}/kbs/v0/auth", http.url))
36+
let http_resp = cli
37+
.post(format!("{}/kbs/v0/auth", url))
3938
.json(&req)
4039
.send()
4140
.context("unable to POST to KBS /auth endpoint")?;
@@ -75,8 +74,8 @@ impl AttestationProtocol for KbsProtocol {
7574
/// a secret (identified as "svsm_secret"). If able to successfully fetch the secret, return a
7675
/// successful AttestationResponse with the secret included.
7776
fn attestation(
78-
&self,
79-
http: &HttpClient,
77+
cli: &Client,
78+
url: &str,
8079
request: AttestationRequest,
8180
) -> anyhow::Result<AttestationResponse> {
8281
// Create a KBS attestation object from the TEE evidence and key.
@@ -97,9 +96,8 @@ impl AttestationProtocol for KbsProtocol {
9796
};
9897

9998
// Attest TEE evidence at KBS /attest endpoint.
100-
let http_resp = http
101-
.cli
102-
.post(format!("{}/kbs/v0/attest", http.url))
99+
let http_resp = cli
100+
.post(format!("{}/kbs/v0/attest", url))
103101
.json(&attestation)
104102
.send()
105103
.context("unable to POST to KBS /attest endpoint")?;
@@ -118,9 +116,8 @@ impl AttestationProtocol for KbsProtocol {
118116

119117
// Successful attestation. Fetch the secret (which should be stored as "svsm_secret" within
120118
// the KBS's RVPS.
121-
let http_resp = http
122-
.cli
123-
.post(format!("{}/kbs/v0/svsm_secret", http.url))
119+
let http_resp = cli
120+
.post(format!("{}/kbs/v0/svsm_secret", url))
124121
.send()
125122
.context("unable to POST to KBS /attest endpoint")?;
126123

aproxy/src/backend/mod.rs

+21-33
Original file line numberDiff line numberDiff line change
@@ -5,61 +5,49 @@
55
// Author: Stefano Garzarella <[email protected]>
66
// Author: Tyler Fanelli <[email protected]>
77

8-
mod kbs;
8+
pub mod kbs;
99

10-
use anyhow::{anyhow, Context};
11-
use kbs::KbsProtocol;
10+
use anyhow::anyhow;
11+
use lazy_static::lazy_static;
1212
use libaproxy::*;
13-
use reqwest::{blocking::Client, cookie::Jar};
14-
use std::{str::FromStr, sync::Arc};
13+
use reqwest::blocking::Client;
14+
use std::{str::FromStr, sync::Mutex};
15+
16+
lazy_static! {
17+
pub static ref BACKEND: Mutex<Option<HttpClient>> = Mutex::new(None);
18+
}
1519

1620
/// HTTP client and protocol identifier.
1721
#[derive(Clone, Debug)]
1822
pub struct HttpClient {
1923
pub cli: Client,
2024
pub url: String,
21-
protocol: Protocol,
25+
pub negotiation: fn(&Client, &str, NegotiationRequest) -> anyhow::Result<NegotiationResponse>,
26+
pub attestation: fn(&Client, &str, AttestationRequest) -> anyhow::Result<AttestationResponse>,
2227
}
2328

2429
impl HttpClient {
25-
pub fn new(url: String, protocol: Protocol) -> anyhow::Result<Self> {
26-
let cli = Client::builder()
27-
.cookie_provider(Arc::new(Jar::default()))
28-
.build()
29-
.context("unable to build HTTP client to interact with attestation server")?;
30-
31-
Ok(Self { cli, url, protocol })
30+
pub fn negotiation(&self, n: NegotiationRequest) -> anyhow::Result<NegotiationResponse> {
31+
(self.negotiation)(&self.cli, &self.url, n)
3232
}
3333

34-
pub fn negotiation(&mut self, req: NegotiationRequest) -> anyhow::Result<NegotiationResponse> {
35-
// Depending on the underlying protocol of the attestation server, gather negotiation
36-
// parameters accordingly.
37-
match self.protocol {
38-
Protocol::Kbs(mut kbs) => kbs.negotiation(self, req),
39-
}
40-
}
41-
42-
pub fn attestation(&self, req: AttestationRequest) -> anyhow::Result<AttestationResponse> {
43-
// Depending on the underlying protocol of the attestation server, attest TEE evidence
44-
// accoridngly.
45-
match self.protocol {
46-
Protocol::Kbs(kbs) => kbs.attestation(self, req),
47-
}
34+
pub fn attestation(&self, a: AttestationRequest) -> anyhow::Result<AttestationResponse> {
35+
(self.attestation)(&self.cli, &self.url, a)
4836
}
4937
}
5038

5139
/// Attestation Protocol identifier.
5240
#[derive(Clone, Copy, Debug)]
5341
pub enum Protocol {
54-
Kbs(KbsProtocol),
42+
Kbs,
5543
}
5644

5745
impl FromStr for Protocol {
5846
type Err = anyhow::Error;
5947

6048
fn from_str(s: &str) -> Result<Self, Self::Err> {
6149
match &s.to_lowercase()[..] {
62-
"kbs" => Ok(Self::Kbs(KbsProtocol)),
50+
"kbs" => Ok(Self::Kbs),
6351
_ => Err(anyhow!("invalid backend attestation protocol selected")),
6452
}
6553
}
@@ -69,13 +57,13 @@ impl FromStr for Protocol {
6957
/// protocols.
7058
pub trait AttestationProtocol {
7159
fn negotiation(
72-
&mut self,
73-
client: &mut HttpClient,
60+
client: &Client,
61+
url: &str,
7462
req: NegotiationRequest,
7563
) -> anyhow::Result<NegotiationResponse>;
7664
fn attestation(
77-
&self,
78-
client: &HttpClient,
65+
client: &Client,
66+
url: &str,
7967
req: AttestationRequest,
8068
) -> anyhow::Result<AttestationResponse>;
8169
}

aproxy/src/main.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
mod attest;
99
mod backend;
1010

11+
use crate::backend::{kbs::KbsProtocol, *};
1112
use anyhow::Context;
1213
use clap::Parser;
13-
use std::{fs, os::unix::net::UnixListener};
14+
use reqwest::{blocking::Client, cookie::Jar};
15+
use std::{fs, mem, os::unix::net::UnixListener, sync::Arc, thread};
1416

1517
#[derive(Parser, Debug)]
1618
#[clap(version, about, long_about = None)]
@@ -21,7 +23,7 @@ struct Args {
2123

2224
/// Backend attestation protocol that the server implements.
2325
#[clap(long = "protocol")]
24-
backend: backend::Protocol,
26+
backend: Protocol,
2527

2628
/// UNIX domain socket path to the SVSM serial port
2729
#[clap(long)]
@@ -39,13 +41,33 @@ fn main() -> anyhow::Result<()> {
3941
let _ = fs::remove_file(args.unix.clone());
4042
}
4143

44+
// Initialize UNIX listener for attestation requests from SVSM.
4245
let listener = UnixListener::bind(args.unix).context("unable to bind to UNIX socket")?;
4346

47+
// Initialize HTTP socket for attestation server (with specific protocol).
48+
let (negotiation, attestation) = match args.backend {
49+
Protocol::Kbs => (KbsProtocol::negotiation, KbsProtocol::attestation),
50+
};
51+
52+
let http = HttpClient {
53+
cli: Client::builder()
54+
.cookie_provider(Arc::new(Jar::default()))
55+
.build()
56+
.context("unable to build HTTP client to interact with attestation server")?,
57+
url: args.url,
58+
attestation,
59+
negotiation,
60+
};
61+
62+
thread::spawn(move || {
63+
let mut backend = BACKEND.lock().unwrap();
64+
let _ = mem::replace(&mut *backend, Some(http));
65+
});
66+
4467
for stream in listener.incoming() {
4568
match stream {
4669
Ok(mut stream) => {
47-
let mut http_client = backend::HttpClient::new(args.url.clone(), args.backend)?;
48-
attest::attest(&mut stream, &mut http_client)?;
70+
attest::attest(&mut stream)?;
4971
}
5072
Err(_) => {
5173
panic!("error");

0 commit comments

Comments
 (0)