You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
5.0 KiB
189 lines
5.0 KiB
var Ber = require('asn1').Ber;
|
|
|
|
var readUInt32BE = require('./buffer-helpers').readUInt32BE;
|
|
var writeUInt32BE = require('./buffer-helpers').writeUInt32BE;
|
|
|
|
// XXX the value of 2400 from dropbear is only for certain strings, not all
|
|
// strings. for example the list strings used during handshakes
|
|
var MAX_STRING_LEN = Infinity;//2400; // taken from dropbear
|
|
|
|
module.exports = {
|
|
iv_inc: iv_inc,
|
|
readInt: readInt,
|
|
readString: readString,
|
|
parseKey: require('./keyParser').parseKey,
|
|
sigSSHToASN1: sigSSHToASN1,
|
|
DSASigBERToBare: DSASigBERToBare,
|
|
ECDSASigASN1ToSSH: ECDSASigASN1ToSSH
|
|
};
|
|
|
|
function iv_inc(iv) {
|
|
var n = 12;
|
|
var c = 0;
|
|
do {
|
|
--n;
|
|
c = iv[n];
|
|
if (c === 255)
|
|
iv[n] = 0;
|
|
else {
|
|
iv[n] = ++c;
|
|
return;
|
|
}
|
|
} while (n > 4);
|
|
}
|
|
|
|
function readInt(buffer, start, stream, cb) {
|
|
var bufferLen = buffer.length;
|
|
if (start < 0 || start >= bufferLen || (bufferLen - start) < 4) {
|
|
stream && stream._cleanup(cb);
|
|
return false;
|
|
}
|
|
|
|
return readUInt32BE(buffer, start);
|
|
}
|
|
|
|
function DSASigBERToBare(signature) {
|
|
if (signature.length <= 40)
|
|
return signature;
|
|
// This is a quick and dirty way to get from BER encoded r and s that
|
|
// OpenSSL gives us, to just the bare values back to back (40 bytes
|
|
// total) like OpenSSH (and possibly others) are expecting
|
|
var asnReader = new Ber.Reader(signature);
|
|
asnReader.readSequence();
|
|
var r = asnReader.readString(Ber.Integer, true);
|
|
var s = asnReader.readString(Ber.Integer, true);
|
|
var rOffset = 0;
|
|
var sOffset = 0;
|
|
if (r.length < 20) {
|
|
var rNew = Buffer.allocUnsafe(20);
|
|
r.copy(rNew, 1);
|
|
r = rNew;
|
|
r[0] = 0;
|
|
}
|
|
if (s.length < 20) {
|
|
var sNew = Buffer.allocUnsafe(20);
|
|
s.copy(sNew, 1);
|
|
s = sNew;
|
|
s[0] = 0;
|
|
}
|
|
if (r.length > 20 && r[0] === 0x00)
|
|
rOffset = 1;
|
|
if (s.length > 20 && s[0] === 0x00)
|
|
sOffset = 1;
|
|
var newSig = Buffer.allocUnsafe((r.length - rOffset) + (s.length - sOffset));
|
|
r.copy(newSig, 0, rOffset);
|
|
s.copy(newSig, r.length - rOffset, sOffset);
|
|
return newSig;
|
|
}
|
|
|
|
function ECDSASigASN1ToSSH(signature) {
|
|
if (signature[0] === 0x00)
|
|
return signature;
|
|
// Convert SSH signature parameters to ASN.1 BER values for OpenSSL
|
|
var asnReader = new Ber.Reader(signature);
|
|
asnReader.readSequence();
|
|
var r = asnReader.readString(Ber.Integer, true);
|
|
var s = asnReader.readString(Ber.Integer, true);
|
|
if (r === null || s === null)
|
|
return false;
|
|
var newSig = Buffer.allocUnsafe(4 + r.length + 4 + s.length);
|
|
writeUInt32BE(newSig, r.length, 0);
|
|
r.copy(newSig, 4);
|
|
writeUInt32BE(newSig, s.length, 4 + r.length);
|
|
s.copy(newSig, 4 + 4 + r.length);
|
|
return newSig;
|
|
}
|
|
|
|
function sigSSHToASN1(sig, type, self, callback) {
|
|
var asnWriter;
|
|
switch (type) {
|
|
case 'ssh-dss':
|
|
if (sig.length > 40)
|
|
return sig;
|
|
// Change bare signature r and s values to ASN.1 BER values for OpenSSL
|
|
asnWriter = new Ber.Writer();
|
|
asnWriter.startSequence();
|
|
var r = sig.slice(0, 20);
|
|
var s = sig.slice(20);
|
|
if (r[0] & 0x80) {
|
|
var rNew = Buffer.allocUnsafe(21);
|
|
rNew[0] = 0x00;
|
|
r.copy(rNew, 1);
|
|
r = rNew;
|
|
} else if (r[0] === 0x00 && !(r[1] & 0x80)) {
|
|
r = r.slice(1);
|
|
}
|
|
if (s[0] & 0x80) {
|
|
var sNew = Buffer.allocUnsafe(21);
|
|
sNew[0] = 0x00;
|
|
s.copy(sNew, 1);
|
|
s = sNew;
|
|
} else if (s[0] === 0x00 && !(s[1] & 0x80)) {
|
|
s = s.slice(1);
|
|
}
|
|
asnWriter.writeBuffer(r, Ber.Integer);
|
|
asnWriter.writeBuffer(s, Ber.Integer);
|
|
asnWriter.endSequence();
|
|
return asnWriter.buffer;
|
|
case 'ecdsa-sha2-nistp256':
|
|
case 'ecdsa-sha2-nistp384':
|
|
case 'ecdsa-sha2-nistp521':
|
|
var r = readString(sig, 0, self, callback);
|
|
if (r === false)
|
|
return false;
|
|
var s = readString(sig, sig._pos, self, callback);
|
|
if (s === false)
|
|
return false;
|
|
|
|
asnWriter = new Ber.Writer();
|
|
asnWriter.startSequence();
|
|
asnWriter.writeBuffer(r, Ber.Integer);
|
|
asnWriter.writeBuffer(s, Ber.Integer);
|
|
asnWriter.endSequence();
|
|
return asnWriter.buffer;
|
|
default:
|
|
return sig;
|
|
}
|
|
}
|
|
|
|
function readString(buffer, start, encoding, stream, cb, maxLen) {
|
|
if (encoding && !Buffer.isBuffer(encoding) && typeof encoding !== 'string') {
|
|
if (typeof cb === 'number')
|
|
maxLen = cb;
|
|
cb = stream;
|
|
stream = encoding;
|
|
encoding = undefined;
|
|
}
|
|
|
|
start || (start = 0);
|
|
var bufferLen = buffer.length;
|
|
var left = (bufferLen - start);
|
|
var len;
|
|
var end;
|
|
if (start < 0 || start >= bufferLen || left < 4) {
|
|
stream && stream._cleanup(cb);
|
|
return false;
|
|
}
|
|
|
|
len = readUInt32BE(buffer, start);
|
|
if (len > (maxLen || MAX_STRING_LEN) || left < (4 + len)) {
|
|
stream && stream._cleanup(cb);
|
|
return false;
|
|
}
|
|
|
|
start += 4;
|
|
end = start + len;
|
|
buffer._pos = end;
|
|
|
|
if (encoding) {
|
|
if (Buffer.isBuffer(encoding)) {
|
|
buffer.copy(encoding, 0, start, end);
|
|
return encoding;
|
|
} else {
|
|
return buffer.toString(encoding, start, end);
|
|
}
|
|
} else {
|
|
return buffer.slice(start, end);
|
|
}
|
|
}
|
|
|
|
|