Skip to content

Commit

Permalink
#48 wish: add support for x509 certificates in text form
Browse files Browse the repository at this point in the history
Reviewed by: Cody Peter Mello <cody.mello@joyent.com>
  • Loading branch information
arekinath committed Dec 19, 2018
1 parent c7a6c68 commit 385ff11
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 13 deletions.
22 changes: 16 additions & 6 deletions lib/formats/pem.js
@@ -1,4 +1,4 @@
// Copyright 2015 Joyent, Inc.
// Copyright 2018 Joyent, Inc.

module.exports = {
read: read,
Expand Down Expand Up @@ -32,14 +32,22 @@ function read(buf, options, forceType) {
buf = buf.toString('ascii');
}

var lines = buf.trim().split('\n');
var lines = buf.trim().split(/[\r\n]+/g);

var m = lines[0].match(/*JSSTYLED*/
/[-]+[ ]*BEGIN ([A-Z0-9][A-Za-z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/);
var m;
var si = -1;
while (!m && si < lines.length) {
m = lines[++si].match(/*JSSTYLED*/
/[-]+[ ]*BEGIN ([A-Z0-9][A-Za-z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/);
}
assert.ok(m, 'invalid PEM header');

var m2 = lines[lines.length - 1].match(/*JSSTYLED*/
/[-]+[ ]*END ([A-Z0-9][A-Za-z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/);
var m2;
var ei = lines.length;
while (!m2 && ei > 0) {
m2 = lines[--ei].match(/*JSSTYLED*/
/[-]+[ ]*END ([A-Z0-9][A-Za-z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/);
}
assert.ok(m2, 'invalid PEM footer');

/* Begin and end banners must match key type */
Expand All @@ -53,6 +61,8 @@ function read(buf, options, forceType) {
alg = m[1].trim();
}

lines = lines.slice(si, ei + 1);

var headers = {};
while (true) {
lines = lines.slice(1);
Expand Down
18 changes: 14 additions & 4 deletions lib/formats/x509-pem.js
Expand Up @@ -29,14 +29,24 @@ function read(buf, options) {

var lines = buf.trim().split(/[\r\n]+/g);

var m = lines[0].match(/*JSSTYLED*/
/[-]+[ ]*BEGIN CERTIFICATE[ ]*[-]+/);
var m;
var si = -1;
while (!m && si < lines.length) {
m = lines[++si].match(/*JSSTYLED*/
/[-]+[ ]*BEGIN CERTIFICATE[ ]*[-]+/);
}
assert.ok(m, 'invalid PEM header');

var m2 = lines[lines.length - 1].match(/*JSSTYLED*/
/[-]+[ ]*END CERTIFICATE[ ]*[-]+/);
var m2;
var ei = lines.length;
while (!m2 && ei > 0) {
m2 = lines[--ei].match(/*JSSTYLED*/
/[-]+[ ]*END CERTIFICATE[ ]*[-]+/);
}
assert.ok(m2, 'invalid PEM footer');

lines = lines.slice(si, ei + 1);

var headers = {};
while (true) {
lines = lines.slice(1);
Expand Down
46 changes: 46 additions & 0 deletions test/assets/jim-x509-text.pem
@@ -0,0 +1,46 @@
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
ab:fd:52:3c:3e:52:c0:7b
Signature Algorithm: sha1WithRSAEncryption
Issuer: DC = jim, DC = com
Validity
Not Before: Jul 22 01:04:26 2016 GMT
Not After : Jul 22 01:04:26 2017 GMT
Subject: DC = jim, DC = com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (1024 bit)
Modulus:
00:d5:9a:5d:d8:0d:5a:a2:98:5c:95:80:af:2b:80:
41:22:b4:0f:be:1a:ae:bb:ad:7a:af:29:5e:34:57:
91:a5:4f:b3:86:40:bf:a2:d3:3a:d7:f2:29:0b:47:
c2:29:0a:f5:5c:b3:7e:c5:ef:c2:a8:84:5f:70:0e:
3f:39:e2:79:1c:50:26:cd:87:42:62:86:8a:f7:23:
96:98:96:9b:c4:16:53:b8:4b:c9:e3:57:0f:4a:3a:
b6:3e:2f:df:f4:00:b4:40:2b:a5:0e:f7:a8:13:c1:
13:96:e6:8f:fc:82:dc:83:c5:42:71:10:5d:83:89:
6c:de:82:e9:90:25:6d:52:37
Exponent: 65537 (0x10001)
Signature Algorithm: sha1WithRSAEncryption
10:53:47:a4:a6:91:97:6b:42:06:7e:8f:25:e1:46:56:ae:a0:
4e:84:38:db:ac:e8:76:2d:c4:81:53:4a:22:1c:1f:e9:58:70:
25:88:3c:bc:86:a5:d0:03:7a:eb:d7:b8:ab:72:6e:39:f2:85:
05:ba:91:07:bc:1d:ba:c9:08:8e:d6:e3:4b:41:c2:2e:5d:38:
86:a1:40:36:c5:c7:a9:82:36:1b:65:a8:67:d5:66:d8:4c:9b:
8a:16:d7:0d:c6:43:95:b2:af:83:9a:3d:f8:ca:f7:35:46:8a:
f8:95:ca:a5:83:97:e8:3c:4f:1a:1f:63:8d:ae:81:b6:3f:03:
3b:79
-----BEGIN CERTIFICATE-----
MIIByzCCATQCCQCr/VI8PlLAezANBgkqhkiG9w0BAQUFADAqMRMwEQYKCZImiZPy
LGQBGRYDamltMRMwEQYKCZImiZPyLGQBGRYDY29tMB4XDTE2MDcyMjAxMDQyNloX
DTE3MDcyMjAxMDQyNlowKjETMBEGCgmSJomT8ixkARkWA2ppbTETMBEGCgmSJomT
8ixkARkWA2NvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1Zpd2A1aophc
lYCvK4BBIrQPvhquu616ryleNFeRpU+zhkC/otM61/IpC0fCKQr1XLN+xe/CqIRf
cA4/OeJ5HFAmzYdCYoaK9yOWmJabxBZTuEvJ41cPSjq2Pi/f9AC0QCulDveoE8ET
luaP/ILcg8VCcRBdg4ls3oLpkCVtUjcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQAQ
U0ekppGXa0IGfo8l4UZWrqBOhDjbrOh2LcSBU0oiHB/pWHAliDy8hqXQA3rr17ir
cm458oUFupEHvB26yQiO1uNLQcIuXTiGoUA2xcepgjYbZahn1WbYTJuKFtcNxkOV
sq+Dmj34yvc1Ror4lcqlg5foPE8aH2ONroG2PwM7eQ==
-----END CERTIFICATE-----
13 changes: 11 additions & 2 deletions test/certs.js
@@ -1,4 +1,4 @@
// Copyright 2016 Joyent, Inc. All rights reserved.
// Copyright 2018 Joyent, Inc. All rights reserved.

var test = require('tape').test;

Expand All @@ -14,7 +14,7 @@ var testDir = path.join(__dirname, 'assets');

var GEORGE_KEY, GEORGE_SSH, GEORGE_X509;
var BARRY_KEY;
var JIM_KEY, JIM_SSH, JIM_X509;
var JIM_KEY, JIM_SSH, JIM_X509, JIM_X509_TXT;
var EC_KEY, EC_KEY2;
var SUE_KEY;

Expand All @@ -32,6 +32,7 @@ test('setup', function (t) {

JIM_SSH = fs.readFileSync(path.join(testDir, 'jim-openssh.pub'));
JIM_X509 = fs.readFileSync(path.join(testDir, 'jim-x509.pem'));
JIM_X509_TXT = fs.readFileSync(path.join(testDir, 'jim-x509-text.pem'));

d = fs.readFileSync(path.join(testDir, 'id_ecdsa'));
EC_KEY = sshpk.parsePrivateKey(d);
Expand Down Expand Up @@ -136,6 +137,14 @@ test('rsa x509 cert self-signed', function (t) {
t.end();
});

test('x509 pem cert with extra text', function (t) {
var cert = sshpk.parseCertificate(JIM_X509_TXT, 'pem');
t.ok(sshpk.Certificate.isCertificate(cert));
t.ok(JIM_KEY.fingerprint().matches(cert.subjectKey));
t.ok(cert.isSignedByKey(JIM_KEY));
t.end();
});

test('create rsa self-signed, loopback', function (t) {
var id = sshpk.identityForHost('foobar.com');
var cert = sshpk.createSelfSignedCertificate(id, JIM_KEY);
Expand Down
28 changes: 27 additions & 1 deletion test/openssl-cmd.js
@@ -1,4 +1,4 @@
// Copyright 2017 Joyent, Inc. All rights reserved.
// Copyright 2018 Joyent, Inc. All rights reserved.

var test = require('tape').test;
var sshpk = require('../lib/index');
Expand Down Expand Up @@ -392,6 +392,32 @@ function genTests() {
kid.stdin.end();
});

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

var ids = [
sshpk.identityFromDN('cn=' + algo + ', c=US'),
sshpk.identityFromDN('cn=' + algo + '.test, c=AU')
];
var cert = sshpk.createSelfSignedCertificate(ids, key);
var certPem = cert.toBuffer('pem');

var kid = spawn('openssl', ['x509', '-text']);
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();

var cert2 = sshpk.parseCertificate(output, 'pem');
t.ok(cert2.fingerprint('sha512').matches(cert));
t.end();
});
kid.stdin.write(certPem);
kid.stdin.end();
});

test('make a self-signed cert with generated key', function (t) {
if (algo !== 'ecdsa') {
t.end();
Expand Down

0 comments on commit 385ff11

Please sign in to comment.