From f472e39614e466b6e930d710671c68166971b317 Mon Sep 17 00:00:00 2001 From: Alex Wilson Date: Thu, 26 May 2022 10:30:40 +1000 Subject: [PATCH] node-sshpk#81 add support for ed25519 private keys in pkcs8 Co-authored-by: Jhonas Wernery --- bin/sshpk-conv | 12 ++++++------ lib/formats/pkcs8.js | 36 ++++++++++++++++++++++++------------ package.json | 5 ++--- test/private-key.js | 10 ++++++++++ 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/bin/sshpk-conv b/bin/sshpk-conv index e839ede..da5569b 100755 --- a/bin/sshpk-conv +++ b/bin/sshpk-conv @@ -91,12 +91,12 @@ if (require.main === module) { console.error('sshpk-conv: converts between SSH key formats\n'); console.error(help); console.error('\navailable key formats:'); - console.error(' - pem, pkcs1 eg id_rsa'); - console.error(' - ssh eg id_rsa.pub'); - console.error(' - pkcs8 format you want for openssl'); - console.error(' - openssh like output of ssh-keygen -o'); - console.error(' - rfc4253 raw OpenSSH wire format'); - console.error(' - dnssec dnssec-keygen format'); + console.error(' - pem, pkcs1 eg id_rsa'); + console.error(' - ssh eg id_rsa.pub'); + console.error(' - pkcs8 format you want for openssl'); + console.error(' - openssh like output of ssh-keygen -o'); + console.error(' - rfc4253 raw OpenSSH wire format'); + console.error(' - dnssec dnssec-keygen format'); console.error(' - putty PuTTY ppk format'); console.error('\navailable fingerprint formats:'); console.error(' - hex colon-separated hex for SSH'); diff --git a/lib/formats/pkcs8.js b/lib/formats/pkcs8.js index 2ca3ca7..07d04c8 100644 --- a/lib/formats/pkcs8.js +++ b/lib/formats/pkcs8.js @@ -385,13 +385,17 @@ function readPkcs8EdDSAPrivate(der) { var k = der.readString(asn1.Ber.OctetString, true); k = utils.zeroPadToLength(k, 32); - var A; - if (der.peek() === asn1.Ber.BitString) { - A = utils.readBitString(der); - A = utils.zeroPadToLength(A, 32); - } else { - A = utils.calculateED25519Public(k); + var A, tag; + while ((tag = der.peek()) !== null) { + if (tag === (asn1.Ber.Context | 1)) { + A = utils.readBitString(der, tag); + } else { + der.readSequence(tag); + der._offset += der.length; + } } + if (A === undefined) + A = utils.calculateED25519Public(k); var key = { type: 'ed25519', @@ -435,8 +439,11 @@ function writePkcs8(der, key) { der.startSequence(); if (PrivateKey.isPrivateKey(key)) { - var sillyInt = Buffer.from([0]); - der.writeBuffer(sillyInt, asn1.Ber.Integer); + var version = 0; + if (key.type === 'ed25519') + version = 1; + var vbuf = Buffer.from([version]); + der.writeBuffer(vbuf, asn1.Ber.Integer); } der.startSequence(); @@ -465,9 +472,9 @@ function writePkcs8(der, key) { case 'ed25519': der.writeOID('1.3.101.112'); if (PrivateKey.isPrivateKey(key)) - throw (new Error('Ed25519 private keys in pkcs8 ' + - 'format are not supported')); - writePkcs8EdDSAPublic(key, der); + writePkcs8EdDSAPrivate(key, der); + else + writePkcs8EdDSAPublic(key, der); break; default: throw (new Error('Unsupported key type: ' + key.type)); @@ -624,8 +631,13 @@ function writePkcs8EdDSAPublic(key, der) { function writePkcs8EdDSAPrivate(key, der) { der.endSequence(); - var k = utils.mpNormalize(key.part.k.data, true); der.startSequence(asn1.Ber.OctetString); + var k = utils.mpNormalize(key.part.k.data); + /* RFCs call for storing exactly 32 bytes, so strip any leading zeros */ + while (k.length > 32 && k[0] === 0x00) + k = k.slice(1); der.writeBuffer(k, asn1.Ber.OctetString); der.endSequence(); + + utils.writeBitString(der, key.part.A.data, asn1.Ber.Context | 1); } diff --git a/package.json b/package.json index 967a8d3..144ec16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sshpk", - "version": "1.17.0", + "version": "1.18.0", "description": "A library for finding and using SSH public keys", "main": "lib/index.js", "scripts": { @@ -49,8 +49,7 @@ "ecc-jsbn": "~0.1.1", "bcrypt-pbkdf": "^1.0.0" }, - "optionalDependencies": { - }, + "optionalDependencies": {}, "devDependencies": { "tape": "^3.5.0", "benchmark": "^1.0.0", diff --git a/test/private-key.js b/test/private-key.js index 3eb25ba..629ec0b 100644 --- a/test/private-key.js +++ b/test/private-key.js @@ -127,6 +127,16 @@ test('PrivateKey load ed25519 key (w/ public curdle-pkix-05)', function (t) { t.end(); }); +test('PrivateKey convert ed25519 key from pkcs1 to pkcs8', function (t) { + var keyPem = fs.readFileSync(path.join(testDir, 'id_ed25519.pem')); + var key = sshpk.parsePrivateKey(keyPem, 'pem'); + var newPem = key.toString('pkcs8'); + var key2 = sshpk.parsePrivateKey(newPem, 'pem'); + t.strictEqual(key.type, 'ed25519'); + t.strictEqual(key.size, 256); + t.end(); +}); + test('PrivateKey invalid ed25519 key (not DER)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'ed25519-invalid-ber.pem'));