Skip to content

Commit

Permalink
crypto: add Date fields for validTo and validFrom
Browse files Browse the repository at this point in the history
Added equivalent fields for `x509.validFrom` and `x509.validTo` in Javascript Date form for ease of use.
  • Loading branch information
RulerOfCakes committed Aug 6, 2024
1 parent c6aeddf commit 21364a2
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 0 deletions.
12 changes: 12 additions & 0 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -2875,6 +2875,18 @@ added: v15.6.0

The date/time until which this certificate is valid.

### `x509.validFromDate`

* Type: {Date}

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

### `x509.validToDate`

* Type: {Date}

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

### `x509.verify(publicKey)`

<!-- YAML
Expand Down
20 changes: 20 additions & 0 deletions lib/internal/crypto/x509.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ class X509Certificate {
infoAccess: this.infoAccess,
validFrom: this.validFrom,
validTo: this.validTo,
validFromDate: this.validFromDate,
validToDate: this.validToDate,
fingerprint: this.fingerprint,
fingerprint256: this.fingerprint256,
fingerprint512: this.fingerprint512,
Expand Down Expand Up @@ -220,6 +222,24 @@ class X509Certificate {
return value;
}

get validFromDate() {
let value = this[kInternalState].get('validFromDate');
if (value === undefined) {
value = this[kHandle].validFromDate();
this[kInternalState].set('validFromDate', value);
}
return value;
}

get validToDate() {
let value = this[kInternalState].get('validToDate');
if (value === undefined) {
value = this[kHandle].validToDate();
this[kInternalState].set('validToDate', value);
}
return value;
}

get fingerprint() {
let value = this[kInternalState].get('fingerprint');
if (value === undefined) {
Expand Down
15 changes: 15 additions & 0 deletions src/crypto/crypto_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ using v8::ArrayBuffer;
using v8::BackingStore;
using v8::Boolean;
using v8::Context;
using v8::Date;
using v8::EscapableHandleScope;
using v8::Integer;
using v8::Local;
Expand Down Expand Up @@ -580,6 +581,20 @@ MaybeLocal<Value> GetValidFrom(
return ToV8Value(env, bio);
}

MaybeLocal<Value> GetValidToDate(Environment* env, X509* cert) {
struct tm tp;
ASN1_TIME_to_tm(X509_get0_notAfter(cert), &tp);
time_t unixtime = timegm(&tp);
return Date::New(env->context(), unixtime * 1000.);
}

MaybeLocal<Value> GetValidFromDate(Environment* env, X509* cert) {
struct tm tp;
ASN1_TIME_to_tm(X509_get0_notBefore(cert), &tp);
time_t unixtime = timegm(&tp);
return Date::New(env->context(), unixtime * 1000.);
}

static inline bool IsSafeAltName(const char* name, size_t length, bool utf8) {
for (size_t i = 0; i < length; i++) {
char c = name[i];
Expand Down
4 changes: 4 additions & 0 deletions src/crypto/crypto_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ v8::MaybeLocal<v8::Value> GetValidFrom(
X509* cert,
const BIOPointer& bio);

v8::MaybeLocal<v8::Value> GetValidToDate(Environment* env, X509* cert);

v8::MaybeLocal<v8::Value> GetValidFromDate(Environment* env, X509* cert);

v8::MaybeLocal<v8::Value> GetFingerprintDigest(
Environment* env,
const EVP_MD* method,
Expand Down
12 changes: 12 additions & 0 deletions src/crypto/crypto_x509.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ Local<FunctionTemplate> X509Certificate::GetConstructorTemplate(
SetProtoMethod(isolate, tmpl, "issuer", Issuer);
SetProtoMethod(isolate, tmpl, "validTo", ValidTo);
SetProtoMethod(isolate, tmpl, "validFrom", ValidFrom);
SetProtoMethod(isolate, tmpl, "validToDate", ValidToDate);
SetProtoMethod(isolate, tmpl, "validFromDate", ValidFromDate);
SetProtoMethod(isolate, tmpl, "fingerprint", Fingerprint<EVP_sha1>);
SetProtoMethod(isolate, tmpl, "fingerprint256", Fingerprint<EVP_sha256>);
SetProtoMethod(isolate, tmpl, "fingerprint512", Fingerprint<EVP_sha512>);
Expand Down Expand Up @@ -249,6 +251,14 @@ static void ReturnProperty(const FunctionCallbackInfo<Value>& args) {
if (Property(env, cert->get()).ToLocal(&ret)) args.GetReturnValue().Set(ret);
}

void X509Certificate::ValidFromDate(const FunctionCallbackInfo<Value>& args) {
ReturnProperty<GetValidFromDate>(args);
}

void X509Certificate::ValidToDate(const FunctionCallbackInfo<Value>& args) {
ReturnProperty<GetValidToDate>(args);
}

void X509Certificate::KeyUsage(const FunctionCallbackInfo<Value>& args) {
ReturnProperty<GetKeyUsage>(args);
}
Expand Down Expand Up @@ -523,6 +533,8 @@ void X509Certificate::RegisterExternalReferences(
registry->Register(Issuer);
registry->Register(ValidTo);
registry->Register(ValidFrom);
registry->Register(ValidToDate);
registry->Register(ValidFromDate);
registry->Register(Fingerprint<EVP_sha1>);
registry->Register(Fingerprint<EVP_sha256>);
registry->Register(Fingerprint<EVP_sha512>);
Expand Down
2 changes: 2 additions & 0 deletions src/crypto/crypto_x509.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class X509Certificate : public BaseObject {
static void InfoAccess(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ValidFrom(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ValidTo(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ValidFromDate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ValidToDate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void KeyUsage(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SerialNumber(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Raw(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down
77 changes: 77 additions & 0 deletions test/parallel/test-crypto-x509.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ const der = Buffer.from(
assert.strictEqual(x509.infoAccess, infoAccessCheck);
assert.strictEqual(x509.validFrom, 'Sep 3 21:40:37 2022 GMT');
assert.strictEqual(x509.validTo, 'Jun 17 21:40:37 2296 GMT');
assert.deepStrictEqual(x509.validFromDate, new Date('September 3, 2022 21:40:37'));
assert.deepStrictEqual(x509.validToDate, new Date('June 17, 2296 21:40:37'));
assert.strictEqual(
x509.fingerprint,
'8B:89:16:C4:99:87:D2:13:1A:64:94:36:38:A5:32:01:F0:95:3B:53');
Expand Down Expand Up @@ -359,3 +361,78 @@ UcXd/5qu2GhokrKU2cPttU+XAN2Om6a0

assert.strictEqual(cert.checkIssued(cert), false);
}

{
// Test date parsing of `validFromDate` and `validToDate` fields, according to RFC 5280.

// Validity dates up until the year 2049 are encoded as UTCTime.
// The fomatting of UTCTime changes from the year ~1949 to 1950~.
const certPemUTCTime = `-----BEGIN CERTIFICATE-----
MIIE/TCCAuWgAwIBAgIUHbXPaFnjeBehMvdHkXZ+E3a78QswDQYJKoZIhvcNAQEL
BQAwDTELMAkGA1UEBhMCS1IwIBgPMTk0OTEyMjUyMzU5NThaFw01MDAxMDEyMzU5
NThaMA0xCzAJBgNVBAYTAktSMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAtFfV2DB2dZFFaR1PPZMmyo0mSDAxGReoixxlhQTFZZymU71emWV/6gR8MxAE
L5+uzpgBvOZWgEbELWeV/gzZGU/x1Cki0dSJ0B8Qwr5HvKX6oOZrJ8t+wn4SRceq
r6MRPskDpTjnvelt+VURGmawtKKHll5fSqfjRWkQC8WQHdogXylRjd3oIh9p1D5P
hphK/jKddxsRkLhJKQWqTjAy2v8hsJAxvpCPnlqMCXxjbQV41UTY8+kY3RPG3d6c
yHBGM7dzM7XWVc79V9z/rjdRcxE2eBqrJT/yR3Cok8wWVVfQEgBfpolHUZxA8K4N
tubTez9zsJy7xUG7udf91wXWVHMBHXg6m/u5nIW0fAXGMtnG/H6FMyyBDbJoUlqm
VRTG71DzvBXpd/qx2P5LkU1JjWY3U8HSn6Q1DJzMIrbOmWpdlFYXxzLlXU2vG8Q3
PmdAHDDYW3M2YBVCdKqOtsuL2dMDuqRWdi3iCCPSR2UCm4HzAVYSe2FP8SPcY3xs
1NX+oDSpTxXruJYHGUp10/pXoqMrGT1IBgv2Dhsm3jcfRLSXkaBDJIKLO6dXmLBt
rlxM0DphiKnP6lDjpv7EDMdwsakz0zib3JrTmSLSbwZXR4abITmtbYbTpY3XAq7c
adO8YCMTCtb50ZbYEpGDAjOcWFHUlQQMsgZM2zc8ZHPY4EkCAwEAAaNTMFEwHQYD
VR0OBBYEFExDmZyzdo8ccjX7iFIwU7JYMV+qMB8GA1UdIwQYMBaAFExDmZyzdo8c
cjX7iFIwU7JYMV+qMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB
ADEF/JIH+Ku9NqrO47Q/CEn9qpIgmqX10d1joDjchPY3OHIIyt8Xpo845mPBTM7L
dnMJSlkzJEk0ep9qAGGdKpBnLq8B/1mgCWQ81jwrwdYSsY+4xark+7+y0fij6qAt
L4T6aA37nbV5q5/DMOwZucFwRTf9ZI1IjC+MaQmnV01vGCogqqfLQ9v26bVBRE1K
UIixH0r3f/LWtuo0KaebZbb+oq6Zb8ljKJaUlt5OB8Zy5NrcP69r29QJUR57ukT6
rt7fk5mOj2NBLMCErLHa7E6+GAUG94QEgdKzZ4yr2aduhMAfnOnK/HfuXO8TVa8/
+oYENr47M8x139+yu92C8Be1MRk0VHteBaScUL+IaY3HgGbYR1lT0azvIyBN/DCN
bYczI7JQGYVitLuaUYFw/RtK7Qg1957/ZmGeGa+86aTLXbqsGjI951D81EIzdqod
1QW/Jn3yMNeVIzF9eYVEy2DIJjGgM2A8NWbqfWGUAUMRgyTxH1j42tnWG3eRnMsX
UnQfpY8i3v6gYoNNgEZktrqgpmukTWgl08TlDtBCjXTBkcBt4dxDApeoy7XWKq+/
qBY/+uIsG30BRgJhAwApjdnCs7l5xpwtqluXFwOxyTWNV5IfChO7QFqWPlSVIHML
UidvpWWipVLZgK+oDks+bKTobcoXGW9oXobiIYqslXPy
-----END CERTIFICATE-----`.trim();
const c1 = new X509Certificate(certPemUTCTime);

assert.deepStrictEqual(c1.validFromDate, new Date('December 25, 1949 23:59:58'));
assert.deepStrictEqual(c1.validToDate, new Date('January 1, 1950 23:59:58'));

// The GeneralizedTime format is used for dates in 2050 or later.
const certPemGeneralizedTime = `-----BEGIN CERTIFICATE-----
MIIE/TCCAuWgAwIBAgIUYHPUNd6S5xlNMjrWSaekgCBrbDQwDQYJKoZIhvcNAQEL
BQAwDTELMAkGA1UEBhMCS1IwIBcNNDkxMjI2MDAwMDAxWhgPMjA1MDAxMDIwMDAw
MDFaMA0xCzAJBgNVBAYTAktSMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAlBPjQXHTzQWflvq6Lc01E0gVSSUQd5XnfK9K8TEN8ic/6iJVBWK8OwTmwh6u
KdSO+DrTpoTA3Wo4T7oSL89xsyJN5JHiIT2VdZvgcXkv+ZL+rZ2INzYSSXbPQ8V+
Md5A7tNWGJOvneD1Pb+AKrVXn6N1+xiKuv08U+d6ZCcv8P2cGUJCQr5BSg6eXPm2
ZIoFhNLDaqleci0P/Bs7uMwKjVr2IP99bCMwTS2STxexEmYf4J3wgNXBOHxspLcS
p7Yt3JgezvzRn5kijQi7ceS24q/fsGCCwB706mOKdYLCfEL1DhhEr27+XICw7zOF
Q8tSe33IfSdxejEVV+lf/jGW5zFH5m+lDTJC0VAUCBG5E7q57yFaoQ44CQWtbMHZ
+dtodKx4B0lzWXJs8xkGo0rl9/1CuY2iPX3lB6xxlX50ruj8stccMwarRzUvfkjw
AhnbUs9X1ooFyVXmVYXWzR0gP1/q05Zob03khX1NipGbMf0RBI4WlItkiRsrEl9x
08YPbrUyd7JnFkgG0O5TcmTzHr9cTJHg5BzclQA9/V0HuslSVOkKMMlKHky2zcqY
dDBmWtfTrvowaB7hTGD6YK4R9JCDUy7oeeK4ZUxRNCnJY698HodE9lQu+F0cJpbY
uZExFapE/AWA8ftlw2/fXoK0L3DhYsOVQkHd2YbrvzZEHVMCAwEAAaNTMFEwHQYD
VR0OBBYEFNptaIzozylFlD0+JKULue+5gvfZMB8GA1UdIwQYMBaAFNptaIzozylF
lD0+JKULue+5gvfZMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB
AFXP4SCP6VFMINaKE/rLJOaFiVVuS4qDfpGRjuBryNxey4ErBFsXcPi/D0LIsNkb
c3qsex1cJadZdg3sqdkyliyYgzjJn1fSsiPT8GMiMnckw9awIwqtucGf+6SPdL6o
9jp0xg6KsRHWjN0GetCz89hy9HwSiSwiLpTxVYOMLjQ+ey8KXPk0LNaXve/++hrr
gN+cvcPKkspAE5SMTSKqHwVUD4MRJgdQqYDqB6demCq9Yl+kyQg9gVnuzkpKeNBT
qNVeeA6gczCpYV4rUMqT0UVVPbPOcygwZP2o7tUyNk6fmYzyLpi5R+FYD/PoowFp
LOrIaG426QaXhLr4U0i+HD/LhHZ4AWWt0OYAvbkk/xrhmagUcyeOxUrcYl6tA3NQ
sjPV2FNGitX+zOyxfMxcjf0RpaBbyMsO6DSfQidDchFvPR9VFX4THs/0mP02IK27
MpsZj8AG2/jjPz6ytnWBJGuLeIt2sWnluZyldX+V9QEEhEmrEweUolacKF5ESODG
SHyZZVSUCK0bJfDfk5rXCQokWCIe+jHbW3CSWWmBRz6blZDeO/wI8nN4TWHDMCu6
lawls1QdAwfP4CWIq4T7gsn/YqxMs74zDCXIF0tfuPmw5FMeCYVgnXQ7et8HBfeE
CWwQO8JZjJqFtqtuzy2n+gLCvqePgG/gmSqHOPm2ZbLW
-----END CERTIFICATE-----`.trim();
const c2 = new X509Certificate(certPemGeneralizedTime);

assert.deepStrictEqual(c2.validFromDate, new Date('December 26, 2049 00:00:01'));
assert.deepStrictEqual(c2.validToDate, new Date('January 2, 2050 00:00:01'));
}

0 comments on commit 21364a2

Please sign in to comment.