mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
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>
This commit is contained in:
parent
5b14c71daf
commit
ab1e391e1d
8 changed files with 113 additions and 3 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -1859,6 +1859,7 @@ dependencies = [
|
|||
"thiserror",
|
||||
"tokio",
|
||||
"url",
|
||||
"webpki-root-certs",
|
||||
"winapi",
|
||||
"windows-sys 0.52.0",
|
||||
"x25519-dalek",
|
||||
|
@ -5974,9 +5975,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
|
||||
checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-tokio-stream"
|
||||
|
@ -8115,6 +8116,15 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-root-certs"
|
||||
version = "0.26.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d93b773107ba49bc84dd3b241e019c702d886fd5c457defe2ea8b1123a5dcd"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.1"
|
||||
|
|
|
@ -191,6 +191,7 @@ twox-hash = "=1.6.3"
|
|||
# Upgrading past 2.4.1 may cause WPT failures
|
||||
url = { version = "< 2.5.0", features = ["serde", "expose_internals"] }
|
||||
uuid = { version = "1.3.0", features = ["v4"] }
|
||||
webpki-root-certs = "0.26.5"
|
||||
webpki-roots = "0.26"
|
||||
which = "4.2.5"
|
||||
yoke = { version = "0.7.4", features = ["derive"] }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 = [
|
||||
|
|
|
@ -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;
|
||||
|
|
29
ext/node/ops/tls.rs
Normal file
29
ext/node/ops/tls.rs
Normal file
|
@ -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
|
||||
}
|
|
@ -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";
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
assertInstanceOf,
|
||||
assertStringIncludes,
|
||||
assertThrows,
|
||||
} from "@std/assert";
|
||||
import { delay } from "@std/async/delay";
|
||||
import { fromFileUrl, join } from "@std/path";
|
||||
|
@ -215,3 +217,13 @@ Deno.test("tls.connect() throws InvalidData when there's error in certificate",
|
|||
"InvalidData: invalid peer certificate: UnknownIssuer",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("tls.rootCertificates is not empty", () => {
|
||||
assert(tls.rootCertificates.length > 0);
|
||||
assert(Object.isFrozen(tls.rootCertificates));
|
||||
assert(tls.rootCertificates instanceof Array);
|
||||
assert(tls.rootCertificates.every((cert) => typeof cert === "string"));
|
||||
assertThrows(() => {
|
||||
(tls.rootCertificates as string[]).push("new cert");
|
||||
}, TypeError);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue