我智商爆棚
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

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);
}
}