Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 039ac19

Browse files
patrickrbctargos
authored andcommitted
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: #59103 PR-URL: #59235 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Filip Skokan <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
1 parent be48760 commit 039ac19

File tree

6 files changed

+134
-0
lines changed

6 files changed

+134
-0
lines changed

deps/ncrypto/ncrypto.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
#include <openssl/rand.h>
99
#include <openssl/x509v3.h>
1010
#include <algorithm>
11+
#include <array>
1112
#include <cstring>
13+
#include <string_view>
1214
#if OPENSSL_VERSION_MAJOR >= 3
1315
#include <openssl/core_names.h>
1416
#include <openssl/params.h>
@@ -1094,6 +1096,29 @@ BIOPointer X509View::getValidTo() const {
10941096
return bio;
10951097
}
10961098

1099+
std::optional<std::string_view> X509View::getSignatureAlgorithm() const {
1100+
if (cert_ == nullptr) return std::nullopt;
1101+
int nid = X509_get_signature_nid(cert_);
1102+
if (nid == NID_undef) return std::nullopt;
1103+
const char* ln = OBJ_nid2ln(nid);
1104+
if (ln == nullptr) return std::nullopt;
1105+
return std::string_view(ln);
1106+
}
1107+
1108+
std::optional<std::string> X509View::getSignatureAlgorithmOID() const {
1109+
if (cert_ == nullptr) return std::nullopt;
1110+
const X509_ALGOR* alg = nullptr;
1111+
X509_get0_signature(nullptr, &alg, cert_);
1112+
if (alg == nullptr) return std::nullopt;
1113+
const ASN1_OBJECT* obj = nullptr;
1114+
X509_ALGOR_get0(&obj, nullptr, nullptr, alg);
1115+
if (obj == nullptr) return std::nullopt;
1116+
std::array<char, 128> buf{};
1117+
int len = OBJ_obj2txt(buf.data(), buf.size(), obj, 1);
1118+
if (len < 0 || static_cast<size_t>(len) >= buf.size()) return std::nullopt;
1119+
return std::string(buf.data(), static_cast<size_t>(len));
1120+
}
1121+
10971122
int64_t X509View::getValidToTime() const {
10981123
#ifdef OPENSSL_IS_BORINGSSL
10991124
// Boringssl does not implement ASN1_TIME_to_tm in a public way,

deps/ncrypto/ncrypto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,8 @@ class X509View final {
11911191
BIOPointer getInfoAccess() const;
11921192
BIOPointer getValidFrom() const;
11931193
BIOPointer getValidTo() const;
1194+
std::optional<std::string_view> getSignatureAlgorithm() const;
1195+
std::optional<std::string> getSignatureAlgorithmOID() const;
11941196
int64_t getValidFromTime() const;
11951197
int64_t getValidToTime() const;
11961198
DataPointer getSerialNumber() const;

doc/api/crypto.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2971,6 +2971,26 @@ added:
29712971

29722972
The date/time until which this certificate is valid, encapsulated in a `Date` object.
29732973

2974+
### `x509.signatureAlgorithm`
2975+
2976+
<!-- YAML
2977+
added: REPLACEME
2978+
-->
2979+
2980+
* Type: {string|undefined}
2981+
2982+
The algorithm used to sign the certificate or `undefined` if the signature algorithm is unknown by OpenSSL.
2983+
2984+
### `x509.signatureAlgorithmOid`
2985+
2986+
<!-- YAML
2987+
added: REPLACEME
2988+
-->
2989+
2990+
* Type: {string}
2991+
2992+
The OID of the algorithm used to sign the certificate.
2993+
29742994
### `x509.verify(publicKey)`
29752995

29762996
<!-- YAML

lib/internal/crypto/x509.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ class X509Certificate {
142142
fingerprint512: this.fingerprint512,
143143
keyUsage: this.keyUsage,
144144
serialNumber: this.serialNumber,
145+
signatureAlgorithm: this.signatureAlgorithm,
146+
signatureAlgorithmOid: this.signatureAlgorithmOid,
145147
}, opts)}`;
146148
}
147149

@@ -285,6 +287,24 @@ class X509Certificate {
285287
return value;
286288
}
287289

290+
get signatureAlgorithm() {
291+
let value = this[kInternalState].get('signatureAlgorithm');
292+
if (value === undefined) {
293+
value = this[kHandle].signatureAlgorithm();
294+
this[kInternalState].set('signatureAlgorithm', value);
295+
}
296+
return value;
297+
}
298+
299+
get signatureAlgorithmOid() {
300+
let value = this[kInternalState].get('signatureAlgorithmOid');
301+
if (value === undefined) {
302+
value = this[kHandle].signatureAlgorithmOid();
303+
this[kInternalState].set('signatureAlgorithmOid', value);
304+
}
305+
return value;
306+
}
307+
288308
get raw() {
289309
let value = this[kInternalState].get('raw');
290310
if (value === undefined) {

src/crypto/crypto_x509.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,30 @@ MaybeLocal<Value> GetValidToDate(Environment* env, const X509View& view) {
225225
return Date::New(env->context(), validToTime * 1000.);
226226
}
227227

228+
MaybeLocal<Value> GetSignatureAlgorithm(Environment* env,
229+
const X509View& view) {
230+
auto algo = view.getSignatureAlgorithm();
231+
if (!algo.has_value()) [[unlikely]]
232+
return Undefined(env->isolate());
233+
Local<Value> ret;
234+
if (!ToV8Value(env, algo.value()).ToLocal(&ret)) {
235+
return {};
236+
}
237+
return ret;
238+
}
239+
240+
MaybeLocal<Value> GetSignatureAlgorithmOID(Environment* env,
241+
const X509View& view) {
242+
auto oid = view.getSignatureAlgorithmOID();
243+
if (!oid.has_value()) [[unlikely]]
244+
return Undefined(env->isolate());
245+
Local<Value> ret;
246+
if (!ToV8Value(env, oid.value()).ToLocal(&ret)) {
247+
return {};
248+
}
249+
return ret;
250+
}
251+
228252
MaybeLocal<Value> GetSerialNumber(Environment* env, const X509View& view) {
229253
if (auto serial = view.getSerialNumber()) {
230254
return OneByteString(env->isolate(),
@@ -342,6 +366,26 @@ void ValidToDate(const FunctionCallbackInfo<Value>& args) {
342366
}
343367
}
344368

369+
void SignatureAlgorithm(const FunctionCallbackInfo<Value>& args) {
370+
Environment* env = Environment::GetCurrent(args);
371+
X509Certificate* cert;
372+
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
373+
Local<Value> ret;
374+
if (GetSignatureAlgorithm(env, cert->view()).ToLocal(&ret)) {
375+
args.GetReturnValue().Set(ret);
376+
}
377+
}
378+
379+
void SignatureAlgorithmOID(const FunctionCallbackInfo<Value>& args) {
380+
Environment* env = Environment::GetCurrent(args);
381+
X509Certificate* cert;
382+
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
383+
Local<Value> ret;
384+
if (GetSignatureAlgorithmOID(env, cert->view()).ToLocal(&ret)) {
385+
args.GetReturnValue().Set(ret);
386+
}
387+
}
388+
345389
void SerialNumber(const FunctionCallbackInfo<Value>& args) {
346390
Environment* env = Environment::GetCurrent(args);
347391
X509Certificate* cert;
@@ -822,6 +866,10 @@ Local<FunctionTemplate> X509Certificate::GetConstructorTemplate(
822866
SetProtoMethodNoSideEffect(isolate, tmpl, "validFrom", ValidFrom);
823867
SetProtoMethodNoSideEffect(isolate, tmpl, "validToDate", ValidToDate);
824868
SetProtoMethodNoSideEffect(isolate, tmpl, "validFromDate", ValidFromDate);
869+
SetProtoMethodNoSideEffect(
870+
isolate, tmpl, "signatureAlgorithm", SignatureAlgorithm);
871+
SetProtoMethodNoSideEffect(
872+
isolate, tmpl, "signatureAlgorithmOid", SignatureAlgorithmOID);
825873
SetProtoMethodNoSideEffect(
826874
isolate, tmpl, "fingerprint", Fingerprint<Digest::SHA1>);
827875
SetProtoMethodNoSideEffect(
@@ -996,6 +1044,8 @@ void X509Certificate::RegisterExternalReferences(
9961044
registry->Register(ValidFrom);
9971045
registry->Register(ValidToDate);
9981046
registry->Register(ValidFromDate);
1047+
registry->Register(SignatureAlgorithm);
1048+
registry->Register(SignatureAlgorithmOID);
9991049
registry->Register(Fingerprint<Digest::SHA1>);
10001050
registry->Register(Fingerprint<Digest::SHA256>);
10011051
registry->Register(Fingerprint<Digest::SHA512>);

test/parallel/test-crypto-x509.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ const der = Buffer.from(
114114
assert.strictEqual(x509.keyUsage, undefined);
115115
assert.strictEqual(x509.serialNumber.toUpperCase(), '147D36C1C2F74206DE9FAB5F2226D78ADB00A426');
116116

117+
assert.strictEqual(x509.signatureAlgorithm, 'sha256WithRSAEncryption');
118+
assert.strictEqual(x509.signatureAlgorithmOid, '1.2.840.113549.1.1.11');
119+
117120
assert.deepStrictEqual(x509.raw, der);
118121

119122
if (!process.features.openssl_is_boringssl) {
@@ -448,3 +451,17 @@ CWwQO8JZjJqFtqtuzy2n+gLCvqePgG/gmSqHOPm2ZbLW
448451
assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z'));
449452
}
450453
}
454+
455+
{
456+
const certPem = `-----BEGIN CERTIFICATE-----
457+
MIGXMHugAwIBAgIBATANBgkrBgEEAYaNHwEFADASMRAwDgYDVQQDEwdVbmtub3du
458+
MB4XDTI0MDEwMTAwMDAwMFoXDTM0MDEwMTAwMDAwMFowEjEQMA4GA1UEAxMHVW5r
459+
bm93bjAaMA0GCSqGSIb3DQEBAQUAAwkAAAAAAAAAAAAwDQYJKwYBBAGGjR8BBQAD
460+
CQAAAAAAAAAAAA==
461+
-----END CERTIFICATE-----`;
462+
463+
const cert = new X509Certificate(certPem);
464+
465+
assert.strictEqual(cert.signatureAlgorithm, undefined);
466+
assert.strictEqual(cert.signatureAlgorithmOid, '1.3.6.1.4.1.99999.1');
467+
}

0 commit comments

Comments
 (0)