Skip to content

Commit

Permalink
xxx: add support for macos pkhh fingerprints
Browse files Browse the repository at this point in the history
  • Loading branch information
arekinath committed May 28, 2024
1 parent 8df0385 commit 9fb6b0f
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 6 deletions.
32 changes: 31 additions & 1 deletion bin/sshpk-conv
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ var options = [
type: 'bool',
help: 'Produce a private key as output'
},
{
names: ['certificate', 'C'],
type: 'bool',
help: 'Expect a certificate as input, not a public/private key'
},
{
names: ['derive', 'd'],
type: 'string',
Expand All @@ -62,6 +67,11 @@ var options = [
type: 'bool',
help: 'With -F, generates an SPKI fingerprint instead of SSH'
},
{
names: ['pkhh', 'P'],
type: 'bool',
help: 'With -F, generates a MacOS pkhh fingerprint instead of SSH'
},
{
names: ['comment', 'c'],
type: 'string',
Expand Down Expand Up @@ -161,6 +171,11 @@ if (require.main === module) {
var f = sshpk.parseKey;
if (opts.private)
f = sshpk.parsePrivateKey;
if (opts.certificate) {
f = sshpk.parseCertificate;
if (fmt === 'auto')
fmt = 'pem';
}
try {
var key = f(buf, fmt, parseOpts);
} catch (e) {
Expand All @@ -176,6 +191,12 @@ if (require.main === module) {
ifError(e);
}

if (opts.certificate) {
var cert = key;
key = cert.subjectKey;
key.comment = cert.subjects[0].toString();
}

if (opts.derive)
key = key.derive(opts.derive);

Expand All @@ -198,13 +219,22 @@ if (require.main === module) {
key.fingerprint('md5').toString());
console.log('SPKI-SHA256 fingerprint: ' +
key.fingerprint('sha256', 'spki').toString());
console.log('MacOS pkhh fingerprint: ' +
key.fingerprint('sha1', 'pkhh').toString());
process.exit(0);
return;
}

if (opts.fingerprint) {
var hash = opts.hash;
var type = opts.spki ? 'spki' : 'ssh';
var type = 'ssh';
if (opts.spki)
type = 'spki';
if (opts.pkhh) {
if (!hash)
hash = 'sha1';
type = 'pkhh';
}
var format = opts.outformat;
var fp = key.fingerprint(hash, type).toString(format);
outFile.write(fp);
Expand Down
8 changes: 6 additions & 2 deletions lib/fingerprint.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,21 @@ function Fingerprint(opts) {

Fingerprint.prototype.toString = function (format) {
if (format === undefined) {
if (this.algorithm === 'md5' || this.hashType === 'spki')
if (this.algorithm === 'md5' || this.hashType === 'spki' ||
this.hashType === 'pkhh') {
format = 'hex';
else
} else {
format = 'base64';
}
}
assert.string(format);

switch (format) {
case 'hex':
if (this.hashType === 'spki')
return (this.hash.toString('hex'));
if (this.hashType === 'pkhh')
return (this.hash.toString('hex').toUpperCase());
return (addColons(this.hash.toString('hex')));
case 'base64':
if (this.hashType === 'spki')
Expand Down
33 changes: 30 additions & 3 deletions lib/formats/pkcs8.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
write: write,
writePkcs8: writePkcs8,
pkcs8ToBuffer: pkcs8ToBuffer,
pkcs8PublicBitstringToBuffer: pkcs8PublicBitstringToBuffer,

readECDSACurve: readECDSACurve,
writeECDSACurve: writeECDSACurve
Expand Down Expand Up @@ -513,14 +514,17 @@ function writePkcs8RSAPublic(key, der) {
der.endSequence();

der.startSequence(asn1.Ber.BitString);
writePkcs8RSAPublicBitstring(key, der);
der.endSequence();
}

function writePkcs8RSAPublicBitstring(key, der) {
der.writeByte(0x00);

der.startSequence();
der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
der.endSequence();

der.endSequence();
}

function writePkcs8DSAPrivate(key, der) {
Expand All @@ -546,9 +550,13 @@ function writePkcs8DSAPublic(key, der) {
der.endSequence();

der.startSequence(asn1.Ber.BitString);
writePkcs8DSAPublicBitstring(key, der);
der.endSequence();
}

function writePkcs8DSAPublicBitstring(key, der) {
der.writeByte(0x00);
der.writeBuffer(key.part.y.data, asn1.Ber.Integer);
der.endSequence();
}

function writeECDSACurve(key, der) {
Expand Down Expand Up @@ -601,6 +609,25 @@ function writePkcs8ECDSAPublic(key, der) {
der.writeBuffer(Q, asn1.Ber.BitString);
}

function pkcs8PublicBitstringToBuffer(key) {
var der = new asn1.BerWriter();
switch (key.type) {
case 'rsa':
writePkcs8RSAPublicBitstring(key, der);
break;
case 'dsa':
writePkcs8DSAPublicBitstring(key, der);
break;
case 'ecdsa':
return (key.part.Q.data);
case 'ed25519':
return (key.part.A.data);
default:
throw (new Error('Unsupported key type: ' + key.type));
}
return (der.buffer);
}

function writePkcs8ECDSAPrivate(key, der) {
writeECDSACurve(key, der);
der.endSequence();
Expand Down
2 changes: 2 additions & 0 deletions lib/key.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ Key.prototype.hash = function (algo, type) {
buf = this.toBuffer('rfc4253');
} else if (type === 'spki') {
buf = formats.pkcs8.pkcs8ToBuffer(this);
} else if (type === 'pkhh') {
buf = formats.pkcs8.pkcs8PublicBitstringToBuffer(this);
} else {
throw (new Error('Hash type ' + type + ' not supported'));
}
Expand Down
12 changes: 12 additions & 0 deletions test/fingerprint.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ var ED2_PEM = '-----BEGIN PUBLIC KEY-----\n' +
'MCowBQYDK2VwAyEA+76Hlm7wYeCHyx5n0aK21NYd+luLS+Q2SwfvvJowqoM=\n' +
'-----END PUBLIC KEY-----\n';

var PKHH_PUBKEY = 'ecdsa-sha2-nistp256 ' +
'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBB0PaRc5Tc9C' +
'w8A6RRqFa+IdHF5LUFK5hkv32GnMmk/Eo2eafy2Ihxp0YnEbyg096g5J8wV6dpXv' +
'o2dXNYDoYjc=';

test('fingerprint', function(t) {
var k = sshpk.parseKey(SSH_1024, 'ssh');
var fp = k.fingerprint('md5').toString();
Expand Down Expand Up @@ -172,3 +177,10 @@ test('invalid fingerprints', function(t) {
}, sshpk.FingerprintFormatError);
t.end();
});

test('pkhh fingerprint for macos', function (t) {
var k = sshpk.parseKey(PKHH_PUBKEY, 'ssh');
var f = k.fingerprint('sha1', 'pkhh');
t.equal(f.toString(), '674C1B03D2A4885BB106E67D8A9BE82C078E27CB');
t.end();
});

0 comments on commit 9fb6b0f

Please sign in to comment.