Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ecdsa cert support for client through SSH agent #1440

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions lib/protocol/Protocol.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const {
bufferFill,
bufferSlice,
convertSignature,
getSignatureAlgo,
sendPacket,
writeUInt32BE,
} = require('./utils.js');
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
45 changes: 41 additions & 4 deletions lib/protocol/keyParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
let pubPEM = null;
let pubSSH = null;

switch (baseType) {
case '[email protected]':
case '[email protected]':
case '[email protected]':
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':
Expand All @@ -1407,6 +1429,17 @@ function isSupportedKeyType(type) {
}
}

function isSupportedCertType(type) {
switch (type) {
case '[email protected]':
case '[email protected]':
case '[email protected]':
return true;
default:
return false;
}
}

function isParsedKey(val) {
if (!val)
return false;
Expand Down Expand Up @@ -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();
Expand Down
12 changes: 12 additions & 0 deletions lib/protocol/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,18 @@ module.exports = {

return signature;
},
getSignatureAlgo: (keyAlgo, keyType) => {
switch (keyType) {
case '[email protected]':
return 'ecdsa-sha2-nistp256';
case '[email protected]':
return 'ecdsa-sha2-nistp384';
case '[email protected]':
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
Expand Down