diff --git a/lib/protocol/Protocol.js b/lib/protocol/Protocol.js index 73024881..2548cd1c 100644 --- a/lib/protocol/Protocol.js +++ b/lib/protocol/Protocol.js @@ -65,6 +65,7 @@ const { bufferFill, bufferSlice, convertSignature, + getSignatureAlgo, sendPacket, writeUInt32BE, } = require('./utils.js'); @@ -703,9 +704,11 @@ class Protocol { const sigLen = signature.length; p = this._packetRW.write.allocStart; + const sigAlgo = getSignatureAlgo(keyAlgo, keyType); + const sigAlgoLen = sigAlgo.length; packet = this._packetRW.write.alloc( 1 + 4 + userLen + 4 + 14 + 4 + 9 + 1 + 4 + algoLen + 4 + pubKeyLen + 4 - + 4 + algoLen + 4 + sigLen + + 4 + sigAlgoLen + 4 + sigLen ); // TODO: simply copy from original "packet" to new `packet` to avoid @@ -729,12 +732,12 @@ class Protocol { writeUInt32BE(packet, pubKeyLen, p += algoLen); packet.set(pubKey, p += 4); - writeUInt32BE(packet, 4 + algoLen + 4 + sigLen, p += pubKeyLen); + writeUInt32BE(packet, 4 + sigAlgoLen + 4 + sigLen, p += pubKeyLen); - writeUInt32BE(packet, algoLen, p += 4); - packet.utf8Write(keyAlgo, p += 4, algoLen); + writeUInt32BE(packet, sigAlgoLen, p += 4); + packet.utf8Write(keyAlgo, p += 4, sigAlgoLen); - writeUInt32BE(packet, sigLen, p += algoLen); + writeUInt32BE(packet, sigLen, p += sigAlgoLen); packet.set(signature, p += 4); // Servers shouldn't send packet type 60 in response to signed publickey diff --git a/lib/protocol/keyParser.js b/lib/protocol/keyParser.js index a276c1ae..4cb6ac43 100644 --- a/lib/protocol/keyParser.js +++ b/lib/protocol/keyParser.js @@ -1390,6 +1390,28 @@ function parseDER(data, baseType, comment, fullType) { return new OpenSSH_Public(fullType, comment, pubPEM, pubSSH, algo); } +function tryParseAsCert(data, baseType, comment) { + if (!isSupportedCertType(baseType)) + return new Error(`Unsupported OpenSSH cert type: ${baseType}`); + + let algo; + const pubPEM = null; + let pubSSH = null; + + switch (baseType) { + case 'ecdsa-sha2-nistp256-cert-v01@openssh.com': + case 'ecdsa-sha2-nistp384-cert-v01@openssh.com': + case 'ecdsa-sha2-nistp521-cert-v01@openssh.com': + algo = baseType; + pubSSH = data; + break; + default: + return new Error(`Unsupported OpenSSH cert type: ${baseType}`); + } + + return new OpenSSH_Public(baseType, comment, pubPEM, pubSSH, algo); +} + function isSupportedKeyType(type) { switch (type) { case 'ssh-rsa': @@ -1407,6 +1429,17 @@ function isSupportedKeyType(type) { } } +function isSupportedCertType(type) { + switch (type) { + case 'ecdsa-sha2-nistp256-cert-v01@openssh.com': + case 'ecdsa-sha2-nistp384-cert-v01@openssh.com': + case 'ecdsa-sha2-nistp521-cert-v01@openssh.com': + return true; + default: + return false; + } +} + function isParsedKey(val) { if (!val) return false; @@ -1461,10 +1494,14 @@ function parseKey(data, passphrase) { data = binaryKeyParser.readRaw(); if (data !== undefined) { ret = parseDER(data, type, '', type); - // Ignore potentially useless errors in case the data was not actually - // in the binary format - if (ret instanceof Error) - ret = null; + // Try parse as cert + if (ret instanceof Error) { + ret = tryParseAsCert(origBuffer, type, ''); + // Ignore potentially useless errors in case the data was not actually + // in the binary format + if (ret instanceof Error) + ret = null; + } } } binaryKeyParser.clear(); diff --git a/lib/protocol/utils.js b/lib/protocol/utils.js index 26f4cab6..6ec733d8 100644 --- a/lib/protocol/utils.js +++ b/lib/protocol/utils.js @@ -340,6 +340,18 @@ module.exports = { return signature; }, + getSignatureAlgo: (keyAlgo, keyType) => { + switch (keyType) { + case 'ecdsa-sha2-nistp256-cert-v01@openssh.com': + return 'ecdsa-sha2-nistp256'; + case 'ecdsa-sha2-nistp384-cert-v01@openssh.com': + return 'ecdsa-sha2-nistp384'; + case 'ecdsa-sha2-nistp521-cert-v01@openssh.com': + return 'ecdsa-sha2-nistp521'; + default: + return keyAlgo; + } + }, sendPacket: (proto, packet, bypass) => { if (!bypass && proto._kexinit !== undefined) { // We're currently in the middle of a handshake