Skip to content

Commit 8b41acf

Browse files
committed
Support for local key provider
1 parent 44f3eb5 commit 8b41acf

File tree

24 files changed

+530
-346
lines changed

24 files changed

+530
-346
lines changed

Cargo.lock

Lines changed: 138 additions & 279 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ members = [
3232
"host-api",
3333
"guest-api",
3434
"load_config",
35+
"key-provider-client",
3536
]
3637
resolver = "2"
3738

@@ -54,6 +55,7 @@ host-api = { path = "host-api", default-features = false }
5455
guest-api = { path = "guest-api", default-features = false }
5556
http-client = { path = "http-client", default-features = false }
5657
load_config = { path = "load_config" }
58+
key-provider-client = { path = "key-provider-client" }
5759

5860
# Core dependencies
5961
anyhow = "1.0.94"
@@ -109,7 +111,7 @@ default-net = "0.22.0"
109111
# Cryptography/Security
110112
aes-gcm = "0.10.3"
111113
curve25519-dalek = "4.1.3"
112-
dcap-qvl = "0.1.6"
114+
dcap-qvl = "0.2.0"
113115
elliptic-curve = { version = "0.13.8", features = ["pkcs8"] }
114116
getrandom = "0.2.15"
115117
hkdf = "0.12.4"
@@ -123,6 +125,7 @@ sha3 = "0.10.8"
123125
blake2 = "0.10.6"
124126
tokio-rustls = { version = "0.26.0", features = ["ring"] }
125127
x25519-dalek = { version = "2.0.1", features = ["static_secrets"] }
128+
sodiumoxide = "0.2.7"
126129

127130
# Certificate/DNS
128131
hickory-resolver = "0.24.1"

host-api/proto/host_api.proto

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,17 @@ message Notification {
1515
string payload = 2;
1616
}
1717

18+
message GetSealingKeyRequest {
19+
bytes quote = 1;
20+
}
21+
22+
message GetSealingKeyResponse {
23+
bytes encrypted_key = 1;
24+
bytes provider_quote = 2;
25+
}
26+
1827
service HostApi {
1928
rpc Info(google.protobuf.Empty) returns (HostInfo);
2029
rpc Notify(Notification) returns (google.protobuf.Empty);
30+
rpc GetSealingKey(GetSealingKeyRequest) returns (GetSealingKeyResponse);
2131
}

key-provider-build/Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ RUN apt update && apt install -y \
2424
wget \
2525
curl \
2626
libclang-dev \
27+
rsyslog \
2728
xorriso
2829

2930
# Runtime dependencies
@@ -34,13 +35,14 @@ RUN apt-get update && \
3435
libsgx-aesm-quote-ex-plugin \
3536
libsgx-aesm-ecdsa-plugin \
3637
libsgx-dcap-quote-verify \
38+
libsgx-dcap-default-qpl \
3739
psmisc
3840

3941
# Install Rust
4042
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
4143
ENV PATH="/root/.cargo/bin:${PATH}"
4244

43-
RUN git clone https://github.com/MoeMahhouk/gramine-sealing-key-provider.git
45+
RUN git clone -b patches https://github.com/kvinwang/gramine-sealing-key-provider
4446

4547
WORKDIR /gramine-sealing-key-provider
4648
# Build gramine-sealing-key-provider binary

key-provider-build/docker-compose.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
services:
22
gramine-sealing-key-provider:
33
container_name: gramine-sealing-key-provider
4+
network_mode: host
45
build:
56
context: .
67
dockerfile: Dockerfile
@@ -9,7 +10,7 @@ services:
910
- "/dev/sgx_enclave:/dev/sgx_enclave"
1011
- "/dev/sgx_provision:/dev/sgx_provision"
1112
volumes:
12-
- ./:/workspace
13+
- "/etc/sgx_default_qcnl.conf:/etc/sgx_default_qcnl.conf"
1314
environment:
1415
- SGX=1
1516
ports:

