Skip to content

Commit 0411edb

Browse files
committed
crypto: add Date fields for validTo and validFrom
Added equivalent fields to `X509Certificate` in Date form.
1 parent e020dd8 commit 0411edb

File tree

6 files changed

+183
-0
lines changed

6 files changed

+183
-0
lines changed

deps/ncrypto/ncrypto.cc

+27
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,21 @@ int PasswordCallback(char* buf, int size, int rwflag, void* u) {
346346
return -1;
347347
}
348348

349+
// provided time must be in UTC
350+
time_t PortableTimeGM(struct tm* t) {
351+
struct tm tmp = *t;
352+
tmp.tm_isdst = 0;
353+
354+
time_t local_ver = mktime(&tmp);
355+
356+
struct tm* utc_tm = gmtime(&local_ver);
357+
time_t utc_ver = mktime(utc_tm);
358+
359+
double seconds = difftime(local_ver, utc_ver);
360+
361+
return local_ver - static_cast<time_t>(seconds);
362+
}
363+
349364
// ============================================================================
350365
// SPKAC
351366

@@ -816,6 +831,18 @@ BIOPointer X509View::getValidTo() const {
816831
return bio;
817832
}
818833

834+
time_t X509View::getValidToTime() const {
835+
struct tm tp;
836+
ASN1_TIME_to_tm(X509_get0_notAfter(cert_), &tp);
837+
return PortableTimeGM(&tp);
838+
}
839+
840+
time_t X509View::getValidFromTime() const {
841+
struct tm tp;
842+
ASN1_TIME_to_tm(X509_get0_notBefore(cert_), &tp);
843+
return PortableTimeGM(&tp);
844+
}
845+
819846
DataPointer X509View::getSerialNumber() const {
820847
ClearErrorOnReturn clearErrorOnReturn;
821848
if (cert_ == nullptr) return {};

deps/ncrypto/ncrypto.h

+2
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ class X509View final {
338338
BIOPointer getInfoAccess() const;
339339
BIOPointer getValidFrom() const;
340340
BIOPointer getValidTo() const;
341+
time_t getValidFromTime() const;
342+
time_t getValidToTime() const;
341343
DataPointer getSerialNumber() const;
342344
Result<EVPKeyPointer, int> getPublicKey() const;
343345
StackOfASN1 getKeyUsage() const;

doc/api/crypto.md

+20
Original file line numberDiff line numberDiff line change
@@ -2865,6 +2865,16 @@ added: v15.6.0
28652865

28662866
The date/time from which this certificate is valid.
28672867

2868+
### `x509.validFromDate`
2869+
2870+
<!-- YAML
2871+
added: REPLACEME
2872+
-->
2873+
2874+
* Type: {Date}
2875+
2876+
The date/time from which this certificate is valid, encapsulated in a `Date` object.
2877+
28682878
### `x509.validTo`
28692879

28702880
<!-- YAML
@@ -2875,6 +2885,16 @@ added: v15.6.0
28752885

28762886
The date/time until which this certificate is valid.
28772887

2888+
### `x509.validToDate`
2889+
2890+
<!-- YAML
2891+
added: REPLACEME
2892+
-->
2893+
2894+
* Type: {Date}
2895+
2896+
The date/time until which this certificate is valid, encapsulated in a `Date` object.
2897+
28782898
### `x509.verify(publicKey)`
28792899

28802900
<!-- YAML

lib/internal/crypto/x509.js

+20
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ class X509Certificate {
135135
infoAccess: this.infoAccess,
136136
validFrom: this.validFrom,
137137
validTo: this.validTo,
138+
validFromDate: this.validFromDate,
139+
validToDate: this.validToDate,
138140
fingerprint: this.fingerprint,
139141
fingerprint256: this.fingerprint256,
140142
fingerprint512: this.fingerprint512,
@@ -220,6 +222,24 @@ class X509Certificate {
220222
return value;
221223
}
222224

225+
get validFromDate() {
226+
let value = this[kInternalState].get('validFromDate');
227+
if (value === undefined) {
228+
value = this[kHandle].validFromDate();
229+
this[kInternalState].set('validFromDate', value);
230+
}
231+
return value;
232+
}
233+
234+
get validToDate() {
235+
let value = this[kInternalState].get('validToDate');
236+
if (value === undefined) {
237+
value = this[kHandle].validToDate();
238+
this[kInternalState].set('validToDate', value);
239+
}
240+
return value;
241+
}
242+
223243
get fingerprint() {
224244
let value = this[kInternalState].get('fingerprint');
225245
if (value === undefined) {

src/crypto/crypto_x509.cc

+37
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ using v8::ArrayBufferView;
2121
using v8::BackingStore;
2222
using v8::Boolean;
2323
using v8::Context;
24+
using v8::Date;
2425
using v8::EscapableHandleScope;
2526
using v8::Function;
2627
using v8::FunctionCallbackInfo;
@@ -241,6 +242,18 @@ MaybeLocal<Value> GetValidTo(Environment* env, const ncrypto::X509View& view) {
241242
return ret;
242243
}
243244

245+
MaybeLocal<Value> GetValidFromDate(Environment* env,
246+
const ncrypto::X509View& view) {
247+
time_t validFromTime = view.getValidFromTime();
248+
return Date::New(env->context(), validFromTime * 1000.);
249+
}
250+
251+
MaybeLocal<Value> GetValidToDate(Environment* env,
252+
const ncrypto::X509View& view) {
253+
time_t validToTime = view.getValidToTime();
254+
return Date::New(env->context(), validToTime * 1000.);
255+
}
256+
244257
MaybeLocal<Value> GetSerialNumber(Environment* env,
245258
const ncrypto::X509View& view) {
246259
if (auto serial = view.getSerialNumber()) {
@@ -352,6 +365,26 @@ void ValidTo(const FunctionCallbackInfo<Value>& args) {
352365
}
353366
}
354367

368+
void ValidFromDate(const FunctionCallbackInfo<Value>& args) {
369+
Environment* env = Environment::GetCurrent(args);
370+
X509Certificate* cert;
371+
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
372+
Local<Value> ret;
373+
if (GetValidFromDate(env, cert->view()).ToLocal(&ret)) {
374+
args.GetReturnValue().Set(ret);
375+
}
376+
}
377+
378+
void ValidToDate(const FunctionCallbackInfo<Value>& args) {
379+
Environment* env = Environment::GetCurrent(args);
380+
X509Certificate* cert;
381+
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
382+
Local<Value> ret;
383+
if (GetValidToDate(env, cert->view()).ToLocal(&ret)) {
384+
args.GetReturnValue().Set(ret);
385+
}
386+
}
387+
355388
void SerialNumber(const FunctionCallbackInfo<Value>& args) {
356389
Environment* env = Environment::GetCurrent(args);
357390
X509Certificate* cert;
@@ -834,6 +867,8 @@ Local<FunctionTemplate> X509Certificate::GetConstructorTemplate(
834867
SetProtoMethodNoSideEffect(isolate, tmpl, "issuer", Issuer);
835868
SetProtoMethodNoSideEffect(isolate, tmpl, "validTo", ValidTo);
836869
SetProtoMethodNoSideEffect(isolate, tmpl, "validFrom", ValidFrom);
870+
SetProtoMethodNoSideEffect(isolate, tmpl, "validToDate", ValidToDate);
871+
SetProtoMethodNoSideEffect(isolate, tmpl, "validFromDate", ValidFromDate);
837872
SetProtoMethodNoSideEffect(
838873
isolate, tmpl, "fingerprint", Fingerprint<EVP_sha1>);
839874
SetProtoMethodNoSideEffect(
@@ -1001,6 +1036,8 @@ void X509Certificate::RegisterExternalReferences(
10011036
registry->Register(Issuer);
10021037
registry->Register(ValidTo);
10031038
registry->Register(ValidFrom);
1039+
registry->Register(ValidToDate);
1040+
registry->Register(ValidFromDate);
10041041
registry->Register(Fingerprint<EVP_sha1>);
10051042
registry->Register(Fingerprint<EVP_sha256>);
10061043
registry->Register(Fingerprint<EVP_sha512>);

test/parallel/test-crypto-x509.js

+77
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ const der = Buffer.from(
9696
assert.strictEqual(x509.infoAccess, infoAccessCheck);
9797
assert.strictEqual(x509.validFrom, 'Sep 3 21:40:37 2022 GMT');
9898
assert.strictEqual(x509.validTo, 'Jun 17 21:40:37 2296 GMT');
99+
assert.deepStrictEqual(x509.validFromDate, new Date('September 3, 2022 21:40:37'));
100+
assert.deepStrictEqual(x509.validToDate, new Date('June 17, 2296 21:40:37'));
99101
assert.strictEqual(
100102
x509.fingerprint,
101103
'8B:89:16:C4:99:87:D2:13:1A:64:94:36:38:A5:32:01:F0:95:3B:53');
@@ -359,3 +361,78 @@ UcXd/5qu2GhokrKU2cPttU+XAN2Om6a0
359361

360362
assert.strictEqual(cert.checkIssued(cert), false);
361363
}
364+
365+
{
366+
// Test date parsing of `validFromDate` and `validToDate` fields, according to RFC 5280.
367+
368+
// Validity dates up until the year 2049 are encoded as UTCTime.
369+
// The fomatting of UTCTime changes from the year ~1949 to 1950~.
370+
const certPemUTCTime = `-----BEGIN CERTIFICATE-----
371+
MIIE/TCCAuWgAwIBAgIUHbXPaFnjeBehMvdHkXZ+E3a78QswDQYJKoZIhvcNAQEL
372+
BQAwDTELMAkGA1UEBhMCS1IwIBgPMTk0OTEyMjUyMzU5NThaFw01MDAxMDEyMzU5
373+
NThaMA0xCzAJBgNVBAYTAktSMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
374+
AgEAtFfV2DB2dZFFaR1PPZMmyo0mSDAxGReoixxlhQTFZZymU71emWV/6gR8MxAE
375+
L5+uzpgBvOZWgEbELWeV/gzZGU/x1Cki0dSJ0B8Qwr5HvKX6oOZrJ8t+wn4SRceq
376+
r6MRPskDpTjnvelt+VURGmawtKKHll5fSqfjRWkQC8WQHdogXylRjd3oIh9p1D5P
377+
hphK/jKddxsRkLhJKQWqTjAy2v8hsJAxvpCPnlqMCXxjbQV41UTY8+kY3RPG3d6c
378+
yHBGM7dzM7XWVc79V9z/rjdRcxE2eBqrJT/yR3Cok8wWVVfQEgBfpolHUZxA8K4N
379+
tubTez9zsJy7xUG7udf91wXWVHMBHXg6m/u5nIW0fAXGMtnG/H6FMyyBDbJoUlqm
380+
VRTG71DzvBXpd/qx2P5LkU1JjWY3U8HSn6Q1DJzMIrbOmWpdlFYXxzLlXU2vG8Q3
381+
PmdAHDDYW3M2YBVCdKqOtsuL2dMDuqRWdi3iCCPSR2UCm4HzAVYSe2FP8SPcY3xs
382+
1NX+oDSpTxXruJYHGUp10/pXoqMrGT1IBgv2Dhsm3jcfRLSXkaBDJIKLO6dXmLBt
383+
rlxM0DphiKnP6lDjpv7EDMdwsakz0zib3JrTmSLSbwZXR4abITmtbYbTpY3XAq7c
384+
adO8YCMTCtb50ZbYEpGDAjOcWFHUlQQMsgZM2zc8ZHPY4EkCAwEAAaNTMFEwHQYD
385+
VR0OBBYEFExDmZyzdo8ccjX7iFIwU7JYMV+qMB8GA1UdIwQYMBaAFExDmZyzdo8c
386+
cjX7iFIwU7JYMV+qMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB
387+
ADEF/JIH+Ku9NqrO47Q/CEn9qpIgmqX10d1joDjchPY3OHIIyt8Xpo845mPBTM7L
388+
dnMJSlkzJEk0ep9qAGGdKpBnLq8B/1mgCWQ81jwrwdYSsY+4xark+7+y0fij6qAt
389+
L4T6aA37nbV5q5/DMOwZucFwRTf9ZI1IjC+MaQmnV01vGCogqqfLQ9v26bVBRE1K
390+
UIixH0r3f/LWtuo0KaebZbb+oq6Zb8ljKJaUlt5OB8Zy5NrcP69r29QJUR57ukT6
391+
rt7fk5mOj2NBLMCErLHa7E6+GAUG94QEgdKzZ4yr2aduhMAfnOnK/HfuXO8TVa8/
392+
+oYENr47M8x139+yu92C8Be1MRk0VHteBaScUL+IaY3HgGbYR1lT0azvIyBN/DCN
393+
bYczI7JQGYVitLuaUYFw/RtK7Qg1957/ZmGeGa+86aTLXbqsGjI951D81EIzdqod
394+
1QW/Jn3yMNeVIzF9eYVEy2DIJjGgM2A8NWbqfWGUAUMRgyTxH1j42tnWG3eRnMsX
395+
UnQfpY8i3v6gYoNNgEZktrqgpmukTWgl08TlDtBCjXTBkcBt4dxDApeoy7XWKq+/
396+
qBY/+uIsG30BRgJhAwApjdnCs7l5xpwtqluXFwOxyTWNV5IfChO7QFqWPlSVIHML
397+
UidvpWWipVLZgK+oDks+bKTobcoXGW9oXobiIYqslXPy
398+
-----END CERTIFICATE-----`.trim();
399+
const c1 = new X509Certificate(certPemUTCTime);
400+
401+
assert.deepStrictEqual(c1.validFromDate, new Date('December 25, 1949 23:59:58'));
402+
assert.deepStrictEqual(c1.validToDate, new Date('January 1, 1950 23:59:58'));
403+
404+
// The GeneralizedTime format is used for dates in 2050 or later.
405+
const certPemGeneralizedTime = `-----BEGIN CERTIFICATE-----
406+
MIIE/TCCAuWgAwIBAgIUYHPUNd6S5xlNMjrWSaekgCBrbDQwDQYJKoZIhvcNAQEL
407+
BQAwDTELMAkGA1UEBhMCS1IwIBcNNDkxMjI2MDAwMDAxWhgPMjA1MDAxMDIwMDAw
408+
MDFaMA0xCzAJBgNVBAYTAktSMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
409+
AgEAlBPjQXHTzQWflvq6Lc01E0gVSSUQd5XnfK9K8TEN8ic/6iJVBWK8OwTmwh6u
410+
KdSO+DrTpoTA3Wo4T7oSL89xsyJN5JHiIT2VdZvgcXkv+ZL+rZ2INzYSSXbPQ8V+
411+
Md5A7tNWGJOvneD1Pb+AKrVXn6N1+xiKuv08U+d6ZCcv8P2cGUJCQr5BSg6eXPm2
412+
ZIoFhNLDaqleci0P/Bs7uMwKjVr2IP99bCMwTS2STxexEmYf4J3wgNXBOHxspLcS
413+
p7Yt3JgezvzRn5kijQi7ceS24q/fsGCCwB706mOKdYLCfEL1DhhEr27+XICw7zOF
414+
Q8tSe33IfSdxejEVV+lf/jGW5zFH5m+lDTJC0VAUCBG5E7q57yFaoQ44CQWtbMHZ
415+
+dtodKx4B0lzWXJs8xkGo0rl9/1CuY2iPX3lB6xxlX50ruj8stccMwarRzUvfkjw
416+
AhnbUs9X1ooFyVXmVYXWzR0gP1/q05Zob03khX1NipGbMf0RBI4WlItkiRsrEl9x
417+
08YPbrUyd7JnFkgG0O5TcmTzHr9cTJHg5BzclQA9/V0HuslSVOkKMMlKHky2zcqY
418+
dDBmWtfTrvowaB7hTGD6YK4R9JCDUy7oeeK4ZUxRNCnJY698HodE9lQu+F0cJpbY
419+
uZExFapE/AWA8ftlw2/fXoK0L3DhYsOVQkHd2YbrvzZEHVMCAwEAAaNTMFEwHQYD
420+
VR0OBBYEFNptaIzozylFlD0+JKULue+5gvfZMB8GA1UdIwQYMBaAFNptaIzozylF
421+
lD0+JKULue+5gvfZMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB
422+
AFXP4SCP6VFMINaKE/rLJOaFiVVuS4qDfpGRjuBryNxey4ErBFsXcPi/D0LIsNkb
423+
c3qsex1cJadZdg3sqdkyliyYgzjJn1fSsiPT8GMiMnckw9awIwqtucGf+6SPdL6o
424+
9jp0xg6KsRHWjN0GetCz89hy9HwSiSwiLpTxVYOMLjQ+ey8KXPk0LNaXve/++hrr
425+
gN+cvcPKkspAE5SMTSKqHwVUD4MRJgdQqYDqB6demCq9Yl+kyQg9gVnuzkpKeNBT
426+
qNVeeA6gczCpYV4rUMqT0UVVPbPOcygwZP2o7tUyNk6fmYzyLpi5R+FYD/PoowFp
427+
LOrIaG426QaXhLr4U0i+HD/LhHZ4AWWt0OYAvbkk/xrhmagUcyeOxUrcYl6tA3NQ
428+
sjPV2FNGitX+zOyxfMxcjf0RpaBbyMsO6DSfQidDchFvPR9VFX4THs/0mP02IK27
429+
MpsZj8AG2/jjPz6ytnWBJGuLeIt2sWnluZyldX+V9QEEhEmrEweUolacKF5ESODG
430+
SHyZZVSUCK0bJfDfk5rXCQokWCIe+jHbW3CSWWmBRz6blZDeO/wI8nN4TWHDMCu6
431+
lawls1QdAwfP4CWIq4T7gsn/YqxMs74zDCXIF0tfuPmw5FMeCYVgnXQ7et8HBfeE
432+
CWwQO8JZjJqFtqtuzy2n+gLCvqePgG/gmSqHOPm2ZbLW
433+
-----END CERTIFICATE-----`.trim();
434+
const c2 = new X509Certificate(certPemGeneralizedTime);
435+
436+
assert.deepStrictEqual(c2.validFromDate, new Date('December 26, 2049 00:00:01'));
437+
assert.deepStrictEqual(c2.validToDate, new Date('January 2, 2050 00:00:01'));
438+
}

0 commit comments

Comments
 (0)