Skip to content

Commit

Permalink
#60 certs should generate GeneralizedTime values for dates >2050
Browse files Browse the repository at this point in the history
Reviewed by: Robert Mustacchi <rm@joyent.com>
  • Loading branch information
arekinath committed Jan 23, 2019
1 parent 684dbe6 commit 1aece0d
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 4 deletions.
30 changes: 26 additions & 4 deletions lib/formats/x509.js
Expand Up @@ -203,6 +203,14 @@ function readDate(der) {
}
}

function writeDate(der, date) {
if (date.getUTCFullYear() >= 2050 || date.getUTCFullYear() < 1950) {
der.writeString(dateToGTime(date), asn1.Ber.GeneralizedTime);
} else {
der.writeString(dateToUTCTime(date), asn1.Ber.UTCTime);
}
}

/* RFC5280, section 4.2.1.6 (GeneralName type) */
var ALTNAME = {
OtherName: Local(0),
Expand Down Expand Up @@ -415,9 +423,11 @@ function gTimeToDate(t) {
return (d);
}

function zeroPad(n) {
function zeroPad(n, m) {
if (m === undefined)
m = 2;
var s = '' + n;
while (s.length < 2)
while (s.length < m)
s = '0' + s;
return (s);
}
Expand All @@ -434,6 +444,18 @@ function dateToUTCTime(d) {
return (s);
}

function dateToGTime(d) {
var s = '';
s += zeroPad(d.getUTCFullYear(), 4);
s += zeroPad(d.getUTCMonth() + 1);
s += zeroPad(d.getUTCDate());
s += zeroPad(d.getUTCHours());
s += zeroPad(d.getUTCMinutes());
s += zeroPad(d.getUTCSeconds());
s += 'Z';
return (s);
}

function sign(cert, key) {
if (cert.signatures.x509 === undefined)
cert.signatures.x509 = {};
Expand Down Expand Up @@ -532,8 +554,8 @@ function writeTBSCert(cert, der) {
cert.issuer.toAsn1(der);

der.startSequence();
der.writeString(dateToUTCTime(cert.validFrom), asn1.Ber.UTCTime);
der.writeString(dateToUTCTime(cert.validUntil), asn1.Ber.UTCTime);
writeDate(der, cert.validFrom);
writeDate(der, cert.validUntil);
der.endSequence();

var subject = cert.subjects[0];
Expand Down
130 changes: 130 additions & 0 deletions test/openssl-cmd.js
Expand Up @@ -541,6 +541,136 @@ test('utf8string in issuer DN (#40)', function (t) {
kid.stdin.end();
});

test('certs with <2050 dates should use UTCTime', function (t) {
var pem = fs.readFileSync(path.join(testDir, 'id_rsa'));
var key = sshpk.parsePrivateKey(pem, 'pkcs1');

var id = sshpk.identityFromDN('cn=foobar');
var opts = {};
opts.validFrom = new Date('1990-01-02T03:04:05Z');
opts.validUntil = new Date('2010-01-02T03:04:05Z');
var cert = sshpk.createSelfSignedCertificate(id, key, opts);
var certPem = cert.toBuffer('pem');

var kid = spawn('openssl', ['asn1parse']);
var bufs = [];
kid.stdout.on('data', bufs.push.bind(bufs));
kid.on('close', function (rc) {
t.equal(rc, 0);
var output = Buffer.concat(bufs).toString('utf8');
var lines = output.split('\n');
var found = 0;
for (var i = 0; i < lines.length; ++i) {
if (!lines[i])
continue;
var line = asn1parse_line2obj(lines[i]);
if (line.tag === 'UTCTIME') {
if (line.value === '900102030405Z' ||
line.value === '100102030405Z') {
++found;
} else {
t.fail('unexpected utctime: ' +
line.value);
}
}
}
t.equal(found, 2);
t.end();
});
kid.stdin.write(certPem);
kid.stdin.end();
});

test('certs with >=2050 dates should use GeneralizedTime', function (t) {
var pem = fs.readFileSync(path.join(testDir, 'id_rsa'));
var key = sshpk.parsePrivateKey(pem, 'pkcs1');

var id = sshpk.identityFromDN('cn=foobar');
var opts = {};
opts.validFrom = new Date('2050-01-02T03:04:05Z');
opts.validUntil = new Date('2051-01-02T03:04:05Z');
var cert = sshpk.createSelfSignedCertificate(id, key, opts);
var certPem = cert.toBuffer('pem');

var kid = spawn('openssl', ['asn1parse']);
var bufs = [];
kid.stdout.on('data', bufs.push.bind(bufs));
kid.on('close', function (rc) {
t.equal(rc, 0);
var output = Buffer.concat(bufs).toString('utf8');
var lines = output.split('\n');
var found = 0;
for (var i = 0; i < lines.length; ++i) {
if (!lines[i])
continue;
var line = asn1parse_line2obj(lines[i]);
if (line.tag === 'UTCTIME') {
t.fail('unexpected utctime: ' + line.value);
}
if (line.tag === 'GENERALIZEDTIME') {
if (line.value === '20500102030405Z') {
++found;
} else if (line.value === '20510102030405Z') {
++found;
} else {
t.fail('bad gentime: ' + line.value);
}
}
}
t.equal(found, 2);
t.end();
});
kid.stdin.write(certPem);
kid.stdin.end();
});

test('certs with <1950 dates should use GeneralizedTime', function (t) {
var pem = fs.readFileSync(path.join(testDir, 'id_rsa'));
var key = sshpk.parsePrivateKey(pem, 'pkcs1');

var id = sshpk.identityFromDN('cn=foobar');
var opts = {};
opts.validFrom = new Date('1949-01-02T03:04:05Z');
opts.validUntil = new Date('1950-01-02T03:04:05Z');
var cert = sshpk.createSelfSignedCertificate(id, key, opts);
var certPem = cert.toBuffer('pem');

var kid = spawn('openssl', ['asn1parse']);
var bufs = [];
kid.stdout.on('data', bufs.push.bind(bufs));
kid.on('close', function (rc) {
t.equal(rc, 0);
var output = Buffer.concat(bufs).toString('utf8');
var lines = output.split('\n');
var found = 0;
for (var i = 0; i < lines.length; ++i) {
if (!lines[i])
continue;
var line = asn1parse_line2obj(lines[i]);
if (line.tag === 'UTCTIME') {
if (line.value === '500102030405Z') {
++found;
} else {
t.fail('unexpected utctime: ' +
line.value);
}
}
if (line.tag === 'GENERALIZEDTIME') {
if (line.value === '19490102030405Z') {
++found;
} else {
t.fail('unexpected gentime: ' +
line.value);
}
}
}
t.equal(found, 2);
t.end();
});
kid.stdin.write(certPem);
kid.stdin.end();
});

test('teardown', function (t) {
temp.cleanup(function () {
t.end();
Expand Down

0 comments on commit 1aece0d

Please sign in to comment.