Skip to content

Commit 1aece0d

Browse files
author
Alex Wilson
committed
#60 certs should generate GeneralizedTime values for dates >2050
Reviewed by: Robert Mustacchi <[email protected]>
1 parent 684dbe6 commit 1aece0d

File tree

2 files changed

+156
-4
lines changed

2 files changed

+156
-4
lines changed

lib/formats/x509.js

+26-4
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,14 @@ function readDate(der) {
203203
}
204204
}
205205

206+
function writeDate(der, date) {
207+
if (date.getUTCFullYear() >= 2050 || date.getUTCFullYear() < 1950) {
208+
der.writeString(dateToGTime(date), asn1.Ber.GeneralizedTime);
209+
} else {
210+
der.writeString(dateToUTCTime(date), asn1.Ber.UTCTime);
211+
}
212+
}
213+
206214
/* RFC5280, section 4.2.1.6 (GeneralName type) */
207215
var ALTNAME = {
208216
OtherName: Local(0),
@@ -415,9 +423,11 @@ function gTimeToDate(t) {
415423
return (d);
416424
}
417425

418-
function zeroPad(n) {
426+
function zeroPad(n, m) {
427+
if (m === undefined)
428+
m = 2;
419429
var s = '' + n;
420-
while (s.length < 2)
430+
while (s.length < m)
421431
s = '0' + s;
422432
return (s);
423433
}
@@ -434,6 +444,18 @@ function dateToUTCTime(d) {
434444
return (s);
435445
}
436446

447+
function dateToGTime(d) {
448+
var s = '';
449+
s += zeroPad(d.getUTCFullYear(), 4);
450+
s += zeroPad(d.getUTCMonth() + 1);
451+
s += zeroPad(d.getUTCDate());
452+
s += zeroPad(d.getUTCHours());
453+
s += zeroPad(d.getUTCMinutes());
454+
s += zeroPad(d.getUTCSeconds());
455+
s += 'Z';
456+
return (s);
457+
}
458+
437459
function sign(cert, key) {
438460
if (cert.signatures.x509 === undefined)
439461
cert.signatures.x509 = {};
@@ -532,8 +554,8 @@ function writeTBSCert(cert, der) {
532554
cert.issuer.toAsn1(der);
533555

534556
der.startSequence();
535-
der.writeString(dateToUTCTime(cert.validFrom), asn1.Ber.UTCTime);
536-
der.writeString(dateToUTCTime(cert.validUntil), asn1.Ber.UTCTime);
557+
writeDate(der, cert.validFrom);
558+
writeDate(der, cert.validUntil);
537559
der.endSequence();
538560

539561
var subject = cert.subjects[0];

test/openssl-cmd.js

+130
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,136 @@ test('utf8string in issuer DN (#40)', function (t) {
541541
kid.stdin.end();
542542
});
543543

544+
test('certs with <2050 dates should use UTCTime', function (t) {
545+
var pem = fs.readFileSync(path.join(testDir, 'id_rsa'));
546+
var key = sshpk.parsePrivateKey(pem, 'pkcs1');
547+
548+
var id = sshpk.identityFromDN('cn=foobar');
549+
var opts = {};
550+
opts.validFrom = new Date('1990-01-02T03:04:05Z');
551+
opts.validUntil = new Date('2010-01-02T03:04:05Z');
552+
var cert = sshpk.createSelfSignedCertificate(id, key, opts);
553+
var certPem = cert.toBuffer('pem');
554+
555+
var kid = spawn('openssl', ['asn1parse']);
556+
var bufs = [];
557+
kid.stdout.on('data', bufs.push.bind(bufs));
558+
kid.on('close', function (rc) {
559+
t.equal(rc, 0);
560+
var output = Buffer.concat(bufs).toString('utf8');
561+
var lines = output.split('\n');
562+
var found = 0;
563+
for (var i = 0; i < lines.length; ++i) {
564+
if (!lines[i])
565+
continue;
566+
var line = asn1parse_line2obj(lines[i]);
567+
if (line.tag === 'UTCTIME') {
568+
if (line.value === '900102030405Z' ||
569+
line.value === '100102030405Z') {
570+
++found;
571+
} else {
572+
t.fail('unexpected utctime: ' +
573+
line.value);
574+
}
575+
}
576+
}
577+
t.equal(found, 2);
578+
t.end();
579+
});
580+
kid.stdin.write(certPem);
581+
kid.stdin.end();
582+
});
583+
584+
test('certs with >=2050 dates should use GeneralizedTime', function (t) {
585+
var pem = fs.readFileSync(path.join(testDir, 'id_rsa'));
586+
var key = sshpk.parsePrivateKey(pem, 'pkcs1');
587+
588+
var id = sshpk.identityFromDN('cn=foobar');
589+
var opts = {};
590+
opts.validFrom = new Date('2050-01-02T03:04:05Z');
591+
opts.validUntil = new Date('2051-01-02T03:04:05Z');
592+
var cert = sshpk.createSelfSignedCertificate(id, key, opts);
593+
var certPem = cert.toBuffer('pem');
594+
595+
var kid = spawn('openssl', ['asn1parse']);
596+
var bufs = [];
597+
kid.stdout.on('data', bufs.push.bind(bufs));
598+
kid.on('close', function (rc) {
599+
t.equal(rc, 0);
600+
var output = Buffer.concat(bufs).toString('utf8');
601+
var lines = output.split('\n');
602+
var found = 0;
603+
for (var i = 0; i < lines.length; ++i) {
604+
if (!lines[i])
605+
continue;
606+
var line = asn1parse_line2obj(lines[i]);
607+
if (line.tag === 'UTCTIME') {
608+
t.fail('unexpected utctime: ' + line.value);
609+
}
610+
if (line.tag === 'GENERALIZEDTIME') {
611+
if (line.value === '20500102030405Z') {
612+
++found;
613+
} else if (line.value === '20510102030405Z') {
614+
++found;
615+
} else {
616+
t.fail('bad gentime: ' + line.value);
617+
}
618+
}
619+
}
620+
t.equal(found, 2);
621+
t.end();
622+
});
623+
kid.stdin.write(certPem);
624+
kid.stdin.end();
625+
});
626+
627+
test('certs with <1950 dates should use GeneralizedTime', function (t) {
628+
var pem = fs.readFileSync(path.join(testDir, 'id_rsa'));
629+
var key = sshpk.parsePrivateKey(pem, 'pkcs1');
630+
631+
var id = sshpk.identityFromDN('cn=foobar');
632+
var opts = {};
633+
opts.validFrom = new Date('1949-01-02T03:04:05Z');
634+
opts.validUntil = new Date('1950-01-02T03:04:05Z');
635+
var cert = sshpk.createSelfSignedCertificate(id, key, opts);
636+
var certPem = cert.toBuffer('pem');
637+
638+
var kid = spawn('openssl', ['asn1parse']);
639+
var bufs = [];
640+
kid.stdout.on('data', bufs.push.bind(bufs));
641+
kid.on('close', function (rc) {
642+
t.equal(rc, 0);
643+
var output = Buffer.concat(bufs).toString('utf8');
644+
var lines = output.split('\n');
645+
var found = 0;
646+
for (var i = 0; i < lines.length; ++i) {
647+
if (!lines[i])
648+
continue;
649+
var line = asn1parse_line2obj(lines[i]);
650+
if (line.tag === 'UTCTIME') {
651+
if (line.value === '500102030405Z') {
652+
++found;
653+
} else {
654+
t.fail('unexpected utctime: ' +
655+
line.value);
656+
}
657+
}
658+
if (line.tag === 'GENERALIZEDTIME') {
659+
if (line.value === '19490102030405Z') {
660+
++found;
661+
} else {
662+
t.fail('unexpected gentime: ' +
663+
line.value);
664+
}
665+
}
666+
}
667+
t.equal(found, 2);
668+
t.end();
669+
});
670+
kid.stdin.write(certPem);
671+
kid.stdin.end();
672+
});
673+
544674
test('teardown', function (t) {
545675
temp.cleanup(function () {
546676
t.end();

0 commit comments

Comments
 (0)