summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tests/unit/tls_test.ts62
-rw-r--r--ext/net/02_tls.js4
-rw-r--r--ext/net/lib.deno_net.d.ts18
-rw-r--r--ext/net/ops_tls.rs48
4 files changed, 113 insertions, 19 deletions
diff --git a/cli/tests/unit/tls_test.ts b/cli/tests/unit/tls_test.ts
index 4b3dba082..26a166801 100644
--- a/cli/tests/unit/tls_test.ts
+++ b/cli/tests/unit/tls_test.ts
@@ -15,6 +15,9 @@ import { TextProtoReader } from "../../../test_util/std/textproto/mod.ts";
const encoder = new TextEncoder();
const decoder = new TextDecoder();
+const cert = await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt");
+const key = await Deno.readTextFile("cli/tests/testdata/tls/localhost.key");
+const caCerts = [await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem")];
async function sleep(msec: number) {
await new Promise((res, _rej) => setTimeout(res, msec));
@@ -184,11 +187,60 @@ Deno.test(
},
);
- const conn = await Deno.connectTls({
- hostname,
- port,
- caCerts: [Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem")],
- });
+ const conn = await Deno.connectTls({ hostname, port, caCerts });
+ assert(conn.rid > 0);
+ const w = new BufWriter(conn);
+ const r = new BufReader(conn);
+ const body = `GET / HTTP/1.1\r\nHost: ${hostname}:${port}\r\n\r\n`;
+ const writeResult = await w.write(encoder.encode(body));
+ assertEquals(body.length, writeResult);
+ await w.flush();
+ const tpr = new TextProtoReader(r);
+ const statusLine = await tpr.readLine();
+ assert(statusLine !== null, `line must be read: ${String(statusLine)}`);
+ const m = statusLine.match(/^(.+?) (.+?) (.+?)$/);
+ assert(m !== null, "must be matched");
+ const [_, proto, status, ok] = m;
+ assertEquals(proto, "HTTP/1.1");
+ assertEquals(status, "200");
+ assertEquals(ok, "OK");
+ const headers = await tpr.readMIMEHeader();
+ assert(headers !== null);
+ const contentLength = parseInt(headers.get("content-length")!);
+ const bodyBuf = new Uint8Array(contentLength);
+ await r.readFull(bodyBuf);
+ assertEquals(decoder.decode(bodyBuf), "Hello World\n");
+ conn.close();
+ listener.close();
+ await resolvable;
+ },
+);
+Deno.test(
+ { permissions: { read: false, net: true } },
+ async function listenTlsWithCertAndKey() {
+ const resolvable = deferred();
+ const hostname = "localhost";
+ const port = 3500;
+
+ const listener = Deno.listenTls({ hostname, port, cert, key });
+
+ const response = encoder.encode(
+ "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n",
+ );
+
+ listener.accept().then(
+ async (conn) => {
+ assert(conn.remoteAddr != null);
+ assert(conn.localAddr != null);
+ await conn.write(response);
+ setTimeout(() => {
+ conn.close();
+ resolvable.resolve();
+ }, 0);
+ },
+ );
+
+ const conn = await Deno.connectTls({ hostname, port, caCerts });
assert(conn.rid > 0);
const w = new BufWriter(conn);
const r = new BufReader(conn);
diff --git a/ext/net/02_tls.js b/ext/net/02_tls.js
index 90f395193..86f651521 100644
--- a/ext/net/02_tls.js
+++ b/ext/net/02_tls.js
@@ -65,7 +65,9 @@
function listenTls({
port,
+ cert,
certFile,
+ key,
keyFile,
hostname = "0.0.0.0",
transport = "tcp",
@@ -73,7 +75,9 @@
}) {
const res = opListenTls({
port,
+ cert,
certFile,
+ key,
keyFile,
hostname,
transport,
diff --git a/ext/net/lib.deno_net.d.ts b/ext/net/lib.deno_net.d.ts
index 048037d02..038452055 100644
--- a/ext/net/lib.deno_net.d.ts
+++ b/ext/net/lib.deno_net.d.ts
@@ -93,11 +93,21 @@ declare namespace Deno {
): Listener;
export interface ListenTlsOptions extends ListenOptions {
+ /** Server private key in PEM format */
+ key?: string;
+ /** Cert chain in PEM format */
+ cert?: string;
/** Path to a file containing a PEM formatted CA certificate. Requires
- * `--allow-read`. */
- certFile: string;
- /** Server public key file. Requires `--allow-read`.*/
- keyFile: string;
+ * `--allow-read`.
+ *
+ * @deprecated This option is deprecated and will be removed in Deno 2.0.
+ */
+ certFile?: string;
+ /** Server private key file. Requires `--allow-read`.
+ *
+ * @deprecated This option is deprecated and will be removed in Deno 2.0.
+ */
+ keyFile?: string;
transport?: "tcp";
}
diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs
index 64f1d458b..7fce34820 100644
--- a/ext/net/ops_tls.rs
+++ b/ext/net/ops_tls.rs
@@ -1004,8 +1004,12 @@ pub struct ListenTlsArgs {
transport: String,
hostname: String,
port: u16,
- cert_file: String,
- key_file: String,
+ cert: Option<String>,
+ // TODO(kt3k): Remove this option at v2.0.
+ cert_file: Option<String>,
+ key: Option<String>,
+ // TODO(kt3k): Remove this option at v2.0.
+ key_file: Option<String>,
alpn_protocols: Option<Vec<String>>,
}
@@ -1020,23 +1024,47 @@ where
assert_eq!(args.transport, "tcp");
let hostname = &*args.hostname;
let port = args.port;
- let cert_file = &*args.cert_file;
- let key_file = &*args.key_file;
+ let cert_file = args.cert_file.as_deref();
+ let key_file = args.key_file.as_deref();
+ let cert = args.cert.as_deref();
+ let key = args.key.as_deref();
{
let permissions = state.borrow_mut::<NP>();
permissions.check_net(&(hostname, Some(port)))?;
- permissions.check_read(Path::new(cert_file))?;
- permissions.check_read(Path::new(key_file))?;
+ if let Some(path) = cert_file {
+ permissions.check_read(Path::new(path))?;
+ }
+ if let Some(path) = key_file {
+ permissions.check_read(Path::new(path))?;
+ }
}
+ let cert_chain = if cert_file.is_some() && cert.is_some() {
+ return Err(generic_error("Both cert and certFile is specified. You can specify either one of them."));
+ } else if let Some(path) = cert_file {
+ load_certs_from_file(path)?
+ } else if let Some(cert) = cert {
+ load_certs(&mut BufReader::new(cert.as_bytes()))?
+ } else {
+ return Err(generic_error("`cert` is not specified."));
+ };
+ let key_der = if key_file.is_some() && key.is_some() {
+ return Err(generic_error(
+ "Both key and keyFile is specified. You can specify either one of them.",
+ ));
+ } else if let Some(path) = key_file {
+ load_private_keys_from_file(path)?.remove(0)
+ } else if let Some(key) = key {
+ load_private_keys(key.as_bytes())?.remove(0)
+ } else {
+ return Err(generic_error("`key` is not specified."));
+ };
+
let mut tls_config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
- .with_single_cert(
- load_certs_from_file(cert_file)?,
- load_private_keys_from_file(key_file)?.remove(0),
- )
+ .with_single_cert(cert_chain, key_der)
.expect("invalid key or certificate");
if let Some(alpn_protocols) = args.alpn_protocols {
super::check_unstable(state, "Deno.listenTls#alpn_protocols");