Skip to content

Commit

Permalink
fix(ext/node): implement X509Certificate#checkHost (#27821)
Browse files Browse the repository at this point in the history
Fixes #27619
  • Loading branch information
littledivy authored and bartlomieju committed Jan 30, 2025
1 parent 2b27d34 commit 6fe2341
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
1 change: 1 addition & 0 deletions ext/node/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ deno_core::extension!(deno_node,
ops::crypto::x509::op_node_x509_parse,
ops::crypto::x509::op_node_x509_ca,
ops::crypto::x509::op_node_x509_check_email,
ops::crypto::x509::op_node_x509_check_host,
ops::crypto::x509::op_node_x509_fingerprint,
ops::crypto::x509::op_node_x509_fingerprint256,
ops::crypto::x509::op_node_x509_fingerprint512,
Expand Down
37 changes: 37 additions & 0 deletions ext/node/ops/crypto/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,43 @@ pub fn op_node_x509_check_email(
false
}

#[op2(fast)]
pub fn op_node_x509_check_host(
#[cppgc] cert: &Certificate,
#[string] host: &str,
) -> bool {
let cert = cert.inner.get().deref();

let subject = cert.subject();
if subject
.iter_common_name()
.any(|e| e.as_str().unwrap_or("") == host)
{
return true;
}

let subject_alt = cert
.extensions()
.iter()
.find(|e| e.oid == x509_parser::oid_registry::OID_X509_EXT_SUBJECT_ALT_NAME)
.and_then(|e| match e.parsed_extension() {
extensions::ParsedExtension::SubjectAlternativeName(s) => Some(s),
_ => None,
});

if let Some(subject_alt) = subject_alt {
for name in &subject_alt.general_names {
if let extensions::GeneralName::DNSName(n) = name {
if *n == host {
return true;
}
}
}
}

false
}

#[op2]
#[string]
pub fn op_node_x509_fingerprint(#[cppgc] cert: &Certificate) -> Option<String> {
Expand Down
8 changes: 6 additions & 2 deletions ext/node/polyfills/internal/crypto/x509.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import {
op_node_x509_ca,
op_node_x509_check_email,
op_node_x509_check_host,
op_node_x509_fingerprint,
op_node_x509_fingerprint256,
op_node_x509_fingerprint512,
Expand Down Expand Up @@ -90,8 +91,11 @@ export class X509Certificate {
}
}

checkHost(_name: string, _options?: X509CheckOptions): string | undefined {
notImplemented("crypto.X509Certificate.prototype.checkHost");
checkHost(name: string, _options?: X509CheckOptions): string | undefined {
validateString(name, "name");
if (op_node_x509_check_host(this.#handle, name)) {
return name;
}
}

checkIP(_ip: string): string | undefined {
Expand Down
39 changes: 39 additions & 0 deletions tests/unit_node/crypto/crypto_key_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
generateKeyPairSync,
KeyObject,
randomBytes,
X509Certificate,
} from "node:crypto";
import { promisify } from "node:util";
import { Buffer } from "node:buffer";
Expand Down Expand Up @@ -716,3 +717,41 @@ Deno.test("RSA export private JWK", function () {
assertEquals((privateKey as any).kty, "RSA");
assertEquals((privateKey as any).n, (publicKey as any).n);
});

Deno.test("X509Certificate checkHost", function () {
const der = Buffer.from(
"308203e8308202d0a0030201020214147d36c1c2f74206de9fab5f2226d78adb00a42630" +
"0d06092a864886f70d01010b0500307a310b3009060355040613025553310b3009060355" +
"04080c024341310b300906035504070c025346310f300d060355040a0c064a6f79656e74" +
"3110300e060355040b0c074e6f64652e6a73310c300a06035504030c036361313120301e" +
"06092a864886f70d010901161172794074696e79636c6f7564732e6f72673020170d3232" +
"303930333231343033375a180f32323936303631373231343033375a307d310b30090603" +
"55040613025553310b300906035504080c024341310b300906035504070c025346310f30" +
"0d060355040a0c064a6f79656e743110300e060355040b0c074e6f64652e6a73310f300d" +
"06035504030c066167656e74313120301e06092a864886f70d010901161172794074696e" +
"79636c6f7564732e6f726730820122300d06092a864886f70d01010105000382010f0030" +
"82010a0282010100d456320afb20d3827093dc2c4284ed04dfbabd56e1ddae529e28b790" +
"cd4256db273349f3735ffd337c7a6363ecca5a27b7f73dc7089a96c6d886db0c62388f1c" +
"dd6a963afcd599d5800e587a11f908960f84ed50ba25a28303ecda6e684fbe7baedc9ce8" +
"801327b1697af25097cee3f175e400984c0db6a8eb87be03b4cf94774ba56fffc8c63c68" +
"d6adeb60abbe69a7b14ab6a6b9e7baa89b5adab8eb07897c07f6d4fa3d660dff574107d2" +
"8e8f63467a788624c574197693e959cea1362ffae1bba10c8c0d88840abfef103631b2e8" +
"f5c39b5548a7ea57e8a39f89291813f45a76c448033a2b7ed8403f4baa147cf35e2d2554" +
"aa65ce49695797095bf4dc6b0203010001a361305f305d06082b06010505070101045130" +
"4f302306082b060105050730018617687474703a2f2f6f6373702e6e6f64656a732e6f72" +
"672f302806082b06010505073002861c687474703a2f2f63612e6e6f64656a732e6f7267" +
"2f63612e63657274300d06092a864886f70d01010b05000382010100c3349810632ccb7d" +
"a585de3ed51e34ed154f0f7215608cf2701c00eda444dc2427072c8aca4da6472c1d9e68" +
"f177f99a90a8b5dbf3884586d61cb1c14ea7016c8d38b70d1b46b42947db30edc1e9961e" +
"d46c0f0e35da427bfbe52900771817e733b371adf19e12137235141a34347db0dfc05579" +
"8b1f269f3bdf5e30ce35d1339d56bb3c570de9096215433047f87ca42447b44e7e6b5d0e" +
"48f7894ab186f85b6b1a74561b520952fea888617f32f582afce1111581cd63efcc68986" +
"00d248bb684dedb9c3d6710c38de9e9bc21f9c3394b729d5f707d64ea890603e5989f8fa" +
"59c19ad1a00732e7adc851b89487cc00799dde068aa64b3b8fd976e8bc113ef2",
"hex",
);

const cert = new X509Certificate(der);
assertEquals(cert.checkHost("www.google.com"), undefined);
assertEquals(cert.checkHost("agent1"), "agent1");
});

0 comments on commit 6fe2341

Please sign in to comment.