/* * Copyright (c) 2014-2015 Sylvain Peyrefitte * * This file is part of node-rdpjs. * * node-rdpjs is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ var spec = require('./spec'); var type = require('../core').type; var error = require('../core').error; var inherits = require('util').inherits; /** * ASN.1 Universal tags * @see http://www.obj-sys.com/asn1tutorial/node124.html */ var UniversalTag = { Boolean : 1, Integer : 2, BitString : 3, OctetString : 4, Null : 5, ObjectIdentifier : 6, ObjectDescriptor : 7, Enumerate : 10, UTF8String : 12, Sequence : 16, Set : 17, PrintableString : 19, T61String : 20, IA5String : 22, UTCTime : 23, GeneralizedTime : 24, UniversalString : 28, BMPString : 30 }; /** * Boolean type * @param value {boolean} inner value */ function Boolean(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Boolean)); this.value = value || false; } inherits(Boolean, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {Boolean} */ Boolean.prototype.decode = function(s, decoder) { this.value = new type.UInt8().read(new type.Stream(decoder.decode(s, this.tag).value)).value !== 0; return this; }; /** * @param decoder {ber.decoder} * @returns {type.*} */ Boolean.prototype.encode = function(encoder) { if(this.value) { return encoder.encode(this.tag, new type.UInt8(0xff)); } else { return encoder.encode(this.tag, new type.UInt8(0)); } }; /** * Integer type * @param value {integer | Buffer} */ function Integer(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Integer)); this.value = value || 0; } inherits(Integer, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {Integer} */ Integer.prototype.decode = function(s, decoder) { var integerBuffer = decoder.decode(s, this.tag).value; if(integerBuffer.length < 5) { var integerStream = new type.Stream(integerBuffer); while (integerStream.availableLength() > 0) { this.value = this.value << 8; this.value |= new type.UInt8().read(integerStream).value; } } // bignum case else { this.value = integerBuffer; } return this; }; /** * @param encoder {ber.decoder} * @returns {type.*} */ Integer.prototype.encode = function(encoder) { if(this.value <= 0xff) { return encoder.encode(this.tag, new type.UInt8(this.value)); } else if(this.value <= 0xffff) { return encoder.encode(this.tag, new type.UInt16Be(this.value)); } else { return encoder.encode(this.tag, new type.UInt32Be(this.value)); } }; /** * Sequence type * @param value {object} */ function Sequence(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Sequence)); this.value = value || []; } inherits(Sequence, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {Sequence} */ Sequence.prototype.decode = function(s, decoder) { var sequenceStream = new type.Stream(decoder.decode(s, this.tag).value); for (var i in this.value) { var rec = sequenceStream.offset; try { this.value[i].decode(sequenceStream, decoder); } catch(e) { if ((e.message === 'NODE_RDP_ASN1_BER_INVALID_TAG') && !this.value[i].opt) { throw new error.ProtocolError('NODE_RDP_ASN1_UNIV_SEQUENCE_FIELD_NOT_PRESENT'); } sequenceStream.offset = rec; } } return this; }; /** * Encode sequence * @param encoder * @returns {type.Component} */ Sequence.prototype.encode = function(encoder) { var sequence = new type.Component([]); for (var i in this.value) { sequence.obj.push(this.value[i].encode(encoder)) } return encoder.encode(this.tag, sequence); }; /** * Enumerate type * @param value {integer} */ function Enumerate(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Enumerate)); this.value = value || 0; } inherits(Enumerate, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {Enumerate} */ Enumerate.prototype.decode = function(s, decoder) { this.value = new type.UInt8().read(new type.Stream(decoder.decode(s, this.tag).value)).value; return this; }; /** * Encode enumerate type * @param encoder * @returns {type.Component} */ Enumerate.prototype.encode = function(encoder) { return encoder.encode(this.tag, new type.UInt8(this.value)); }; /** * OctetString type * @param value {Buffer} */ function OctetString(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.OctetString)); this.value = value || Buffer.alloc(0); } inherits(OctetString, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {OctetString} */ OctetString.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; /** * Encode Octet String * @param encoder * @returns {type.Component} */ OctetString.prototype.encode = function(encoder) { return encoder.encode(this.tag, new type.BinaryString(this.value)); }; /** * ObjectIdentifier type * @param value {Buffer} */ function ObjectIdentifier(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.ObjectIdentifier)); this.value = value || Buffer.alloc(5); } inherits(ObjectIdentifier, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {ObjectIdentifier} */ ObjectIdentifier.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; /** * Null type */ function Null() { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Null)); } inherits(Null, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {Null} */ Null.prototype.decode = function(s, decoder) { decoder.decode(s, this.tag); return this; }; /** * Choice type * @param value {object} list of available type */ function Choice(value) { // not tagged type spec.Asn1Spec.call(this, new spec.Asn1Tag()); this.value = value; } inherits(Choice, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {Choice} */ Choice.prototype.decode = function(s, decoder) { for (var i in this.value) { var rec = s.offset; try { this.value[i].decode(s, decoder); break; } catch(e) { s.offset = rec; } } return this; }; /** * SetOf type * @param factory {function} type builder * @param value {object} list of available type */ function SetOf(factory, value) { // not tagged type spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Set)); this.factory = factory; this.value = value || []; } inherits(SetOf, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {SetOf} */ SetOf.prototype.decode = function(s, decoder) { var setOfStream = new type.Stream(decoder.decode(s, this.tag).value); while (setOfStream.availableLength() > 0) { this.value.push(this.factory().decode(setOfStream, decoder)); } return this; }; /** * SequenceOf type * @param factory {function} type builder * @param value {object} list of available type */ function SequenceOf(factory, value) { // not tagged type spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Sequence)); this.factory = factory; this.value = value || []; } inherits(SequenceOf, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {SequenceOf} */ SequenceOf.prototype.decode = function(s, decoder) { var sequenceOfStream = new type.Stream(decoder.decode(s, this.tag).value); while (sequenceOfStream.availableLength() > 0) { this.value.push(this.factory().decode(sequenceOfStream, decoder)); } return this; }; /** * BitString type * @param value {Buffer} */ function BitString(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.BitString)); this.value = []; } inherits(BitString, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {BitString} */ BitString.prototype.decode = function(s, decoder) { var bitStream = new type.Stream(decoder.decode(s, this.tag).value); var padding = new type.UInt8().read(bitStream).value; var value = []; for(var i = 0; i < padding; i++) { value.push(0); } while(bitStream.availableLength() > 0) { var octet = new type.UInt8().read(bitStream).value; var currentPadding = 0; if(bitStream.availableLength() === 0) { currentPadding = padding; } for(var i = 7; i >= currentPadding; i--) { value.push(((octet >> i) & 1)?1:0); } } this.value = value; return this; }; /** * Convert bit string to buffer object * @returns {Buffer} */ BitString.prototype.toBuffer = function () { var length = this.value.length / 8; var resultStream = new type.Stream(length); for (var i = 0; i < length; i ++) { var currentOctet = 0; for (var j = 0; j < 8; j++) { currentOctet = currentOctet | (this.value[i * 8 + j] << (7 - j)); } new type.UInt8(currentOctet).write(resultStream); } return resultStream.buffer; } /** * T61String type * @param value {Buffer} */ function T61String(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.T61String)); this.value = value; } inherits(T61String, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {T61String} */ T61String.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; /** * PrintableString type * @param value {Buffer} */ function PrintableString(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.PrintableString)); this.value = value; } inherits(PrintableString, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {PrintableString} */ PrintableString.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; /** * UniversalString type * @param value {Buffer} */ function UniversalString(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UniversalString)); this.value = value; } inherits(UniversalString, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {UniversalString} */ UniversalString.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; /** * UTF8String type * @param value {Buffer} */ function UTF8String(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UTF8String)); this.value = value; } inherits(UTF8String, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {UTF8String} */ UTF8String.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; /** * BMPString type * @param value {Buffer} */ function BMPString(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.BMPString)); this.value = value; } inherits(BMPString, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {BMPString} */ BMPString.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; /** * IA5String type * @param value {Buffer} */ function IA5String(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.IA5String)); this.value = value; } inherits(IA5String, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {IA5String} */ IA5String.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; /** * UTCTime type * @param value {Buffer} */ function UTCTime(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UTCTime)); this.value = value; } inherits(UTCTime, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {UTCTime} */ UTCTime.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; /** * GeneralizedTime type * @param value {Buffer} */ function GeneralizedTime(value) { spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.GeneralizedTime)); this.value = value; } inherits(GeneralizedTime, spec.Asn1Spec); /** * @param s {type.Stream} * @param decoder {ber.decoder} * @returns {GeneralizedTime} */ GeneralizedTime.prototype.decode = function(s, decoder) { this.value = decoder.decode(s, this.tag).value; return this; }; module.exports = { Boolean : Boolean, Integer : Integer, Sequence : Sequence, Enumerate : Enumerate, OctetString : OctetString, ObjectIdentifier : ObjectIdentifier, Null : Null, Choice : Choice, SequenceOf : SequenceOf, SetOf : SetOf, BitString : BitString, T61String : T61String, PrintableString : PrintableString, UniversalString : UniversalString, UTF8String : UTF8String, BMPString : BMPString, IA5String : IA5String, UTCTime : UTCTime, GeneralizedTime : GeneralizedTime };