diff --git a/Cargo.lock b/Cargo.lock index 7411274..0c22f45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -953,6 +953,15 @@ dependencies = [ "sct", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -1225,7 +1234,7 @@ dependencies = [ [[package]] name = "wasmedge_quickjs" -version = "0.5.0-alpha" +version = "0.6.0-alpha" dependencies = [ "argparse", "chat-prompts", @@ -1239,6 +1248,7 @@ dependencies = [ "libc", "log", "rustls", + "rustls-pemfile", "tokio-rustls-wasi", "tokio_wasi", "url", diff --git a/Cargo.toml b/Cargo.toml index 97782a8..9badf2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ crypto-wasi = { version = "0.1.1", optional = true } chat-prompts = { version = "0.3", optional = true } wasi-nn = { git = "https://github.com/second-state/wasmedge-wasi-nn", branch = "ggml", optional = true } endpoints = { version = "0.2", optional = true } +rustls-pemfile = "1.0.4" [features] default = ["tls"] diff --git a/README.md b/README.md index 30191cf..47fa670 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,9 @@ cargo build --target wasm32-wasi --release wasmedge --dir .:. target/wasm32-wasi/release/wasmedge_quickjs.wasm example_js/hello.js WasmEdge Runtime Hello WasmEdge Runtime ``` + +### Usage with custom ssl certs +```bash +$ wasmedge --dir .:. --dir /etc/ssl:/etc/ssl:readonly --env SSL_CERT_FILE="/etc/ssl/cert.pem" target/wasm32-wasi/release/wasmedge_quickjs.wasm example_js/wasi_https_fetch.js +``` +substitute the value of `/etc/ssl` and `/etc/ssl/cert.pem` with the location of your cert folder and cert file diff --git a/scripts/get_cert.sh b/scripts/get_cert.sh new file mode 100755 index 0000000..0c13f7a --- /dev/null +++ b/scripts/get_cert.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Check if a domain is provided as an argument +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +# Retrieve and print the combined TLS certificates +openssl s_client -showcerts -connect "$1":443 2>/dev/null < /dev/null | awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{print}' \ No newline at end of file diff --git a/src/event_loop/certs.rs b/src/event_loop/certs.rs new file mode 100644 index 0000000..84d7a89 --- /dev/null +++ b/src/event_loop/certs.rs @@ -0,0 +1,20 @@ +use std::{env, io}; +use std::fs::File; +use std::io::BufReader; +use rustls::Certificate; + + +const ENV_CERT_FILE: &str = "SSL_CERT_FILE"; + +pub fn load_certs_from_env() -> io::Result> { + let file_name = match env::var(ENV_CERT_FILE) { + Ok(val) => val, + Err(_) => { + return io::Result::Err(io::Error::from(io::ErrorKind::NotFound)); + }, + }; + let file = File::open(file_name)?; + let mut reader = BufReader::new(file); + let mut certs = rustls_pemfile::certs(&mut reader)?; + Ok(certs.into_iter().map(Certificate).collect()) +} \ No newline at end of file diff --git a/src/event_loop/mod.rs b/src/event_loop/mod.rs index c16417d..a03bb81 100644 --- a/src/event_loop/mod.rs +++ b/src/event_loop/mod.rs @@ -1,6 +1,7 @@ mod poll; pub mod wasi_fs; mod wasi_sock; +mod certs; use crate::{quickjs_sys as qjs, Context, JsClassTool, JsValue}; use std::borrow::BorrowMut; @@ -134,13 +135,21 @@ impl AsyncTlsConn { let io = tokio::net::TcpStream::connect(addr).await?; let mut root_store = rustls::RootCertStore::empty(); - root_store.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| { - OwnedTrustAnchor::from_subject_spki_name_constraints( - ta.subject, - ta.spki, - ta.name_constraints, - ) - })); + if let Ok(custom_certs) = certs::load_certs_from_env() { + log::info!("using custom certs"); + for cert in custom_certs { + root_store.add(&cert).unwrap(); + } + } else { + log::info!("falling back to webpki certs"); + root_store.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| { + OwnedTrustAnchor::from_subject_spki_name_constraints( + ta.subject, + ta.spki, + ta.name_constraints, + ) + })); + } let config = rustls::ClientConfig::builder() .with_safe_defaults()