key-provider-build/entrypoint.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/bin/sh
2-
set -e
3-
AESM_PATH=/opt/intel/sgx-aesm-service/aesm LD_LIBRARY_PATH=/opt/intel/sgx-aesm-service/aesm /opt/intel/sgx-aesm-service/aesm/aesm_service --no-syslog
2+
rsyslogd
3+
AESM_PATH=/opt/intel/sgx-aesm-service/aesm LD_LIBRARY_PATH=/opt/intel/sgx-aesm-service/aesm /opt/intel/sgx-aesm-service/aesm/aesm_service
4+
45
echo "Starting Gramine Sealing Key Provider"
56
make SGX=1 run-provider

key-provider-build/run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/bin/sh
2-
docker compose up --build
2+
docker compose up --build

key-provider-client/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "key-provider-client"
3+
version.workspace = true
4+
authors.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
8+
[dependencies]
9+
anyhow.workspace = true
10+
serde = { workspace = true, features = ["derive"] }
11+
serde_json.workspace = true
12+
sodiumoxide.workspace = true
13+
tokio = { workspace = true, features = ["net", "io-util"] }

key-provider-client/src/guest.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use sodiumoxide::crypto::box_::{self, PublicKey, SecretKey};
2+
use sodiumoxide::crypto::sealedbox;
3+
use std::sync::OnceLock;
4+
5+
pub use box_::PUBLICKEYBYTES;
6+
7+
#[allow(clippy::result_unit_err)]
8+
fn ensure_sodium_initialized() -> Result<(), ()> {
9+
static SODIUM_INIT: OnceLock<Result<(), ()>> = OnceLock::new();
10+
*SODIUM_INIT.get_or_init(sodiumoxide::init)
11+
}
12+
13+
pub fn generate_keypair() -> (PublicKey, SecretKey) {
14+
ensure_sodium_initialized().expect("Failed to initialize sodium");
15+
box_::gen_keypair()
16+
}
17+
18+
#[allow(clippy::result_unit_err)]
19+
pub fn open_sealed_box(
20+
sealed_box: &[u8],
21+
public_key: &PublicKey,
22+
secret_key: &SecretKey,
23+
) -> Result<Vec<u8>, ()> {
24+
ensure_sodium_initialized().expect("Failed to initialize sodium");
25+
sealedbox::open(sealed_box, public_key, secret_key)
26+
}

key-provider-client/src/host.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use anyhow::{bail, Context, Result};
2+
use serde::{Deserialize, Serialize};
3+
use std::net::IpAddr;
4+
use tokio::{
5+
io::{AsyncReadExt, AsyncWriteExt},
6+
net::TcpStream,
7+
};
8+
9+
#[derive(Serialize, Deserialize)]
10+
struct QuoteRequest<'a> {
11+
quote: &'a [u8],
12+
}
13+
14+
#[derive(Serialize, Deserialize, Debug)]
15+
pub struct QuoteResponse {
16+
pub encrypted_key: Vec<u8>,
17+
pub provider_quote: Vec<u8>,
18+
}
19+
20+
pub async fn get_key(quote: Vec<u8>, address: IpAddr, port: u16) -> Result<QuoteResponse> {
21+
if quote.len() > 1024 * 1024 {
22+
bail!("Quote is too long");
23+
}
24+
let mut tcp_stream = TcpStream::connect((address, port))
25+
.await
26+
.context("Failed to connect to key provider")?;
27+
let payload = QuoteRequest { quote: &quote };
28+
let serialized = serde_json::to_vec(&payload)?;
29+
let length = serialized.len() as u32;
30+
tcp_stream
31+
.write_all(&length.to_be_bytes())
32+
.await
33+
.context("Failed to write length")?;
34+
tcp_stream
35+
.write_all(&serialized)
36+
.await
37+
.context("Failed to write payload")?;
38+
39+
let mut response_length = [0; 4];
40+
tcp_stream
41+
.read_exact(&mut response_length)
42+
.await
43+
.context("Failed to read response length")?;
44+
let response_length = u32::from_be_bytes(response_length);
45+
let mut response = vec![0; response_length as usize];
46+
tcp_stream
47+
.read_exact(&mut response)
48+
.await
49+
.context("Failed to read response")?;
50+
let response: QuoteResponse =
51+
serde_json::from_slice(&response).context("Failed to deserialize response")?;
52+
Ok(response)
53+
}

0 commit comments

Comments
 (0)