added mRATLS to tonic examples
This commit is contained in:
parent
e36329c4be
commit
f2f2d545b3
28
Cargo.toml
28
Cargo.toml
@ -19,6 +19,18 @@ ring = "0.17" # hash256
|
||||
rcgen = "0.13"
|
||||
log = "0.4"
|
||||
hex = "0.4"
|
||||
tokio-rustls = "0.26"
|
||||
tower = { version = "0.5", features = ["full"] }
|
||||
tower-http = { version = "0.5", features = ["full"] }
|
||||
hyper = "1.4.1"
|
||||
hyper-util = "0.1.7"
|
||||
hyper-rustls = { version = "0.27", features = ["http2"] }
|
||||
prost = "0.13"
|
||||
|
||||
[dependencies.tonic]
|
||||
version = "0.12"
|
||||
#features = ["rustls-0_23"]
|
||||
optional = true
|
||||
|
||||
[dependencies.actix-web]
|
||||
version = "4.3"
|
||||
@ -52,17 +64,29 @@ version = "1"
|
||||
default-features = false
|
||||
features = ["precommit-hook", "run-cargo-test", "run-cargo-clippy"]
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.12"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
occlum = []
|
||||
reqwest = ["dep:reqwest"]
|
||||
actix-web = ["dep:actix-web", "actix-service", "actix-http"]
|
||||
tonic = ["dep:tonic"]
|
||||
|
||||
|
||||
[[example]]
|
||||
name = "server"
|
||||
name = "mratls_https_server"
|
||||
required-features = ["actix-web"]
|
||||
|
||||
[[example]]
|
||||
name = "client"
|
||||
name = "mratls_https_client"
|
||||
required-features = ["reqwest"]
|
||||
|
||||
[[example]]
|
||||
name = "mratls_grpcs_server"
|
||||
required-features = ["tonic"]
|
||||
|
||||
[[example]]
|
||||
name = "mratls_grpcs_client"
|
||||
required-features = ["tonic"]
|
||||
|
21
README.md
21
README.md
@ -1,6 +1,7 @@
|
||||
# Occlum SGX Remote Attestation integrated in TLS connection
|
||||
|
||||
Steps to test the project:
|
||||
|
||||
```
|
||||
occlum-cargo build --example server --features="occlum,actix-web"
|
||||
strip -s target/x86_64-unknown-linux-musl/debug/examples/server
|
||||
@ -10,3 +11,23 @@ occlum-cargo build --example client --features="occlum,reqwest"
|
||||
strip -s target/x86_64-unknown-linux-musl/debug/examples/client
|
||||
./build_client.sh
|
||||
```
|
||||
|
||||
## Mutual RATLS examples
|
||||
|
||||
Examples show how to use the mRATLS (Mutual Remote Attestation TLS) in different situations:
|
||||
|
||||
* The first example shows how to create mRATLS HTTPS server and client
|
||||
* The second example shows how to create mRATLS GRPCs server and client
|
||||
|
||||
Both the server and the client must be running inside the enclave.
|
||||
So during the remote attestation peers, acquire their RA certificates.
|
||||
And during the TLS handshake, they verify each other's RA certificates.
|
||||
The config allows to whitelist MRENCLAVE, MRSIGNER, PRODID, SVN of the peer.
|
||||
|
||||
## RATLS examples
|
||||
|
||||
Example shows how to create RATLS HTTPS server and client.
|
||||
The server must be running inside the enclave.
|
||||
The client can be running anywhere.
|
||||
The server config allows to whitelist the public ec25519 key of the client.
|
||||
The client config allows to whitelist MRENCLAVE, MRSIGNER, PRODID, SVN of the server.
|
||||
|
6
build.rs
Normal file
6
build.rs
Normal file
@ -0,0 +1,6 @@
|
||||
fn main() {
|
||||
tonic_build::configure()
|
||||
.build_server(true)
|
||||
.compile(&["examples/echo.proto"], &["examples"])
|
||||
.unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e));
|
||||
}
|
37
examples/echo.proto
Normal file
37
examples/echo.proto
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package grpc.examples.unaryecho;
|
||||
|
||||
// EchoRequest is the request for echo.
|
||||
message EchoRequest {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
// EchoResponse is the response for echo.
|
||||
message EchoResponse {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
// Echo is the echo service.
|
||||
service Echo {
|
||||
// UnaryEcho is unary echo.
|
||||
rpc UnaryEcho(EchoRequest) returns (EchoResponse) {}
|
||||
}
|
64
examples/mratls_grpcs_client.rs
Normal file
64
examples/mratls_grpcs_client.rs
Normal file
@ -0,0 +1,64 @@
|
||||
pub mod pb {
|
||||
tonic::include_proto!("/grpc.examples.unaryecho");
|
||||
}
|
||||
|
||||
use hyper::Uri;
|
||||
use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};
|
||||
use occlum_ratls::prelude::*;
|
||||
use occlum_ratls::RaTlsConfigBuilder;
|
||||
use occlum_sgx::SGXMeasurement;
|
||||
use pb::{echo_client::EchoClient, EchoRequest};
|
||||
use tokio_rustls::rustls::ClientConfig;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mrsigner_hex = "83D719E77DEACA1470F6BAF62A4D774303C899DB69020F9C70EE1DFC08C7CE9E";
|
||||
let mut mrsigner = [0u8; 32];
|
||||
hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed");
|
||||
|
||||
let config = RaTlsConfig::new().allow_instance_measurement(
|
||||
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]),
|
||||
);
|
||||
|
||||
let tls = ClientConfig::from_ratls_config(config)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?;
|
||||
|
||||
let mut http = HttpConnector::new();
|
||||
http.enforce_http(false);
|
||||
|
||||
// We have to do some wrapping here to map the request type from
|
||||
// `https://example.com` -> `https://[::1]:50051` because `rustls`
|
||||
// doesn't accept ip's as `ServerName`.
|
||||
let connector = tower::ServiceBuilder::new()
|
||||
.layer_fn(move |s| {
|
||||
let tls = tls.clone();
|
||||
|
||||
hyper_rustls::HttpsConnectorBuilder::new()
|
||||
.with_tls_config(tls)
|
||||
.https_or_http()
|
||||
.enable_http2()
|
||||
.wrap_connector(s)
|
||||
})
|
||||
// Since our cert is signed with `example.com` but we actually want to connect
|
||||
// to a local server we will override the Uri passed from the `HttpsConnector`
|
||||
// and map it to the correct `Uri` that will connect us directly to the local server.
|
||||
.map_request(|_| Uri::from_static("https://[::1]:50051"))
|
||||
.service(http);
|
||||
|
||||
let client = hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(connector);
|
||||
|
||||
// Using `with_origin` will let the codegenerated client set the `scheme` and
|
||||
// `authority` from the provided `Uri`.
|
||||
let uri = Uri::from_static("https://example.com");
|
||||
let mut client = EchoClient::with_origin(client, uri);
|
||||
|
||||
let request = tonic::Request::new(EchoRequest {
|
||||
message: "hello".into(),
|
||||
});
|
||||
|
||||
let response = client.unary_echo(request).await?;
|
||||
|
||||
println!("RESPONSE={:?}", response);
|
||||
|
||||
Ok(())
|
||||
}
|
114
examples/mratls_grpcs_server.rs
Normal file
114
examples/mratls_grpcs_server.rs
Normal file
@ -0,0 +1,114 @@
|
||||
pub mod pb {
|
||||
tonic::include_proto!("/grpc.examples.unaryecho");
|
||||
}
|
||||
|
||||
use hyper::server::conn::http2::Builder;
|
||||
use hyper_util::{
|
||||
rt::{TokioExecutor, TokioIo},
|
||||
service::TowerToHyperService,
|
||||
};
|
||||
use pb::{EchoRequest, EchoResponse};
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio_rustls::{
|
||||
rustls::{pki_types::CertificateDer, ServerConfig},
|
||||
TlsAcceptor,
|
||||
};
|
||||
use tonic::{body::boxed, service::Routes, Request, Response, Status};
|
||||
use tower::ServiceBuilder;
|
||||
use tower::ServiceExt;
|
||||
|
||||
use occlum_ratls::prelude::*;
|
||||
use occlum_ratls::RaTlsConfigBuilder;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mrsigner_hex = "83D719E77DEACA1470F6BAF62A4D774303C899DB69020F9C70EE1DFC08C7CE9E";
|
||||
let mut mrsigner = [0u8; 32];
|
||||
hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed");
|
||||
|
||||
let config = RaTlsConfig::new().allow_instance_measurement(
|
||||
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]),
|
||||
);
|
||||
|
||||
let mut tls = ServerConfig::from_ratls_config(config)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?;
|
||||
tls.alpn_protocols = vec![b"h2".to_vec()];
|
||||
|
||||
let server = EchoServer::default();
|
||||
|
||||
let svc = Routes::new(pb::echo_server::EchoServer::new(server)).prepare();
|
||||
|
||||
let http = Builder::new(TokioExecutor::new());
|
||||
|
||||
let listener = TcpListener::bind("[::1]:50051").await?;
|
||||
let tls_acceptor = TlsAcceptor::from(Arc::new(tls));
|
||||
|
||||
loop {
|
||||
let (conn, addr) = match listener.accept().await {
|
||||
Ok(incoming) => incoming,
|
||||
Err(e) => {
|
||||
eprintln!("Error accepting connection: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let http = http.clone();
|
||||
let tls_acceptor = tls_acceptor.clone();
|
||||
let svc = svc.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut certificates = Vec::new();
|
||||
|
||||
let conn = tls_acceptor
|
||||
.accept_with(conn, |info| {
|
||||
if let Some(certs) = info.peer_certificates() {
|
||||
for cert in certs {
|
||||
certificates.push(cert.clone());
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let extension_layer =
|
||||
tower_http::add_extension::AddExtensionLayer::new(Arc::new(ConnInfo {
|
||||
addr,
|
||||
certificates,
|
||||
}));
|
||||
let svc = ServiceBuilder::new().layer(extension_layer).service(svc);
|
||||
|
||||
http.serve_connection(
|
||||
TokioIo::new(conn),
|
||||
TowerToHyperService::new(svc.map_request(|req: hyper::Request<_>| req.map(boxed))),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ConnInfo {
|
||||
addr: std::net::SocketAddr,
|
||||
certificates: Vec<CertificateDer<'static>>,
|
||||
}
|
||||
|
||||
type EchoResult<T> = Result<Response<T>, Status>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EchoServer {}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl pb::echo_server::Echo for EchoServer {
|
||||
async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {
|
||||
let conn_info = request.extensions().get::<Arc<ConnInfo>>().unwrap();
|
||||
println!(
|
||||
"Got a request from: {:?} with certs: {:?}",
|
||||
conn_info.addr, conn_info.certificates
|
||||
);
|
||||
|
||||
let message = request.into_inner().message;
|
||||
Ok(Response::new(EchoResponse { message }))
|
||||
}
|
||||
}
|
@ -2,3 +2,4 @@
|
||||
pub mod actix_web;
|
||||
#[cfg(feature = "reqwest")]
|
||||
pub mod reqwest;
|
||||
//mod tonic_server;
|
||||
|
97
src/http/tonic_server.rs
Normal file
97
src/http/tonic_server.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use hyper::server::conn::http2::Builder;
|
||||
use hyper_util::{
|
||||
rt::{TokioExecutor, TokioIo},
|
||||
service::TowerToHyperService,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio_rustls::{
|
||||
rustls::{pki_types::CertificateDer, ServerConfig},
|
||||
TlsAcceptor,
|
||||
};
|
||||
use tonic::transport::server::TcpIncoming;
|
||||
use tonic::{body::boxed, service::Routes, Request, Response, Status};
|
||||
use tower::ServiceExt;
|
||||
use tower_http::ServiceBuilderExt;
|
||||
|
||||
use crate::{config::RaTlsConfig, RaTlsConfigBuilder};
|
||||
|
||||
fn bind_ratls(config: RaTlsConfig) -> Result<(), std::io::Error> {
|
||||
let config = ServerConfig::from_ratls_config(config)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?;
|
||||
let tls_acceptor = TlsAcceptor::from(Arc::new(config));
|
||||
|
||||
// add tls_acceptor to the server
|
||||
let incoming = TcpIncoming::new("[::1]:50051".parse().unwrap(), true, None)?;
|
||||
|
||||
let svc = tower::ServiceBuilder::new()
|
||||
.add_extension(Arc::new(ConnInfo { addr, certificates }))
|
||||
.service(svc);
|
||||
|
||||
self.bind_rustls_0_23(addr, config)
|
||||
}
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let listener = TcpListener::bind("[::1]:50051").await?;
|
||||
let tls_acceptor = TlsAcceptor::from(Arc::new(tls));
|
||||
|
||||
loop {
|
||||
let (conn, addr) = match listener.accept().await {
|
||||
Ok(incoming) => incoming,
|
||||
Err(e) => {
|
||||
eprintln!("Error accepting connection: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let http = http.clone();
|
||||
let tls_acceptor = tls_acceptor.clone();
|
||||
let svc = svc.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut certificates = Vec::new();
|
||||
|
||||
let conn = tls_acceptor
|
||||
.accept_with(conn, |info| {
|
||||
if let Some(certs) = info.peer_certificates() {
|
||||
for cert in certs {
|
||||
certificates.push(cert.clone());
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
http.serve_connection(
|
||||
TokioIo::new(conn),
|
||||
TowerToHyperService::new(svc.map_request(|req: http::Request<_>| req.map(boxed))),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ConnInfo {
|
||||
addr: std::net::SocketAddr,
|
||||
certificates: Vec<CertificateDer<'static>>,
|
||||
}
|
||||
|
||||
type EchoResult<T> = Result<Response<T>, Status>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EchoServer {}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl pb::echo_server::Echo for EchoServer {
|
||||
async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {
|
||||
let conn_info = request.extensions().get::<Arc<ConnInfo>>().unwrap();
|
||||
println!(
|
||||
"Got a request from: {:?} with certs: {:?}",
|
||||
conn_info.addr, conn_info.certificates
|
||||
);
|
||||
|
||||
let message = request.into_inner().message;
|
||||
Ok(Response::new(EchoResponse { message }))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user