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"
 | 
					rcgen = "0.13"
 | 
				
			||||||
log = "0.4"
 | 
					log = "0.4"
 | 
				
			||||||
hex = "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]
 | 
					[dependencies.actix-web]
 | 
				
			||||||
version = "4.3"
 | 
					version = "4.3"
 | 
				
			||||||
@ -52,17 +64,29 @@ version = "1"
 | 
				
			|||||||
default-features = false
 | 
					default-features = false
 | 
				
			||||||
features = ["precommit-hook", "run-cargo-test", "run-cargo-clippy"]
 | 
					features = ["precommit-hook", "run-cargo-test", "run-cargo-clippy"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[build-dependencies]
 | 
				
			||||||
 | 
					tonic-build = "0.12"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[features]
 | 
					[features]
 | 
				
			||||||
default = []
 | 
					default = []
 | 
				
			||||||
occlum = []
 | 
					occlum = []
 | 
				
			||||||
reqwest = ["dep:reqwest"]
 | 
					reqwest = ["dep:reqwest"]
 | 
				
			||||||
actix-web = ["dep:actix-web", "actix-service", "actix-http"]
 | 
					actix-web = ["dep:actix-web", "actix-service", "actix-http"]
 | 
				
			||||||
 | 
					tonic = ["dep:tonic"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[example]]
 | 
					[[example]]
 | 
				
			||||||
name = "server"
 | 
					name = "mratls_https_server"
 | 
				
			||||||
required-features = ["actix-web"]
 | 
					required-features = ["actix-web"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[example]]
 | 
					[[example]]
 | 
				
			||||||
name = "client"
 | 
					name = "mratls_https_client"
 | 
				
			||||||
required-features = ["reqwest"]
 | 
					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
 | 
					# Occlum SGX Remote Attestation integrated in TLS connection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Steps to test the project:
 | 
					Steps to test the project:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
occlum-cargo build --example server --features="occlum,actix-web"
 | 
					occlum-cargo build --example server --features="occlum,actix-web"
 | 
				
			||||||
strip -s target/x86_64-unknown-linux-musl/debug/examples/server
 | 
					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
 | 
					strip -s target/x86_64-unknown-linux-musl/debug/examples/client
 | 
				
			||||||
./build_client.sh
 | 
					./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;
 | 
					pub mod actix_web;
 | 
				
			||||||
#[cfg(feature = "reqwest")]
 | 
					#[cfg(feature = "reqwest")]
 | 
				
			||||||
pub mod 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