Skip to content

Commit

Permalink
#22 x509 certificates with string containing "_" can't be parsed by G…
Browse files Browse the repository at this point in the history
…o TLS

Reviewed by: Cody Mello <cody.mello@joyent.com>
Approved by: Cody Mello <cody.mello@joyent.com>
  • Loading branch information
arekinath committed Jan 14, 2017
1 parent 6b3727f commit 3ae5356
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 2 deletions.
24 changes: 23 additions & 1 deletion lib/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,35 @@ Identity.prototype.toString = function () {
}).join(', '));
};

/*
* These are from X.680 -- PrintableString allowed chars are in section 37.4
* table 8. Spec for IA5Strings is "1,6 + SPACE + DEL" where 1 refers to
* ISO IR #001 (standard ASCII control characters) and 6 refers to ISO IR #006
* (the basic ASCII character set).
*/
/* JSSTYLED */
var NOT_PRINTABLE = /[^a-zA-Z0-9 '(),+.\/:=?-]/;
/* JSSTYLED */
var NOT_IA5 = /[^\x00-\x7f]/;

Identity.prototype.toAsn1 = function (der, tag) {
der.startSequence(tag);
this.components.forEach(function (c) {
der.startSequence(asn1.Ber.Constructor | asn1.Ber.Set);
der.startSequence();
der.writeOID(c.oid);
der.writeString(c.value, asn1.Ber.PrintableString);
/*
* If we fit in a PrintableString, use that. Otherwise use an
* IA5String or UTF8String.
*/
if (c.value.match(NOT_IA5)) {
var v = new Buffer(c.value, 'utf8');
der.writeBuffer(v, asn1.Ber.Utf8String);
} else if (c.value.match(NOT_PRINTABLE)) {
der.writeString(c.value, asn1.Ber.IA5String);
} else {
der.writeString(c.value, asn1.Ber.PrintableString);
}
der.endSequence();
der.endSequence();
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sshpk",
"version": "1.10.1",
"version": "1.10.2",
"description": "A library for finding and using SSH public keys",
"main": "lib/index.js",
"scripts": {
Expand Down
95 changes: 95 additions & 0 deletions test/openssl-cmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,101 @@ function genTests() {
kid.stdin.write(certPem);
kid.stdin.end();
});

test('make a self-signed cert with utf8 chars', function (t) {
var pem = fs.readFileSync(path.join(testDir, 'id_' + algo));
var key = sshpk.parsePrivateKey(pem, 'pkcs1');

var id = sshpk.identityFromDN('cn=おはよう');
var cert = sshpk.createSelfSignedCertificate(id, key);
var certPem = cert.toBuffer('pem');

fs.writeFileSync(path.join(tmp, 'ca.pem'), certPem);

var kid = spawn('openssl', ['verify',
'-CAfile', path.join(tmp, 'ca.pem')]);
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();
t.strictEqual(output.trim(), 'stdin: OK');
t.end();
});
kid.stdin.write(certPem);
kid.stdin.end();
});

test('verify a self-signed cert with utf8 chars', function (t) {
var pem = fs.readFileSync(path.join(testDir, 'id_' + algo));
var key = sshpk.parsePrivateKey(pem, 'pkcs1');

var id = sshpk.identityFromDN('cn=おはよう');
var cert = sshpk.createSelfSignedCertificate(id, key);
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 foundString = false;
lines.forEach(function (line) {
if (line.indexOf('おはよう') !== -1) {
t.strictEqual(
line.indexOf('PRINTABLESTRING'),
-1);
t.strictEqual(
line.indexOf('IA5STRING'),
-1);
t.notStrictEqual(
line.indexOf('UTF8STRING'), -1);
foundString = true;
}
});
t.ok(foundString);
t.end();
});
kid.stdin.write(certPem);
kid.stdin.end();
});

test('make a self-signed cert with non-printable chars', function (t) {
var pem = fs.readFileSync(path.join(testDir, 'id_' + algo));
var key = sshpk.parsePrivateKey(pem, 'pkcs1');

var id = sshpk.identityFromDN('cn=foo_bar@');
var cert = sshpk.createSelfSignedCertificate(id, key);
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 foundString = false;
lines.forEach(function (line) {
if (line.indexOf('foo_bar@') !== -1) {
t.strictEqual(
line.indexOf('PRINTABLESTRING'),
-1);
t.strictEqual(
line.indexOf('UTF8STRING'), -1);
t.notStrictEqual(
line.indexOf('IA5STRING'), -1);
foundString = true;
}
});
t.ok(foundString);
t.end();
});
kid.stdin.write(certPem);
kid.stdin.end();
});
});

test('teardown', function (t) {
Expand Down

0 comments on commit 3ae5356

Please sign in to comment.