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