"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/asn1/lib/ber/reader.js" (8 Mar 2017, 5589 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 
    5 var ASN1 = require('./types');
    6 var errors = require('./errors');
    7 
    8 
    9 ///--- Globals
   10 
   11 var newInvalidAsn1Error = errors.newInvalidAsn1Error;
   12 
   13 
   14 
   15 ///--- API
   16 
   17 function Reader(data) {
   18   if (!data || !Buffer.isBuffer(data))
   19     throw new TypeError('data must be a node Buffer');
   20 
   21   this._buf = data;
   22   this._size = data.length;
   23 
   24   // These hold the "current" state
   25   this._len = 0;
   26   this._offset = 0;
   27 }
   28 
   29 Object.defineProperty(Reader.prototype, 'length', {
   30   enumerable: true,
   31   get: function () { return (this._len); }
   32 });
   33 
   34 Object.defineProperty(Reader.prototype, 'offset', {
   35   enumerable: true,
   36   get: function () { return (this._offset); }
   37 });
   38 
   39 Object.defineProperty(Reader.prototype, 'remain', {
   40   get: function () { return (this._size - this._offset); }
   41 });
   42 
   43 Object.defineProperty(Reader.prototype, 'buffer', {
   44   get: function () { return (this._buf.slice(this._offset)); }
   45 });
   46 
   47 
   48 /**
   49  * Reads a single byte and advances offset; you can pass in `true` to make this
   50  * a "peek" operation (i.e., get the byte, but don't advance the offset).
   51  *
   52  * @param {Boolean} peek true means don't move offset.
   53  * @return {Number} the next byte, null if not enough data.
   54  */
   55 Reader.prototype.readByte = function(peek) {
   56   if (this._size - this._offset < 1)
   57     return null;
   58 
   59   var b = this._buf[this._offset] & 0xff;
   60 
   61   if (!peek)
   62     this._offset += 1;
   63 
   64   return b;
   65 };
   66 
   67 
   68 Reader.prototype.peek = function() {
   69   return this.readByte(true);
   70 };
   71 
   72 
   73 /**
   74  * Reads a (potentially) variable length off the BER buffer.  This call is
   75  * not really meant to be called directly, as callers have to manipulate
   76  * the internal buffer afterwards.
   77  *
   78  * As a result of this call, you can call `Reader.length`, until the
   79  * next thing called that does a readLength.
   80  *
   81  * @return {Number} the amount of offset to advance the buffer.
   82  * @throws {InvalidAsn1Error} on bad ASN.1
   83  */
   84 Reader.prototype.readLength = function(offset) {
   85   if (offset === undefined)
   86     offset = this._offset;
   87 
   88   if (offset >= this._size)
   89     return null;
   90 
   91   var lenB = this._buf[offset++] & 0xff;
   92   if (lenB === null)
   93     return null;
   94 
   95   if ((lenB & 0x80) == 0x80) {
   96     lenB &= 0x7f;
   97 
   98     if (lenB == 0)
   99       throw newInvalidAsn1Error('Indefinite length not supported');
  100 
  101     if (lenB > 4)
  102       throw newInvalidAsn1Error('encoding too long');
  103 
  104     if (this._size - offset < lenB)
  105       return null;
  106 
  107     this._len = 0;
  108     for (var i = 0; i < lenB; i++)
  109       this._len = (this._len << 8) + (this._buf[offset++] & 0xff);
  110 
  111   } else {
  112     // Wasn't a variable length
  113     this._len = lenB;
  114   }
  115 
  116   return offset;
  117 };
  118 
  119 
  120 /**
  121  * Parses the next sequence in this BER buffer.
  122  *
  123  * To get the length of the sequence, call `Reader.length`.
  124  *
  125  * @return {Number} the sequence's tag.
  126  */
  127 Reader.prototype.readSequence = function(tag) {
  128   var seq = this.peek();
  129   if (seq === null)
  130     return null;
  131   if (tag !== undefined && tag !== seq)
  132     throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
  133                               ': got 0x' + seq.toString(16));
  134 
  135   var o = this.readLength(this._offset + 1); // stored in `length`
  136   if (o === null)
  137     return null;
  138 
  139   this._offset = o;
  140   return seq;
  141 };
  142 
  143 
  144 Reader.prototype.readInt = function() {
  145   return this._readTag(ASN1.Integer);
  146 };
  147 
  148 
  149 Reader.prototype.readBoolean = function() {
  150   return (this._readTag(ASN1.Boolean) === 0 ? false : true);
  151 };
  152 
  153 
  154 Reader.prototype.readEnumeration = function() {
  155   return this._readTag(ASN1.Enumeration);
  156 };
  157 
  158 
  159 Reader.prototype.readString = function(tag, retbuf) {
  160   if (!tag)
  161     tag = ASN1.OctetString;
  162 
  163   var b = this.peek();
  164   if (b === null)
  165     return null;
  166 
  167   if (b !== tag)
  168     throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
  169                               ': got 0x' + b.toString(16));
  170 
  171   var o = this.readLength(this._offset + 1); // stored in `length`
  172 
  173   if (o === null)
  174     return null;
  175 
  176   if (this.length > this._size - o)
  177     return null;
  178 
  179   this._offset = o;
  180 
  181   if (this.length === 0)
  182     return retbuf ? new Buffer(0) : '';
  183 
  184   var str = this._buf.slice(this._offset, this._offset + this.length);
  185   this._offset += this.length;
  186 
  187   return retbuf ? str : str.toString('utf8');
  188 };
  189 
  190 Reader.prototype.readOID = function(tag) {
  191   if (!tag)
  192     tag = ASN1.OID;
  193 
  194   var b = this.readString(tag, true);
  195   if (b === null)
  196     return null;
  197 
  198   var values = [];
  199   var value = 0;
  200 
  201   for (var i = 0; i < b.length; i++) {
  202     var byte = b[i] & 0xff;
  203 
  204     value <<= 7;
  205     value += byte & 0x7f;
  206     if ((byte & 0x80) == 0) {
  207       values.push(value);
  208       value = 0;
  209     }
  210   }
  211 
  212   value = values.shift();
  213   values.unshift(value % 40);
  214   values.unshift((value / 40) >> 0);
  215 
  216   return values.join('.');
  217 };
  218 
  219 
  220 Reader.prototype._readTag = function(tag) {
  221   assert.ok(tag !== undefined);
  222 
  223   var b = this.peek();
  224 
  225   if (b === null)
  226     return null;
  227 
  228   if (b !== tag)
  229     throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
  230                               ': got 0x' + b.toString(16));
  231 
  232   var o = this.readLength(this._offset + 1); // stored in `length`
  233   if (o === null)
  234     return null;
  235 
  236   if (this.length > 4)
  237     throw newInvalidAsn1Error('Integer too long: ' + this.length);
  238 
  239   if (this.length > this._size - o)
  240     return null;
  241   this._offset = o;
  242 
  243   var fb = this._buf[this._offset];
  244   var value = 0;
  245 
  246   for (var i = 0; i < this.length; i++) {
  247     value <<= 8;
  248     value |= (this._buf[this._offset++] & 0xff);
  249   }
  250 
  251   if ((fb & 0x80) == 0x80 && i !== 4)
  252     value -= (1 << (i * 8));
  253 
  254   return value >> 0;
  255 };
  256 
  257 
  258 
  259 ///--- Exported API
  260 
  261 module.exports = Reader;