mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 00:20:08 +01:00
crypto: expose signatureAlgorithm on X509Certificate
Adds the `signatureAlgorithm` property to a X509Certificate allowing users to retrieve a string representing the algorithm used to sign the certificate. This string is defined by the OpenSSL library. Fixes: https://github.com/nodejs/node/issues/59103 PR-URL: https://github.com/nodejs/node/pull/59235 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
This commit is contained in:
parent
f1a8f447d7
commit
64a8b4b1ba
25
deps/ncrypto/ncrypto.cc
vendored
25
deps/ncrypto/ncrypto.cc
vendored
|
|
@ -8,7 +8,9 @@
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <string_view>
|
||||||
#if OPENSSL_VERSION_MAJOR >= 3
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
#include <openssl/core_names.h>
|
#include <openssl/core_names.h>
|
||||||
#include <openssl/params.h>
|
#include <openssl/params.h>
|
||||||
|
|
@ -1094,6 +1096,29 @@ BIOPointer X509View::getValidTo() const {
|
||||||
return bio;
|
return bio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string_view> X509View::getSignatureAlgorithm() const {
|
||||||
|
if (cert_ == nullptr) return std::nullopt;
|
||||||
|
int nid = X509_get_signature_nid(cert_);
|
||||||
|
if (nid == NID_undef) return std::nullopt;
|
||||||
|
const char* ln = OBJ_nid2ln(nid);
|
||||||
|
if (ln == nullptr) return std::nullopt;
|
||||||
|
return std::string_view(ln);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> X509View::getSignatureAlgorithmOID() const {
|
||||||
|
if (cert_ == nullptr) return std::nullopt;
|
||||||
|
const X509_ALGOR* alg = nullptr;
|
||||||
|
X509_get0_signature(nullptr, &alg, cert_);
|
||||||
|
if (alg == nullptr) return std::nullopt;
|
||||||
|
const ASN1_OBJECT* obj = nullptr;
|
||||||
|
X509_ALGOR_get0(&obj, nullptr, nullptr, alg);
|
||||||
|
if (obj == nullptr) return std::nullopt;
|
||||||
|
std::array<char, 128> buf{};
|
||||||
|
int len = OBJ_obj2txt(buf.data(), buf.size(), obj, 1);
|
||||||
|
if (len < 0 || static_cast<size_t>(len) >= buf.size()) return std::nullopt;
|
||||||
|
return std::string(buf.data(), static_cast<size_t>(len));
|
||||||
|
}
|
||||||
|
|
||||||
int64_t X509View::getValidToTime() const {
|
int64_t X509View::getValidToTime() const {
|
||||||
#ifdef OPENSSL_IS_BORINGSSL
|
#ifdef OPENSSL_IS_BORINGSSL
|
||||||
// Boringssl does not implement ASN1_TIME_to_tm in a public way,
|
// Boringssl does not implement ASN1_TIME_to_tm in a public way,
|
||||||
|
|
|
||||||
2
deps/ncrypto/ncrypto.h
vendored
2
deps/ncrypto/ncrypto.h
vendored
|
|
@ -1191,6 +1191,8 @@ class X509View final {
|
||||||
BIOPointer getInfoAccess() const;
|
BIOPointer getInfoAccess() const;
|
||||||
BIOPointer getValidFrom() const;
|
BIOPointer getValidFrom() const;
|
||||||
BIOPointer getValidTo() const;
|
BIOPointer getValidTo() const;
|
||||||
|
std::optional<std::string_view> getSignatureAlgorithm() const;
|
||||||
|
std::optional<std::string> getSignatureAlgorithmOID() const;
|
||||||
int64_t getValidFromTime() const;
|
int64_t getValidFromTime() const;
|
||||||
int64_t getValidToTime() const;
|
int64_t getValidToTime() const;
|
||||||
DataPointer getSerialNumber() const;
|
DataPointer getSerialNumber() const;
|
||||||
|
|
|
||||||
|
|
@ -2971,6 +2971,26 @@ added:
|
||||||
|
|
||||||
The date/time until which this certificate is valid, encapsulated in a `Date` object.
|
The date/time until which this certificate is valid, encapsulated in a `Date` object.
|
||||||
|
|
||||||
|
### `x509.signatureAlgorithm`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* Type: {string|undefined}
|
||||||
|
|
||||||
|
The algorithm used to sign the certificate or `undefined` if the signature algorithm is unknown by OpenSSL.
|
||||||
|
|
||||||
|
### `x509.signatureAlgorithmOid`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* Type: {string}
|
||||||
|
|
||||||
|
The OID of the algorithm used to sign the certificate.
|
||||||
|
|
||||||
### `x509.verify(publicKey)`
|
### `x509.verify(publicKey)`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,8 @@ class X509Certificate {
|
||||||
fingerprint512: this.fingerprint512,
|
fingerprint512: this.fingerprint512,
|
||||||
keyUsage: this.keyUsage,
|
keyUsage: this.keyUsage,
|
||||||
serialNumber: this.serialNumber,
|
serialNumber: this.serialNumber,
|
||||||
|
signatureAlgorithm: this.signatureAlgorithm,
|
||||||
|
signatureAlgorithmOid: this.signatureAlgorithmOid,
|
||||||
}, opts)}`;
|
}, opts)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,6 +287,24 @@ class X509Certificate {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get signatureAlgorithm() {
|
||||||
|
let value = this[kInternalState].get('signatureAlgorithm');
|
||||||
|
if (value === undefined) {
|
||||||
|
value = this[kHandle].signatureAlgorithm();
|
||||||
|
this[kInternalState].set('signatureAlgorithm', value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get signatureAlgorithmOid() {
|
||||||
|
let value = this[kInternalState].get('signatureAlgorithmOid');
|
||||||
|
if (value === undefined) {
|
||||||
|
value = this[kHandle].signatureAlgorithmOid();
|
||||||
|
this[kInternalState].set('signatureAlgorithmOid', value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
get raw() {
|
get raw() {
|
||||||
let value = this[kInternalState].get('raw');
|
let value = this[kInternalState].get('raw');
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,30 @@ MaybeLocal<Value> GetValidToDate(Environment* env, const X509View& view) {
|
||||||
return Date::New(env->context(), validToTime * 1000.);
|
return Date::New(env->context(), validToTime * 1000.);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeLocal<Value> GetSignatureAlgorithm(Environment* env,
|
||||||
|
const X509View& view) {
|
||||||
|
auto algo = view.getSignatureAlgorithm();
|
||||||
|
if (!algo.has_value()) [[unlikely]]
|
||||||
|
return Undefined(env->isolate());
|
||||||
|
Local<Value> ret;
|
||||||
|
if (!ToV8Value(env, algo.value()).ToLocal(&ret)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeLocal<Value> GetSignatureAlgorithmOID(Environment* env,
|
||||||
|
const X509View& view) {
|
||||||
|
auto oid = view.getSignatureAlgorithmOID();
|
||||||
|
if (!oid.has_value()) [[unlikely]]
|
||||||
|
return Undefined(env->isolate());
|
||||||
|
Local<Value> ret;
|
||||||
|
if (!ToV8Value(env, oid.value()).ToLocal(&ret)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
MaybeLocal<Value> GetSerialNumber(Environment* env, const X509View& view) {
|
MaybeLocal<Value> GetSerialNumber(Environment* env, const X509View& view) {
|
||||||
if (auto serial = view.getSerialNumber()) {
|
if (auto serial = view.getSerialNumber()) {
|
||||||
return OneByteString(env->isolate(),
|
return OneByteString(env->isolate(),
|
||||||
|
|
@ -342,6 +366,26 @@ void ValidToDate(const FunctionCallbackInfo<Value>& args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SignatureAlgorithm(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
X509Certificate* cert;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||||
|
Local<Value> ret;
|
||||||
|
if (GetSignatureAlgorithm(env, cert->view()).ToLocal(&ret)) {
|
||||||
|
args.GetReturnValue().Set(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignatureAlgorithmOID(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
X509Certificate* cert;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||||
|
Local<Value> ret;
|
||||||
|
if (GetSignatureAlgorithmOID(env, cert->view()).ToLocal(&ret)) {
|
||||||
|
args.GetReturnValue().Set(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SerialNumber(const FunctionCallbackInfo<Value>& args) {
|
void SerialNumber(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
X509Certificate* cert;
|
X509Certificate* cert;
|
||||||
|
|
@ -822,6 +866,10 @@ Local<FunctionTemplate> X509Certificate::GetConstructorTemplate(
|
||||||
SetProtoMethodNoSideEffect(isolate, tmpl, "validFrom", ValidFrom);
|
SetProtoMethodNoSideEffect(isolate, tmpl, "validFrom", ValidFrom);
|
||||||
SetProtoMethodNoSideEffect(isolate, tmpl, "validToDate", ValidToDate);
|
SetProtoMethodNoSideEffect(isolate, tmpl, "validToDate", ValidToDate);
|
||||||
SetProtoMethodNoSideEffect(isolate, tmpl, "validFromDate", ValidFromDate);
|
SetProtoMethodNoSideEffect(isolate, tmpl, "validFromDate", ValidFromDate);
|
||||||
|
SetProtoMethodNoSideEffect(
|
||||||
|
isolate, tmpl, "signatureAlgorithm", SignatureAlgorithm);
|
||||||
|
SetProtoMethodNoSideEffect(
|
||||||
|
isolate, tmpl, "signatureAlgorithmOid", SignatureAlgorithmOID);
|
||||||
SetProtoMethodNoSideEffect(
|
SetProtoMethodNoSideEffect(
|
||||||
isolate, tmpl, "fingerprint", Fingerprint<Digest::SHA1>);
|
isolate, tmpl, "fingerprint", Fingerprint<Digest::SHA1>);
|
||||||
SetProtoMethodNoSideEffect(
|
SetProtoMethodNoSideEffect(
|
||||||
|
|
@ -996,6 +1044,8 @@ void X509Certificate::RegisterExternalReferences(
|
||||||
registry->Register(ValidFrom);
|
registry->Register(ValidFrom);
|
||||||
registry->Register(ValidToDate);
|
registry->Register(ValidToDate);
|
||||||
registry->Register(ValidFromDate);
|
registry->Register(ValidFromDate);
|
||||||
|
registry->Register(SignatureAlgorithm);
|
||||||
|
registry->Register(SignatureAlgorithmOID);
|
||||||
registry->Register(Fingerprint<Digest::SHA1>);
|
registry->Register(Fingerprint<Digest::SHA1>);
|
||||||
registry->Register(Fingerprint<Digest::SHA256>);
|
registry->Register(Fingerprint<Digest::SHA256>);
|
||||||
registry->Register(Fingerprint<Digest::SHA512>);
|
registry->Register(Fingerprint<Digest::SHA512>);
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,9 @@ const der = Buffer.from(
|
||||||
assert.strictEqual(x509.keyUsage, undefined);
|
assert.strictEqual(x509.keyUsage, undefined);
|
||||||
assert.strictEqual(x509.serialNumber.toUpperCase(), '147D36C1C2F74206DE9FAB5F2226D78ADB00A426');
|
assert.strictEqual(x509.serialNumber.toUpperCase(), '147D36C1C2F74206DE9FAB5F2226D78ADB00A426');
|
||||||
|
|
||||||
|
assert.strictEqual(x509.signatureAlgorithm, 'sha256WithRSAEncryption');
|
||||||
|
assert.strictEqual(x509.signatureAlgorithmOid, '1.2.840.113549.1.1.11');
|
||||||
|
|
||||||
assert.deepStrictEqual(x509.raw, der);
|
assert.deepStrictEqual(x509.raw, der);
|
||||||
|
|
||||||
if (!process.features.openssl_is_boringssl) {
|
if (!process.features.openssl_is_boringssl) {
|
||||||
|
|
@ -448,3 +451,17 @@ CWwQO8JZjJqFtqtuzy2n+gLCvqePgG/gmSqHOPm2ZbLW
|
||||||
assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z'));
|
assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const certPem = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIGXMHugAwIBAgIBATANBgkrBgEEAYaNHwEFADASMRAwDgYDVQQDEwdVbmtub3du
|
||||||
|
MB4XDTI0MDEwMTAwMDAwMFoXDTM0MDEwMTAwMDAwMFowEjEQMA4GA1UEAxMHVW5r
|
||||||
|
bm93bjAaMA0GCSqGSIb3DQEBAQUAAwkAAAAAAAAAAAAwDQYJKwYBBAGGjR8BBQAD
|
||||||
|
CQAAAAAAAAAAAA==
|
||||||
|
-----END CERTIFICATE-----`;
|
||||||
|
|
||||||
|
const cert = new X509Certificate(certPem);
|
||||||
|
|
||||||
|
assert.strictEqual(cert.signatureAlgorithm, undefined);
|
||||||
|
assert.strictEqual(cert.signatureAlgorithmOid, '1.3.6.1.4.1.99999.1');
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user