Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 127 additions & 36 deletions lib/ber/reader.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.

var assert = require('assert');
var Buffer = require('safer-buffer').Buffer;

var ASN1 = require('./types');
var errors = require('./errors');
Expand All @@ -10,8 +11,6 @@ var errors = require('./errors');

var newInvalidAsn1Error = errors.newInvalidAsn1Error;



///--- API

function Reader(data) {
Expand All @@ -20,7 +19,8 @@ function Reader(data) {

this._buf = data;
this._size = data.length;

this._blocklevel = 0;
this._blockInfo = {};
// These hold the "current" state
this._len = 0;
this._offset = 0;
Expand Down Expand Up @@ -54,7 +54,8 @@ Object.defineProperty(Reader.prototype, 'buffer', {
*/
Reader.prototype.readByte = function(peek) {
if (this._size - this._offset < 1)
return null;
return null;


var b = this._buf[this._offset] & 0xff;

Expand All @@ -65,6 +66,59 @@ Reader.prototype.readByte = function(peek) {
};


Reader.prototype.readBlock = function(offset)
{
if (offset === undefined) {
offset = this._offset;
}
var currOffset = offset;
var b, lenB;

if (this._blockInfo[offset] !== undefined) {
return this._blockInfo[offset];
}

while(this.remain > 0) {
b = this._buf[currOffset++];
lenB = this._buf[currOffset++];

if ((b == 0) && (lenB == 0)) {
break; // end of block
}
var len = 0;
if ((lenB & 0x80) == 0x80) {
lenB &= 0x7f;

if (lenB == 0) {
this._blocklevel++;
lenB = this.readBlock(currOffset);
this._blocklevel--;
}
else {
if (lenB > 4)
throw InvalidAsn1Error('encoding too long');

if (this._size - this.offset < lenB) {
return null;
}

for (var i = 0; i < lenB; i++) {
len = (len << 8) + (this._buf[currOffset++] & 0xff);
}
lenB = len;
}
}
currOffset += lenB;
if (currOffset > this._size) {
throw new Error("invalid block at offset " + offset);
}
}
lenB = currOffset - offset;
this._blockInfo[offset] = lenB;

return lenB;
}

Reader.prototype.peek = function() {
return this.readByte(true);
};
Expand All @@ -81,36 +135,38 @@ Reader.prototype.peek = function() {
* @return {Number} the amount of offset to advance the buffer.
* @throws {InvalidAsn1Error} on bad ASN.1
*/
Reader.prototype.readLength = function(offset) {
Reader.prototype.readLength = function (offset) {
if (offset === undefined)
offset = this._offset;

if (offset >= this._size)
return null;
return null;

var lenB = this._buf[offset++] & 0xff;
if (lenB === null)
return null;
return null;


if ((lenB & 0x80) == 0x80) {
if ((lenB & 0x80) === 0x80) {
lenB &= 0x7f;

if (lenB == 0)
throw newInvalidAsn1Error('Indefinite length not supported');

if (lenB > 4)
throw newInvalidAsn1Error('encoding too long');

if (this._size - offset < lenB)
return null;
if (lenB === 0) {
this._len = this.readBlock(offset);
}
else {
if (lenB > 4)
throw newInvalidAsn1Error('encoding too long');

this._len = 0;
for (var i = 0; i < lenB; i++)
this._len = (this._len << 8) + (this._buf[offset++] & 0xff);
if (this._size - offset < lenB)
return null;

this._len = 0;
for (var i = 0; i < lenB; i++)
this._len = (this._len << 8) + (this._buf[offset++] & 0xff);
}
} else {
// Wasn't a variable length
this._len = lenB;
// Wasn't a variable length
this._len = lenB;
}

return offset;
Expand All @@ -124,7 +180,7 @@ Reader.prototype.readLength = function(offset) {
*
* @return {Number} the sequence's tag.
*/
Reader.prototype.readSequence = function(tag) {
Reader.prototype.readSequence = function (tag) {
var seq = this.peek();
if (seq === null)
return null;
Expand All @@ -141,28 +197,29 @@ Reader.prototype.readSequence = function(tag) {
};


Reader.prototype.readInt = function() {
Reader.prototype.readInt = function () {
return this._readTag(ASN1.Integer);
};


Reader.prototype.readBoolean = function() {
Reader.prototype.readBoolean = function () {
return (this._readTag(ASN1.Boolean) === 0 ? false : true);
};


Reader.prototype.readEnumeration = function() {
Reader.prototype.readEnumeration = function () {
return this._readTag(ASN1.Enumeration);
};


Reader.prototype.readString = function(tag, retbuf) {

Reader.prototype.readString = function (tag, retbuf) {
if (!tag)
tag = ASN1.OctetString;

var b = this.peek();
if (b === null)
return null;
if (b === null)
return null;

if (b !== tag)
throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
Expand All @@ -176,18 +233,52 @@ Reader.prototype.readString = function(tag, retbuf) {
if (this.length > this._size - o)
return null;


var length = this.length;
if (this._blockInfo[this._offset + 2] !== undefined) {
length = length - 2;
}

this._offset = o;

if (length === 0)
return retbuf ? Buffer.alloc(0) : '';

if (this.length === 0)
return retbuf ? new Buffer(0) : '';


var str = this._buf.slice(this._offset, this._offset + this.length);
var str = this._buf.slice(this._offset, this._offset + length);
this._offset += this.length;

return retbuf ? str : str.toString('utf8');
};

Reader.prototype.readOID = function(tag) {
Reader.prototype.readRelativeOID = function(tag) {
if (!tag)
tag = ASN1.RelativeOID;

var b = this.readString(tag, true);
if (b === null)
return null;

var values = [];
var value = 0;

for (var i = 0; i < b.length; i++) {
var byte = b[i] & 0xff;

value += byte & 0x7F;
if ((byte & 0x80) == 0x80) {
value <<= 7;
continue;
}
values.push(value);
value = 0;
}

return values.join('.');
};

Reader.prototype.readOID = function (tag) {
if (!tag)
tag = ASN1.OID;

Expand All @@ -203,7 +294,7 @@ Reader.prototype.readOID = function(tag) {

value <<= 7;
value += byte & 0x7f;
if ((byte & 0x80) == 0) {
if ((byte & 0x80) === 0) {
values.push(value);
value = 0;
}
Expand All @@ -217,7 +308,7 @@ Reader.prototype.readOID = function(tag) {
};


Reader.prototype._readTag = function(tag) {
Reader.prototype._readTag = function (tag) {
assert.ok(tag !== undefined);

var b = this.peek();
Expand All @@ -233,7 +324,7 @@ Reader.prototype._readTag = function(tag) {
if (o === null)
return null;

if (this.length > 4)
if (this.length > 8)
throw newInvalidAsn1Error('Integer too long: ' + this.length);

if (this.length > this._size - o)
Expand All @@ -248,7 +339,7 @@ Reader.prototype._readTag = function(tag) {
value |= (this._buf[this._offset++] & 0xff);
}

if ((fb & 0x80) == 0x80 && i !== 4)
if ((fb & 0x80) === 0x80 && i !== 4)
value -= (1 << (i * 8));

return value >> 0;
Expand Down
Loading