utils.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. var Ber = require('asn1').Ber;
  2. var readUInt32BE = require('./buffer-helpers').readUInt32BE;
  3. var writeUInt32BE = require('./buffer-helpers').writeUInt32BE;
  4. // XXX the value of 2400 from dropbear is only for certain strings, not all
  5. // strings. for example the list strings used during handshakes
  6. var MAX_STRING_LEN = Infinity;//2400; // taken from dropbear
  7. module.exports = {
  8. iv_inc: iv_inc,
  9. readInt: readInt,
  10. readString: readString,
  11. parseKey: require('./keyParser').parseKey,
  12. sigSSHToASN1: sigSSHToASN1,
  13. DSASigBERToBare: DSASigBERToBare,
  14. ECDSASigASN1ToSSH: ECDSASigASN1ToSSH
  15. };
  16. function iv_inc(iv) {
  17. var n = 12;
  18. var c = 0;
  19. do {
  20. --n;
  21. c = iv[n];
  22. if (c === 255)
  23. iv[n] = 0;
  24. else {
  25. iv[n] = ++c;
  26. return;
  27. }
  28. } while (n > 4);
  29. }
  30. function readInt(buffer, start, stream, cb) {
  31. var bufferLen = buffer.length;
  32. if (start < 0 || start >= bufferLen || (bufferLen - start) < 4) {
  33. stream && stream._cleanup(cb);
  34. return false;
  35. }
  36. return readUInt32BE(buffer, start);
  37. }
  38. function DSASigBERToBare(signature) {
  39. if (signature.length <= 40)
  40. return signature;
  41. // This is a quick and dirty way to get from BER encoded r and s that
  42. // OpenSSL gives us, to just the bare values back to back (40 bytes
  43. // total) like OpenSSH (and possibly others) are expecting
  44. var asnReader = new Ber.Reader(signature);
  45. asnReader.readSequence();
  46. var r = asnReader.readString(Ber.Integer, true);
  47. var s = asnReader.readString(Ber.Integer, true);
  48. var rOffset = 0;
  49. var sOffset = 0;
  50. if (r.length < 20) {
  51. var rNew = Buffer.allocUnsafe(20);
  52. r.copy(rNew, 1);
  53. r = rNew;
  54. r[0] = 0;
  55. }
  56. if (s.length < 20) {
  57. var sNew = Buffer.allocUnsafe(20);
  58. s.copy(sNew, 1);
  59. s = sNew;
  60. s[0] = 0;
  61. }
  62. if (r.length > 20 && r[0] === 0x00)
  63. rOffset = 1;
  64. if (s.length > 20 && s[0] === 0x00)
  65. sOffset = 1;
  66. var newSig = Buffer.allocUnsafe((r.length - rOffset) + (s.length - sOffset));
  67. r.copy(newSig, 0, rOffset);
  68. s.copy(newSig, r.length - rOffset, sOffset);
  69. return newSig;
  70. }
  71. function ECDSASigASN1ToSSH(signature) {
  72. if (signature[0] === 0x00)
  73. return signature;
  74. // Convert SSH signature parameters to ASN.1 BER values for OpenSSL
  75. var asnReader = new Ber.Reader(signature);
  76. asnReader.readSequence();
  77. var r = asnReader.readString(Ber.Integer, true);
  78. var s = asnReader.readString(Ber.Integer, true);
  79. if (r === null || s === null)
  80. return false;
  81. var newSig = Buffer.allocUnsafe(4 + r.length + 4 + s.length);
  82. writeUInt32BE(newSig, r.length, 0);
  83. r.copy(newSig, 4);
  84. writeUInt32BE(newSig, s.length, 4 + r.length);
  85. s.copy(newSig, 4 + 4 + r.length);
  86. return newSig;
  87. }
  88. function sigSSHToASN1(sig, type, self, callback) {
  89. var asnWriter;
  90. switch (type) {
  91. case 'ssh-dss':
  92. if (sig.length > 40)
  93. return sig;
  94. // Change bare signature r and s values to ASN.1 BER values for OpenSSL
  95. asnWriter = new Ber.Writer();
  96. asnWriter.startSequence();
  97. var r = sig.slice(0, 20);
  98. var s = sig.slice(20);
  99. if (r[0] & 0x80) {
  100. var rNew = Buffer.allocUnsafe(21);
  101. rNew[0] = 0x00;
  102. r.copy(rNew, 1);
  103. r = rNew;
  104. } else if (r[0] === 0x00 && !(r[1] & 0x80)) {
  105. r = r.slice(1);
  106. }
  107. if (s[0] & 0x80) {
  108. var sNew = Buffer.allocUnsafe(21);
  109. sNew[0] = 0x00;
  110. s.copy(sNew, 1);
  111. s = sNew;
  112. } else if (s[0] === 0x00 && !(s[1] & 0x80)) {
  113. s = s.slice(1);
  114. }
  115. asnWriter.writeBuffer(r, Ber.Integer);
  116. asnWriter.writeBuffer(s, Ber.Integer);
  117. asnWriter.endSequence();
  118. return asnWriter.buffer;
  119. case 'ecdsa-sha2-nistp256':
  120. case 'ecdsa-sha2-nistp384':
  121. case 'ecdsa-sha2-nistp521':
  122. var r = readString(sig, 0, self, callback);
  123. if (r === false)
  124. return false;
  125. var s = readString(sig, sig._pos, self, callback);
  126. if (s === false)
  127. return false;
  128. asnWriter = new Ber.Writer();
  129. asnWriter.startSequence();
  130. asnWriter.writeBuffer(r, Ber.Integer);
  131. asnWriter.writeBuffer(s, Ber.Integer);
  132. asnWriter.endSequence();
  133. return asnWriter.buffer;
  134. default:
  135. return sig;
  136. }
  137. }
  138. function readString(buffer, start, encoding, stream, cb, maxLen) {
  139. if (encoding && !Buffer.isBuffer(encoding) && typeof encoding !== 'string') {
  140. if (typeof cb === 'number')
  141. maxLen = cb;
  142. cb = stream;
  143. stream = encoding;
  144. encoding = undefined;
  145. }
  146. start || (start = 0);
  147. var bufferLen = buffer.length;
  148. var left = (bufferLen - start);
  149. var len;
  150. var end;
  151. if (start < 0 || start >= bufferLen || left < 4) {
  152. stream && stream._cleanup(cb);
  153. return false;
  154. }
  155. len = readUInt32BE(buffer, start);
  156. if (len > (maxLen || MAX_STRING_LEN) || left < (4 + len)) {
  157. stream && stream._cleanup(cb);
  158. return false;
  159. }
  160. start += 4;
  161. end = start + len;
  162. buffer._pos = end;
  163. if (encoding) {
  164. if (Buffer.isBuffer(encoding)) {
  165. buffer.copy(encoding, 0, start, end);
  166. return encoding;
  167. } else {
  168. return buffer.toString(encoding, start, end);
  169. }
  170. } else {
  171. return buffer.slice(start, end);
  172. }
  173. }