wip: pack ssh private keys
This commit is contained in:
parent
ce26bf4e95
commit
931e884ba9
@ -5,6 +5,8 @@ var path = require('path');
|
|||||||
var jwktossh = require('../index.js');
|
var jwktossh = require('../index.js');
|
||||||
|
|
||||||
var pubfile = process.argv[2];
|
var pubfile = process.argv[2];
|
||||||
|
var comment = process.argv[3] || 'root@localhost';
|
||||||
|
var pub = ('public' === process.argv[4]);
|
||||||
|
|
||||||
if (!pubfile) {
|
if (!pubfile) {
|
||||||
console.error("specify a path to JWK");
|
console.error("specify a path to JWK");
|
||||||
@ -12,7 +14,6 @@ if (!pubfile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var jwk = require(path.join(process.cwd(), pubfile));
|
var jwk = require(path.join(process.cwd(), pubfile));
|
||||||
var comment = process.argv[3] || 'root@localhost';
|
var out = jwktossh.pack({ jwk: jwk, comment: comment, public: pub });
|
||||||
var pub = jwktossh.pack({ jwk: jwk, comment: comment });
|
|
||||||
|
|
||||||
console.info(pub);
|
console.info(out);
|
||||||
|
7
fixtures/privkey-ec-p256.jwk.json
Normal file
7
fixtures/privkey-ec-p256.jwk.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"kty": "EC",
|
||||||
|
"crv": "P-256",
|
||||||
|
"d": "BzKpRmMyXZ4jnSt3ARz0ul6R79AXAr5gQqDAmoFeEKw",
|
||||||
|
"x": "fVmT3gUr4sZIY0Dofcgl15RMeQjfTMofeAiSda4oH_M",
|
||||||
|
"y": "r3eBz3QeZqEhHmgwYfCWoyhLuQqtHD7gqnGqwXssa_E"
|
||||||
|
}
|
7
fixtures/privkey-ec-p256.jwk.json.2
Normal file
7
fixtures/privkey-ec-p256.jwk.json.2
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"kty": "EC",
|
||||||
|
"crv": "P-256",
|
||||||
|
"d": "BzKpRmMyXZ4jnSt3ARz0ul6R79AXAr5gQqDAmoFeEKw",
|
||||||
|
"x": "fVmT3gUr4sZIY0Dofcgl15RMeQjfTMofeAiSda4oH_M",
|
||||||
|
"y": "r3eBz3QeZqEhHmgwYfCWoyhLuQqtHD7gqnGqwXssa_E"
|
||||||
|
}
|
7
fixtures/privkey-ec-p256.openssh.b64
Normal file
7
fixtures/privkey-ec-p256.openssh.b64
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
|
||||||
|
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQR9WZPeBSvixkhjQOh9yCXXlEx5CN9M
|
||||||
|
yh94CJJ1rigf8693gc90HmahIR5oMGHwlqMoS7kKrRw+4KpxqsF7LGvxAAAAqJZtgRuWbY
|
||||||
|
EbAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH1Zk94FK+LGSGNA
|
||||||
|
6H3IJdeUTHkI30zKH3gIknWuKB/zr3eBz3QeZqEhHmgwYfCWoyhLuQqtHD7gqnGqwXssa/
|
||||||
|
EAAAAgBzKpRmMyXZ4jnSt3ARz0ul6R79AXAr5gQqDAmoFeEKwAAAAOYWpAYm93aWUubG9j
|
||||||
|
YWwBAg==
|
7
fixtures/privkey-ec-p256.openssh.b64.2
Normal file
7
fixtures/privkey-ec-p256.openssh.b64.2
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
|
||||||
|
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQR9WZPeBSvixkhjQOh9yCXXlEx5CN9M
|
||||||
|
yh94CJJ1rigf8693gc90HmahIR5oMGHwlqMoS7kKrRw+4KpxqsF7LGvxAAAAqGJjanNiY2
|
||||||
|
pzAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH1Zk94FK+LGSGNA
|
||||||
|
6H3IJdeUTHkI30zKH3gIknWuKB/zr3eBz3QeZqEhHmgwYfCWoyhLuQqtHD7gqnGqwXssa/
|
||||||
|
EAAAAgBzKpRmMyXZ4jnSt3ARz0ul6R79AXAr5gQqDAmoFeEKwAAAAOYWpAYm93aWUubG9j
|
||||||
|
YWwBAg==
|
20
fixtures/privkey-ec-p256.openssh.hex
Normal file
20
fixtures/privkey-ec-p256.openssh.hex
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
00000000: 6f70 656e 7373 682d 6b65 792d 7631 0000 openssh-key-v1..
|
||||||
|
00000010: 0000 046e 6f6e 6500 0000 046e 6f6e 6500 ...none....none.
|
||||||
|
00000020: 0000 0000 0000 0100 0000 6800 0000 1365 ..........h....e
|
||||||
|
00000030: 6364 7361 2d73 6861 322d 6e69 7374 7032 cdsa-sha2-nistp2
|
||||||
|
00000040: 3536 0000 0008 6e69 7374 7032 3536 0000 56....nistp256..
|
||||||
|
00000050: 0041 047d 5993 de05 2be2 c648 6340 e87d .A.}Y...+..Hc@.}
|
||||||
|
00000060: c825 d794 4c79 08df 4cca 1f78 0892 75ae .%..Ly..L..x..u.
|
||||||
|
00000070: 281f f3af 7781 cf74 1e66 a121 1e68 3061 (...w..t.f.!.h0a
|
||||||
|
00000080: f096 a328 4bb9 0aad 1c3e e0aa 71aa c17b ...(K....>..q..{
|
||||||
|
00000090: 2c6b f100 0000 a896 6d81 1b96 6d81 1b00 ,k......m...m...
|
||||||
|
000000a0: 0000 1365 6364 7361 2d73 6861 322d 6e69 ...ecdsa-sha2-ni
|
||||||
|
000000b0: 7374 7032 3536 0000 0008 6e69 7374 7032 stp256....nistp2
|
||||||
|
000000c0: 3536 0000 0041 047d 5993 de05 2be2 c648 56...A.}Y...+..H
|
||||||
|
000000d0: 6340 e87d c825 d794 4c79 08df 4cca 1f78 c@.}.%..Ly..L..x
|
||||||
|
000000e0: 0892 75ae 281f f3af 7781 cf74 1e66 a121 ..u.(...w..t.f.!
|
||||||
|
000000f0: 1e68 3061 f096 a328 4bb9 0aad 1c3e e0aa .h0a...(K....>..
|
||||||
|
00000100: 71aa c17b 2c6b f100 0000 2007 32a9 4663 q..{,k.... .2.Fc
|
||||||
|
00000110: 325d 9e23 9d2b 7701 1cf4 ba5e 91ef d017 2].#.+w....^....
|
||||||
|
00000120: 02be 6042 a0c0 9a81 5e10 ac00 0000 0e61 ..`B....^......a
|
||||||
|
00000130: 6a40 626f 7769 652e 6c6f 6361 6c01 02 j@bowie.local..
|
20
fixtures/privkey-ec-p256.openssh.hex.2
Normal file
20
fixtures/privkey-ec-p256.openssh.hex.2
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
00000000: 6f70 656e 7373 682d 6b65 792d 7631 0000 openssh-key-v1..
|
||||||
|
00000010: 0000 046e 6f6e 6500 0000 046e 6f6e 6500 ...none....none.
|
||||||
|
00000020: 0000 0000 0000 0100 0000 6800 0000 1365 ..........h....e
|
||||||
|
00000030: 6364 7361 2d73 6861 322d 6e69 7374 7032 cdsa-sha2-nistp2
|
||||||
|
00000040: 3536 0000 0008 6e69 7374 7032 3536 0000 56....nistp256..
|
||||||
|
00000050: 0041 047d 5993 de05 2be2 c648 6340 e87d .A.}Y...+..Hc@.}
|
||||||
|
00000060: c825 d794 4c79 08df 4cca 1f78 0892 75ae .%..Ly..L..x..u.
|
||||||
|
00000070: 281f f3af 7781 cf74 1e66 a121 1e68 3061 (...w..t.f.!.h0a
|
||||||
|
00000080: f096 a328 4bb9 0aad 1c3e e0aa 71aa c17b ...(K....>..q..{
|
||||||
|
00000090: 2c6b f100 0000 a862 636a 7362 636a 7300 ,k.....bcjsbcjs.
|
||||||
|
000000a0: 0000 1365 6364 7361 2d73 6861 322d 6e69 ...ecdsa-sha2-ni
|
||||||
|
000000b0: 7374 7032 3536 0000 0008 6e69 7374 7032 stp256....nistp2
|
||||||
|
000000c0: 3536 0000 0041 047d 5993 de05 2be2 c648 56...A.}Y...+..H
|
||||||
|
000000d0: 6340 e87d c825 d794 4c79 08df 4cca 1f78 c@.}.%..Ly..L..x
|
||||||
|
000000e0: 0892 75ae 281f f3af 7781 cf74 1e66 a121 ..u.(...w..t.f.!
|
||||||
|
000000f0: 1e68 3061 f096 a328 4bb9 0aad 1c3e e0aa .h0a...(K....>..
|
||||||
|
00000100: 71aa c17b 2c6b f100 0000 2007 32a9 4663 q..{,k.... .2.Fc
|
||||||
|
00000110: 325d 9e23 9d2b 7701 1cf4 ba5e 91ef d017 2].#.+w....^....
|
||||||
|
00000120: 02be 6042 a0c0 9a81 5e10 ac00 0000 0e61 ..`B....^......a
|
||||||
|
00000130: 6a40 626f 7769 652e 6c6f 6361 6c01 02 j@bowie.local..
|
9
fixtures/privkey-ec-p256.openssh.pem
Normal file
9
fixtures/privkey-ec-p256.openssh.pem
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
|
||||||
|
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQR9WZPeBSvixkhjQOh9yCXXlEx5CN9M
|
||||||
|
yh94CJJ1rigf8693gc90HmahIR5oMGHwlqMoS7kKrRw+4KpxqsF7LGvxAAAAqJZtgRuWbY
|
||||||
|
EbAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH1Zk94FK+LGSGNA
|
||||||
|
6H3IJdeUTHkI30zKH3gIknWuKB/zr3eBz3QeZqEhHmgwYfCWoyhLuQqtHD7gqnGqwXssa/
|
||||||
|
EAAAAgBzKpRmMyXZ4jnSt3ARz0ul6R79AXAr5gQqDAmoFeEKwAAAAOYWpAYm93aWUubG9j
|
||||||
|
YWwBAg==
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
9
fixtures/privkey-ec-p256.openssh.pem.2
Normal file
9
fixtures/privkey-ec-p256.openssh.pem.2
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
|
||||||
|
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQR9WZPeBSvixkhjQOh9yCXXlEx5CN9M
|
||||||
|
yh94CJJ1rigf8693gc90HmahIR5oMGHwlqMoS7kKrRw+4KpxqsF7LGvxAAAAqGJjanNiY2
|
||||||
|
pzAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH1Zk94FK+LGSGNA
|
||||||
|
6H3IJdeUTHkI30zKH3gIknWuKB/zr3eBz3QeZqEhHmgwYfCWoyhLuQqtHD7gqnGqwXssa/
|
||||||
|
EAAAAgBzKpRmMyXZ4jnSt3ARz0ul6R79AXAr5gQqDAmoFeEKwAAAAOYWpAYm93aWUubG9j
|
||||||
|
YWwBAg==
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
1
fixtures/privkey-ec-p256.openssh.pem.2.pub
Normal file
1
fixtures/privkey-ec-p256.openssh.pem.2.pub
Normal file
@ -0,0 +1 @@
|
|||||||
|
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH1Zk94FK+LGSGNA6H3IJdeUTHkI30zKH3gIknWuKB/zr3eBz3QeZqEhHmgwYfCWoyhLuQqtHD7gqnGqwXssa/E= root@localhost
|
1
fixtures/privkey-ec-p256.openssh.pem.pub
Normal file
1
fixtures/privkey-ec-p256.openssh.pem.pub
Normal file
@ -0,0 +1 @@
|
|||||||
|
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH1Zk94FK+LGSGNA6H3IJdeUTHkI30zKH3gIknWuKB/zr3eBz3QeZqEhHmgwYfCWoyhLuQqtHD7gqnGqwXssa/E= root@localhost
|
@ -6,6 +6,14 @@ Enc.base64ToHex = function (b64) {
|
|||||||
return Buffer.from(b64, 'base64').toString('hex');
|
return Buffer.from(b64, 'base64').toString('hex');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Enc.binToBuf = function (bin) {
|
||||||
|
return Buffer.from(bin, 'binary');
|
||||||
|
};
|
||||||
|
|
||||||
|
Enc.bufToBase64 = function (u8) {
|
||||||
|
return Buffer.from(u8).toString('base64');
|
||||||
|
};
|
||||||
|
|
||||||
Enc.binToHex = function (bin) {
|
Enc.binToHex = function (bin) {
|
||||||
return Buffer.from(bin, 'binary').toString('hex');
|
return Buffer.from(bin, 'binary').toString('hex');
|
||||||
};
|
};
|
||||||
@ -13,3 +21,7 @@ Enc.binToHex = function (bin) {
|
|||||||
Enc.hexToBase64 = function (hex) {
|
Enc.hexToBase64 = function (hex) {
|
||||||
return Buffer.from(hex, 'hex').toString('base64');
|
return Buffer.from(hex, 'hex').toString('base64');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Enc.hexToBin = function (hex) {
|
||||||
|
return Buffer.from(hex, 'hex').toString('binary');
|
||||||
|
};
|
||||||
|
11
lib/pem.js
Normal file
11
lib/pem.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var PEM = module.exports;
|
||||||
|
var Enc = require('./encoding.js');
|
||||||
|
|
||||||
|
PEM.packBlock = function (opts) {
|
||||||
|
return '-----BEGIN ' + opts.type + '-----\n'
|
||||||
|
+ Enc.bufToBase64(opts.bytes).match(/.{1,70}/g).join('\n') + '\n'
|
||||||
|
+ '-----END ' + opts.type + '-----'
|
||||||
|
;
|
||||||
|
};
|
@ -1,34 +1,87 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Enc = require('./encoding.js');
|
var Enc = require('./encoding.js');
|
||||||
|
var PEM = require('./pem.js');
|
||||||
var SSH = module.exports;
|
var SSH = module.exports;
|
||||||
|
|
||||||
SSH.pack = function (opts) {
|
SSH.pack = function (opts) {
|
||||||
|
if (opts.jwk.d && !opts.public) {
|
||||||
|
return SSH._packPrivate(opts);
|
||||||
|
} else {
|
||||||
|
delete opts.jwk.d;
|
||||||
|
return SSH._packPublic(opts);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://tools.ietf.org/html/rfc4253#section-6.6
|
||||||
|
SSH._packPublic = function (opts) {
|
||||||
|
var els = SSH._packKey(opts);
|
||||||
|
var hex = SSH._packElements(els);
|
||||||
|
var typ = Enc.hexToBin(els[0]);
|
||||||
|
var parts = [ typ, Enc.hexToBase64(hex) ];
|
||||||
|
if (opts.comment) { parts.push(opts.comment); }
|
||||||
|
return parts.join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
SSH._packPrivate = function (opts) {
|
||||||
|
var pubjwk = JSON.parse(JSON.stringify(opts.jwk));
|
||||||
|
delete pubjwk.d;
|
||||||
|
var pubels = SSH._packKey({ jwk: pubjwk });
|
||||||
|
var pubhex = SSH._packElements(pubels);
|
||||||
|
var els = SSH._packKey(opts);
|
||||||
|
var hex = SSH._packElements(els);
|
||||||
|
var privlen = hex.length/2;
|
||||||
|
var padlen = (privlen % 8) && (8 - (privlen % 8)) || 0; // blocksize is 8 (no cipher)
|
||||||
|
var bin = "openssh-key-v1" + String.fromCharCode(0)
|
||||||
|
+ Enc.hexToBin(
|
||||||
|
SSH._packElements([
|
||||||
|
Enc.binToHex("none") // ciphername
|
||||||
|
, Enc.binToHex("none") // kdfname
|
||||||
|
, "" // empty kdf
|
||||||
|
])
|
||||||
|
+ SSH._numToUint32Hex(1) // number of keys (always 1)
|
||||||
|
+ SSH._numToUint32Hex(pubhex.length/2) // pubkey length
|
||||||
|
+ pubhex
|
||||||
|
+ SSH._numToUint32Hex(8 + privlen + padlen) // privkey length
|
||||||
|
+ '62636a7362636a73' // 64-bit dummy checksum ("bcjs", "bcjs")
|
||||||
|
+ hex // (only cihpered keys use real checksums)
|
||||||
|
);
|
||||||
|
var pad = '';
|
||||||
|
var i;
|
||||||
|
for (i = 1; i <= padlen; i += 1) {
|
||||||
|
pad += '0' + i;
|
||||||
|
}
|
||||||
|
return PEM.packBlock({
|
||||||
|
type: "OPENSSH PRIVATE KEY"
|
||||||
|
, bytes: Enc.binToBuf(bin + Enc.hexToBin(pad))
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
SSH._packKey = function (opts) {
|
||||||
var jwk = opts.jwk;
|
var jwk = opts.jwk;
|
||||||
var els = [];
|
var els = [];
|
||||||
var ssh = {
|
|
||||||
type: ''
|
|
||||||
, _elements: els
|
|
||||||
, comment: opts.comment || ''
|
|
||||||
};
|
|
||||||
var len;
|
var len;
|
||||||
|
|
||||||
if ("RSA" === jwk.kty) {
|
if ("RSA" === jwk.kty) {
|
||||||
ssh.type = 'ssh-rsa';
|
els.push(Enc.binToHex('ssh-rsa'));
|
||||||
els.push(Enc.binToHex(ssh.type));
|
|
||||||
els.push(SSH._padRsa(Enc.base64ToHex(jwk.e)));
|
els.push(SSH._padRsa(Enc.base64ToHex(jwk.e)));
|
||||||
els.push(SSH._padRsa(Enc.base64ToHex(jwk.n)));
|
els.push(SSH._padRsa(Enc.base64ToHex(jwk.n)));
|
||||||
return SSH._packElements(ssh);
|
if (jwk.d) {
|
||||||
|
els.push(SSH._padRsa(Enc.base64ToHex(jwk.d)));
|
||||||
|
els.push(SSH._padRsa(Enc.base64ToHex(jwk.qi)));
|
||||||
|
els.push(SSH._padRsa(Enc.base64ToHex(jwk.p)));
|
||||||
|
els.push(SSH._padRsa(Enc.base64ToHex(jwk.q)));
|
||||||
|
els.push(Enc.binToHex(opts.comment || ''));
|
||||||
|
}
|
||||||
|
return SSH._packElements(els);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("P-256" === jwk.crv) {
|
if ("P-256" === jwk.crv) {
|
||||||
ssh.type = 'ecdsa-sha2-nistp256';
|
els.push(Enc.binToHex('ecdsa-sha2-nistp256'));
|
||||||
els.push(Enc.binToHex(ssh.type));
|
|
||||||
els.push(Enc.binToHex('nistp256'));
|
els.push(Enc.binToHex('nistp256'));
|
||||||
len = 32;
|
len = 32;
|
||||||
} else if ("P-384" === jwk.crv) {
|
} else if ("P-384" === jwk.crv) {
|
||||||
ssh.type = 'ecdsa-sha2-nistp384';
|
els.push(Enc.binToHex('ecdsa-sha2-nistp384'));
|
||||||
els.push(Enc.binToHex(ssh.type));
|
|
||||||
els.push(Enc.binToHex('nistp384'));
|
els.push(Enc.binToHex('nistp384'));
|
||||||
len = 48;
|
len = 48;
|
||||||
} else {
|
} else {
|
||||||
@ -39,14 +92,18 @@ SSH.pack = function (opts) {
|
|||||||
+ SSH._padEc(Enc.base64ToHex(jwk.x), len)
|
+ SSH._padEc(Enc.base64ToHex(jwk.x), len)
|
||||||
+ SSH._padEc(Enc.base64ToHex(jwk.y), len)
|
+ SSH._padEc(Enc.base64ToHex(jwk.y), len)
|
||||||
);
|
);
|
||||||
return SSH._packElements(ssh);
|
if (jwk.d) {
|
||||||
|
els.push(SSH._padEc(Enc.base64ToHex(jwk.d), len));
|
||||||
|
els.push(Enc.binToHex(opts.comment || ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
return els;
|
||||||
};
|
};
|
||||||
|
|
||||||
SSH._packElements = function (ssh) {
|
SSH._packElements = function(els) {
|
||||||
var hex = ssh._elements.map(function (hex) {
|
return els.map(function (hex) {
|
||||||
return SSH._numToUint32Hex(hex.length/2) + hex;
|
return SSH._numToUint32Hex(hex.length/2) + hex;
|
||||||
}).join('');
|
}).join('');
|
||||||
return [ ssh.type, Enc.hexToBase64(hex), ssh.comment ].join(' ');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SSH._numToUint32Hex = function (num) {
|
SSH._numToUint32Hex = function (num) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user