Skip to content

Commit

Permalink
Add support for ed25519 private keys in pkcs8 (#92)
Browse files Browse the repository at this point in the history
Reviewed by: Brian Bennett
  • Loading branch information
teutat3s committed Oct 19, 2023
1 parent 3e83664 commit 8df0385
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 21 deletions.
12 changes: 6 additions & 6 deletions bin/sshpk-conv
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
36 changes: 24 additions & 12 deletions lib/formats/pkcs8.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
}
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down Expand Up @@ -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",
Expand Down
10 changes: 10 additions & 0 deletions test/private-key.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
Expand Down

0 comments on commit 8df0385

Please sign in to comment.