mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
parent
5d9172467e
commit
a0dd0cbcb9
9 changed files with 626 additions and 40 deletions
128
Cargo.lock
generated
128
Cargo.lock
generated
|
@ -109,6 +109,45 @@ version = "0.7.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "asn1-rs"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0"
|
||||
dependencies = [
|
||||
"asn1-rs-derive",
|
||||
"asn1-rs-impl",
|
||||
"displaydoc",
|
||||
"nom",
|
||||
"num-traits",
|
||||
"rusticata-macros",
|
||||
"thiserror",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asn1-rs-derive"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.56",
|
||||
"quote 1.0.26",
|
||||
"syn 1.0.109",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asn1-rs-impl"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.56",
|
||||
"quote 1.0.26",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ast_node"
|
||||
version = "0.8.6"
|
||||
|
@ -1108,6 +1147,7 @@ version = "0.34.0"
|
|||
dependencies = [
|
||||
"aes",
|
||||
"cbc",
|
||||
"data-encoding",
|
||||
"deno_core",
|
||||
"digest 0.10.6",
|
||||
"ecb",
|
||||
|
@ -1135,6 +1175,7 @@ dependencies = [
|
|||
"signature",
|
||||
"tokio",
|
||||
"typenum",
|
||||
"x509-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1339,6 +1380,20 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der-parser"
|
||||
version = "8.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e"
|
||||
dependencies = [
|
||||
"asn1-rs",
|
||||
"displaydoc",
|
||||
"nom",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"rusticata-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.17"
|
||||
|
@ -1388,6 +1443,17 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.56",
|
||||
"quote 1.0.26",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dissimilar"
|
||||
version = "1.0.4"
|
||||
|
@ -2722,6 +2788,12 @@ version = "0.3.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.5.4"
|
||||
|
@ -2812,6 +2884,16 @@ dependencies = [
|
|||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "5.0.0"
|
||||
|
@ -2910,6 +2992,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oid-registry"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff"
|
||||
dependencies = [
|
||||
"asn1-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
|
@ -3601,6 +3692,15 @@ dependencies = [
|
|||
"semver 1.0.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusticata-macros"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.9"
|
||||
|
@ -4745,8 +4845,10 @@ version = "0.3.20"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4755,6 +4857,15 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
|
@ -5670,6 +5781,23 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x509-parser"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab0c2f54ae1d92f4fcb99c0b7ccf0b1e3451cbd395e5f115ccbdbcb18d4f634"
|
||||
dependencies = [
|
||||
"asn1-rs",
|
||||
"data-encoding",
|
||||
"der-parser",
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"oid-registry",
|
||||
"rusticata-macros",
|
||||
"thiserror",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "0.2.3"
|
||||
|
|
|
@ -232,6 +232,7 @@
|
|||
"test-crypto-hmac.js",
|
||||
"test-crypto-prime.js",
|
||||
"test-crypto-secret-keygen.js",
|
||||
"test-crypto-x509.js",
|
||||
"test-dgram-close-during-bind.js",
|
||||
"test-dgram-close-signal.js",
|
||||
"test-diagnostics-channel-has-subscribers.js",
|
||||
|
|
22
cli/tests/node_compat/test/fixtures/keys/ca1-cert.pem
vendored
Normal file
22
cli/tests/node_compat/test/fixtures/keys/ca1-cert.pem
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDlDCCAnygAwIBAgIUSrFsjf1qfQ0t/KvfnEsOksatAikwDQYJKoZIhvcNAQEL
|
||||
BQAwejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEPMA0G
|
||||
A1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQwwCgYDVQQDDANjYTExIDAe
|
||||
BgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMCAXDTIyMDkwMzIxNDAzN1oY
|
||||
DzIyOTYwNjE3MjE0MDM3WjB6MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExCzAJ
|
||||
BgNVBAcMAlNGMQ8wDQYDVQQKDAZKb3llbnQxEDAOBgNVBAsMB05vZGUuanMxDDAK
|
||||
BgNVBAMMA2NhMTEgMB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNvf4OGGep+ak+4DNjbuNgy0S/
|
||||
AZPxahEFp4gpbcvsi9YLOPZ31qpilQeQf7d27scIZ02Qx1YBAzljxELB8H/ZxuYS
|
||||
cQK0s+DNP22xhmgwMWznO7TezkHP5ujN2UkbfbUpfUxGFgncXeZf9wR7yFWppeHi
|
||||
RWNBOgsvY7sTrS12kXjWGjqntF7xcEDHc7h+KyF6ZjVJZJCnP6pJEQ+rUjd51eCZ
|
||||
Xt4WjowLnQiCS1VKzXiP83a++Ma1BKKkUitTR112/Uwd5eGoiByhmLzb/BhxnHJN
|
||||
07GXjhlMItZRm/jfbZsx1mwnNOO3tx4r08l+DaqkinIadvazs+1ugCaKQn8xAgMB
|
||||
AAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFqG0RXURDam
|
||||
56x5accdg9sY5zEGP5VQhkK3ZDc2NyNNa25rwvrjCpO+e0OSwKAmm4aX6iIf2woY
|
||||
wF2f9swWYzxn9CG4fDlUA8itwlnHxupeL4fGMTYb72vf31plUXyBySRsTwHwBloc
|
||||
F7KvAZpYYKN9EMH1S/267By6H2I33BT/Ethv//n8dSfmuCurR1kYRaiOC4PVeyFk
|
||||
B3sj8TtolrN0y/nToWUhmKiaVFnDx3odQ00yhmxR3t21iB7yDkko6D8Vf2dVC4j/
|
||||
YYBVprXGlTP/hiYRLDoP20xKOYznx5cvHPJ9p+lVcOZUJsJj/Iy750+2n5UiBmXt
|
||||
lz88C25ucKA=
|
||||
-----END CERTIFICATE-----
|
109
cli/tests/node_compat/test/parallel/test-crypto-x509.js
Normal file
109
cli/tests/node_compat/test/parallel/test-crypto-x509.js
Normal file
|
@ -0,0 +1,109 @@
|
|||
// deno-fmt-ignore-file
|
||||
// deno-lint-ignore-file
|
||||
|
||||
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const {
|
||||
X509Certificate,
|
||||
} = require('crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const { readFileSync } = require('fs');
|
||||
|
||||
const cert = readFileSync(fixtures.path('keys', 'agent1-cert.pem'));
|
||||
const ca = readFileSync(fixtures.path('keys', 'ca1-cert.pem'));
|
||||
|
||||
[1, {}, false, null].forEach((i) => {
|
||||
assert.throws(() => new X509Certificate(i), {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
});
|
||||
|
||||
const subjectCheck = `C=US
|
||||
ST=CA
|
||||
L=SF
|
||||
O=Joyent
|
||||
OU=Node.js
|
||||
CN=agent1
|
||||
Email=ry@tinyclouds.org`;
|
||||
|
||||
const issuerCheck = `C=US
|
||||
ST=CA
|
||||
L=SF
|
||||
O=Joyent
|
||||
OU=Node.js
|
||||
CN=ca1
|
||||
Email=ry@tinyclouds.org`;
|
||||
|
||||
let infoAccessCheck = `OCSP - URI:http://ocsp.nodejs.org/
|
||||
CA Issuers - URI:http://ca.nodejs.org/ca.cert`;
|
||||
if (!common.hasOpenSSL3)
|
||||
infoAccessCheck += '\n';
|
||||
|
||||
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 x509 = new X509Certificate(cert);
|
||||
|
||||
assert(!x509.ca);
|
||||
assert.strictEqual(x509.subject, subjectCheck);
|
||||
assert.strictEqual(x509.subjectAltName, undefined);
|
||||
assert.strictEqual(x509.issuer, issuerCheck);
|
||||
assert.strictEqual(x509.validFrom, 'Sep 3 21:40:37 2022 +00:00');
|
||||
assert.strictEqual(x509.validTo, 'Jun 17 21:40:37 2296 +00:00');
|
||||
assert.strictEqual(
|
||||
x509.fingerprint,
|
||||
'8B:89:16:C4:99:87:D2:13:1A:64:94:36:38:A5:32:01:F0:95:3B:53');
|
||||
assert.strictEqual(
|
||||
x509.fingerprint256,
|
||||
'2C:62:59:16:91:89:AB:90:6A:3E:98:88:A6:D3:C5:58:58:6C:AE:FF:9C:33:' +
|
||||
'22:7C:B6:77:D3:34:E7:53:4B:05'
|
||||
);
|
||||
assert.strictEqual(
|
||||
x509.fingerprint512,
|
||||
'0B:6F:D0:4D:6B:22:53:99:66:62:51:2D:2C:96:F2:58:3F:95:1C:CC:4C:44:' +
|
||||
'9D:B5:59:AA:AD:A8:F6:2A:24:8A:BB:06:A5:26:42:52:30:A3:37:61:30:A9:' +
|
||||
'5A:42:63:E0:21:2F:D6:70:63:07:96:6F:27:A7:78:12:08:02:7A:8B'
|
||||
);
|
||||
assert.strictEqual(x509.keyUsage, undefined);
|
||||
assert.strictEqual(x509.serialNumber, '147D36C1C2F74206DE9FAB5F2226D78ADB00A426');
|
||||
|
||||
assert.strictEqual(x509.checkEmail('ry@tinyclouds.org'), 'ry@tinyclouds.org');
|
||||
assert.strictEqual(x509.checkEmail('sally@example.com'), undefined);
|
||||
}
|
|
@ -16,6 +16,7 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
aes.workspace = true
|
||||
cbc.workspace = true
|
||||
data-encoding = "2.3.3"
|
||||
deno_core.workspace = true
|
||||
digest = { version = "0.10.5", features = ["core-api", "std"] }
|
||||
ecb.workspace = true
|
||||
|
@ -43,3 +44,4 @@ sha3 = "0.10.5"
|
|||
signature.workspace = true
|
||||
tokio.workspace = true
|
||||
typenum = "1.15.0"
|
||||
x509-parser = "0.15.0"
|
||||
|
|
|
@ -23,6 +23,7 @@ use rsa::RsaPublicKey;
|
|||
mod cipher;
|
||||
mod digest;
|
||||
mod primes;
|
||||
pub mod x509;
|
||||
|
||||
#[op]
|
||||
pub fn op_node_check_prime(num: serde_v8::BigInt, checks: usize) -> bool {
|
||||
|
|
315
ext/node/crypto/x509.rs
Normal file
315
ext/node/crypto/x509.rs
Normal file
|
@ -0,0 +1,315 @@
|
|||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::op;
|
||||
use deno_core::OpState;
|
||||
use deno_core::Resource;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use x509_parser::der_parser::asn1_rs::Any;
|
||||
use x509_parser::der_parser::asn1_rs::Tag;
|
||||
use x509_parser::der_parser::oid::Oid;
|
||||
use x509_parser::extensions;
|
||||
use x509_parser::pem;
|
||||
use x509_parser::prelude::*;
|
||||
|
||||
use digest::Digest;
|
||||
|
||||
struct Certificate {
|
||||
_buf: Vec<u8>,
|
||||
pem: Option<pem::Pem>,
|
||||
cert: X509Certificate<'static>,
|
||||
}
|
||||
|
||||
impl Certificate {
|
||||
fn fingerprint<D: Digest>(&self) -> Option<String> {
|
||||
self.pem.as_ref().map(|pem| {
|
||||
let mut hasher = D::new();
|
||||
hasher.update(&pem.contents);
|
||||
let bytes = hasher.finalize();
|
||||
// OpenSSL returns colon separated upper case hex values.
|
||||
let mut hex = String::with_capacity(bytes.len() * 2);
|
||||
for byte in bytes {
|
||||
hex.push_str(&format!("{:02X}:", byte));
|
||||
}
|
||||
hex.pop();
|
||||
hex
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Certificate {
|
||||
type Target = X509Certificate<'static>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.cert
|
||||
}
|
||||
}
|
||||
|
||||
impl Resource for Certificate {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"x509Certificate".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_parse(
|
||||
state: &mut OpState,
|
||||
buf: &[u8],
|
||||
) -> Result<u32, AnyError> {
|
||||
let pem = match pem::parse_x509_pem(buf) {
|
||||
Ok((_, pem)) => Some(pem),
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let cert = pem
|
||||
.as_ref()
|
||||
.map(|pem| pem.parse_x509())
|
||||
.unwrap_or_else(|| X509Certificate::from_der(buf).map(|(_, cert)| cert))?;
|
||||
|
||||
let cert = Certificate {
|
||||
_buf: buf.to_vec(),
|
||||
// SAFETY: Extending the lifetime of the certificate. Backing buffer is
|
||||
// owned by the resource.
|
||||
cert: unsafe { std::mem::transmute(cert) },
|
||||
pem,
|
||||
};
|
||||
let rid = state.resource_table.add(cert);
|
||||
Ok(rid)
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_ca(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<bool, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
Ok(cert.is_ca())
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_check_email(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
email: &str,
|
||||
) -> Result<bool, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
|
||||
let subject = cert.subject();
|
||||
if subject
|
||||
.iter_email()
|
||||
.any(|e| e.as_str().unwrap_or("") == email)
|
||||
{
|
||||
return Ok(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 {
|
||||
dbg!(name);
|
||||
if let extensions::GeneralName::RFC822Name(n) = name {
|
||||
if *n == email {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_fingerprint(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
Ok(cert.fingerprint::<sha1::Sha1>())
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_fingerprint256(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
Ok(cert.fingerprint::<sha2::Sha256>())
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_fingerprint512(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
Ok(cert.fingerprint::<sha2::Sha512>())
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_get_issuer(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<String, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
Ok(x509name_to_string(cert.issuer(), oid_registry())?)
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_get_subject(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<String, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
Ok(x509name_to_string(cert.subject(), oid_registry())?)
|
||||
}
|
||||
|
||||
// Attempt to convert attribute to string. If type is not a string, return value is the hex
|
||||
// encoding of the attribute value
|
||||
fn attribute_value_to_string(
|
||||
attr: &Any,
|
||||
_attr_type: &Oid,
|
||||
) -> Result<String, X509Error> {
|
||||
// TODO: replace this with helper function, when it is added to asn1-rs
|
||||
match attr.tag() {
|
||||
Tag::NumericString
|
||||
| Tag::BmpString
|
||||
| Tag::VisibleString
|
||||
| Tag::PrintableString
|
||||
| Tag::GeneralString
|
||||
| Tag::ObjectDescriptor
|
||||
| Tag::GraphicString
|
||||
| Tag::T61String
|
||||
| Tag::VideotexString
|
||||
| Tag::Utf8String
|
||||
| Tag::Ia5String => {
|
||||
let s = core::str::from_utf8(attr.data)
|
||||
.map_err(|_| X509Error::InvalidAttributes)?;
|
||||
Ok(s.to_owned())
|
||||
}
|
||||
_ => {
|
||||
// type is not a string, get slice and convert it to base64
|
||||
Ok(data_encoding::HEXUPPER.encode(attr.as_bytes()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn x509name_to_string(
|
||||
name: &X509Name,
|
||||
oid_registry: &oid_registry::OidRegistry,
|
||||
) -> Result<String, x509_parser::error::X509Error> {
|
||||
name.iter_rdn().fold(Ok(String::new()), |acc, rdn| {
|
||||
acc.and_then(|mut _vec| {
|
||||
rdn
|
||||
.iter()
|
||||
.fold(Ok(String::new()), |acc2, attr| {
|
||||
acc2.and_then(|mut _vec2| {
|
||||
let val_str =
|
||||
attribute_value_to_string(attr.attr_value(), attr.attr_type())?;
|
||||
// look ABBREV, and if not found, use shortname
|
||||
let abbrev = match oid2abbrev(attr.attr_type(), oid_registry) {
|
||||
Ok(s) => String::from(s),
|
||||
_ => format!("{:?}", attr.attr_type()),
|
||||
};
|
||||
let rdn = format!("{}={}", abbrev, val_str);
|
||||
match _vec2.len() {
|
||||
0 => Ok(rdn),
|
||||
_ => Ok(_vec2 + " + " + &rdn),
|
||||
}
|
||||
})
|
||||
})
|
||||
.map(|v| match _vec.len() {
|
||||
0 => v,
|
||||
_ => _vec + "\n" + &v,
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_get_valid_from(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<String, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
Ok(cert.validity().not_before.to_string())
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_get_valid_to(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<String, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
Ok(cert.validity().not_after.to_string())
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_get_serial_number(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<String, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
let mut s = cert.serial.to_str_radix(16);
|
||||
s.make_ascii_uppercase();
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_x509_key_usage(
|
||||
state: &mut OpState,
|
||||
rid: u32,
|
||||
) -> Result<u16, AnyError> {
|
||||
let cert = state
|
||||
.resource_table
|
||||
.get::<Certificate>(rid)
|
||||
.or_else(|_| Err(bad_resource_id()))?;
|
||||
|
||||
let key_usage = cert
|
||||
.extensions()
|
||||
.iter()
|
||||
.find(|e| e.oid == x509_parser::oid_registry::OID_X509_EXT_KEY_USAGE)
|
||||
.and_then(|e| match e.parsed_extension() {
|
||||
extensions::ParsedExtension::KeyUsage(k) => Some(k),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
Ok(key_usage.map(|k| k.flags).unwrap_or(0))
|
||||
}
|
|
@ -194,6 +194,18 @@ deno_core::extension!(deno_node,
|
|||
crypto::op_node_generate_secret,
|
||||
crypto::op_node_generate_secret_async,
|
||||
crypto::op_node_sign,
|
||||
crypto::x509::op_node_x509_parse,
|
||||
crypto::x509::op_node_x509_ca,
|
||||
crypto::x509::op_node_x509_check_email,
|
||||
crypto::x509::op_node_x509_fingerprint,
|
||||
crypto::x509::op_node_x509_fingerprint256,
|
||||
crypto::x509::op_node_x509_fingerprint512,
|
||||
crypto::x509::op_node_x509_get_issuer,
|
||||
crypto::x509::op_node_x509_get_subject,
|
||||
crypto::x509::op_node_x509_get_valid_from,
|
||||
crypto::x509::op_node_x509_get_valid_to,
|
||||
crypto::x509::op_node_x509_get_serial_number,
|
||||
crypto::x509::op_node_x509_key_usage,
|
||||
winerror::op_node_sys_to_uv_error,
|
||||
v8::op_v8_cached_data_version_tag,
|
||||
v8::op_v8_get_heap_statistics,
|
||||
|
|
|
@ -5,9 +5,12 @@ import { KeyObject } from "ext:deno_node/internal/crypto/keys.ts";
|
|||
import { Buffer } from "ext:deno_node/buffer.ts";
|
||||
import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts";
|
||||
import { isArrayBufferView } from "ext:deno_node/internal/util/types.ts";
|
||||
import { validateString } from "ext:deno_node/internal/validators.mjs";
|
||||
import { notImplemented } from "ext:deno_node/_utils.ts";
|
||||
import { BinaryLike } from "ext:deno_node/internal/crypto/types.ts";
|
||||
|
||||
const { ops } = globalThis.__bootstrap.core;
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export type PeerCertificate = any;
|
||||
|
||||
|
@ -35,6 +38,8 @@ export interface X509CheckOptions {
|
|||
}
|
||||
|
||||
export class X509Certificate {
|
||||
#handle: number;
|
||||
|
||||
constructor(buffer: BinaryLike) {
|
||||
if (typeof buffer === "string") {
|
||||
buffer = Buffer.from(buffer);
|
||||
|
@ -48,20 +53,21 @@ export class X509Certificate {
|
|||
);
|
||||
}
|
||||
|
||||
notImplemented("crypto.X509Certificate");
|
||||
this.#handle = ops.op_node_x509_parse(buffer);
|
||||
}
|
||||
|
||||
get ca(): boolean {
|
||||
notImplemented("crypto.X509Certificate.prototype.ca");
|
||||
|
||||
return false;
|
||||
return ops.op_node_x509_ca(this.#handle);
|
||||
}
|
||||
|
||||
checkEmail(
|
||||
_email: string,
|
||||
email: string,
|
||||
_options?: Pick<X509CheckOptions, "subject">,
|
||||
): string | undefined {
|
||||
notImplemented("crypto.X509Certificate.prototype.checkEmail");
|
||||
validateString(email, "email");
|
||||
if (ops.op_node_x509_check_email(this.#handle, email)) {
|
||||
return email;
|
||||
}
|
||||
}
|
||||
|
||||
checkHost(_name: string, _options?: X509CheckOptions): string | undefined {
|
||||
|
@ -81,21 +87,15 @@ export class X509Certificate {
|
|||
}
|
||||
|
||||
get fingerprint(): string {
|
||||
notImplemented("crypto.X509Certificate.prototype.fingerprint");
|
||||
|
||||
return "";
|
||||
return ops.op_node_x509_fingerprint(this.#handle);
|
||||
}
|
||||
|
||||
get fingerprint256(): string {
|
||||
notImplemented("crypto.X509Certificate.prototype.fingerprint256");
|
||||
|
||||
return "";
|
||||
return ops.op_node_x509_fingerprint256(this.#handle);
|
||||
}
|
||||
|
||||
get fingerprint512(): string {
|
||||
notImplemented("crypto.X509Certificate.prototype.fingerprint512");
|
||||
|
||||
return "";
|
||||
return ops.op_node_x509_fingerprint512(this.#handle);
|
||||
}
|
||||
|
||||
get infoAccess(): string | undefined {
|
||||
|
@ -105,21 +105,27 @@ export class X509Certificate {
|
|||
}
|
||||
|
||||
get issuer(): string {
|
||||
notImplemented("crypto.X509Certificate.prototype.issuer");
|
||||
|
||||
return "";
|
||||
return ops.op_node_x509_get_issuer(this.#handle);
|
||||
}
|
||||
|
||||
get issuerCertificate(): X509Certificate | undefined {
|
||||
notImplemented("crypto.X509Certificate.prototype.issuerCertificate");
|
||||
|
||||
return {} as X509Certificate;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
get keyUsage(): string[] {
|
||||
notImplemented("crypto.X509Certificate.prototype.keyUsage");
|
||||
|
||||
return [];
|
||||
get keyUsage(): string[] | undefined {
|
||||
const flags = ops.op_node_x509_key_usage(this.#handle);
|
||||
if (flags === 0) return undefined;
|
||||
const result: string[] = [];
|
||||
if (flags & 0x01) result.push("DigitalSignature");
|
||||
if (flags >> 1 & 0x01) result.push("NonRepudiation");
|
||||
if (flags >> 2 & 0x01) result.push("KeyEncipherment");
|
||||
if (flags >> 3 & 0x01) result.push("DataEncipherment");
|
||||
if (flags >> 4 & 0x01) result.push("KeyAgreement");
|
||||
if (flags >> 5 & 0x01) result.push("KeyCertSign");
|
||||
if (flags >> 6 & 0x01) result.push("CRLSign");
|
||||
if (flags >> 7 & 0x01) result.push("EncipherOnly");
|
||||
if (flags >> 8 & 0x01) result.push("DecipherOnly");
|
||||
return result;
|
||||
}
|
||||
|
||||
get publicKey(): KeyObject {
|
||||
|
@ -135,21 +141,15 @@ export class X509Certificate {
|
|||
}
|
||||
|
||||
get serialNumber(): string {
|
||||
notImplemented("crypto.X509Certificate.prototype.serialNumber");
|
||||
|
||||
return "";
|
||||
return ops.op_node_x509_get_serial_number(this.#handle);
|
||||
}
|
||||
|
||||
get subject(): string {
|
||||
notImplemented("crypto.X509Certificate.prototype.subject");
|
||||
|
||||
return "";
|
||||
return ops.op_node_x509_get_subject(this.#handle);
|
||||
}
|
||||
|
||||
get subjectAltName(): string | undefined {
|
||||
notImplemented("crypto.X509Certificate.prototype.subjectAltName");
|
||||
|
||||
return "";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
toJSON(): string {
|
||||
|
@ -165,15 +165,11 @@ export class X509Certificate {
|
|||
}
|
||||
|
||||
get validFrom(): string {
|
||||
notImplemented("crypto.X509Certificate.prototype.validFrom");
|
||||
|
||||
return "";
|
||||
return ops.op_node_x509_get_valid_from(this.#handle);
|
||||
}
|
||||
|
||||
get validTo(): string {
|
||||
notImplemented("crypto.X509Certificate.prototype.validTo");
|
||||
|
||||
return "";
|
||||
return ops.op_node_x509_get_valid_to(this.#handle);
|
||||
}
|
||||
|
||||
verify(_publicKey: KeyObject): boolean {
|
||||
|
|
Loading…
Reference in a new issue