"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/sshpk/node_modules/asn1/lib/ber/writer.js" (7 Feb 2017, 7587 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
    2 
    3 var assert = require('assert');
    4 var ASN1 = require('./types');
    5 var errors = require('./errors');
    6 
    7 
    8 ///--- Globals
    9 
   10 var newInvalidAsn1Error = errors.newInvalidAsn1Error;
   11 
   12 var DEFAULT_OPTS = {
   13   size: 1024,
   14   growthFactor: 8
   15 };
   16 
   17 
   18 ///--- Helpers
   19 
   20 function merge(from, to) {
   21   assert.ok(from);
   22   assert.equal(typeof(from), 'object');
   23   assert.ok(to);
   24   assert.equal(typeof(to), 'object');
   25 
   26   var keys = Object.getOwnPropertyNames(from);
   27   keys.forEach(function(key) {
   28     if (to[key])
   29       return;
   30 
   31     var value = Object.getOwnPropertyDescriptor(from, key);
   32     Object.defineProperty(to, key, value);
   33   });
   34 
   35   return to;
   36 }
   37 
   38 
   39 
   40 ///--- API
   41 
   42 function Writer(options) {
   43   options = merge(DEFAULT_OPTS, options || {});
   44 
   45   this._buf = new Buffer(options.size || 1024);
   46   this._size = this._buf.length;
   47   this._offset = 0;
   48   this._options = options;
   49 
   50   // A list of offsets in the buffer where we need to insert
   51   // sequence tag/len pairs.
   52   this._seq = [];
   53 }
   54 
   55 Object.defineProperty(Writer.prototype, 'buffer', {
   56   get: function () {
   57     if (this._seq.length)
   58       throw new InvalidAsn1Error(this._seq.length + ' unended sequence(s)');
   59 
   60     return (this._buf.slice(0, this._offset));
   61   }
   62 });
   63 
   64 Writer.prototype.writeByte = function(b) {
   65   if (typeof(b) !== 'number')
   66     throw new TypeError('argument must be a Number');
   67 
   68   this._ensure(1);
   69   this._buf[this._offset++] = b;
   70 };
   71 
   72 
   73 Writer.prototype.writeInt = function(i, tag) {
   74   if (typeof(i) !== 'number')
   75     throw new TypeError('argument must be a Number');
   76   if (typeof(tag) !== 'number')
   77     tag = ASN1.Integer;
   78 
   79   var sz = 4;
   80 
   81   while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) &&
   82          (sz > 1)) {
   83     sz--;
   84     i <<= 8;
   85   }
   86 
   87   if (sz > 4)
   88     throw new InvalidAsn1Error('BER ints cannot be > 0xffffffff');
   89 
   90   this._ensure(2 + sz);
   91   this._buf[this._offset++] = tag;
   92   this._buf[this._offset++] = sz;
   93 
   94   while (sz-- > 0) {
   95     this._buf[this._offset++] = ((i & 0xff000000) >>> 24);
   96     i <<= 8;
   97   }
   98 
   99 };
  100 
  101 
  102 Writer.prototype.writeNull = function() {
  103   this.writeByte(ASN1.Null);
  104   this.writeByte(0x00);
  105 };
  106 
  107 
  108 Writer.prototype.writeEnumeration = function(i, tag) {
  109   if (typeof(i) !== 'number')
  110     throw new TypeError('argument must be a Number');
  111   if (typeof(tag) !== 'number')
  112     tag = ASN1.Enumeration;
  113 
  114   return this.writeInt(i, tag);
  115 };
  116 
  117 
  118 Writer.prototype.writeBoolean = function(b, tag) {
  119   if (typeof(b) !== 'boolean')
  120     throw new TypeError('argument must be a Boolean');
  121   if (typeof(tag) !== 'number')
  122     tag = ASN1.Boolean;
  123 
  124   this._ensure(3);
  125   this._buf[this._offset++] = tag;
  126   this._buf[this._offset++] = 0x01;
  127   this._buf[this._offset++] = b ? 0xff : 0x00;
  128 };
  129 
  130 
  131 Writer.prototype.writeString = function(s, tag) {
  132   if (typeof(s) !== 'string')
  133     throw new TypeError('argument must be a string (was: ' + typeof(s) + ')');
  134   if (typeof(tag) !== 'number')
  135     tag = ASN1.OctetString;
  136 
  137   var len = Buffer.byteLength(s);
  138   this.writeByte(tag);
  139   this.writeLength(len);
  140   if (len) {
  141     this._ensure(len);
  142     this._buf.write(s, this._offset);
  143     this._offset += len;
  144   }
  145 };
  146 
  147 
  148 Writer.prototype.writeBuffer = function(buf, tag) {
  149   if (typeof(tag) !== 'number')
  150     throw new TypeError('tag must be a number');
  151   if (!Buffer.isBuffer(buf))
  152     throw new TypeError('argument must be a buffer');
  153 
  154   this.writeByte(tag);
  155   this.writeLength(buf.length);
  156   this._ensure(buf.length);
  157   buf.copy(this._buf, this._offset, 0, buf.length);
  158   this._offset += buf.length;
  159 };
  160 
  161 
  162 Writer.prototype.writeStringArray = function(strings) {
  163   if ((!strings instanceof Array))
  164     throw new TypeError('argument must be an Array[String]');
  165 
  166   var self = this;
  167   strings.forEach(function(s) {
  168     self.writeString(s);
  169   });
  170 };
  171 
  172 // This is really to solve DER cases, but whatever for now
  173 Writer.prototype.writeOID = function(s, tag) {
  174   if (typeof(s) !== 'string')
  175     throw new TypeError('argument must be a string');
  176   if (typeof(tag) !== 'number')
  177     tag = ASN1.OID;
  178 
  179   if (!/^([0-9]+\.){3,}[0-9]+$/.test(s))
  180     throw new Error('argument is not a valid OID string');
  181 
  182   function encodeOctet(bytes, octet) {
  183     if (octet < 128) {
  184         bytes.push(octet);
  185     } else if (octet < 16384) {
  186         bytes.push((octet >>> 7) | 0x80);
  187         bytes.push(octet & 0x7F);
  188     } else if (octet < 2097152) {
  189       bytes.push((octet >>> 14) | 0x80);
  190       bytes.push(((octet >>> 7) | 0x80) & 0xFF);
  191       bytes.push(octet & 0x7F);
  192     } else if (octet < 268435456) {
  193       bytes.push((octet >>> 21) | 0x80);
  194       bytes.push(((octet >>> 14) | 0x80) & 0xFF);
  195       bytes.push(((octet >>> 7) | 0x80) & 0xFF);
  196       bytes.push(octet & 0x7F);
  197     } else {
  198       bytes.push(((octet >>> 28) | 0x80) & 0xFF);
  199       bytes.push(((octet >>> 21) | 0x80) & 0xFF);
  200       bytes.push(((octet >>> 14) | 0x80) & 0xFF);
  201       bytes.push(((octet >>> 7) | 0x80) & 0xFF);
  202       bytes.push(octet & 0x7F);
  203     }
  204   }
  205 
  206   var tmp = s.split('.');
  207   var bytes = [];
  208   bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10));
  209   tmp.slice(2).forEach(function(b) {
  210     encodeOctet(bytes, parseInt(b, 10));
  211   });
  212 
  213   var self = this;
  214   this._ensure(2 + bytes.length);
  215   this.writeByte(tag);
  216   this.writeLength(bytes.length);
  217   bytes.forEach(function(b) {
  218     self.writeByte(b);
  219   });
  220 };
  221 
  222 
  223 Writer.prototype.writeLength = function(len) {
  224   if (typeof(len) !== 'number')
  225     throw new TypeError('argument must be a Number');
  226 
  227   this._ensure(4);
  228 
  229   if (len <= 0x7f) {
  230     this._buf[this._offset++] = len;
  231   } else if (len <= 0xff) {
  232     this._buf[this._offset++] = 0x81;
  233     this._buf[this._offset++] = len;
  234   } else if (len <= 0xffff) {
  235     this._buf[this._offset++] = 0x82;
  236     this._buf[this._offset++] = len >> 8;
  237     this._buf[this._offset++] = len;
  238   } else if (len <= 0xffffff) {
  239     this._buf[this._offset++] = 0x83;
  240     this._buf[this._offset++] = len >> 16;
  241     this._buf[this._offset++] = len >> 8;
  242     this._buf[this._offset++] = len;
  243   } else {
  244     throw new InvalidAsn1ERror('Length too long (> 4 bytes)');
  245   }
  246 };
  247 
  248 Writer.prototype.startSequence = function(tag) {
  249   if (typeof(tag) !== 'number')
  250     tag = ASN1.Sequence | ASN1.Constructor;
  251 
  252   this.writeByte(tag);
  253   this._seq.push(this._offset);
  254   this._ensure(3);
  255   this._offset += 3;
  256 };
  257 
  258 
  259 Writer.prototype.endSequence = function() {
  260   var seq = this._seq.pop();
  261   var start = seq + 3;
  262   var len = this._offset - start;
  263 
  264   if (len <= 0x7f) {
  265     this._shift(start, len, -2);
  266     this._buf[seq] = len;
  267   } else if (len <= 0xff) {
  268     this._shift(start, len, -1);
  269     this._buf[seq] = 0x81;
  270     this._buf[seq + 1] = len;
  271   } else if (len <= 0xffff) {
  272     this._buf[seq] = 0x82;
  273     this._buf[seq + 1] = len >> 8;
  274     this._buf[seq + 2] = len;
  275   } else if (len <= 0xffffff) {
  276     this._shift(start, len, 1);
  277     this._buf[seq] = 0x83;
  278     this._buf[seq + 1] = len >> 16;
  279     this._buf[seq + 2] = len >> 8;
  280     this._buf[seq + 3] = len;
  281   } else {
  282     throw new InvalidAsn1Error('Sequence too long');
  283   }
  284 };
  285 
  286 
  287 Writer.prototype._shift = function(start, len, shift) {
  288   assert.ok(start !== undefined);
  289   assert.ok(len !== undefined);
  290   assert.ok(shift);
  291 
  292   this._buf.copy(this._buf, start + shift, start, start + len);
  293   this._offset += shift;
  294 };
  295 
  296 Writer.prototype._ensure = function(len) {
  297   assert.ok(len);
  298 
  299   if (this._size - this._offset < len) {
  300     var sz = this._size * this._options.growthFactor;
  301     if (sz - this._offset < len)
  302       sz += len;
  303 
  304     var buf = new Buffer(sz);
  305 
  306     this._buf.copy(buf, 0, 0, this._offset);
  307     this._buf = buf;
  308     this._size = sz;
  309   }
  310 };
  311 
  312 
  313 
  314 ///--- Exported API
  315 
  316 module.exports = Writer;