diff options
Diffstat (limited to 'ext/node')
-rw-r--r-- | ext/node/Cargo.toml | 1 | ||||
-rw-r--r-- | ext/node/lib.rs | 1 | ||||
-rw-r--r-- | ext/node/ops/mod.rs | 1 | ||||
-rw-r--r-- | ext/node/ops/tls.rs | 29 | ||||
-rw-r--r-- | ext/node/polyfills/tls.ts | 57 |
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"; |