mirror of
https://github.com/actix/examples
synced 2025-06-26 17:17:42 +02:00
restructure folders
This commit is contained in:
14
https-tls/awc_https/Cargo.toml
Normal file
14
https-tls/awc_https/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "awc_https"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.0.0-rc.1"
|
||||
awc = { version = "3.0.0-beta.19", features = ["rustls"] }
|
||||
|
||||
env_logger = "0.9"
|
||||
log = "0.4"
|
||||
mime = "0.3"
|
||||
rustls = "0.20"
|
||||
webpki-roots = "0.22"
|
5
https-tls/awc_https/README.md
Normal file
5
https-tls/awc_https/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
The goal of this example is to show you how to use the `awc` for secure HTTPS communication using Rustls.
|
||||
|
||||
It uses best practices for efficient client set up and demonstrates how to increase the default payload limit.
|
||||
|
||||
This example downloads a 10MB image from Wikipedia when hitting a server route. `cargo run` this example and go to <http://localhost:8080/> in your browser.
|
83
https-tls/awc_https/src/main.rs
Normal file
83
https-tls/awc_https/src/main.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use std::{sync::Arc, time::Instant};
|
||||
|
||||
use actix_web::{get, middleware, web::Data, App, HttpResponse, HttpServer};
|
||||
use awc::{http::header, Client, Connector};
|
||||
use rustls::{ClientConfig, OwnedTrustAnchor, RootCertStore};
|
||||
|
||||
const MAP_URL: &str =
|
||||
"https://upload.wikimedia.org/wikipedia/commons/f/ff/Pizigani_1367_Chart_10MB.jpg";
|
||||
|
||||
#[get("/")]
|
||||
async fn fetch_image(client: Data<Client>) -> HttpResponse {
|
||||
let start = Instant::now();
|
||||
|
||||
let mut res = client.get(MAP_URL).send().await.unwrap();
|
||||
|
||||
if !res.status().is_success() {
|
||||
log::error!("Wikipedia did not return expected image");
|
||||
return HttpResponse::InternalServerError().finish();
|
||||
}
|
||||
|
||||
let payload = res
|
||||
.body()
|
||||
// expected image is larger than default body limit
|
||||
.limit(20_000_000) // 20MB
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
log::info!(
|
||||
"it took {}ms to download image to memory",
|
||||
start.elapsed().as_millis()
|
||||
);
|
||||
|
||||
HttpResponse::Ok()
|
||||
.content_type(mime::IMAGE_JPEG)
|
||||
.body(payload)
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
|
||||
let client_tls_config = Arc::new(rustls_config());
|
||||
|
||||
log::info!("starting HTTP server at http://localhost:8080");
|
||||
|
||||
HttpServer::new(move || {
|
||||
// create client _inside_ `HttpServer::new` closure to have one per worker thread
|
||||
let client = Client::builder()
|
||||
// Wikipedia requires a User-Agent header to make requests
|
||||
.add_default_header((header::USER_AGENT, "awc-example/1.0"))
|
||||
// a "connector" wraps the stream into an encrypted connection
|
||||
.connector(Connector::new().rustls(Arc::clone(&client_tls_config)))
|
||||
.finish();
|
||||
|
||||
App::new()
|
||||
.wrap(middleware::Logger::default())
|
||||
.app_data(Data::new(client))
|
||||
.service(fetch_image)
|
||||
})
|
||||
.bind(("127.0.0.1", 8080))?
|
||||
.workers(2)
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
||||
/// Create simple rustls client config from root certificates.
|
||||
fn rustls_config() -> ClientConfig {
|
||||
let mut root_store = RootCertStore::empty();
|
||||
root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(
|
||||
|ta| {
|
||||
OwnedTrustAnchor::from_subject_spki_name_constraints(
|
||||
ta.subject,
|
||||
ta.spki,
|
||||
ta.name_constraints,
|
||||
)
|
||||
},
|
||||
));
|
||||
|
||||
rustls::ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_root_certificates(root_store)
|
||||
.with_no_client_auth()
|
||||
}
|
16
https-tls/openssl-auto-le/Cargo.toml
Normal file
16
https-tls/openssl-auto-le/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "openssl-auto-le"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = { version = "4.0.0-rc.2", features = ["openssl"] }
|
||||
actix-files = "0.6.0-beta.16"
|
||||
|
||||
acme-micro = "0.12"
|
||||
anyhow = "1"
|
||||
env_logger = "0.9"
|
||||
futures-util = { version = "0.3.7", default-features = false, features = ["std"] }
|
||||
log = "0.4"
|
||||
openssl = { version = "0.10", features = ["v110"] }
|
||||
reqwest = "0.11"
|
5
https-tls/openssl-auto-le/README.md
Normal file
5
https-tls/openssl-auto-le/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Automatic Let's Encrypt TLS/SSL (via OpenSSL)
|
||||
|
||||
We use (acme-micro)[https://github.com/kpcyrd/acme-micro] to auto-generate TLS/SSL certificates via OpenSSL for a given domain.
|
||||
|
||||
Process is explained in code.
|
198
https-tls/openssl-auto-le/src/main.rs
Normal file
198
https-tls/openssl-auto-le/src/main.rs
Normal file
@ -0,0 +1,198 @@
|
||||
use std::{fs, time::Duration};
|
||||
|
||||
use acme_micro::{create_p384_key, Certificate, Directory, DirectoryUrl};
|
||||
use actix_files::Files;
|
||||
use actix_web::{rt, web, App, HttpRequest, HttpServer, Responder};
|
||||
use anyhow::anyhow;
|
||||
use openssl::{
|
||||
pkey::PKey,
|
||||
ssl::{SslAcceptor, SslMethod},
|
||||
x509::X509,
|
||||
};
|
||||
|
||||
pub async fn gen_tls_cert(
|
||||
user_email: &str,
|
||||
user_domain: &str,
|
||||
) -> anyhow::Result<Certificate> {
|
||||
// Create acme-challenge dir.
|
||||
fs::create_dir("./acme-challenge").unwrap();
|
||||
|
||||
let domain = user_domain.to_string();
|
||||
|
||||
// Create temporary Actix Web server for ACME challenge.
|
||||
let srv = HttpServer::new(|| {
|
||||
App::new().service(
|
||||
Files::new(
|
||||
// HTTP route
|
||||
"/.well-known/acme-challenge",
|
||||
// Server's dir
|
||||
"acme-challenge",
|
||||
)
|
||||
.show_files_listing(),
|
||||
)
|
||||
})
|
||||
.bind((domain, 80))?
|
||||
.shutdown_timeout(0)
|
||||
.run();
|
||||
|
||||
let srv_handle = srv.handle();
|
||||
let srv_task = rt::spawn(srv);
|
||||
|
||||
// Use DirectoryUrl::LetsEncryptStaging for dev/testing.
|
||||
let url = DirectoryUrl::LetsEncrypt;
|
||||
|
||||
// Create a directory entrypoint.
|
||||
let dir = Directory::from_url(url)?;
|
||||
|
||||
// Our contact addresses; note the `mailto:`
|
||||
let user_email_mailto: String = "mailto:{email}".replace("{email}", user_email);
|
||||
let contact = vec![user_email_mailto];
|
||||
|
||||
// Generate a private key and register an account with our ACME provider.
|
||||
// We should write it to disk any use `load_account` afterwards.
|
||||
let acc = dir.register_account(contact.clone())?;
|
||||
|
||||
// Load an account from string
|
||||
let privkey = acc.acme_private_key_pem()?;
|
||||
let acc = dir.load_account(&privkey, contact)?;
|
||||
|
||||
// Order a new TLS certificate for the domain.
|
||||
let mut ord_new = acc.new_order(user_domain, &[])?;
|
||||
|
||||
// If the ownership of the domain have already been
|
||||
// authorized in a previous order, we might be able to
|
||||
// skip validation. The ACME API provider decides.
|
||||
let ord_csr = loop {
|
||||
// Are we done?
|
||||
if let Some(ord_csr) = ord_new.confirm_validations() {
|
||||
break ord_csr;
|
||||
}
|
||||
|
||||
// Get the possible authorizations (for a single domain
|
||||
// this will only be one element).
|
||||
let auths = ord_new.authorizations()?;
|
||||
|
||||
// For HTTP, the challenge is a text file that needs to
|
||||
// be placed in our web server's root:
|
||||
//
|
||||
// <mydomain>/acme-challenge/<token>
|
||||
//
|
||||
// The important thing is that it's accessible over the
|
||||
// web for the domain we are trying to get a
|
||||
// certificate for:
|
||||
//
|
||||
// http://mydomain.io/.well-known/acme-challenge/<token>
|
||||
let chall = auths[0]
|
||||
.http_challenge()
|
||||
.ok_or(anyhow!("no HTTP challenge accessible"))?;
|
||||
|
||||
// The token is the filename.
|
||||
let token = chall.http_token();
|
||||
|
||||
// The proof is the contents of the file
|
||||
let proof = chall.http_proof()?;
|
||||
|
||||
// Place the file/contents in the correct place.
|
||||
let path = format!("acme-challenge/{}", token);
|
||||
fs::write(&path, &proof)?;
|
||||
|
||||
// After the file is accessible from the web, the calls
|
||||
// this to tell the ACME API to start checking the
|
||||
// existence of the proof.
|
||||
//
|
||||
// The order at ACME will change status to either
|
||||
// confirm ownership of the domain, or fail due to the
|
||||
// not finding the proof. To see the change, we poll
|
||||
// the API with 5000 milliseconds wait between.
|
||||
chall.validate(Duration::from_millis(5000))?;
|
||||
|
||||
// Update the state against the ACME API.
|
||||
ord_new.refresh()?;
|
||||
};
|
||||
|
||||
// Ownership is proven. Create a private key for
|
||||
// the certificate. These are provided for convenience; we
|
||||
// could provide our own keypair instead if we want.
|
||||
let pkey_pri = create_p384_key()?;
|
||||
|
||||
// Submit the CSR. This causes the ACME provider to enter a
|
||||
// state of "processing" that must be polled until the
|
||||
// certificate is either issued or rejected. Again we poll
|
||||
// for the status change.
|
||||
let ord_cert = ord_csr.finalize_pkey(pkey_pri, Duration::from_millis(5000))?;
|
||||
|
||||
// Now download the certificate. Also stores the cert in
|
||||
// the persistence.
|
||||
let cert = ord_cert.download_cert()?;
|
||||
|
||||
// Stop temporary server for ACME challenge
|
||||
srv_handle.stop(true).await;
|
||||
srv_task.await??;
|
||||
|
||||
// Delete acme-challenge dir
|
||||
fs::remove_dir_all("./acme-challenge")?;
|
||||
|
||||
Ok(cert)
|
||||
}
|
||||
|
||||
// "Hello world" example
|
||||
async fn index(_req: HttpRequest) -> impl Responder {
|
||||
"Hello world!"
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
|
||||
// IMPORTANT: Use your own email and domain!
|
||||
let email = "example@example.com";
|
||||
let domain = "mydomain.io";
|
||||
|
||||
// Load keys
|
||||
// ==============================================
|
||||
// = IMPORTANT: =
|
||||
// = This process has to be repeated =
|
||||
// = before the certificate expires (< 90 days) =
|
||||
// ==============================================
|
||||
// Obtain TLS certificate
|
||||
let cert = gen_tls_cert(email, domain).await?;
|
||||
let mut ssl_builder = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
|
||||
|
||||
// Get and add private key
|
||||
let pkey_der = PKey::private_key_from_der(&cert.private_key_der()?)?;
|
||||
ssl_builder.set_private_key(&pkey_der)?;
|
||||
|
||||
// Get and add certificate
|
||||
let cert_der = X509::from_der(&cert.certificate_der()?)?;
|
||||
ssl_builder.set_certificate(&cert_der)?;
|
||||
|
||||
// Get and add intermediate certificate to the chain
|
||||
let icert_url = "https://letsencrypt.org/certs/lets-encrypt-r3.der";
|
||||
let icert_bytes = reqwest::get(icert_url).await?.bytes().await?;
|
||||
let intermediate_cert = X509::from_der(&icert_bytes)?;
|
||||
ssl_builder.add_extra_chain_cert(intermediate_cert)?;
|
||||
|
||||
// NOTE:
|
||||
// Storing pkey_der, cert_der and intermediate_cert somewhere
|
||||
// (in order to avoid unnecessarily regeneration of TLS/SSL) is recommended
|
||||
|
||||
log::info!("starting HTTP server at http://localhost:443");
|
||||
|
||||
// Start HTTP server!
|
||||
let srv = HttpServer::new(|| App::new().route("/", web::get().to(index)))
|
||||
.bind_openssl((domain, 443), ssl_builder)?
|
||||
.run();
|
||||
|
||||
let srv_handle = srv.handle();
|
||||
|
||||
let _auto_shutdown_task = rt::spawn(async move {
|
||||
// Shutdown server every 4 weeks so that TLS certs can be regenerated if needed.
|
||||
// This is only appropriate in contexts like Kubernetes which can orchestrate restarts.
|
||||
rt::time::sleep(Duration::from_secs(60 * 60 * 24 * 28)).await;
|
||||
srv_handle.stop(true).await;
|
||||
});
|
||||
|
||||
srv.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
9
https-tls/openssl/Cargo.toml
Normal file
9
https-tls/openssl/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "openssl-example"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = { version = "4.0.0-beta.21", features = ["openssl"] }
|
||||
env_logger = "0.9"
|
||||
openssl = "0.10"
|
34
https-tls/openssl/README.md
Normal file
34
https-tls/openssl/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# tls example
|
||||
|
||||
## Usage
|
||||
|
||||
### Certificate
|
||||
|
||||
We put the self-signed certificate in this directory as an example
|
||||
but your browser would complain that it isn't secure.
|
||||
So we recommend to use [`mkcert`] to trust it. To use local CA, you should run:
|
||||
|
||||
```bash
|
||||
mkcert -install
|
||||
```
|
||||
|
||||
If you want to generate your own cert/private key file, then run:
|
||||
|
||||
```bash
|
||||
mkcert 127.0.0.1
|
||||
```
|
||||
|
||||
[`mkcert`]: https://github.com/FiloSottile/mkcert
|
||||
|
||||
### server
|
||||
|
||||
```bash
|
||||
cd security/openssl
|
||||
cargo run (or ``cargo watch -x run``)
|
||||
# Started http server: 127.0.0.1:8443
|
||||
```
|
||||
|
||||
### web client
|
||||
|
||||
- curl: ``curl -v https://127.0.0.1:8443/index.html --compressed -k``
|
||||
- browser: [https://127.0.0.1:8443/index.html](https://127.0.0.1:8443/index.html)
|
24
https-tls/openssl/cert.pem
Normal file
24
https-tls/openssl/cert.pem
Normal file
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEDDCCAnSgAwIBAgIQLu2TV80hCgYgZe18ovEhmzANBgkqhkiG9w0BAQsFADBZ
|
||||
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExFzAVBgNVBAsMDmh1eXV1
|
||||
bWlAcmlyaWthMR4wHAYDVQQDDBVta2NlcnQgaHV5dXVtaUByaXJpa2EwHhcNMTkw
|
||||
NjAxMDAwMDAwWhcNMzAwNTE5MDM0MjI2WjBCMScwJQYDVQQKEx5ta2NlcnQgZGV2
|
||||
ZWxvcG1lbnQgY2VydGlmaWNhdGUxFzAVBgNVBAsMDmh1eXV1bWlAcmlyaWthMIIB
|
||||
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5fRUIbEv2DjBmK7+syGVvh3I
|
||||
FWDlVjU9N7ypxauQbXPHAzpATzghLnpm5CqQFoTnJwA4//A85775djcVlsAUqen2
|
||||
ZYi+4jTYeuRLrAJ0dkrUS8/7+T0fGzGZ8obCsII5iSE2BMS7AxbqlQtClDdkNwcK
|
||||
rCuzrmIyMA8Bc2V231xIgcWFJ7en8OaZJRlYYK7kp2cJ8g0PbPnVq+9TAfFYcKEy
|
||||
FWqJsYYY36bLbWyqYXGMOtAh2bhy+YGYL3Jhk+cw7iMCjye4FbDAIQzt9cH1KGGM
|
||||
2VWZFiwn6VJquX1Z+n9KAhfzxuzYQHSrlJ+Rt++gezpTtNw8q15Ko78oiu7CLQID
|
||||
AQABo2cwZTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYD
|
||||
VR0TAQH/BAIwADAfBgNVHSMEGDAWgBSljCjB0QNrBG+8BV3nFnUyBn54jjAPBgNV
|
||||
HREECDAGhwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBgQAsUrfA8deCaHYy7wB1jEVK
|
||||
pNZKRNcDKxqr/PXJQlfwwlq1qZTBzloMNTzfVBRkn/I7y+Bj/b1uYFmjQoQ3qG9s
|
||||
tIXFCYOop1cLltmWXC479/UtbEmhz0t+mzK0MFkLhxtbKqwvMGbcGGDFI/2/MGZN
|
||||
XFZXL1bclFieZxO5ePEkZSDkPcWvh9uYWCp8r7H6aAd/iwH4lDxfajyhDneRmd/v
|
||||
Mq0PgqTZhVHOP7JdVNA+6cewROyPL7ElLs66ujE9hsRvs6eXLjgLZrHOZShnoQxK
|
||||
JJv8UfoE90FX1uDt9w9i3raig/O3oePNkU263kJlR+J1rdVdYV+pCCb7L4Vk+1l3
|
||||
S4VFVGVHN8x35dISCJwZrtnqPlfpCiLjtEJOu1zJUEY2Q0n7Km3z3zQcs6iCeOQi
|
||||
O9MVJ4aiALdNvyCG7lL4+AJ/kWbwHFM6wOAKSrkpZ20msMuEgIlhCOi8PgYlKb+b
|
||||
V/lV6IJPVrAOOclgcvtfZ/LdsTxn15yLIieqgR0Lf/s=
|
||||
-----END CERTIFICATE-----
|
28
https-tls/openssl/key.pem
Normal file
28
https-tls/openssl/key.pem
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDl9FQhsS/YOMGY
|
||||
rv6zIZW+HcgVYOVWNT03vKnFq5Btc8cDOkBPOCEuembkKpAWhOcnADj/8Dznvvl2
|
||||
NxWWwBSp6fZliL7iNNh65EusAnR2StRLz/v5PR8bMZnyhsKwgjmJITYExLsDFuqV
|
||||
C0KUN2Q3BwqsK7OuYjIwDwFzZXbfXEiBxYUnt6fw5pklGVhgruSnZwnyDQ9s+dWr
|
||||
71MB8VhwoTIVaomxhhjfpsttbKphcYw60CHZuHL5gZgvcmGT5zDuIwKPJ7gVsMAh
|
||||
DO31wfUoYYzZVZkWLCfpUmq5fVn6f0oCF/PG7NhAdKuUn5G376B7OlO03DyrXkqj
|
||||
vyiK7sItAgMBAAECggEBAIabZmAukz4zwwe4cDm1kC0wy73P8Y9sLMCivJKMYkff
|
||||
vQBjqd91kN7fIbmwPJYiCBlpZPRU0aIqxWZwyj9rgu0Pmn9G884AdzRAzRcMfNX9
|
||||
6ZXTUsFMCRhnCaHRRsgCAuIFwdQ6wOoHERxb8gZHAm+/vHyaPFz4+D3vmr7NBy+p
|
||||
fgpdDCGwkltKI73efk6H4oAeyztDwNev/TZ3Y+O3UKuAUfVReBX0us/lYgEf/KXV
|
||||
USd7envxACy+PDcqmn/HL6IUnbrc1zB92dmSSUUtLjOz//z1zM05ME/E2keMQwsW
|
||||
7LDen0Lm0Nh6AcOCxmnN4u0lJ3nWzU7PsHJKY/LznPUCgYEA5kQq/AG6LlL9Iu1E
|
||||
Y55AB1rkvseof41liaqXVccB5tr55IF75d0wPd6jF04W+x6LwmL6EUYPRGkkOdHE
|
||||
raz9CDE3a7hWbAghxIwLrI1s+faT5aaHG9o6mTeDyfgEEoBg8X2nQHQJPayDJZcW
|
||||
kiXQyHEtj/G4m/Y+WDFXastZz8MCgYEA/6c8+cI3Slvg3CZLG9f6rdAlrOSIQynF
|
||||
muXyVeUaxrU0OPC9H3WEwWv7n4adQU2g0L6TBTdlOOiv5SPIsOPQVN2JZVdxwg0V
|
||||
n5+7/WRrI9rAXnmu1x0q1e/TZ9Msggmrn5SdHaEfuug4DnHv4nct356joDwYB2i3
|
||||
xYl+yCSMd08CgYEAqduvOaasiG9/e7w6rqGV6dcK1hDCIxVSyXKloAjlRj5SCFXb
|
||||
53x6kakh9ZcNLMEjp4kLnqJnsLc+mcg7pUHuhZSIpVWdqqN1BV+pXOgWc22JO+bT
|
||||
05/vigaBmQLzPhKlcH6YWds+1dfkBl6lr7llgfa6/Wv6GlJTOwtqyMSow7ECgYEA
|
||||
zGQ8j8ICymRihh/ndL9cH5KGTI/5kRjYb1rgQGQG4E8HDW8LBRfDp5BZf9Tz7L3P
|
||||
kJSMnmMHflQqLJxLW4EHkpH7wxYCUQ589z2R4qhiMCw4GFBYxIsBMEGpVxyyPNTW
|
||||
baM3afTjlV8LUiEtlHWMK3h9gSIKZAIIytl+jy0JUGkCgYA3wrpcG3wgXeuEtoie
|
||||
ve/kFS5JRaOeV/9OLE2JGaGaumPlN0L14kCVvb6uqLa/P88BwBUxvGQ7FDBdh4sk
|
||||
ypuSe9ZPCNDgnsbnfM8QgFqIW6MDdizLtj7no1SKeaUU3JWWc0kH2KWMw/sYZ7ec
|
||||
0tcEInxEd7FbssGfMqF9fQtnNw==
|
||||
-----END PRIVATE KEY-----
|
44
https-tls/openssl/src/main.rs
Normal file
44
https-tls/openssl/src/main.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use std::io;
|
||||
|
||||
use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
/// simple handle
|
||||
async fn index(req: HttpRequest) -> Result<HttpResponse, Error> {
|
||||
println!("{:?}", req);
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("text/plain")
|
||||
.body("Welcome!"))
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
std::env::set_var("RUST_LOG", "actix_web=debug");
|
||||
env_logger::init();
|
||||
|
||||
println!("Started http server: 127.0.0.1:8443");
|
||||
|
||||
// load ssl keys
|
||||
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
|
||||
builder
|
||||
.set_private_key_file("key.pem", SslFiletype::PEM)
|
||||
.unwrap();
|
||||
builder.set_certificate_chain_file("cert.pem").unwrap();
|
||||
|
||||
HttpServer::new(|| {
|
||||
App::new()
|
||||
// enable logger
|
||||
.wrap(middleware::Logger::default())
|
||||
// register simple handler, handle all methods
|
||||
.service(web::resource("/index.html").to(index))
|
||||
// with path parameters
|
||||
.service(web::resource("/").route(web::get().to(|| async {
|
||||
HttpResponse::Found()
|
||||
.append_header(("LOCATION", "/index.html"))
|
||||
.finish()
|
||||
})))
|
||||
})
|
||||
.bind_openssl("127.0.0.1:8443", builder)?
|
||||
.run()
|
||||
.await
|
||||
}
|
12
https-tls/rustls-client-cert/Cargo.toml
Normal file
12
https-tls/rustls-client-cert/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "rustls-client-cert"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-tls = "3.0"
|
||||
actix-web = { version = "4.0.0-rc.1", features = ["rustls"] }
|
||||
env_logger = "0.9"
|
||||
log = "0.4"
|
||||
rustls = "0.20.2"
|
||||
rustls-pemfile = "0.2.1"
|
33
https-tls/rustls-client-cert/README.md
Normal file
33
https-tls/rustls-client-cert/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Access Client Certificate (via Rustls)
|
||||
|
||||
## Usage
|
||||
|
||||
### Certificate
|
||||
|
||||
All the self-signed certificate are in the ./certs directory, including the CA certificate
|
||||
generated by [`mkcert`] that was used to create the server and client certs.
|
||||
|
||||
### Server
|
||||
|
||||
```sh
|
||||
cd security/rustls-client-cert
|
||||
cargo run
|
||||
```
|
||||
|
||||
The server runs HTTP on port 8080 and HTTPS on port 8443.
|
||||
|
||||
### Providing Client Cert
|
||||
|
||||
Using [HTTPie]:
|
||||
```sh
|
||||
http https://127.0.0.1:8443/ --verify=certs/rootCA.pem --cert=certs/client-cert.pem --cert-key=certs/client-key.pem
|
||||
```
|
||||
|
||||
Using [cURL]:
|
||||
```sh
|
||||
curl https://127.0.0.1:8443/ --cacert certs/rootCA.pem --cert certs/client-cert.pem --key certs/client-key.pem
|
||||
```
|
||||
|
||||
[`mkcert`]: https://github.com/FiloSottile/mkcert
|
||||
[cURL]: https://curl.haxx.se/
|
||||
[HTTPie]: https://httpie.org/
|
26
https-tls/rustls-client-cert/certs/client-cert.pem
Normal file
26
https-tls/rustls-client-cert/certs/client-cert.pem
Normal file
@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEVDCCArygAwIBAgIRAOAgy58Y3ViVpV9G8DTyKzMwDQYJKoZIhvcNAQELBQAw
|
||||
bTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSEwHwYDVQQLDBhyb2JA
|
||||
c29tYnJhLng1Mi5kZXYgKFJvYikxKDAmBgNVBAMMH21rY2VydCByb2JAc29tYnJh
|
||||
Lng1Mi5kZXYgKFJvYikwHhcNMTkwNjAxMDAwMDAwWhcNMzAxMDI1MTczODMxWjBM
|
||||
MScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxITAfBgNV
|
||||
BAsMGHJvYkBzb21icmEueDUyLmRldiAoUm9iKTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAJsp9QFEpfEWFB3CyFTA2Rv2tUMwnpQcDtiB1hwH03EYcMlG
|
||||
pEkMh1tPTK8WZo2igMJrBtP2Vf2AN0/hmFWUZV1ZEUUNXXW0QD2mHS8Rgz7nAgmq
|
||||
V5XvmLLeeo2vMdw1B2qsRxCPTjbInDsZsBqv2GyXWo5/9o3PD32h4LNk3w0VyA47
|
||||
f/jdpMWlcIXQoyJJV1U1FPLf92xYZvWc9Vf/+K6mStESEpoFll+b4uqjPpwrEz9Q
|
||||
KBY4eyXwhGCrjQC0+jJFNlIcbV5FgQSYd4DVMcw6SWdMeV/+VtQs+JQrENjNB3am
|
||||
nJ5xpoZ7mmNDOkWg4zvoYRL6o7LtqT+8EXptzMMCAwEAAaOBjzCBjDAOBgNVHQ8B
|
||||
Af8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMAwGA1UdEwEB
|
||||
/wQCMAAwHwYDVR0jBBgwFoAUfpWkO5lYpQJz4omoVdVzuuZnn80wLAYDVR0RBCUw
|
||||
I4IJbG9jYWxob3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEB
|
||||
CwUAA4IBgQB8ulsrStRha8SRxoPRlTNIb9WMjNl5KdZF+ePpUctBX0lFmxqn0upu
|
||||
l3BoZkhMrpPRRcGlDPImuL7tfxk/IuTA6S1AEQtEHCC8WyZbq3RODPzVY6J/IOUv
|
||||
H2ZwZYo0c714FyNx8igBpVSjHT6yCIeQkSQlTXsWxddToSeKYvXg8VI+M5L0DH1Y
|
||||
jRb2u3GpMPdLhMqGNZPcwbLkVyMe5aj4hx334fa3uLf/CK6/5ev4+ozSNz3Qr8S7
|
||||
iPE8WXrny/qEJmTEme7eq6K/QPTC9ly3j+5Ms3Uepnk0Jez9/ksOrlbYrWXhwD0P
|
||||
Nwvn3HtiYy8q1HwRw5U+LMNyh6lIyfJUsu2tRmYz1fiH74tMDFb2pjDpcmvgaSJY
|
||||
eSwKksOiX1No6K980ECEkCX9iQFwD5edTCnD2lz+AVGDzZPkY/551Ohl+KMh/mFG
|
||||
uZNtgjUeMh0btfc9D+PLLLHjpSMVkRMEEmtm/Zi2nKeVCAdIomFfk+EFIEOdaMyk
|
||||
SUZMUFzBP+4=
|
||||
-----END CERTIFICATE-----
|
28
https-tls/rustls-client-cert/certs/client-key.pem
Normal file
28
https-tls/rustls-client-cert/certs/client-key.pem
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCbKfUBRKXxFhQd
|
||||
wshUwNkb9rVDMJ6UHA7YgdYcB9NxGHDJRqRJDIdbT0yvFmaNooDCawbT9lX9gDdP
|
||||
4ZhVlGVdWRFFDV11tEA9ph0vEYM+5wIJqleV75iy3nqNrzHcNQdqrEcQj042yJw7
|
||||
GbAar9hsl1qOf/aNzw99oeCzZN8NFcgOO3/43aTFpXCF0KMiSVdVNRTy3/dsWGb1
|
||||
nPVX//iupkrREhKaBZZfm+Lqoz6cKxM/UCgWOHsl8IRgq40AtPoyRTZSHG1eRYEE
|
||||
mHeA1THMOklnTHlf/lbULPiUKxDYzQd2ppyecaaGe5pjQzpFoOM76GES+qOy7ak/
|
||||
vBF6bczDAgMBAAECggEAOAzN/mlH8HDjT2TfbQ5E3z8dd2oGvsXr7vXn3DRPgxkr
|
||||
FOo5ylGGS8u3jb/vx9Yd4R08WDEyGuLIGEkL+E4k17Wm8WTEkBJO6nYpMKmI2Z4l
|
||||
NEyeWwE0DdkkOC5DOqLFTRlyil7aCBwro4XCAcHn0kJSagt7ivpzRBTH0MXtdRIL
|
||||
L37nOInga2puSeHLOGj9W1Q0AX0EIiecqLPpCLmz+xotlevFBmlQ4iFT7xkoKH+s
|
||||
NeqWEd0HTNYkYQZtZ9husDzNK4x59MKUYS1oWB8A8JKu5E4ovdb6R6LjyN/Y5lNl
|
||||
3Z4Mg2DJ4iBN4DRnEBwiY8bdeqYboMNNyAbCU+nPYQKBgQDLP0lEYsdcSNF5Uv0c
|
||||
fe5pUvAzyTUzVhP7LLOk2jdRxs85MNbYJkays40rROqm2+StSFgih3NpA9D1pl7f
|
||||
ucJABlK9OkTtOshFSR6Q+0NomKLHhBGvYpouC2tIHjGsE/KjiQa4I1Pia72xpIWT
|
||||
QK3isM2c11924RqdoJ0mpBKpOwKBgQDDb8k4U512u+exVvFQ8JEbro4oy4jsc74L
|
||||
BZG6PbHZcIADKANmB15ahN3tCkDwJQ8iJYX7bmzn+8jR2HtznchgJwWN9aGtEP4C
|
||||
qTmmyrJd09pMMs5W4/BucD7wJ7s32PwVUwj0nvW+BHE4LQk5td4a3VE1wj1EZ8bR
|
||||
+JCK081yGQKBgQCG1vKtuvbWY70NR6CCwY1lNNAFG0z/RPE2pz57dQZUa5hZMeyn
|
||||
NCWdMv/KIAupLaN1ztQh/Ej198Eu5/RzaxLTVR6ZScomtOPfC5aKyxe6keEUiqsM
|
||||
91agi5TeIKIFrqpAEo1xpoZlZeNQsnyn57Y0+eU/U6eS/96fisoXs6xptwKBgQCy
|
||||
loDqnsXCTR0AmbE0RFBlWlH/h1Ycs/tSeQlchanyR3JC8BqC7nLTBp0BUaBbkZHN
|
||||
ozpWsuaD6jntQAQ3d1Q2QRI7Ud0ml+N1rQvIlWr+gGv3u2mATxRS5vEsZTIYa4iX
|
||||
N+R0HJn0xHxtWAIZIU7Pf7QJCvEPhEFTd+8lXTxcaQKBgG5d4vG5AyYXuiKKmm+d
|
||||
MM4PPMJNw3+u5G50hgI4D/1WlirP9m6HIpFouNNGoggxpBBUeokIBPsXbq/fnkq2
|
||||
uZmkAkWZeMeWHbI0lHSsE98ZTQHg36dNJ9hRHVRJ9PA2/YTSnr3WzDaaA1v5aoTv
|
||||
xJyGdLlEy+RiIZCPk9RKtVc4
|
||||
-----END PRIVATE KEY-----
|
40
https-tls/rustls-client-cert/certs/rootCA-key.pem
Normal file
40
https-tls/rustls-client-cert/certs/rootCA-key.pem
Normal file
@ -0,0 +1,40 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
nctls65dJGslcxgwD6O1rA==
|
||||
-----END PRIVATE KEY-----
|
27
https-tls/rustls-client-cert/certs/rootCA.pem
Normal file
27
https-tls/rustls-client-cert/certs/rootCA.pem
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEqTCCAxGgAwIBAgIQL82W4ilLJ4cs8zMbhJ+7aTANBgkqhkiG9w0BAQsFADBt
|
||||
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExITAfBgNVBAsMGHJvYkBz
|
||||
b21icmEueDUyLmRldiAoUm9iKTEoMCYGA1UEAwwfbWtjZXJ0IHJvYkBzb21icmEu
|
||||
eDUyLmRldiAoUm9iKTAeFw0yMDEwMjUxNzIyMzlaFw0zMDEwMjUxNjIyMzlaMG0x
|
||||
HjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEhMB8GA1UECwwYcm9iQHNv
|
||||
bWJyYS54NTIuZGV2IChSb2IpMSgwJgYDVQQDDB9ta2NlcnQgcm9iQHNvbWJyYS54
|
||||
NTIuZGV2IChSb2IpMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAq8NA
|
||||
5lGYNYUxCknpFKQ14RBJlbEgjcfHIi8hp9TobzUigyOQoZ9W50WmChRuuAO/fXIG
|
||||
i8ioejoteNPVbJj7ggMKx13256cvDKVR79NKeoHBSYUUjs2NyZZ3zPUeUe0tXPHR
|
||||
J4RMWLmpYKdI6NCYjDX6ouCIeh6sinTOSV+0dbnfHvFGESFpUeiUdsnCRorsa/oB
|
||||
n+hIn5dvftuxSDYDbADsSLDqhxY4xsQJKP00uNysLP0vewBqTSULNeHMNf0Yhpiy
|
||||
ot/tbcRqQAzSzRIvWeCgw0GcjqPW27/p/x/4Sh3XzjT6w1xVtF7ZniW37M4gQktN
|
||||
HnMWVgceqo0TaCwo+B37XJa/fBRH0x8HnMda1JeZ7X8/Szyc7YEa1M6ZkKONeCEg
|
||||
C7+8jp/aTM/0DuvIIhxHwK/9PGvWYDFJny2Jf8pq1jJ66Gr0uWxRJHobf2kB+aF3
|
||||
KUs5nK49Kw+TmZcB+SbU256e2wPhusxqxXnYi9WjdIyCqF3B1hYxEiaRiFRTAgMB
|
||||
AAGjRTBDMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud
|
||||
DgQWBBR+laQ7mVilAnPiiahV1XO65mefzTANBgkqhkiG9w0BAQsFAAOCAYEAe3A5
|
||||
5z5JWHSXEcQI/LstAVJfiloehyhvYgcNpImlsm5A41VzMd1iWdpLY+WSKWjHKFs0
|
||||
u5Id+sGEZRHBicYDts0azH3Sklj0FrNrpRdvf8jJuMvVC1EoUFijG+V/RdL14bxq
|
||||
kyp5dtxVcvtvULT+ID5vSVYBwGOBp36Fg5Qs4QOuSPkVGwjaEdJvzqb1XDLncsve
|
||||
ap6ALzwOXUsN8Icrq4/GlVDX11rOnfWhNQRiWKJtin4vzxL002rPWwSsekcuLEFQ
|
||||
NCBYaBBDlp4fLh2XVuB7xvKXTPm8K9hIxrTBEh8kj8p5p95DOTWpLgXuBcdXmNDV
|
||||
/4NBzsWwuO3I7/ilHbH+gEsM390p056Bmv2cF0bWb+xT2vyNymhmSCn77QEmcsOF
|
||||
LDqsjDc7JsQGUVIAgtM50md/QvaXxTVoAMXtSWeyK8QsC2syZqWlXiYkrwYjp+KI
|
||||
6jX4EpLwKdQOzZdjgnIZvG94o5lR8cPyZlaUKVunOTvAXiT3AWeBppCk6SEH
|
||||
-----END CERTIFICATE-----
|
25
https-tls/rustls-client-cert/certs/server-cert.pem
Normal file
25
https-tls/rustls-client-cert/certs/server-cert.pem
Normal file
@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIESjCCArKgAwIBAgIRAKNTHdWsrKKCpKt19C/sI4UwDQYJKoZIhvcNAQELBQAw
|
||||
bTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSEwHwYDVQQLDBhyb2JA
|
||||
c29tYnJhLng1Mi5kZXYgKFJvYikxKDAmBgNVBAMMH21rY2VydCByb2JAc29tYnJh
|
||||
Lng1Mi5kZXYgKFJvYikwHhcNMTkwNjAxMDAwMDAwWhcNMzAxMDI1MTczODM4WjBM
|
||||
MScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxITAfBgNV
|
||||
BAsMGHJvYkBzb21icmEueDUyLmRldiAoUm9iKTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBANDv0oRupAGtAl9ZZTeTwdToYh/Gtaj3bAyhQQz+dQ5GzLS3
|
||||
+Zvo3daepwnoNABoxuPwptb/jJ6Ec8rdvUiJkKb+jAuZ0vSuEqPTcgvbnqsV+7UT
|
||||
8WleCUnOIY6FB+uTaLEptu5k+Pf7i3m1RqW1gRVlYcHsLuv3NBQW0bz+XUZvcirW
|
||||
KVCxz2ex2aFzWXrAZEuOwMX+x+Wicd4tRfcio4mOI+jCRCsbwW0TsyWStrimcbl0
|
||||
ldbRi8DeADf3VPQCMYmcJARYsTfRwK75OFMgmD0GTi8WURWQCbTJnwzop7Famno0
|
||||
/I/Ef65Dngleb6HwG91EtEVU7QHqSXlUK41Au9kCAwEAAaOBhTCBgjAOBgNVHQ8B
|
||||
Af8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAfBgNV
|
||||
HSMEGDAWgBR+laQ7mVilAnPiiahV1XO65mefzTAsBgNVHREEJTAjgglsb2NhbGhv
|
||||
c3SHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggGBAJJ0
|
||||
7oDkVmdB/P0PX0vIn+CPmiE8IrO8stItOGlVRy9TDWFRdMpY13BOjlNY2efNU2Tz
|
||||
or+lyfV7D8PiCk5q3e8sLtOlIAT32IRIrGXl5E4q7zDnOckQjZIUZwSFAFVygy4F
|
||||
rPgJCS9uqz9vz086SyRD0krTM5u9yMAvG2uJLEk5oaVWAKdDRplStmMx7QQHMZ4G
|
||||
iNYMDpj4dU4gkrvZeC+JKwjbSJ3hje8CZCA1atzz/5WWEt2D8Yf9tw27T/hinrMi
|
||||
rrjPpEcA6C8wvHxqYpiptQC1FF5vaUyRqjF+irHgQdNUCE0nJSwAsIDW0TDiVGDD
|
||||
OJKs6EYuzJ8OcWw6IFx8YNvdxZJSr8SaavrH76myHieTkqhWvjSQERUw71iUwe0q
|
||||
5Nev+J2N9U7oZBTCIsD/qKOQTD9mRjJpYLnXNqEyJhzRgCA5+TQIXbTa10eo9Svg
|
||||
CTkqxsixmdTKD8ZIlUPhLI9ehr0Spbt+2Xh3yAtlSrfAt5p2hgVCoxalEwWpwA==
|
||||
-----END CERTIFICATE-----
|
28
https-tls/rustls-client-cert/certs/server-key.pem
Normal file
28
https-tls/rustls-client-cert/certs/server-key.pem
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDQ79KEbqQBrQJf
|
||||
WWU3k8HU6GIfxrWo92wMoUEM/nUORsy0t/mb6N3WnqcJ6DQAaMbj8KbW/4yehHPK
|
||||
3b1IiZCm/owLmdL0rhKj03IL256rFfu1E/FpXglJziGOhQfrk2ixKbbuZPj3+4t5
|
||||
tUaltYEVZWHB7C7r9zQUFtG8/l1Gb3Iq1ilQsc9nsdmhc1l6wGRLjsDF/sflonHe
|
||||
LUX3IqOJjiPowkQrG8FtE7Mlkra4pnG5dJXW0YvA3gA391T0AjGJnCQEWLE30cCu
|
||||
+ThTIJg9Bk4vFlEVkAm0yZ8M6KexWpp6NPyPxH+uQ54JXm+h8BvdRLRFVO0B6kl5
|
||||
VCuNQLvZAgMBAAECggEAZ8PzZVodkcd+uiQHpMZ5KWgP84AYkEXxH4SmbfGh6Ok4
|
||||
mTgVe1z3b7NzefQcf2eJ/4JxGa3pBID7kPD3JKNNd+JLYyeOIX6iO0K0DTeRYZ6V
|
||||
V6UD7DSLoGADQmjHOjQHdpUlCNiU3XPMHTHuWDYAWcPz/P9zfjVTY/bBS394i5W/
|
||||
nFLHMEGD/9KETUm2Wdmu+84fhAg+gSbDOHKOmrqiRoSmBInfUEjTL22gU1hPkjWY
|
||||
17i9veMGVPQeA89XYmFavgWIMHwiOD0Fom2y26OIDWDXAJf7oOoONElWF2OjiSAa
|
||||
7IHl8EED/aDIt9Xyv8J9qXzkAtLPXO8vFG2Uq0/BQQKBgQD1MlCsnMVf3dck8yg6
|
||||
YwFkFHZxnFBzBPwuDoMD2OBIZcrwcBhUQo0u8M0NohgjvBB7XUrW+/5ucF9BaecC
|
||||
3Rz/JwPk7oPafYVbEFGv+CeGJFKL/lq7NwF62N7EYo3N2ijYjGYiZFmxgOVEfzSd
|
||||
WRSH+b6Q923lEpWoFaeFww+5HQKBgQDaJIRTr1stXXFXVj/ETJG4uT3I7qlfR7zp
|
||||
/t/YHX6QnV5dFdBCEXSW41YoqvUn12Ox28nvQMDFWVkQGfAELYqkf/ozBQ9d6ee8
|
||||
3bU9V14YWaGSK1RT83cgWUtDnUjtLuk9MG+5x3EQcfq5ng6ud+Hr8ut+gz0PbLcK
|
||||
gR3uTQkM7QKBgENUSarccaZdeFKBIq7FuQAOTmfsEHtFBypuebN4vj2jFhLn9QZO
|
||||
MA6PuP7hX9eQMMZvW7mlALy6xq1jszeqF+hIgl0+0Z4Rkajr1kKH1fKTzsb6VVfL
|
||||
RvDA1IsAtQetvEGabAFNpQOE7W/drkj2yRh9j8Km7tpUPBwnthSY95xRAoGAL5uu
|
||||
oZDwxjrRhK0XJ6FKYFVVTagAoQHIEg2FDuaI+8jMkmYzWGf02QVuhVuiO3q/kE6W
|
||||
iLfKGogAbwoqHs9Npc8kbMQa8XUeFVMRvfx2VbwiDgOU2OmWwyGZ0nzeMJ1/W9JZ
|
||||
X+NOIretb5s2Ow+A5/zRNoAv8FDatdkuDhcT9ZUCgYBtEI9pmWYXxGfaVQErJcsS
|
||||
3a8PU875sE06DiEcvooljcLp6dCmGocRQOGpSXfy3zjX4F/HZjDK+GKPg2bCirKr
|
||||
nRPWf0t3DSeSyDINj+a0fg4KvYR4FcocJDzTFJh/9CrtNktqwHAqrQUSokBbW8n6
|
||||
Kj/AYLWOIXATfCrOgdoAAg==
|
||||
-----END PRIVATE KEY-----
|
120
https-tls/rustls-client-cert/src/main.rs
Normal file
120
https-tls/rustls-client-cert/src/main.rs
Normal file
@ -0,0 +1,120 @@
|
||||
//! This example shows how to use `actix_web::HttpServer::on_connect` to access client certificates
|
||||
//! pass them to a handler through connection-local data.
|
||||
|
||||
use std::{any::Any, env, fs::File, io::BufReader, net::SocketAddr};
|
||||
|
||||
use actix_tls::accept::rustls::{reexports::ServerConfig, TlsStream};
|
||||
use actix_web::{
|
||||
dev::Extensions, rt::net::TcpStream, web, App, HttpRequest, HttpResponse,
|
||||
HttpServer, Responder,
|
||||
};
|
||||
use log::info;
|
||||
use rustls::{
|
||||
server::AllowAnyAnonymousOrAuthenticatedClient, Certificate, PrivateKey,
|
||||
RootCertStore,
|
||||
};
|
||||
use rustls_pemfile::{certs, pkcs8_private_keys};
|
||||
|
||||
const CA_CERT: &str = "certs/rootCA.pem";
|
||||
const SERVER_CERT: &str = "certs/server-cert.pem";
|
||||
const SERVER_KEY: &str = "certs/server-key.pem";
|
||||
|
||||
#[allow(dead_code)] // it is debug printed
|
||||
#[derive(Debug, Clone)]
|
||||
struct ConnectionInfo {
|
||||
bind: SocketAddr,
|
||||
peer: SocketAddr,
|
||||
ttl: Option<u32>,
|
||||
}
|
||||
|
||||
async fn route_whoami(req: HttpRequest) -> impl Responder {
|
||||
let conn_info = req.conn_data::<ConnectionInfo>().unwrap();
|
||||
let client_cert = req.conn_data::<Certificate>();
|
||||
|
||||
if let Some(cert) = client_cert {
|
||||
HttpResponse::Ok().body(format!("{:?}\n\n{:?}", &conn_info, &cert))
|
||||
} else {
|
||||
HttpResponse::Unauthorized().body("No client certificate provided.")
|
||||
}
|
||||
}
|
||||
|
||||
fn get_client_cert(connection: &dyn Any, data: &mut Extensions) {
|
||||
if let Some(tls_socket) = connection.downcast_ref::<TlsStream<TcpStream>>() {
|
||||
info!("TLS on_connect");
|
||||
|
||||
let (socket, tls_session) = tls_socket.get_ref();
|
||||
|
||||
data.insert(ConnectionInfo {
|
||||
bind: socket.local_addr().unwrap(),
|
||||
peer: socket.peer_addr().unwrap(),
|
||||
ttl: socket.ttl().ok(),
|
||||
});
|
||||
|
||||
if let Some(certs) = tls_session.peer_certificates() {
|
||||
info!("client certificate found");
|
||||
|
||||
// insert a `rustls::Certificate` into request data
|
||||
data.insert(certs.last().unwrap().clone());
|
||||
}
|
||||
} else if let Some(socket) = connection.downcast_ref::<TcpStream>() {
|
||||
info!("plaintext on_connect");
|
||||
|
||||
data.insert(ConnectionInfo {
|
||||
bind: socket.local_addr().unwrap(),
|
||||
peer: socket.peer_addr().unwrap(),
|
||||
ttl: socket.ttl().ok(),
|
||||
});
|
||||
} else {
|
||||
unreachable!("socket should be TLS or plaintext");
|
||||
}
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
if env::var("RUST_LOG").is_err() {
|
||||
env::set_var("RUST_LOG", "info");
|
||||
}
|
||||
|
||||
env_logger::init();
|
||||
|
||||
let mut cert_store = RootCertStore::empty();
|
||||
|
||||
// import CA cert
|
||||
let ca_cert = &mut BufReader::new(File::open(CA_CERT)?);
|
||||
let ca_cert = Certificate(certs(ca_cert).unwrap()[0].clone());
|
||||
|
||||
cert_store
|
||||
.add(&ca_cert)
|
||||
.expect("root CA not added to store");
|
||||
|
||||
// set up client authentication requirements
|
||||
let client_auth = AllowAnyAnonymousOrAuthenticatedClient::new(cert_store);
|
||||
let config = ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_client_cert_verifier(client_auth);
|
||||
|
||||
// import server cert and key
|
||||
let cert_file = &mut BufReader::new(File::open(SERVER_CERT)?);
|
||||
let key_file = &mut BufReader::new(File::open(SERVER_KEY)?);
|
||||
|
||||
let cert_chain = certs(cert_file)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(Certificate)
|
||||
.collect();
|
||||
let mut keys: Vec<PrivateKey> = pkcs8_private_keys(key_file)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PrivateKey)
|
||||
.collect();
|
||||
let config = config.with_single_cert(cert_chain, keys.remove(0)).unwrap();
|
||||
|
||||
// start server
|
||||
HttpServer::new(|| App::new().default_service(web::to(route_whoami)))
|
||||
.on_connect(get_client_cert)
|
||||
.bind(("localhost", 8080))?
|
||||
.bind_rustls(("localhost", 8443), config)?
|
||||
.workers(1)
|
||||
.run()
|
||||
.await
|
||||
}
|
15
https-tls/rustls/Cargo.toml
Normal file
15
https-tls/rustls/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "rustls-example"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "rustls-server"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
env_logger = "0.9"
|
||||
rustls = "0.20.2"
|
||||
rustls-pemfile = "0.2.1"
|
||||
actix-web = { version = "4.0.0-beta.21", features = ["rustls"] }
|
||||
actix-files = "0.6.0-beta.15"
|
43
https-tls/rustls/README.md
Normal file
43
https-tls/rustls/README.md
Normal file
@ -0,0 +1,43 @@
|
||||
# TLS / HTTPS (via Rustls)
|
||||
|
||||
## Usage
|
||||
|
||||
### Certificate
|
||||
|
||||
We put the self-signed certificate in this directory as an example
|
||||
but your browser would complain that it isn't secure.
|
||||
So we recommend to use [`mkcert`] to trust it. To use local CA, you should run:
|
||||
|
||||
```bash
|
||||
mkcert -install
|
||||
```
|
||||
|
||||
If you want to generate your own cert/private key file, then run:
|
||||
|
||||
```bash
|
||||
mkcert 127.0.0.1 localhost
|
||||
```
|
||||
|
||||
For `rsa` keys use `rsa_private_keys` function instead `pkcs8_private_keys`
|
||||
```rs
|
||||
let mut keys = pkcs8_private_keys(key_file).unwrap(); // pkcs8
|
||||
let mut keys = rsa_private_keys(key_file).unwrap(); // rsa
|
||||
```
|
||||
|
||||
[`mkcert`]: https://github.com/FiloSottile/mkcert
|
||||
|
||||
### Running the Example Server
|
||||
|
||||
```bash
|
||||
cd security/rustls
|
||||
cargo run # (or ``cargo watch -x run``)
|
||||
# Started http server: 127.0.0.1:8443
|
||||
```
|
||||
|
||||
If you prefer reloading you can substitute `cargo watch -x run`.
|
||||
That requires you install the `cargo-watch` crate.
|
||||
|
||||
### web client
|
||||
|
||||
- curl: ``curl -v https://127.0.0.1:8443/index.html --compressed -k``
|
||||
- browser: [https://127.0.0.1:8443/index.html](https://127.0.0.1:8443/index.html)
|
25
https-tls/rustls/cert.pem
Normal file
25
https-tls/rustls/cert.pem
Normal file
@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEJzCCAo+gAwIBAgIQKu5MWHrdyO4HsnfIu8alTDANBgkqhkiG9w0BAQsFADBt
|
||||
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExITAfBgNVBAsMGHJvYkBz
|
||||
b21icmEueDUyLmRldiAoUm9iKTEoMCYGA1UEAwwfbWtjZXJ0IHJvYkBzb21icmEu
|
||||
eDUyLmRldiAoUm9iKTAeFw0yMTEwMDYyMTMxMzNaFw0yNDAxMDYyMjMxMzNaMEwx
|
||||
JzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTEhMB8GA1UE
|
||||
CwwYcm9iQHNvbWJyYS54NTIuZGV2IChSb2IpMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAoI9BHaflPrNfnGKO6WmaEwhXfKKBH9sWlo4NKdP9ECZTC2Ef
|
||||
ubvQzhjcJsPWIwYj1NDiAa11WfD6ayKG7YleoNynsDKnsOEBfXtFHU2IPWaESX4Q
|
||||
rO8OaTXx001qdjwE3j/+K0AD43umXdnCeks3JYYlyG4/XxKa62pmpwu6KMgKbygA
|
||||
MS3dIMe7WcYbKX+qPNl4xoF5xkeqlp2urO3SWPkgIYB+cDNsWRHb5vsMWw9s7Zos
|
||||
W4mWAPZz0bLKw6w6imfo0rq0j5aoPJLNAyuH3/qhZIZC13tUCAxymIq0+pCeO+lZ
|
||||
f0OC05dB/Hw1zSLxAxHgDzpOsaq9/NXSkIwEzwIDAQABo2QwYjAOBgNVHQ8BAf8E
|
||||
BAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHwYDVR0jBBgwFoAUto/ox0MqZShm
|
||||
QpViV/gjfJKrMDkwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBgQCxMiND9F3xsyGlIyqIgHc+fp+wzFI5Yz9qD/02RP558qXHAj2o
|
||||
6zGECzc4PeiBLh7Y7wHjcu4TTLIXnRtrdVFBUT/s58l/uoK8NGVjky74Rc4A+djt
|
||||
zwcHS0snuj+FJ859Y+uS3rGKAmBAKWD22wmhB96UNRiZjG1QdJ/Or6hMZ3PVbELs
|
||||
Hgv69UG1jJiL8y7cn4foBXC6Wgb10tPXNoz7TpD3B14+Pd82yergAHswCp3nj9Ip
|
||||
D+9Ohko26OItO1dJYeDZWi0CurWdjP7xnEsZo2OaLIlSMiUbSyJOCMk/xWJCjuLW
|
||||
BEc1VzaFwhkGZJUa1F6TOIc70geLC4wQWOaqZoLbsQfihYgRoUMZJOmjcDXJrNZz
|
||||
wZofnBI+0tDsZfKjwXFyA4bzUD1I3lFY5Zy3wgQprUrZCm69uo8G4RtMWP9DmXCc
|
||||
SEw6CxBVPu/l/ljYoxdqCyJTLvdQ97OlGgLv3b0DDcWqi7e0zB8NqT0aCTPm7J/M
|
||||
OBWicNgMJ+1qL8M=
|
||||
-----END CERTIFICATE-----
|
28
https-tls/rustls/key.pem
Normal file
28
https-tls/rustls/key.pem
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCgj0Edp+U+s1+c
|
||||
Yo7paZoTCFd8ooEf2xaWjg0p0/0QJlMLYR+5u9DOGNwmw9YjBiPU0OIBrXVZ8Ppr
|
||||
IobtiV6g3KewMqew4QF9e0UdTYg9ZoRJfhCs7w5pNfHTTWp2PATeP/4rQAPje6Zd
|
||||
2cJ6SzclhiXIbj9fEprramanC7ooyApvKAAxLd0gx7tZxhspf6o82XjGgXnGR6qW
|
||||
na6s7dJY+SAhgH5wM2xZEdvm+wxbD2ztmixbiZYA9nPRssrDrDqKZ+jSurSPlqg8
|
||||
ks0DK4ff+qFkhkLXe1QIDHKYirT6kJ476Vl/Q4LTl0H8fDXNIvEDEeAPOk6xqr38
|
||||
1dKQjATPAgMBAAECggEAVBfTvgmSuw1NtWW1fjDuHqvOzpt6T8n7Aa2y3UaHk67O
|
||||
7fXXnPruuRMyMyd8/2kW2T7yMHi+LvZU4kn6K204X75SIanWRIEEu8kVgOx7v9Ty
|
||||
0l8xsrGedaJoXwh8CyMSValkoRhtMPcxQpRsFItSfdfN8DU2AcCH3WckDrfIr9SJ
|
||||
qvag8VsYeg/PH3rP3bNAh4xousaJzcvr8ifuNcN7NmoUDMoTXk3Pxhxeryj+sACS
|
||||
cFxt777edShuYqL2BAziY/cTl0zcvCarX27NUS+q9exF7VYvMCuqiWHYcYkLlkH1
|
||||
UfrwPXQmdX5/CUBqt36xBsKyub5j74KoEk7shzOmkQKBgQDKTr0vc+53QNUR1mUD
|
||||
7a8Pw+oWW1ddcd9SYtvzEJeNqb7s2aZsEzTRk4Pxdx3wrm8PAaPqjzJWwx1SmazU
|
||||
iLt55SRFu3sPw8gTwNQj01fy2roae/ZzMP4MJRzw6vFtNPPcevLQK9JN9uKBQep+
|
||||
NU3xHYNYnT2I+X7QVJi6AsMwxwKBgQDLLA6iOwN+3aQmLlW1A4reRpIkFQ75RD92
|
||||
BtCnYQwXCqOtU4uUz3fIlmcuCI5jhqAYWG0m9IL+rxQD2SdFu9UaG1pEsMkapjUh
|
||||
+mPLAm3UcoqnhKygGiiQ8iPL9zMFai3dfbBYrmBMsYgFxT7wkPuAgjWM0bvfyUqA
|
||||
lwKrkykTuQKBgHdSZacdW6MerA0vRLlCcSR9Sw4QpcDJrwwqnswIFztIyQFthgjs
|
||||
cxTBSusadKBGYd6Z+xIXj3s47YyQcy2Pz/OfQPuYDodH1DRCYV0YBCGK/IUuZDeg
|
||||
x9Zl9WHrUKY2uzZpldlOX2X4nbPbKvFxgx0ZaSTU6Txm23MI0mOzyWh1AoGBAJYu
|
||||
jvKkpMTWmUwP3BLd93yutcAuQM9I/5ADIaFYP1OY7bxlkTwC0AxaARMqB/bRwO2+
|
||||
D5FIFLymNilSD5GgcrnFlkhIVZ95VLU1HScnOIBd2thRXjlKnMnn80YGCJTsE9Mx
|
||||
4XTsEQsf/+gkEY5J3V704RiiwDl/1a6P8c1aDnchAoGALEDzByXeADMiYjKi6M19
|
||||
1WK3+TDD9Sy8fu4x2qmTho9Z9nk5bw6ZPHbXDTaQ+jxnOD4Io6iZIQLEYMwzbXnO
|
||||
951+ck9E5mwWo/IyNROOMo0aNT9yqLANu5Hp1CliQ5Yqmb1R1Qhuk4SZTWmUGjo/
|
||||
3I+uWHi2Foc2FU8LSAb4hLk=
|
||||
-----END PRIVATE KEY-----
|
64
https-tls/rustls/src/main.rs
Normal file
64
https-tls/rustls/src/main.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
|
||||
use actix_files::Files;
|
||||
use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer};
|
||||
use rustls::{Certificate, PrivateKey, ServerConfig};
|
||||
use rustls_pemfile::{certs, pkcs8_private_keys};
|
||||
|
||||
/// simple handle
|
||||
async fn index(req: HttpRequest) -> HttpResponse {
|
||||
println!("{:?}", req);
|
||||
HttpResponse::Ok()
|
||||
.content_type("text/html; charset=utf-8")
|
||||
.body("<!DOCTYPE html><html><body><p>Welcome!</p></body></html>")
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
if std::env::var("RUST_LOG").is_err() {
|
||||
std::env::set_var("RUST_LOG", "actix_web=info");
|
||||
}
|
||||
env_logger::init();
|
||||
|
||||
// load ssl keys
|
||||
let config = ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_no_client_auth();
|
||||
let cert_file = &mut BufReader::new(File::open("cert.pem").unwrap());
|
||||
let key_file = &mut BufReader::new(File::open("key.pem").unwrap());
|
||||
let cert_chain = certs(cert_file)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(Certificate)
|
||||
.collect();
|
||||
let mut keys: Vec<PrivateKey> = pkcs8_private_keys(key_file)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PrivateKey)
|
||||
.collect();
|
||||
if keys.is_empty() {
|
||||
eprintln!("Could not locate PKCS 8 private keys.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
let config = config.with_single_cert(cert_chain, keys.remove(0)).unwrap();
|
||||
|
||||
println!("Starting https server: 127.0.0.1:8443");
|
||||
HttpServer::new(|| {
|
||||
App::new()
|
||||
// enable logger
|
||||
.wrap(middleware::Logger::default())
|
||||
// register simple handler, handle all methods
|
||||
.service(web::resource("/index.html").to(index))
|
||||
// with path parameters
|
||||
.service(web::resource("/").route(web::get().to(|| async {
|
||||
HttpResponse::Found()
|
||||
.append_header(("LOCATION", "/index.html"))
|
||||
.finish()
|
||||
})))
|
||||
.service(Files::new("/static", "static"))
|
||||
})
|
||||
.bind_rustls("127.0.0.1:8443", config)?
|
||||
.run()
|
||||
.await
|
||||
}
|
Reference in New Issue
Block a user