summaryrefslogtreecommitdiff
path: root/ext/node
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2024-09-18 21:14:26 +0200
committerGitHub <noreply@github.com>2024-09-18 21:14:26 +0200
commitab1e391e1d700a68964e899963670e903f498cdf (patch)
tree923a469665b841605d81b7f615658a0bb363c35c /ext/node
parent5b14c71dafc119d5cf251d6e63cb5f53a661a391 (diff)
feat(ext/node): add rootCertificates to node:tls (#25707)
Closes https://github.com/denoland/deno/issues/25604 Signed-off-by: Satya Rohith <me@satyarohith.com> Co-authored-by: Satya Rohith <me@satyarohith.com>
Diffstat (limited to 'ext/node')
-rw-r--r--ext/node/Cargo.toml1
-rw-r--r--ext/node/lib.rs1
-rw-r--r--ext/node/ops/mod.rs1
-rw-r--r--ext/node/ops/tls.rs29
-rw-r--r--ext/node/polyfills/tls.ts57
5 files changed, 88 insertions, 1 deletions
diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml
index 452f7420b..24e7ecf2e 100644
--- a/ext/node/Cargo.toml
+++ b/ext/node/Cargo.toml
@@ -94,6 +94,7 @@ stable_deref_trait = "1.2.0"
thiserror.workspace = true
tokio.workspace = true
url.workspace = true
+webpki-root-certs.workspace = true
winapi.workspace = true
x25519-dalek = { version = "2.0.0", features = ["static_secrets"] }
x509-parser = "0.15.0"
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index dab9cc7bd..af14e3e85 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -407,6 +407,7 @@ deno_core::extension!(deno_node,
ops::ipc::op_node_ipc_unref,
ops::process::op_node_process_kill,
ops::process::op_process_abort,
+ ops::tls::op_get_root_certificates,
],
esm_entry_point = "ext:deno_node/02_init.js",
esm = [
diff --git a/ext/node/ops/mod.rs b/ext/node/ops/mod.rs
index d11cc7461..b562261f3 100644
--- a/ext/node/ops/mod.rs
+++ b/ext/node/ops/mod.rs
@@ -11,6 +11,7 @@ pub mod ipc;
pub mod os;
pub mod process;
pub mod require;
+pub mod tls;
pub mod util;
pub mod v8;
pub mod vm;
diff --git a/ext/node/ops/tls.rs b/ext/node/ops/tls.rs
new file mode 100644
index 000000000..86b177960
--- /dev/null
+++ b/ext/node/ops/tls.rs
@@ -0,0 +1,29 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+use base64::Engine;
+use deno_core::op2;
+use webpki_root_certs;
+
+#[op2]
+#[serde]
+pub fn op_get_root_certificates() -> Vec<String> {
+ let certs = webpki_root_certs::TLS_SERVER_ROOT_CERTS
+ .iter()
+ .map(|cert| {
+ let b64 = base64::engine::general_purpose::STANDARD.encode(cert);
+ let pem_lines = b64
+ .chars()
+ .collect::<Vec<char>>()
+ // Node uses 72 characters per line, so we need to follow node even though
+ // it's not spec compliant https://datatracker.ietf.org/doc/html/rfc7468#section-2
+ .chunks(72)
+ .map(|c| c.iter().collect::<String>())
+ .collect::<Vec<String>>()
+ .join("\n");
+ let pem = format!(
+ "-----BEGIN CERTIFICATE-----\n{pem_lines}\n-----END CERTIFICATE-----\n",
+ );
+ pem
+ })
+ .collect::<Vec<String>>();
+ certs
+}
diff --git a/ext/node/polyfills/tls.ts b/ext/node/polyfills/tls.ts
index 7d00bc6e5..4cfe9ebd6 100644
--- a/ext/node/polyfills/tls.ts
+++ b/ext/node/polyfills/tls.ts
@@ -7,6 +7,10 @@
import { notImplemented } from "ext:deno_node/_utils.ts";
import tlsCommon from "node:_tls_common";
import tlsWrap from "node:_tls_wrap";
+import { op_get_root_certificates } from "ext:core/ops";
+import { primordials } from "ext:core/mod.js";
+
+const { ObjectFreeze } = primordials;
// openssl -> rustls
const cipherMap = {
@@ -30,7 +34,58 @@ export function getCiphers() {
return Object.keys(cipherMap).map((name) => name.toLowerCase());
}
-export const rootCertificates = undefined;
+let lazyRootCertificates: string[] | null = null;
+function ensureLazyRootCertificates(target: string[]) {
+ if (lazyRootCertificates === null) {
+ lazyRootCertificates = op_get_root_certificates() as string[];
+ lazyRootCertificates.forEach((v) => target.push(v));
+ ObjectFreeze(target);
+ }
+}
+export const rootCertificates = new Proxy([] as string[], {
+ // @ts-ignore __proto__ is not in the types
+ __proto__: null,
+ get(target, prop) {
+ ensureLazyRootCertificates(target);
+ return Reflect.get(target, prop);
+ },
+ ownKeys(target) {
+ ensureLazyRootCertificates(target);
+ return Reflect.ownKeys(target);
+ },
+ has(target, prop) {
+ ensureLazyRootCertificates(target);
+ return Reflect.has(target, prop);
+ },
+ getOwnPropertyDescriptor(target, prop) {
+ ensureLazyRootCertificates(target);
+ return Reflect.getOwnPropertyDescriptor(target, prop);
+ },
+ set(target, prop, value) {
+ ensureLazyRootCertificates(target);
+ return Reflect.set(target, prop, value);
+ },
+ defineProperty(target, prop, descriptor) {
+ ensureLazyRootCertificates(target);
+ return Reflect.defineProperty(target, prop, descriptor);
+ },
+ deleteProperty(target, prop) {
+ ensureLazyRootCertificates(target);
+ return Reflect.deleteProperty(target, prop);
+ },
+ isExtensible(target) {
+ ensureLazyRootCertificates(target);
+ return Reflect.isExtensible(target);
+ },
+ preventExtensions(target) {
+ ensureLazyRootCertificates(target);
+ return Reflect.preventExtensions(target);
+ },
+ setPrototypeOf() {
+ return false;
+ },
+});
+
export const DEFAULT_ECDH_CURVE = "auto";
export const DEFAULT_MAX_VERSION = "TLSv1.3";
export const DEFAULT_MIN_VERSION = "TLSv1.2";