summaryrefslogtreecommitdiff
path: root/ext/node/ops/crypto/x509.rs
diff options
context:
space:
mode:
authorDivy Srivastava <dj.srivastava23@gmail.com>2024-08-11 06:28:54 -0700
committerGitHub <noreply@github.com>2024-08-11 18:58:54 +0530
commitb61fd622a5facc0ec29a8c3b04289ff5354ae03f (patch)
treeba6e5bf4c9e4fbb592f5dac719b22f2859ac5cbf /ext/node/ops/crypto/x509.rs
parentd6f662ac8280511fb4ef0f81777a0a6c5c08c0fa (diff)
fix(ext/node): rewrite X509Certificate resource and add `publicKey()` (#24988)
**Changes**: - Remove unsafe usage, rewrite Rust representation with `yoke`. - Implement `X509Certificate.prototype.publicKey()` Fixes https://github.com/denoland/deno/issues/23307
Diffstat (limited to 'ext/node/ops/crypto/x509.rs')
-rw-r--r--ext/node/ops/crypto/x509.rs94
1 files changed, 63 insertions, 31 deletions
diff --git a/ext/node/ops/crypto/x509.rs b/ext/node/ops/crypto/x509.rs
index c9a23aca0..b44ff3a4b 100644
--- a/ext/node/ops/crypto/x509.rs
+++ b/ext/node/ops/crypto/x509.rs
@@ -2,7 +2,6 @@
use deno_core::error::AnyError;
use deno_core::op2;
-use deno_core::v8;
use x509_parser::der_parser::asn1_rs::Any;
use x509_parser::der_parser::asn1_rs::Tag;
@@ -11,19 +10,33 @@ use x509_parser::extensions;
use x509_parser::pem;
use x509_parser::prelude::*;
+use super::KeyObjectHandle;
+
+use std::ops::Deref;
+use yoke::Yoke;
+use yoke::Yokeable;
+
use digest::Digest;
+enum CertificateSources {
+ Der(Box<[u8]>),
+ Pem(pem::Pem),
+}
+
+#[derive(Yokeable)]
+struct CertificateView<'a> {
+ cert: X509Certificate<'a>,
+}
+
pub(crate) struct Certificate {
- _buf: Vec<u8>,
- pem: Option<pem::Pem>,
- cert: X509Certificate<'static>,
+ inner: Yoke<CertificateView<'static>, Box<CertificateSources>>,
}
impl deno_core::GarbageCollected for Certificate {}
impl Certificate {
fn fingerprint<D: Digest>(&self) -> Option<String> {
- self.pem.as_ref().map(|pem| {
+ if let CertificateSources::Pem(pem) = self.inner.backing_cart().as_ref() {
let mut hasher = D::new();
hasher.update(&pem.contents);
let bytes = hasher.finalize();
@@ -33,13 +46,15 @@ impl Certificate {
hex.push_str(&format!("{:02X}:", byte));
}
hex.pop();
- hex
- })
+ Some(hex)
+ } else {
+ None
+ }
}
}
-impl std::ops::Deref for Certificate {
- type Target = X509Certificate<'static>;
+impl<'a> Deref for CertificateView<'a> {
+ type Target = X509Certificate<'a>;
fn deref(&self) -> &Self::Target {
&self.cert
@@ -47,36 +62,35 @@ impl std::ops::Deref for Certificate {
}
#[op2]
-pub fn op_node_x509_parse<'s>(
- scope: &'s mut v8::HandleScope,
+#[cppgc]
+pub fn op_node_x509_parse(
#[buffer] buf: &[u8],
-) -> Result<v8::Local<'s, v8::Object>, AnyError> {
- let pem = match pem::parse_x509_pem(buf) {
- Ok((_, pem)) => Some(pem),
- Err(_) => None,
+) -> Result<Certificate, AnyError> {
+ let source = match pem::parse_x509_pem(buf) {
+ Ok((_, pem)) => CertificateSources::Pem(pem),
+ Err(_) => CertificateSources::Der(buf.to_vec().into_boxed_slice()),
};
- 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::<X509Certificate<'_>, X509Certificate<'_>>(cert)
- },
- pem,
- };
+ let inner =
+ Yoke::<CertificateView<'static>, Box<CertificateSources>>::try_attach_to_cart(
+ Box::new(source),
+ |source| {
+ let cert = match source {
+ CertificateSources::Pem(pem) => pem.parse_x509()?,
+ CertificateSources::Der(buf) => {
+ X509Certificate::from_der(buf).map(|(_, cert)| cert)?
+ }
+ };
+ Ok::<_, AnyError>(CertificateView { cert })
+ },
+ )?;
- let obj = deno_core::cppgc::make_cppgc_object(scope, cert);
- Ok(obj)
+ Ok(Certificate { inner })
}
#[op2(fast)]
pub fn op_node_x509_ca(#[cppgc] cert: &Certificate) -> Result<bool, AnyError> {
+ let cert = cert.inner.get().deref();
Ok(cert.is_ca())
}
@@ -85,6 +99,7 @@ pub fn op_node_x509_check_email(
#[cppgc] cert: &Certificate,
#[string] email: &str,
) -> Result<bool, AnyError> {
+ let cert = cert.inner.get().deref();
let subject = cert.subject();
if subject
.iter_email()
@@ -144,6 +159,7 @@ pub fn op_node_x509_fingerprint512(
pub fn op_node_x509_get_issuer(
#[cppgc] cert: &Certificate,
) -> Result<String, AnyError> {
+ let cert = cert.inner.get().deref();
Ok(x509name_to_string(cert.issuer(), oid_registry())?)
}
@@ -152,9 +168,21 @@ pub fn op_node_x509_get_issuer(
pub fn op_node_x509_get_subject(
#[cppgc] cert: &Certificate,
) -> Result<String, AnyError> {
+ let cert = cert.inner.get().deref();
Ok(x509name_to_string(cert.subject(), oid_registry())?)
}
+#[op2]
+#[cppgc]
+pub fn op_node_x509_public_key(
+ #[cppgc] cert: &Certificate,
+) -> Result<KeyObjectHandle, AnyError> {
+ let cert = cert.inner.get().deref();
+ let public_key = &cert.tbs_certificate.subject_pki;
+
+ KeyObjectHandle::new_x509_public_key(public_key)
+}
+
// 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(
@@ -220,6 +248,7 @@ fn x509name_to_string(
pub fn op_node_x509_get_valid_from(
#[cppgc] cert: &Certificate,
) -> Result<String, AnyError> {
+ let cert = cert.inner.get().deref();
Ok(cert.validity().not_before.to_string())
}
@@ -228,6 +257,7 @@ pub fn op_node_x509_get_valid_from(
pub fn op_node_x509_get_valid_to(
#[cppgc] cert: &Certificate,
) -> Result<String, AnyError> {
+ let cert = cert.inner.get().deref();
Ok(cert.validity().not_after.to_string())
}
@@ -236,6 +266,7 @@ pub fn op_node_x509_get_valid_to(
pub fn op_node_x509_get_serial_number(
#[cppgc] cert: &Certificate,
) -> Result<String, AnyError> {
+ let cert = cert.inner.get().deref();
let mut s = cert.serial.to_str_radix(16);
s.make_ascii_uppercase();
Ok(s)
@@ -245,6 +276,7 @@ pub fn op_node_x509_get_serial_number(
pub fn op_node_x509_key_usage(
#[cppgc] cert: &Certificate,
) -> Result<u16, AnyError> {
+ let cert = cert.inner.get().deref();
let key_usage = cert
.extensions()
.iter()