From 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:47:29 +0200 Subject: Adding upstream version 115.8.0esr. Signed-off-by: Daniel Baumann --- dom/webauthn/tests/pkijs/asn1.js | 5466 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 5466 insertions(+) create mode 100644 dom/webauthn/tests/pkijs/asn1.js (limited to 'dom/webauthn/tests/pkijs/asn1.js') diff --git a/dom/webauthn/tests/pkijs/asn1.js b/dom/webauthn/tests/pkijs/asn1.js new file mode 100644 index 0000000000..ddee052407 --- /dev/null +++ b/dom/webauthn/tests/pkijs/asn1.js @@ -0,0 +1,5466 @@ +/* + * Copyright (c) 2014, GMO GlobalSign + * Copyright (c) 2015, Peculiar Ventures + * All rights reserved. + * + * Author 2014-2015, Yury Strozhevsky . + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ +( +function(in_window) +{ + //************************************************************************************** + // #region Declaration of global variables + //************************************************************************************** + // #region "org" namespace + if(typeof in_window.org === "undefined") + in_window.org = {}; + else + { + if(typeof in_window.org !== "object") + throw new Error("Name org already exists and it's not an object"); + } + // #endregion + + // #region "org.pkijs" namespace + if(typeof in_window.org.pkijs === "undefined") + in_window.org.pkijs = {}; + else + { + if(typeof in_window.org.pkijs !== "object") + throw new Error("Name org.pkijs already exists and it's not an object" + " but " + (typeof in_window.org.pkijs)); + } + // #endregion + + // #region "org.pkijs.asn1" namespace + if(typeof in_window.org.pkijs.asn1 === "undefined") + in_window.org.pkijs.asn1 = {}; + else + { + if(typeof in_window.org.pkijs.asn1 !== "object") + throw new Error("Name org.pkijs.asn1 already exists and it's not an object" + " but " + (typeof in_window.org.pkijs.asn1)); + } + // #endregion + + // #region "local" namespace + var local = {}; + // #endregion + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Aux-functions + //************************************************************************************** + function util_frombase(input_buffer, input_base) + { + /// Convert number from 2^base to 2^10 + /// Array of bytes representing the number to convert + /// The base of initial number + + var result = 0; + + for(var i = (input_buffer.length - 1); i >= 0; i-- ) + result += input_buffer[(input_buffer.length - 1) - i] * Math.pow(2, input_base * i); + + return result; + } + //************************************************************************************** + function util_tobase(value, base, reserved) + { + /// Convert number from 2^10 to 2^base + /// The number to convert + /// The base for 2^base + /// Pre-defined number of bytes in output array (-1 = limited by function itself) + + reserved = reserved || (-1); + + var result = 0; + var biggest = Math.pow(2, base); + + for(var i = 1; i < 8; i++) + { + if(value < biggest) + { + var ret_buf; + + if( reserved < 0 ) + { + ret_buf = new ArrayBuffer(i); + result = i; + } + else + { + if(reserved < i) + return (new ArrayBuffer(0)); + + ret_buf = new ArrayBuffer(reserved); + + result = reserved; + } + + var ret_view = new Uint8Array(ret_buf); + + for(var j = ( i - 1 ); j >= 0; j-- ) + { + var basis = Math.pow(2, j * base); + + ret_view[ result - j - 1 ] = Math.floor( value / basis ); + value -= ( ret_view[ result - j - 1 ] ) * basis; + } + + return ret_buf; + } + + biggest *= Math.pow(2, base); + } + } + //************************************************************************************** + function util_encode_tc(value) + { + /// Encode integer value to "two complement" format + /// Value to encode + + var mod_value = (value < 0) ? (value * (-1)) : value; + var big_int = 128; + + for(var i = 1; i < 8; i++) + { + if( mod_value <= big_int ) + { + if( value < 0 ) + { + var small_int = big_int - mod_value; + + var ret_buf = util_tobase( small_int, 8, i ); + var ret_view = new Uint8Array(ret_buf); + + ret_view[ 0 ] |= 0x80; + + return ret_buf; + } + else + { + var ret_buf = util_tobase( mod_value, 8, i ); + var ret_view = new Uint8Array(ret_buf); + + if( ret_view[ 0 ] & 0x80 ) + { + var temp_buf = util_copybuf(ret_buf); + var temp_view = new Uint8Array(temp_buf); + + ret_buf = new ArrayBuffer( ret_buf.byteLength + 1 ); + ret_view = new Uint8Array(ret_buf); + + for(var k = 0; k < temp_buf.byteLength; k++) + ret_view[k + 1] = temp_view[k]; + + ret_view[0] = 0x00; + } + + return ret_buf; + } + } + + big_int *= Math.pow(2, 8); + } + + return (new ArrayBuffer(0)); + } + //************************************************************************************** + function util_decode_tc() + { + /// Decoding of "two complement" values + /// The function must be called in scope of instance of "hex_block" class ("value_hex" and "warnings" properties must be present) + + var buf = new Uint8Array(this.value_hex); + + if(this.value_hex.byteLength >= 2) + { + var condition_1 = (buf[0] == 0xFF) && (buf[1] & 0x80); + var condition_2 = (buf[0] == 0x00) && ((buf[1] & 0x80) == 0x00); + + if(condition_1 || condition_2) + this.warnings.push("Needlessly long format"); + } + + // #region Create big part of the integer + var big_int_buffer = new ArrayBuffer(this.value_hex.byteLength); + var big_int_view = new Uint8Array(big_int_buffer); + for(var i = 0; i < this.value_hex.byteLength; i++) + big_int_view[i] = 0; + + big_int_view[0] = (buf[0] & 0x80); // mask only the biggest bit + + var big_int = util_frombase(big_int_view, 8); + // #endregion + + // #region Create small part of the integer + var small_int_buffer = new ArrayBuffer(this.value_hex.byteLength); + var small_int_view = new Uint8Array(small_int_buffer); + for(var j = 0; j < this.value_hex.byteLength; j++) + small_int_view[j] = buf[j]; + + small_int_view[0] &= 0x7F; // mask biggest bit + + var small_int = util_frombase(small_int_view, 8); + // #endregion + + return (small_int - big_int); + } + //************************************************************************************** + function util_copybuf(input_buffer) + { + /// Creating a copy of input ArrayBuffer + /// ArrayBuffer for coping + + if(check_buffer_params(input_buffer, 0, input_buffer.byteLength) === false) + return (new ArrayBuffer(0)); + + var input_view = new Uint8Array(input_buffer); + + var ret_buf = new ArrayBuffer(input_buffer.byteLength); + var ret_view = new Uint8Array(ret_buf); + + for(var i = 0; i < input_buffer.byteLength; i++) + ret_view[i] = input_view[i]; + + return ret_buf; + } + //************************************************************************************** + function util_copybuf_offset(input_buffer, input_offset, input_length) + { + /// Creating a copy of input ArrayBuffer + /// ArrayBuffer for coping + + if(check_buffer_params(input_buffer, input_offset, input_length) === false) + return (new ArrayBuffer(0)); + + var input_view = new Uint8Array(input_buffer, input_offset, input_length); + + var ret_buf = new ArrayBuffer(input_length); + var ret_view = new Uint8Array(ret_buf); + + for(var i = 0; i < input_length; i++) + ret_view[i] = input_view[i]; + + return ret_buf; + } + //************************************************************************************** + function util_concatbuf(input_buf1, input_buf2) + { + /// Concatenate two ArrayBuffers + /// First ArrayBuffer (first part of concatenated array) + /// Second ArrayBuffer (second part of concatenated array) + + var input_view1 = new Uint8Array(input_buf1); + var input_view2 = new Uint8Array(input_buf2); + + var ret_buf = new ArrayBuffer(input_buf1.byteLength + input_buf2.byteLength); + var ret_view = new Uint8Array(ret_buf); + + for(var i = 0; i < input_buf1.byteLength; i++) + ret_view[i] = input_view1[i]; + + for(var j = 0; j < input_buf2.byteLength; j++) + ret_view[input_buf1.byteLength + j] = input_view2[j]; + + return ret_buf; + } + //************************************************************************************** + function check_buffer_params(input_buffer, input_offset, input_length) + { + if((input_buffer instanceof ArrayBuffer) === false) + { + this.error = "Wrong parameter: input_buffer must be \"ArrayBuffer\""; + return false; + } + + if(input_buffer.byteLength === 0) + { + this.error = "Wrong parameter: input_buffer has zero length"; + return false; + } + + if(input_offset < 0) + { + this.error = "Wrong parameter: input_offset less than zero"; + return false; + } + + if(input_length < 0) + { + this.error = "Wrong parameter: input_length less than zero"; + return false; + } + + if((input_buffer.byteLength - input_offset - input_length) < 0) + { + this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + return false; + } + + return true; + } + //************************************************************************************** + function to_hex_codes(input_buffer, input_offset, input_lenght) + { + if(check_buffer_params(input_buffer, input_offset, input_lenght) === false) + return ""; + + var result = ""; + + var int_buffer = new Uint8Array(input_buffer, input_offset, input_lenght); + + for(var i = 0; i < int_buffer.length; i++) + { + var str = int_buffer[i].toString(16).toUpperCase(); + result = result + ((str.length === 1) ? " 0" : " ") + str; + } + + return result; + } + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of base block class + //************************************************************************************** + local.base_block = + function() + { + /// General class of all ASN.1 blocks + + if(arguments[0] instanceof Object) + { + this.block_length = in_window.org.pkijs.getValue(arguments[0], "block_length", 0); + this.error = in_window.org.pkijs.getValue(arguments[0], "error", new String()); + this.warnings = in_window.org.pkijs.getValue(arguments[0], "warnings", new Array()); + if("value_before_decode" in arguments[0]) + this.value_before_decode = util_copybuf(arguments[0].value_before_decode); + else + this.value_before_decode = new ArrayBuffer(0); + } + else + { + this.block_length = 0; + this.error = new String(); + this.warnings = new Array(); + /// Copy of the value of incoming ArrayBuffer done before decoding + this.value_before_decode = new ArrayBuffer(0); + } + }; + //************************************************************************************** + local.base_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "base_block"; + }; + //************************************************************************************** + local.base_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + return { + block_name: local.base_block.prototype.block_name.call(this), + block_length: this.block_length, + error: this.error, + warnings: this.warnings, + value_before_decode: in_window.org.pkijs.bufferToHexCodes(this.value_before_decode, 0, this.value_before_decode.byteLength) + }; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of hex block class + //************************************************************************************** + local.hex_block = + function() + { + /// Descendant of "base_block" with internal ArrayBuffer. Need to have it in case it is not possible to store ASN.1 value in native formats + + local.base_block.call(this, arguments[0]); + + if(arguments[0] instanceof Object) + { + this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false); + if("value_hex" in arguments[0]) + this.value_hex = util_copybuf(arguments[0].value_hex); + else + this.value_hex = new ArrayBuffer(0); + } + else + { + this.is_hex_only = false; + this.value_hex = new ArrayBuffer(0); + } + }; + //************************************************************************************** + local.hex_block.prototype = new local.base_block(); + local.hex_block.constructor = local.hex_block; + //************************************************************************************** + local.hex_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "hex_block"; + }; + //************************************************************************************** + local.hex_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + // #region Basic check for parameters + if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false) + return (-1); + // #endregion + + // #region Getting Uint8Array from ArrayBuffer + var int_buffer = new Uint8Array(input_buffer, input_offset, input_length); + // #endregion + + // #region Initial checks + if(int_buffer.length == 0) + { + this.warnings.push("Zero buffer length"); + return input_offset; + } + // #endregion + + // #region Copy input buffer to internal buffer + this.value_hex = new ArrayBuffer(input_length); + var view = new Uint8Array(this.value_hex); + + for(var i = 0; i < int_buffer.length; i++) + view[i] = int_buffer[i]; + // #endregion + + this.block_length = input_length; + + return (input_offset + input_length); + }; + //************************************************************************************** + local.hex_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + if(this.is_hex_only !== true) + { + this.error = "Flag \"is_hex_only\" is not set, abort"; + return (new ArrayBuffer(0)); + } + + var ret_buf = new ArrayBuffer(this.value_hex.byteLength); + + if(size_only === true) + return ret_buf; + + var ret_view = new Uint8Array(ret_buf); + var cur_view = new Uint8Array(this.value_hex); + + for(var i = 0; i < cur_view.length; i++) + ret_view[i] = cur_view[i]; + + return ret_buf; + }; + //************************************************************************************** + local.hex_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.base_block.prototype.toJSON.call(this); + + _object.block_name = local.hex_block.prototype.block_name.call(this); + _object.is_hex_only = this.is_hex_only; + _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of identification block class + //************************************************************************************** + local.identification_block = + function() + { + /// Base class of ASN.1 "identification block" + + local.hex_block.call(this, arguments[0]); + + this.tag_class = (-1); + this.tag_number = (-1); + this.is_constructed = false; + + if(arguments[0] instanceof Object) + { + if("id_block" in arguments[0]) + { + // #region Properties from hex_block class + this.is_hex_only = in_window.org.pkijs.getValue(arguments[0].id_block, "is_hex_only", false); + this.value_hex = in_window.org.pkijs.getValue(arguments[0].id_block, "value_hex", new ArrayBuffer(0)); + // #endregion + + this.tag_class = in_window.org.pkijs.getValue(arguments[0].id_block, "tag_class", (-1)); + this.tag_number = in_window.org.pkijs.getValue(arguments[0].id_block, "tag_number", (-1)); + this.is_constructed = in_window.org.pkijs.getValue(arguments[0].id_block, "is_constructed", false); + } + } + }; + //************************************************************************************** + local.identification_block.prototype = new local.hex_block(); + local.identification_block.constructor = local.identification_block; + //************************************************************************************** + local.identification_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "identification_block"; + }; + //************************************************************************************** + local.identification_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + var first_octet = 0; + + switch(this.tag_class) + { + case 1: + first_octet |= 0x00; // UNIVERSAL + break; + case 2: + first_octet |= 0x40; // APPLICATION + break; + case 3: + first_octet |= 0x80; // CONTEXT-SPECIFIC + break; + case 4: + first_octet |= 0xC0; // PRIVATE + break; + default: + this.error = "Unknown tag class"; + return (new ArrayBuffer(0)); + } + + if(this.is_constructed) + first_octet |= 0x20; + + if((this.tag_number < 31) && (!this.is_hex_only)) + { + var ret_buf = new ArrayBuffer(1); + var ret_view = new Uint8Array(ret_buf); + + if(!size_only) + { + var number = this.tag_number; + number &= 0x1F; + first_octet |= number; + + ret_view[0] = first_octet; + } + + return ret_buf; + } + else + { + if(this.is_hex_only === false) + { + var encoded_buf = util_tobase(this.tag_number, 7); + var encoded_view = new Uint8Array(encoded_buf); + var size = encoded_buf.byteLength; + + var ret_buf = new ArrayBuffer(size + 1); + var ret_view = new Uint8Array(ret_buf); + + ret_view[0] = (first_octet | 0x1F); + + if(!size_only) + { + for(var i = 0; i < (size - 1) ; i++) + ret_view[i + 1] = encoded_view[i] | 0x80; + + ret_view[size] = encoded_view[size - 1]; + } + + return ret_buf; + } + else + { + var ret_buf = new ArrayBuffer(this.value_hex.byteLength + 1); + var ret_view = new Uint8Array(ret_buf); + + ret_view[0] = (first_octet | 0x1F); + + if(size_only === false) + { + var cur_view = new Uint8Array(this.value_hex); + + for(var i = 0; i < (cur_view.length - 1); i++) + ret_view[i + 1] = cur_view[i] | 0x80; + + ret_view[this.value_hex.byteLength] = cur_view[cur_view.length - 1]; + } + + return ret_buf; + } + } + }; + //************************************************************************************** + local.identification_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + // #region Basic check for parameters + if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false) + return (-1); + // #endregion + + // #region Getting Uint8Array from ArrayBuffer + var int_buffer = new Uint8Array(input_buffer, input_offset, input_length); + // #endregion + + // #region Initial checks + if(int_buffer.length == 0) + { + this.error = "Zero buffer length"; + return (-1); + } + // #endregion + + // #region Find tag class + var tag_class_mask = int_buffer[0] & 0xC0; + + switch(tag_class_mask) + { + case 0x00: + this.tag_class = (1); // UNIVERSAL + break; + case 0x40: + this.tag_class = (2); // APPLICATION + break; + case 0x80: + this.tag_class = (3); // CONTEXT-SPECIFIC + break; + case 0xC0: + this.tag_class = (4); // PRIVATE + break; + default: + this.error = "Unknown tag class"; + return ( -1 ); + } + // #endregion + + // #region Find it's constructed or not + this.is_constructed = (int_buffer[0] & 0x20) == 0x20; + // #endregion + + // #region Find tag number + this.is_hex_only = false; + + var tag_number_mask = int_buffer[0] & 0x1F; + + // #region Simple case (tag number < 31) + if(tag_number_mask != 0x1F) + { + this.tag_number = (tag_number_mask); + this.block_length = 1; + } + // #endregion + // #region Tag number bigger or equal to 31 + else + { + var count = 1; + + this.value_hex = new ArrayBuffer(255); + var tag_number_buffer_max_length = 255; + var int_tag_number_buffer = new Uint8Array(this.value_hex); + + while(int_buffer[count] & 0x80) + { + int_tag_number_buffer[count - 1] = int_buffer[count] & 0x7F; + count++; + + if(count >= int_buffer.length) + { + this.error = "End of input reached before message was fully decoded"; + return (-1); + } + + // #region In case if tag number length is greater than 255 bytes (rare but possible case) + if(count == tag_number_buffer_max_length) + { + tag_number_buffer_max_length += 255; + + var temp_buffer = new ArrayBuffer(tag_number_buffer_max_length); + var temp_buffer_view = new Uint8Array(temp_buffer); + + for(var i = 0; i < int_tag_number_buffer.length; i++) + temp_buffer_view[i] = int_tag_number_buffer[i]; + + this.value_hex = new ArrayBuffer(tag_number_buffer_max_length); + int_tag_number_buffer = new Uint8Array(this.value_hex); + } + // #endregion + } + + this.block_length = (count + 1); + int_tag_number_buffer[count - 1] = int_buffer[count] & 0x7F; // Write last byte to buffer + + // #region Cut buffer + var temp_buffer = new ArrayBuffer(count); + var temp_buffer_view = new Uint8Array(temp_buffer); + for(var i = 0; i < count; i++) + temp_buffer_view[i] = int_tag_number_buffer[i]; + + this.value_hex = new ArrayBuffer(count); + int_tag_number_buffer = new Uint8Array(this.value_hex); + int_tag_number_buffer.set(temp_buffer_view); + // #endregion + + // #region Try to convert long tag number to short form + if(this.block_length <= 9) + this.tag_number = util_frombase(int_tag_number_buffer, 7); + else + { + this.is_hex_only = true; + this.warnings.push("Tag too long, represented as hex-coded"); + } + // #endregion + } + // #endregion + // #endregion + + // #region Check if constructed encoding was using for primitive type + if(((this.tag_class == 1)) && + (this.is_constructed)) + { + switch(this.tag_number) + { + case 1: // BOOLEAN + case 2: // REAL + case 5: // NULL + case 6: // OBJECT IDENTIFIER + case 9: // REAL + case 14: // TIME + case 23: + case 24: + case 31: + case 32: + case 33: + case 34: + this.error = "Constructed encoding used for primitive type"; + return (-1); + default: + ; + } + } + // #endregion + + return ( input_offset + this.block_length ); // Return current offset in input buffer + }; + //************************************************************************************** + local.identification_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.hex_block.prototype.toJSON.call(this); + + _object.block_name = local.identification_block.prototype.block_name.call(this); + _object.tag_class = this.tag_class; + _object.tag_number = this.tag_number; + _object.is_constructed = this.is_constructed; + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of length block class + //************************************************************************************** + local.length_block = + function() + { + /// Base class of ASN.1 "length block" + + local.base_block.call(this, arguments[0]); + + this.is_indefinite_form = false; + this.long_form_used = false; + this.length = (0); + + if(arguments[0] instanceof Object) + { + if("len_block" in arguments[0]) + { + this.is_indefinite_form = in_window.org.pkijs.getValue(arguments[0].len_block, "is_indefinite_form", false); + this.long_form_used = in_window.org.pkijs.getValue(arguments[0].len_block, "long_form_used", false); + this.length = in_window.org.pkijs.getValue(arguments[0].len_block, "length", 0); + } + } + }; + //************************************************************************************** + local.length_block.prototype = new local.base_block(); + local.length_block.constructor = local.length_block; + //************************************************************************************** + local.length_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "length_block"; + }; + //************************************************************************************** + local.length_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + // #region Basic check for parameters + if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false) + return (-1); + // #endregion + + // #region Getting Uint8Array from ArrayBuffer + var int_buffer = new Uint8Array(input_buffer, input_offset, input_length); + // #endregion + + // #region Initial checks + if(int_buffer.length == 0) + { + this.error = "Zero buffer length"; + return (-1); + } + + if(int_buffer[0] == 0xFF) + { + this.error = "Length block 0xFF is reserved by standard"; + return (-1); + } + // #endregion + + // #region Check for length form type + this.is_indefinite_form = int_buffer[0] == 0x80; + // #endregion + + // #region Stop working in case of indefinite length form + if(this.is_indefinite_form == true) + { + this.block_length = 1; + return (input_offset + this.block_length); + } + // #endregion + + // #region Check is long form of length encoding using + this.long_form_used = !!(int_buffer[0] & 0x80); + // #endregion + + // #region Stop working in case of short form of length value + if(this.long_form_used == false) + { + this.length = (int_buffer[0]); + this.block_length = 1; + return (input_offset + this.block_length); + } + // #endregion + + // #region Calculate length value in case of long form + var count = int_buffer[0] & 0x7F; + + if(count > 8) // Too big length value + { + this.error = "Too big integer"; + return (-1); + } + + if((count + 1) > int_buffer.length) + { + this.error = "End of input reached before message was fully decoded"; + return (-1); + } + + var length_buffer_view = new Uint8Array(count); + + for(var i = 0; i < count; i++) + length_buffer_view[i] = int_buffer[i + 1]; + + if(length_buffer_view[count - 1] == 0x00) + this.warnings.push("Needlessly long encoded length"); + + this.length = util_frombase(length_buffer_view, 8); + + if(this.long_form_used && (this.length <= 127)) + this.warnings.push("Unneccesary usage of long length form"); + + this.block_length = count + 1; + // #endregion + + return (input_offset + this.block_length); // Return current offset in input buffer + }; + //************************************************************************************** + local.length_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + if(this.length > 127) + this.long_form_used = true; + + if(this.is_indefinite_form) + { + var ret_buf = new ArrayBuffer(1); + + if(size_only === false) + { + var ret_view = new Uint8Array(ret_buf); + ret_view[0] = 0x80; + } + + return ret_buf; + } + + if(this.long_form_used === true) + { + var encoded_buf = util_tobase(this.length, 8); + + if(encoded_buf.byteLength > 127) + { + this.error = "Too big length"; + return (new ArrayBuffer(0)); + } + + var ret_buf = new ArrayBuffer(encoded_buf.byteLength + 1); + + if(size_only === true) + return ret_buf; + + var encoded_view = new Uint8Array(encoded_buf); + var ret_view = new Uint8Array(ret_buf); + + ret_view[0] = encoded_buf.byteLength | 0x80; + + for(var i = 0; i < encoded_buf.byteLength; i++) + ret_view[i + 1] = encoded_view[i]; + + return ret_buf; + } + else + { + var ret_buf = new ArrayBuffer(1); + + if(size_only === false) + { + var ret_view = new Uint8Array(ret_buf); + + ret_view[0] = this.length; + } + + return ret_buf; + } + + return (new ArrayBuffer(0)); + }; + //************************************************************************************** + local.length_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.base_block.prototype.toJSON.call(this); + + _object.block_name = local.length_block.prototype.block_name.call(this); + _object.is_indefinite_form = this.is_indefinite_form; + _object.long_form_used = this.long_form_used; + _object.length = this.length; + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of value block class + //************************************************************************************** + local.value_block = + function() + { + /// Generic class of ASN.1 "value block" + local.base_block.call(this, arguments[0]); + }; + //************************************************************************************** + local.value_block.prototype = new local.base_block(); + local.value_block.constructor = local.value_block; + //************************************************************************************** + local.value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "value_block"; + }; + //************************************************************************************** + local.value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.base_block.prototype.toJSON.call(this); + + _object.block_name = local.value_block.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of basic ASN.1 block class + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_block = + function() + { + /// Base class of ASN.1 block (identification block + length block + value block) + + local.base_block.call(this, arguments[0]); + + if(arguments[0] instanceof Object) + { + this.name = in_window.org.pkijs.getValue(arguments[0], "name", ""); + this.optional = in_window.org.pkijs.getValue(arguments[0], "optional", false); + + if("primitive_schema" in arguments[0]) + this.primitive_schema = arguments[0].primitive_schema; + } + + this.id_block = new local.identification_block(arguments[0]); + this.len_block = new local.length_block(arguments[0]); + this.value_block = new local.value_block(arguments[0]); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_block.prototype = new local.base_block(); + in_window.org.pkijs.asn1.ASN1_block.constructor = in_window.org.pkijs.asn1.ASN1_block; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "ASN1_block"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length); + if(result_offset == (-1)) + { + this.error = this.value_block.error; + return result_offset; + } + + if(this.id_block.error.length == 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length == 0) + this.block_length += this.len_block.block_length; + + if(this.value_block.error.length == 0) + this.block_length += this.value_block.block_length; + + return result_offset; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + var ret_buf; + + var id_block_buf = this.id_block.toBER(size_only); + var value_block_size_buf = this.value_block.toBER(true); + + this.len_block.length = value_block_size_buf.byteLength; + var len_block_buf = this.len_block.toBER(size_only); + + ret_buf = util_concatbuf(id_block_buf, len_block_buf); + + var value_block_buf; + + if(size_only === false) + value_block_buf = this.value_block.toBER(size_only); + else + value_block_buf = new ArrayBuffer(this.len_block.length); + + ret_buf = util_concatbuf(ret_buf, value_block_buf); + + if(this.len_block.is_indefinite_form === true) + { + var indef_buf = new ArrayBuffer(2); + + if(size_only === false) + { + var indef_view = new Uint8Array(indef_buf); + + indef_view[0] = 0x00; + indef_view[1] = 0x00; + } + + ret_buf = util_concatbuf(ret_buf, indef_buf); + } + + return ret_buf; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.base_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.ASN1_block.prototype.block_name.call(this); + _object.id_block = this.id_block.toJSON(); + _object.len_block = this.len_block.toJSON(); + _object.value_block = this.value_block.toJSON(); + + if("name" in this) + _object.name = this.name; + if("optional" in this) + _object.optional = this.optional; + if("primitive_schema" in this) + _object.primitive_schema = this.primitive_schema.toJSON(); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of basic block for all PRIMITIVE types + //************************************************************************************** + local.ASN1_PRIMITIVE_value_block = + function() + { + /// Base class of ASN.1 value block for primitive values (non-constructive encoding) + + local.value_block.call(this, arguments[0]); + + if(arguments[0] instanceof Object) + { + // #region Variables from "hex_block" class + if("value_hex" in arguments[0]) + this.value_hex = util_copybuf(arguments[0].value_hex); + else + this.value_hex = new ArrayBuffer(0); + + this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", true); + // #endregion + } + else + { + // #region Variables from "hex_block" class + this.value_hex = new ArrayBuffer(0); + this.is_hex_only = true; + // #endregion + } + }; + //************************************************************************************** + local.ASN1_PRIMITIVE_value_block.prototype = new local.value_block(); + local.ASN1_PRIMITIVE_value_block.constructor = local.ASN1_PRIMITIVE_value_block; + //************************************************************************************** + local.ASN1_PRIMITIVE_value_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + // #region Basic check for parameters + if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false) + return (-1); + // #endregion + + // #region Getting Uint8Array from ArrayBuffer + var int_buffer = new Uint8Array(input_buffer, input_offset, input_length); + // #endregion + + // #region Initial checks + if(int_buffer.length == 0) + { + this.warnings.push("Zero buffer length"); + return input_offset; + } + // #endregion + + // #region Copy input buffer into internal buffer + this.value_hex = new ArrayBuffer(int_buffer.length); + var value_hex_view = new Uint8Array(this.value_hex); + + for(var i = 0; i < int_buffer.length; i++) + value_hex_view[i] = int_buffer[i]; + // #endregion + + this.block_length = input_length; + + return (input_offset + input_length); + }; + //************************************************************************************** + local.ASN1_PRIMITIVE_value_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + return util_copybuf(this.value_hex); + }; + //************************************************************************************** + local.ASN1_PRIMITIVE_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "ASN1_PRIMITIVE_value_block"; + }; + //************************************************************************************** + local.ASN1_PRIMITIVE_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.value_block.prototype.toJSON.call(this); + + _object.block_name = local.ASN1_PRIMITIVE_value_block.prototype.block_name.call(this); + _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength); + _object.is_hex_only = this.is_hex_only; + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_PRIMITIVE = + function() + { + /// Base class of ASN.1 block for primitive values (non-constructive encoding) + + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.id_block.is_constructed = false; + this.value_block = new local.ASN1_PRIMITIVE_value_block(arguments[0]); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_PRIMITIVE.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.ASN1_PRIMITIVE.constructor = in_window.org.pkijs.asn1.ASN1_PRIMITIVE; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_PRIMITIVE.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "PRIMITIVE"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_PRIMITIVE.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.ASN1_PRIMITIVE.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of basic block for all CONSTRUCTED types + //************************************************************************************** + local.ASN1_CONSTRUCTED_value_block = + function() + { + /// Base class of ASN.1 value block for constructive values (constructive encoding) + + local.value_block.call(this, arguments[0]); + + if(arguments[0] instanceof Object) + { + this.value = in_window.org.pkijs.getValue(arguments[0], "value", new Array()); + this.is_indefinite_form = in_window.org.pkijs.getValue(arguments[0], "is_indefinite_form", false); + } + else + { + this.value = new Array(); + this.is_indefinite_form = false; + } + }; + //************************************************************************************** + local.ASN1_CONSTRUCTED_value_block.prototype = new local.value_block(); + local.ASN1_CONSTRUCTED_value_block.constructor = local.ASN1_CONSTRUCTED_value_block; + //************************************************************************************** + local.ASN1_CONSTRUCTED_value_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + // #region Store initial offset and length + var initial_offset = input_offset; + var initial_length = input_length; + // #endregion + + // #region Basic check for parameters + if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false) + return (-1); + // #endregion + + // #region Getting Uint8Array from ArrayBuffer + var int_buffer = new Uint8Array(input_buffer, input_offset, input_length); + // #endregion + + // #region Initial checks + if(int_buffer.length == 0) + { + this.warnings.push("Zero buffer length"); + return input_offset; + } + // #endregion + + // #region Aux function + function check_len(_indefinite_length, _length) + { + if(_indefinite_length == true) + return 1; + + return _length; + } + // #endregion + + var current_offset = input_offset; + + while(check_len(this.is_indefinite_form, input_length) > 0) + { + var return_object = fromBER_raw(input_buffer, current_offset, input_length); + if(return_object.offset == (-1)) + { + this.error = return_object.result.error; + this.warnings.concat(return_object.result.warnings); + return (-1); + } + + current_offset = return_object.offset; + + this.block_length += return_object.result.block_length; + input_length -= return_object.result.block_length; + + this.value.push(return_object.result); + + if((this.is_indefinite_form == true) && (return_object.result.block_name() == in_window.org.pkijs.asn1.EOC.prototype.block_name())) + break; + } + + if(this.is_indefinite_form == true) + { + if(this.value[this.value.length - 1].block_name() == in_window.org.pkijs.asn1.EOC.prototype.block_name()) + this.value.pop(); + else + this.warnings.push("No EOC block encoded"); + } + + // #region Copy "input_buffer" to "value_before_decode" + this.value_before_decode = util_copybuf_offset(input_buffer, initial_offset, initial_length); + // #endregion + + return current_offset; + }; + //************************************************************************************** + local.ASN1_CONSTRUCTED_value_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + var ret_buf = new ArrayBuffer(0); + + for(var i = 0; i < this.value.length; i++) + { + var value_buf = this.value[i].toBER(size_only); + ret_buf = util_concatbuf(ret_buf, value_buf); + } + + return ret_buf; + }; + //************************************************************************************** + local.ASN1_CONSTRUCTED_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "ASN1_CONSTRUCTED_value_block"; + }; + //************************************************************************************** + local.ASN1_CONSTRUCTED_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.value_block.prototype.toJSON.call(this); + + _object.block_name = local.ASN1_CONSTRUCTED_value_block.prototype.block_name.call(this); + _object.is_indefinite_form = this.is_indefinite_form; + _object.value = new Array(); + for(var i = 0; i < this.value.length; i++) + _object.value.push(this.value[i].toJSON()); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_CONSTRUCTED = + function() + { + /// Base class of ASN.1 block for constructive values (constructive encoding) + + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.id_block.is_constructed = true; + this.value_block = new local.ASN1_CONSTRUCTED_value_block(arguments[0]); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.constructor = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "CONSTRUCTED"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + this.value_block.is_indefinite_form = this.len_block.is_indefinite_form; + + var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length); + if(result_offset == (-1)) + { + this.error = this.value_block.error; + return result_offset; + } + + if(this.id_block.error.length == 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length == 0) + this.block_length += this.len_block.block_length; + + if(this.value_block.error.length == 0) + this.block_length += this.value_block.block_length; + + return result_offset; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of ASN.1 EOC type class + //************************************************************************************** + local.EOC_value_block = + function() + { + local.value_block.call(this, arguments[0]); + }; + //************************************************************************************** + local.EOC_value_block.prototype = new local.value_block(); + local.EOC_value_block.constructor = local.EOC_value_block; + //************************************************************************************** + local.EOC_value_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + // #region There is no "value block" for EOC type and we need to return the same offset + return input_offset; + // #endregion + }; + //************************************************************************************** + local.EOC_value_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + return (new ArrayBuffer(0)); + }; + //************************************************************************************** + local.EOC_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "EOC_value_block"; + }; + //************************************************************************************** + local.EOC_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.value_block.prototype.toJSON.call(this); + + _object.block_name = local.EOC_value_block.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.EOC = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.EOC_value_block(); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 0; // EOC + }; + //************************************************************************************** + in_window.org.pkijs.asn1.EOC.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.EOC.constructor = local.EOC_value_block; + //************************************************************************************** + in_window.org.pkijs.asn1.EOC.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "END_OF_CONTENT"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.EOC.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.EOC.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of ASN.1 BOOLEAN type class + //************************************************************************************** + local.BOOLEAN_value_block = + function() + { + local.value_block.call(this, arguments[0]); + + if(arguments[0] instanceof Object) + { + this.value = in_window.org.pkijs.getValue(arguments[0], "value", false); + + // #region Variables from hex_block class + this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false); + if("value_hex" in arguments[0]) + this.value_hex = util_copybuf(arguments[0].value_hex); + else + { + this.value_hex = new ArrayBuffer(1); + if(this.value === true) + { + var view = new Uint8Array(this.value_hex); + view[0] = 0xFF; + } + } + // #endregion + } + else + { + this.value = false; + + // #region Variables from hex_block class + this.is_hex_only = false; + this.value_hex = new ArrayBuffer(1); + // #endregion + } + }; + //************************************************************************************** + local.BOOLEAN_value_block.prototype = new local.value_block(); + local.BOOLEAN_value_block.constructor = local.BOOLEAN_value_block; + //************************************************************************************** + local.BOOLEAN_value_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + // #region Basic check for parameters + if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false) + return (-1); + // #endregion + + // #region Getting Uint8Array from ArrayBuffer + var int_buffer = new Uint8Array(input_buffer, input_offset, input_length); + // #endregion + + if(input_length > 1) + this.warnings.push("BOOLEAN value encoded in more then 1 octet"); + + this.value = int_buffer[0] != 0x00; + + this.is_hex_only = true; + + // #region Copy input buffer to internal array + this.value_hex = new ArrayBuffer(int_buffer.length); + var view = new Uint8Array(this.value_hex); + + for(var i = 0; i < int_buffer.length; i++) + view[i] = int_buffer[i]; + // #endregion + + this.block_length = input_length; + + return (input_offset + input_length); + }; + //************************************************************************************** + local.BOOLEAN_value_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + return this.value_hex; + }; + //************************************************************************************** + local.BOOLEAN_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "BOOLEAN_value_block"; + }; + //************************************************************************************** + local.BOOLEAN_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.value_block.prototype.toJSON.call(this); + + _object.block_name = local.BOOLEAN_value_block.prototype.block_name.call(this); + _object.value = this.value; + _object.is_hex_only = this.is_hex_only; + _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BOOLEAN = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.BOOLEAN_value_block(arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 1; // BOOLEAN + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BOOLEAN.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.BOOLEAN.constructor = local.BOOLEAN_value_block; + //************************************************************************************** + in_window.org.pkijs.asn1.BOOLEAN.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "BOOLEAN"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BOOLEAN.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.BOOLEAN.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of ASN.1 SEQUENCE and SET type classes + //************************************************************************************** + in_window.org.pkijs.asn1.SEQUENCE = + function() + { + in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 16; // SEQUENCE + }; + //************************************************************************************** + in_window.org.pkijs.asn1.SEQUENCE.prototype = new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED(); + in_window.org.pkijs.asn1.SEQUENCE.constructor = in_window.org.pkijs.asn1.SEQUENCE; + //************************************************************************************** + in_window.org.pkijs.asn1.SEQUENCE.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "SEQUENCE"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.SEQUENCE.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.SEQUENCE.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.SET = + function() + { + in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 17; // SET + }; + //************************************************************************************** + in_window.org.pkijs.asn1.SET.prototype = new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED(); + in_window.org.pkijs.asn1.SET.constructor = in_window.org.pkijs.asn1.SET; + //************************************************************************************** + in_window.org.pkijs.asn1.SET.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "SET"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.SET.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.SET.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of ASN.1 NULL type class + //************************************************************************************** + in_window.org.pkijs.asn1.NULL = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 5; // NULL + }; + //************************************************************************************** + in_window.org.pkijs.asn1.NULL.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.NULL.constructor = in_window.org.pkijs.asn1.NULL; + //************************************************************************************** + in_window.org.pkijs.asn1.NULL.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "NULL"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.NULL.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + if(this.len_block.length > 0) + this.warnings.push("Non-zero length of value block for NULL type"); + + if(this.id_block.error.length === 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length === 0) + this.block_length += this.len_block.block_length; + + this.block_length += input_length; + + return (input_offset + input_length); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.NULL.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + var ret_buf = new ArrayBuffer(2); + + if(size_only === true) + return ret_buf; + + var ret_view = new Uint8Array(ret_buf); + ret_view[0] = 0x05; + ret_view[1] = 0x00; + + return ret_buf; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.NULL.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.NULL.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of ASN.1 OCTETSTRING type class + //************************************************************************************** + local.OCTETSTRING_value_block = + function() + { + /// + /// + /// + /// Value for the OCTETSTRING may be as hex, as well as a constructed value. + /// Constructed values consists of other OCTETSTRINGs + + local.ASN1_CONSTRUCTED_value_block.call(this, arguments[0]); + + if(arguments[0] instanceof Object) + { + this.is_constructed = in_window.org.pkijs.getValue(arguments[0], "is_constructed", false); + + // #region Variables from hex_block type + this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false); + if("value_hex" in arguments[0]) + this.value_hex = util_copybuf(arguments[0].value_hex); + else + this.value_hex = new ArrayBuffer(0); + // #endregion + } + else + { + this.is_constructed = false; + + // #region Variables from hex_block type + this.is_hex_only = false; + this.value_hex = new ArrayBuffer(0); + // #endregion + } + }; + //************************************************************************************** + local.OCTETSTRING_value_block.prototype = new local.ASN1_CONSTRUCTED_value_block(); + local.OCTETSTRING_value_block.constructor = local.OCTETSTRING_value_block; + //************************************************************************************** + local.OCTETSTRING_value_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = 0; + + if(this.is_constructed == true) + { + this.is_hex_only = false; + + result_offset = local.ASN1_CONSTRUCTED_value_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length); + if(result_offset == (-1)) + return result_offset; + + for(var i = 0; i < this.value.length; i++) + { + var current_block_name = this.value[i].block_name(); + + if(current_block_name == in_window.org.pkijs.asn1.EOC.prototype.block_name()) + { + if(this.is_indefinite_form == true) + break; + else + { + this.error = "EOC is unexpected, OCTET STRING may consists of OCTET STRINGs only"; + return (-1); + } + } + + if(current_block_name != in_window.org.pkijs.asn1.OCTETSTRING.prototype.block_name()) + { + this.error = "OCTET STRING may consists of OCTET STRINGs only"; + return (-1); + } + } + } + else + { + this.is_hex_only = true; + + result_offset = local.hex_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length); + this.block_length = input_length; + } + + return result_offset; + }; + //************************************************************************************** + local.OCTETSTRING_value_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + if(this.is_constructed === true) + return local.ASN1_CONSTRUCTED_value_block.prototype.toBER.call(this, size_only); + else + { + var ret_buf = new ArrayBuffer(this.value_hex.byteLength); + + if(size_only === true) + return ret_buf; + + if(this.value_hex.byteLength == 0) + return ret_buf; + + ret_buf = util_copybuf(this.value_hex); + + return ret_buf; + } + + return (new ArrayBuffer(0)); + }; + //************************************************************************************** + local.OCTETSTRING_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "OCTETSTRING_value_block"; + }; + //************************************************************************************** + local.OCTETSTRING_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.ASN1_CONSTRUCTED_value_block.prototype.toJSON.call(this); + + _object.block_name = local.OCTETSTRING_value_block.prototype.block_name.call(this); + _object.is_constructed = this.is_constructed; + _object.is_hex_only = this.is_hex_only; + _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.OCTETSTRING = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.OCTETSTRING_value_block(arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 4; // OCTETSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.OCTETSTRING.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.OCTETSTRING.constructor = in_window.org.pkijs.asn1.OCTETSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.OCTETSTRING.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + this.value_block.is_constructed = this.id_block.is_constructed; + this.value_block.is_indefinite_form = this.len_block.is_indefinite_form; + + // #region Ability to encode empty OCTET STRING + if(input_length == 0) + { + if(this.id_block.error.length == 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length == 0) + this.block_length += this.len_block.block_length; + + return input_offset; + } + // #endregion + + return in_window.org.pkijs.asn1.ASN1_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.OCTETSTRING.prototype.block_name = + function() + { + return "OCTETSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.OCTETSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.OCTETSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.OCTETSTRING.prototype.isEqual = + function(octetString) + { + /// + /// The OCTETSTRING to compare with + + // #region Check input type + if((octetString instanceof in_window.org.pkijs.asn1.OCTETSTRING) == false) + return false; + // #endregion + + // #region Compare two JSON strings + if(JSON.stringify(this) != JSON.stringify(octetString)) + return false; + // #endregion + + return true; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of ASN.1 BITSTRING type class + //************************************************************************************** + local.BITSTRING_value_block = + function() + { + local.ASN1_CONSTRUCTED_value_block.call(this, arguments[0]); + + if(arguments[0] instanceof Object) + { + this.unused_bits = in_window.org.pkijs.getValue(arguments[0], "unused_bits", 0); + this.is_constructed = in_window.org.pkijs.getValue(arguments[0], "is_constructed", false); + + // #region Variables from hex_block type + this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false); + + if("value_hex" in arguments[0]) + this.value_hex = util_copybuf(arguments[0].value_hex); + else + this.value_hex = new ArrayBuffer(0); + + this.block_length = this.value_hex.byteLength; + // #endregion + } + else + { + this.unused_bits = 0; + this.is_constructed = false; + + // #region Variables from hex_block type + this.is_hex_only = false; + this.value_hex = new ArrayBuffer(0); + // #endregion + } + }; + //************************************************************************************** + local.BITSTRING_value_block.prototype = new local.ASN1_CONSTRUCTED_value_block(); + local.BITSTRING_value_block.constructor = local.BITSTRING_value_block; + //************************************************************************************** + local.BITSTRING_value_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + // #region Ability to decode zero-length BITSTRING value + if(input_length == 0) + return input_offset; + // #endregion + + var result_offset = (-1); + + // #region If the BISTRING supposed to be a constructed value + if(this.is_constructed == true) + { + result_offset = local.ASN1_CONSTRUCTED_value_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length); + if(result_offset == (-1)) + return result_offset; + + for(var i = 0; i < this.value.length; i++) + { + var current_block_name = this.value[i].block_name(); + + if(current_block_name == in_window.org.pkijs.asn1.EOC.prototype.block_name()) + { + if(this.is_indefinite_form == true) + break; + else + { + this.error = "EOC is unexpected, BIT STRING may consists of BIT STRINGs only"; + return (-1); + } + } + + if(current_block_name != in_window.org.pkijs.asn1.BITSTRING.prototype.block_name()) + { + this.error = "BIT STRING may consists of BIT STRINGs only"; + return (-1); + } + + if((this.unused_bits > 0) && (this.value[i].unused_bits > 0)) + { + this.error = "Usign of \"unused bits\" inside constructive BIT STRING allowed for least one only"; + return (-1); + } + else + { + this.unused_bits = this.value[i].unused_bits; + if(this.unused_bits > 7) + { + this.error = "Unused bits for BITSTRING must be in range 0-7"; + return (-1); + } + } + } + + return result_offset; + } + // #endregion + // #region If the BITSTRING supposed to be a primitive value + else + { + // #region Basic check for parameters + if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false) + return (-1); + // #endregion + + var int_buffer = new Uint8Array(input_buffer, input_offset, input_length); + + this.unused_bits = int_buffer[0]; + if(this.unused_bits > 7) + { + this.error = "Unused bits for BITSTRING must be in range 0-7"; + return (-1); + } + + // #region Copy input buffer to internal buffer + this.value_hex = new ArrayBuffer(int_buffer.length - 1); + var view = new Uint8Array(this.value_hex); + for(var i = 0; i < (input_length - 1) ; i++) + view[i] = int_buffer[i + 1]; + // #endregion + + this.block_length = int_buffer.length; + + return (input_offset + input_length); + } + // #endregion + }; + //************************************************************************************** + local.BITSTRING_value_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + if(this.is_constructed === true) + return local.ASN1_CONSTRUCTED_value_block.prototype.toBER.call(this, size_only); + else + { + if(size_only === true) + return (new ArrayBuffer(this.value_hex.byteLength + 1)); + + if(this.value_hex.byteLength == 0) + return (new ArrayBuffer(0)); + + var cur_view = new Uint8Array(this.value_hex); + + var ret_buf = new ArrayBuffer(this.value_hex.byteLength + 1); + var ret_view = new Uint8Array(ret_buf); + + ret_view[0] = this.unused_bits; + + for(var i = 0; i < this.value_hex.byteLength; i++) + ret_view[i + 1] = cur_view[i]; + + return ret_buf; + } + + return (new ArrayBuffer(0)); + }; + //************************************************************************************** + local.BITSTRING_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "BITSTRING_value_block"; + }; + //************************************************************************************** + local.BITSTRING_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.ASN1_CONSTRUCTED_value_block.prototype.toJSON.call(this); + + _object.block_name = local.BITSTRING_value_block.prototype.block_name.call(this); + _object.unused_bits = this.unused_bits; + _object.is_constructed = this.is_constructed; + _object.is_hex_only = this.is_hex_only; + _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BITSTRING = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.BITSTRING_value_block(arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 3; // BITSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BITSTRING.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.BITSTRING.constructor = in_window.org.pkijs.asn1.BITSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.BITSTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "BITSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BITSTRING.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + // #region Ability to encode empty BITSTRING + if(input_length == 0) + return input_offset; + // #endregion + + this.value_block.is_constructed = this.id_block.is_constructed; + this.value_block.is_indefinite_form = this.len_block.is_indefinite_form; + + return in_window.org.pkijs.asn1.ASN1_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BITSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.BITSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of ASN.1 INTEGER type class + //************************************************************************************** + local.INTEGER_value_block = + function() + { + local.value_block.call(this, arguments[0]); + + if(arguments[0] instanceof Object) + { + this.value_dec = in_window.org.pkijs.getValue(arguments[0], "value", 0); + + // #region Variables from hex_block type + this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false); + if("value_hex" in arguments[0]) + { + this.value_hex = util_copybuf(arguments[0].value_hex); + + if(this.value_hex.byteLength >= 4) // Dummy's protection + this.is_hex_only = true; + else + this.value_dec = util_decode_tc.call(this); + } + else + this.value_hex = util_encode_tc(this.value_dec); + // #endregion + } + else + { + this.value_dec = 0; + + // #region Variables from hex_block type + this.is_hex_only = false; + this.value_hex = new ArrayBuffer(0); + // #endregion + } + }; + //************************************************************************************** + local.INTEGER_value_block.prototype = new local.value_block(); + local.INTEGER_value_block.constructor = local.INTEGER_value_block; + //************************************************************************************** + local.INTEGER_value_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = local.hex_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length); + if(result_offset == (-1)) + return result_offset; + + if(this.value_hex.byteLength > 4) // In JavaScript we can effectively work with 32-bit integers only + { + this.warnings.push("Too big INTEGER for decoding, hex only"); + this.is_hex_only = true; + } + else + this.value_dec = util_decode_tc.call(this); + + this.block_length = input_length; + + return (input_offset + input_length); + }; + //************************************************************************************** + local.INTEGER_value_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + if(this.is_hex_only === false) + { + var encoded_buf = util_encode_tc(this.value_dec); + if(encoded_buf.byteLength == 0) + { + this.error = "Error during encoding INTEGER value"; + return (new ArrayBuffer(0)); + } + + return util_copybuf(encoded_buf); + } + else + return util_copybuf(this.value_hex); + + return (new ArrayBuffer(0)); + }; + //************************************************************************************** + local.INTEGER_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "INTEGER_value_block"; + }; + //************************************************************************************** + local.INTEGER_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.value_block.prototype.toJSON.call(this); + + _object.block_name = local.INTEGER_value_block.prototype.block_name.call(this); + _object.value_dec = this.value_dec; + _object.is_hex_only = this.is_hex_only; + _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.INTEGER = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.INTEGER_value_block(arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 2; // INTEGER + }; + //************************************************************************************** + in_window.org.pkijs.asn1.INTEGER.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.INTEGER.constructor = in_window.org.pkijs.asn1.INTEGER; + //************************************************************************************** + in_window.org.pkijs.asn1.INTEGER.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "INTEGER"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.INTEGER.prototype.isEqual = + function() + { + /// Compare two INTEGER object, or INTEGER and ArrayBuffer objects + /// + + if(arguments[0] instanceof in_window.org.pkijs.asn1.INTEGER) + { + if(this.value_block.is_hex_only && arguments[0].value_block.is_hex_only) // Compare two ArrayBuffers + return in_window.org.pkijs.isEqual_buffer(this.value_block.value_hex, arguments[0].value_block.value_hex); + else + { + if(this.value_block.is_hex_only === arguments[0].value_block.is_hex_only) + return (this.value_block.value_dec == arguments[0].value_block.value_dec); + else + return false; + } + } + else + { + if(arguments[0] instanceof ArrayBuffer) + return in_window.org.pkijs.isEqual_buffer(this.value_block.value_hex, arguments[0]); + else + return false; + } + + return false; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.INTEGER.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.INTEGER.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of ASN.1 ENUMERATED type class + //************************************************************************************** + in_window.org.pkijs.asn1.ENUMERATED = + function() + { + in_window.org.pkijs.asn1.INTEGER.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 10; // ENUMERATED + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ENUMERATED.prototype = new in_window.org.pkijs.asn1.INTEGER(); + in_window.org.pkijs.asn1.ENUMERATED.constructor = in_window.org.pkijs.asn1.ENUMERATED; + //************************************************************************************** + in_window.org.pkijs.asn1.ENUMERATED.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "ENUMERATED"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.ENUMERATED.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.INTEGER.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.ENUMERATED.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of ASN.1 OBJECT IDENTIFIER type class + //************************************************************************************** + local.SID_value_block = + function() + { + local.hex_block.call(this, arguments[0]); + + if(arguments[0] instanceof Object) + { + this.value_dec = in_window.org.pkijs.getValue(arguments[0], "value_dec", -1); + this.is_first_sid = in_window.org.pkijs.getValue(arguments[0], "is_first_sid", false); + } + else + { + this.value_dec = (-1); + this.is_first_sid = false; + } + }; + //************************************************************************************** + local.SID_value_block.prototype = new local.hex_block(); + local.SID_value_block.constructor = local.SID_value_block; + //************************************************************************************** + local.SID_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "sid_block"; + }; + //************************************************************************************** + local.SID_value_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + if(input_length == 0) + return input_offset; + + // #region Basic check for parameters + if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false) + return (-1); + // #endregion + + var int_buffer = new Uint8Array(input_buffer, input_offset, input_length); + + this.value_hex = new ArrayBuffer(input_length); + var view = new Uint8Array(this.value_hex); + + for(var i = 0; i < input_length; i++) + { + view[i] = int_buffer[i] & 0x7F; + + this.block_length++; + + if((int_buffer[i] & 0x80) == 0x00) + break; + } + + // #region Ajust size of value_hex buffer + var temp_value_hex = new ArrayBuffer(this.block_length); + var temp_view = new Uint8Array(temp_value_hex); + + for(var i = 0; i < this.block_length; i++) + temp_view[i] = view[i]; + + this.value_hex = util_copybuf(temp_value_hex); + view = new Uint8Array(this.value_hex); + // #endregion + + if((int_buffer[this.block_length - 1] & 0x80) != 0x00) + { + this.error = "End of input reached before message was fully decoded"; + return (-1); + } + + if(view[0] == 0x00) + this.warnings.push("Needlessly long format of SID encoding"); + + if(this.block_length <= 8) + this.value_dec = util_frombase(view, 7); + else + { + this.is_hex_only = true; + this.warnings.push("Too big SID for decoding, hex only"); + } + + return (input_offset + this.block_length); + }; + //************************************************************************************** + local.SID_value_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + if(this.is_hex_only) + { + if(size_only === true) + return (new ArrayBuffer(this.value_hex.byteLength)); + + var cur_view = new Uint8Array(this.value_hex); + + var ret_buf = new ArrayBuffer(this.block_length); + var ret_view = new Uint8Array(ret_buf); + + for(var i = 0; i < (this.block_length - 1) ; i++) + ret_view[i] = cur_view[i] | 0x80; + + ret_view[this.block_length - 1] = cur_view[this.block_length - 1]; + + return ret_buf; + } + else + { + var encoded_buf = util_tobase(this.value_dec, 7); + if(encoded_buf.byteLength === 0) + { + this.error = "Error during encoding SID value"; + return (new ArrayBuffer(0)); + } + + var ret_buf = new ArrayBuffer(encoded_buf.byteLength); + + if(size_only === false) + { + var encoded_view = new Uint8Array(encoded_buf); + var ret_view = new Uint8Array(ret_buf); + + for(var i = 0; i < (encoded_buf.byteLength - 1) ; i++) + ret_view[i] = encoded_view[i] | 0x80; + + ret_view[encoded_buf.byteLength - 1] = encoded_view[encoded_buf.byteLength - 1]; + } + + return ret_buf; + } + }; + //************************************************************************************** + local.SID_value_block.prototype.toString = + function() + { + var result = ""; + + if(this.is_hex_only === true) + result = to_hex_codes(this.value_hex); + else + { + if(this.is_first_sid) + { + var sid_value = this.value_dec; + + if(this.value_dec <= 39) + result = "0."; + else + { + if(this.value_dec <= 79) + { + result = "1."; + sid_value -= 40; + } + else + { + result = "2."; + sid_value -= 80; + } + } + + result = result + sid_value.toString(); + } + else + result = this.value_dec.toString(); + } + + return result; + }; + //************************************************************************************** + local.SID_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.hex_block.prototype.toJSON.call(this); + + _object.block_name = local.SID_value_block.prototype.block_name.call(this); + _object.value_dec = this.value_dec; + _object.is_first_sid = this.is_first_sid; + + return _object; + }; + //************************************************************************************** + local.OID_value_block = + function() + { + local.value_block.call(this, arguments[0]); + + this.value = new Array(); + + if(arguments[0] instanceof Object) + this.fromString(in_window.org.pkijs.getValue(arguments[0], "value", "")); + }; + //************************************************************************************** + local.OID_value_block.prototype = new local.value_block(); + local.OID_value_block.constructor = local.OID_value_block; + //************************************************************************************** + local.OID_value_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = input_offset; + + while(input_length > 0) + { + var sid_block = new local.SID_value_block(); + result_offset = sid_block.fromBER(input_buffer, result_offset, input_length); + if(result_offset == (-1)) + { + this.block_length = 0; + this.error = sid_block.error; + return result_offset; + } + + if(this.value.length == 0) + sid_block.is_first_sid = true; + + this.block_length += sid_block.block_length; + input_length -= sid_block.block_length; + + this.value.push(sid_block); + } + + return result_offset; + }; + //************************************************************************************** + local.OID_value_block.prototype.toBER = + function(size_only) + { + /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + /// Flag that we need only a size of encoding, not a real array of bytes + + if(typeof size_only === "undefined") + size_only = false; + + var ret_buf = new ArrayBuffer(0); + + for(var i = 0; i < this.value.length; i++) + { + var value_buf = this.value[i].toBER(size_only); + if(value_buf.byteLength === 0) + { + this.error = this.value[i].error; + return (new ArrayBuffer(0)); + } + + ret_buf = util_concatbuf(ret_buf, value_buf); + } + + return ret_buf; + }; + //************************************************************************************** + local.OID_value_block.prototype.fromString = + function(str) + { + this.value = new Array(); // Clear existing SID values + + var pos1 = 0; + var pos2 = 0; + + var sid = ""; + + var flag = false; + + do + { + pos2 = str.indexOf('.', pos1); + if(pos2 === (-1)) + sid = str.substr(pos1); + else + sid = str.substr(pos1, pos2 - pos1); + + pos1 = pos2 + 1; + + if(flag) + { + var sid_block = this.value[0]; + + var plus = 0; + + switch(sid_block.value_dec) + { + case 0: + break; + case 1: + plus = 40; + break; + case 2: + plus = 80; + break; + default: + this.value = new Array(); // clear SID array + return false; // ??? + } + + var parsedSID = parseInt(sid, 10); + if(isNaN(parsedSID)) + return true; + + sid_block.value_dec = parsedSID + plus; + + flag = false; + } + else + { + var sid_block = new local.SID_value_block(); + sid_block.value_dec = parseInt(sid, 10); + if(isNaN(sid_block.value_dec)) + return true; + + if(this.value.length === 0) + { + sid_block.is_first_sid = true; + flag = true; + } + + this.value.push(sid_block); + } + + } while(pos2 !== (-1)); + + return true; + }; + //************************************************************************************** + local.OID_value_block.prototype.toString = + function() + { + var result = ""; + var is_hex_only = false; + + for(var i = 0; i < this.value.length; i++) + { + is_hex_only = this.value[i].is_hex_only; + + var sid_str = this.value[i].toString(); + + if(i !== 0) + result = result + "."; + + if(is_hex_only) + { + sid_str = "{" + sid_str + "}"; + + if(this.value[i].is_first_sid) + result = "2.{" + sid_str + " - 80}"; + else + result = result + sid_str; + } + else + result = result + sid_str; + } + + return result; + }; + //************************************************************************************** + local.OID_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "OID_value_block"; + }; + //************************************************************************************** + local.OID_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.value_block.prototype.toJSON.call(this); + + _object.block_name = local.OID_value_block.prototype.block_name.call(this); + _object.value = local.OID_value_block.prototype.toString.call(this); + _object.sid_array = new Array(); + for(var i = 0; i < this.value.length; i++) + _object.sid_array.push(this.value[i].toJSON()); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.OID = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.OID_value_block(arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 6; // OBJECT IDENTIFIER + }; + //************************************************************************************** + in_window.org.pkijs.asn1.OID.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.OID.constructor = in_window.org.pkijs.asn1.OID; + //************************************************************************************** + in_window.org.pkijs.asn1.OID.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "OID"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.OID.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.OID.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of all string's classes + //************************************************************************************** + local.UTF8STRING_value_block = + function() + { + local.hex_block.call(this, arguments[0]); + + this.is_hex_only = true; + this.value = ""; // String representation of decoded ArrayBuffer + }; + //************************************************************************************** + local.UTF8STRING_value_block.prototype = new local.hex_block(); + local.UTF8STRING_value_block.constructor = local.UTF8STRING_value_block; + //************************************************************************************** + local.UTF8STRING_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "UTF8STRING_value_block"; + }; + //************************************************************************************** + local.UTF8STRING_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.hex_block.prototype.toJSON.call(this); + + _object.block_name = local.UTF8STRING_value_block.prototype.block_name.call(this); + _object.value = this.value; + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTF8STRING = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.UTF8STRING_value_block(); + + if(arguments[0] instanceof Object) + { + if("value" in arguments[0]) + in_window.org.pkijs.asn1.UTF8STRING.prototype.fromString.call(this,arguments[0].value); + } + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 12; // UTF8STRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTF8STRING.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.UTF8STRING.constructor = in_window.org.pkijs.asn1.UTF8STRING; + //************************************************************************************** + in_window.org.pkijs.asn1.UTF8STRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "UTF8STRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTF8STRING.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length); + if(result_offset == (-1)) + { + this.error = this.value_block.error; + return result_offset; + } + + in_window.org.pkijs.asn1.UTF8STRING.prototype.fromBuffer.call(this, this.value_block.value_hex); + + if(this.id_block.error.length == 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length == 0) + this.block_length += this.len_block.block_length; + + if(this.value_block.error.length == 0) + this.block_length += this.value_block.block_length; + + return result_offset; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTF8STRING.prototype.fromBuffer = + function(input_buffer) + { + /// Array with encoded string + this.value_block.value = String.fromCharCode.apply(null, new Uint8Array(input_buffer)); + + try + { + this.value_block.value = decodeURIComponent(escape(this.value_block.value)); + } + catch(ex) + { + this.warnings.push("Error during \"decodeURIComponent\": " + ex + ", using raw string"); + } + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTF8STRING.prototype.fromString = + function(input_string) + { + /// String with UNIVERSALSTRING value + + var str = unescape(encodeURIComponent(input_string)); + var str_len = str.length; + + this.value_block.value_hex = new ArrayBuffer(str_len); + var view = new Uint8Array(this.value_block.value_hex); + + for(var i = 0; i < str_len; i++) + view[i] = str.charCodeAt(i); + + this.value_block.value = input_string; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.UTF8STRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + local.BMPSTRING_value_block = + function() + { + local.hex_block.call(this, arguments[0]); + + this.is_hex_only = true; + this.value = ""; + }; + //************************************************************************************** + local.BMPSTRING_value_block.prototype = new local.hex_block(); + local.BMPSTRING_value_block.constructor = local.BMPSTRING_value_block; + //************************************************************************************** + local.BMPSTRING_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "BMPSTRING_value_block"; + }; + //************************************************************************************** + local.BMPSTRING_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.hex_block.prototype.toJSON.call(this); + + _object.block_name = local.BMPSTRING_value_block.prototype.block_name.call(this); + _object.value = this.value; + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BMPSTRING = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.BMPSTRING_value_block(); + + if(arguments[0] instanceof Object) + { + if("value" in arguments[0]) + in_window.org.pkijs.asn1.BMPSTRING.prototype.fromString.call(this, arguments[0].value); + } + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 30; // BMPSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BMPSTRING.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.BMPSTRING.constructor = in_window.org.pkijs.asn1.BMPSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.BMPSTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "BMPSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BMPSTRING.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length); + if(result_offset == (-1)) + { + this.error = this.value_block.error; + return result_offset; + } + + in_window.org.pkijs.asn1.BMPSTRING.prototype.fromBuffer.call(this, this.value_block.value_hex); + + if(this.id_block.error.length == 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length == 0) + this.block_length += this.len_block.block_length; + + if(this.value_block.error.length == 0) + this.block_length += this.value_block.block_length; + + return result_offset; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BMPSTRING.prototype.fromBuffer = + function(input_buffer) + { + /// Array with encoded string + + var copy_buffer = in_window.org.pkijs.copyBuffer(input_buffer); + + var value_view = new Uint8Array(copy_buffer); + + for(var i = 0; i < value_view.length; i = i + 2) + { + var temp = value_view[i]; + + value_view[i] = value_view[i + 1]; + value_view[i + 1] = temp; + } + + this.value_block.value = String.fromCharCode.apply(null, new Uint16Array(copy_buffer)); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BMPSTRING.prototype.fromString = + function(input_string) + { + /// String with UNIVERSALSTRING value + + var str_length = input_string.length; + + this.value_block.value_hex = new ArrayBuffer(str_length * 2); + var value_hex_view = new Uint8Array(this.value_block.value_hex); + + for(var i = 0; i < str_length; i++) + { + var code_buf = util_tobase(input_string.charCodeAt(i), 8); + var code_view = new Uint8Array(code_buf); + if(code_view.length > 2) + continue; + + var dif = 2 - code_view.length; + + for(var j = (code_view.length - 1) ; j >= 0; j--) + value_hex_view[i * 2 + j + dif] = code_view[j]; + } + + this.value_block.value = input_string; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.BMPSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.BMPSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + local.UNIVERSALSTRING_value_block = + function() + { + local.hex_block.call(this, arguments[0]); + + this.is_hex_only = true; + this.value = ""; + }; + //************************************************************************************** + local.UNIVERSALSTRING_value_block.prototype = new local.hex_block(); + local.UNIVERSALSTRING_value_block.constructor = local.UNIVERSALSTRING_value_block; + //************************************************************************************** + local.UNIVERSALSTRING_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "UNIVERSALSTRING_value_block"; + }; + //************************************************************************************** + local.UNIVERSALSTRING_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.hex_block.prototype.toJSON.call(this); + + _object.block_name = local.UNIVERSALSTRING_value_block.prototype.block_name.call(this); + _object.value = this.value; + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UNIVERSALSTRING = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.UNIVERSALSTRING_value_block(); + + if(arguments[0] instanceof Object) + { + if("value" in arguments[0]) + in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromString.call(this, arguments[0].value); + } + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 28; // UNIVERSALSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + in_window.org.pkijs.asn1.UNIVERSALSTRING.constructor = in_window.org.pkijs.asn1.UNIVERSALSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "UNIVERSALSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length); + if(result_offset == (-1)) + { + this.error = this.value_block.error; + return result_offset; + } + + in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromBuffer.call(this, this.value_block.value_hex); + + if(this.id_block.error.length == 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length == 0) + this.block_length += this.len_block.block_length; + + if(this.value_block.error.length == 0) + this.block_length += this.value_block.block_length; + + return result_offset; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromBuffer = + function(input_buffer) + { + /// Array with encoded string + + var copy_buffer = in_window.org.pkijs.copyBuffer(input_buffer); + + var value_view = new Uint8Array(copy_buffer); + + for(var i = 0; i < value_view.length; i = i + 4) + { + value_view[i] = value_view[i + 3]; + value_view[i + 1] = value_view[i + 2]; + value_view[i + 2] = 0x00; + value_view[i + 3] = 0x00; + } + + this.value_block.value = String.fromCharCode.apply(null, new Uint32Array(copy_buffer)); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromString = + function(input_string) + { + /// String with UNIVERSALSTRING value + + var str_length = input_string.length; + + this.value_block.value_hex = new ArrayBuffer(str_length * 4); + var value_hex_view = new Uint8Array(this.value_block.value_hex); + + for(var i = 0; i < str_length; i++) + { + var code_buf = util_tobase(input_string.charCodeAt(i), 8); + var code_view = new Uint8Array(code_buf); + if(code_view.length > 4) + continue; + + var dif = 4 - code_view.length; + + for(var j = (code_view.length - 1) ; j >= 0; j--) + value_hex_view[i*4 + j + dif] = code_view[j]; + } + + this.value_block.value = input_string; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + local.SIMPLESTRING_value_block = + function() + { + local.hex_block.call(this, arguments[0]); + + /// Native string representation + this.value = ""; + this.is_hex_only = true; + }; + //************************************************************************************** + local.SIMPLESTRING_value_block.prototype = new local.hex_block(); + local.SIMPLESTRING_value_block.constructor = local.SIMPLESTRING_value_block; + //************************************************************************************** + local.SIMPLESTRING_value_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "SIMPLESTRING_value_block"; + }; + //************************************************************************************** + local.SIMPLESTRING_value_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.hex_block.prototype.toJSON.call(this); + + _object.block_name = local.SIMPLESTRING_value_block.prototype.block_name.call(this); + _object.value = this.value; + + return _object; + }; + //************************************************************************************** + local.SIMPLESTRING_block = + function() + { + in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]); + + this.value_block = new local.SIMPLESTRING_value_block(); + + if(arguments[0] instanceof Object) + { + if("value" in arguments[0]) + local.SIMPLESTRING_block.prototype.fromString.call(this, arguments[0].value); + } + }; + //************************************************************************************** + local.SIMPLESTRING_block.prototype = new in_window.org.pkijs.asn1.ASN1_block(); + local.SIMPLESTRING_block.constructor = local.SIMPLESTRING_block; + //************************************************************************************** + local.SIMPLESTRING_block.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "SIMPLESTRING"; + }; + //************************************************************************************** + local.SIMPLESTRING_block.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length); + if(result_offset == (-1)) + { + this.error = this.value_block.error; + return result_offset; + } + + local.SIMPLESTRING_block.prototype.fromBuffer.call(this, this.value_block.value_hex); + + if(this.id_block.error.length == 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length == 0) + this.block_length += this.len_block.block_length; + + if(this.value_block.error.length == 0) + this.block_length += this.value_block.block_length; + + return result_offset; + }; + //************************************************************************************** + local.SIMPLESTRING_block.prototype.fromBuffer = + function(input_buffer) + { + /// Array with encoded string + + this.value_block.value = String.fromCharCode.apply(null, new Uint8Array(input_buffer)); + }; + //************************************************************************************** + local.SIMPLESTRING_block.prototype.fromString = + function(input_string) + { + /// String with UNIVERSALSTRING value + var str_len = input_string.length; + + this.value_block.value_hex = new ArrayBuffer(str_len); + var view = new Uint8Array(this.value_block.value_hex); + + for(var i = 0; i < str_len; i++) + view[i] = input_string.charCodeAt(i); + + this.value_block.value = input_string; + }; + //************************************************************************************** + local.SIMPLESTRING_block.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this); + + _object.block_name = local.SIMPLESTRING_block.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.NUMERICSTRING = + function() + { + local.SIMPLESTRING_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 18; // NUMERICSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.NUMERICSTRING.prototype = new local.SIMPLESTRING_block(); + in_window.org.pkijs.asn1.NUMERICSTRING.constructor = in_window.org.pkijs.asn1.NUMERICSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.NUMERICSTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "NUMERICSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.NUMERICSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.NUMERICSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.PRINTABLESTRING = + function() + { + local.SIMPLESTRING_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 19; // PRINTABLESTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.PRINTABLESTRING.prototype = new local.SIMPLESTRING_block(); + in_window.org.pkijs.asn1.PRINTABLESTRING.constructor = in_window.org.pkijs.asn1.PRINTABLESTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.PRINTABLESTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "PRINTABLESTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.PRINTABLESTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.PRINTABLESTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.TELETEXSTRING = + function() + { + local.SIMPLESTRING_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 20; // TELETEXSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.TELETEXSTRING.prototype = new local.SIMPLESTRING_block(); + in_window.org.pkijs.asn1.TELETEXSTRING.constructor = in_window.org.pkijs.asn1.TELETEXSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.TELETEXSTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "TELETEXSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.TELETEXSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.TELETEXSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.VIDEOTEXSTRING = + function() + { + local.SIMPLESTRING_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 21; // VIDEOTEXSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.VIDEOTEXSTRING.prototype = new local.SIMPLESTRING_block(); + in_window.org.pkijs.asn1.VIDEOTEXSTRING.constructor = in_window.org.pkijs.asn1.VIDEOTEXSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.VIDEOTEXSTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "VIDEOTEXSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.VIDEOTEXSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.VIDEOTEXSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.IA5STRING = + function() + { + local.SIMPLESTRING_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 22; // IA5STRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.IA5STRING.prototype = new local.SIMPLESTRING_block(); + in_window.org.pkijs.asn1.IA5STRING.constructor = in_window.org.pkijs.asn1.IA5STRING; + //************************************************************************************** + in_window.org.pkijs.asn1.IA5STRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "IA5STRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.IA5STRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.IA5STRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GRAPHICSTRING = + function() + { + local.SIMPLESTRING_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 25; // GRAPHICSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GRAPHICSTRING.prototype = new local.SIMPLESTRING_block(); + in_window.org.pkijs.asn1.GRAPHICSTRING.constructor = in_window.org.pkijs.asn1.GRAPHICSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.GRAPHICSTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "GRAPHICSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GRAPHICSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.GRAPHICSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.VISIBLESTRING = + function() + { + local.SIMPLESTRING_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 26; // VISIBLESTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.VISIBLESTRING.prototype = new local.SIMPLESTRING_block(); + in_window.org.pkijs.asn1.VISIBLESTRING.constructor = in_window.org.pkijs.asn1.VISIBLESTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.VISIBLESTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "VISIBLESTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.VISIBLESTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.VISIBLESTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALSTRING = + function() + { + local.SIMPLESTRING_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 27; // GENERALSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALSTRING.prototype = new local.SIMPLESTRING_block(); + in_window.org.pkijs.asn1.GENERALSTRING.constructor = in_window.org.pkijs.asn1.GENERALSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALSTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "GENERALSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.GENERALSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.CHARACTERSTRING = + function() + { + local.SIMPLESTRING_block.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 29; // CHARACTERSTRING + }; + //************************************************************************************** + in_window.org.pkijs.asn1.CHARACTERSTRING.prototype = new local.SIMPLESTRING_block(); + in_window.org.pkijs.asn1.CHARACTERSTRING.constructor = in_window.org.pkijs.asn1.CHARACTERSTRING; + //************************************************************************************** + in_window.org.pkijs.asn1.CHARACTERSTRING.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "CHARACTERSTRING"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.CHARACTERSTRING.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.CHARACTERSTRING.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of all date and time classes + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME = + function() + { + in_window.org.pkijs.asn1.VISIBLESTRING.call(this, arguments[0]); + + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + + // #region Create UTCTIME from ASN.1 UTC string value + if((arguments[0] instanceof Object) && ("value" in arguments[0])) + { + in_window.org.pkijs.asn1.UTCTIME.prototype.fromString.call(this, arguments[0].value); + + this.value_block.value_hex = new ArrayBuffer(arguments[0].value.length); + var view = new Uint8Array(this.value_block.value_hex); + + for(var i = 0; i < arguments[0].value.length; i++) + view[i] = arguments[0].value.charCodeAt(i); + } + // #endregion + // #region Create UTCTIME from JavaScript Date type + if((arguments[0] instanceof Object) && ("value_date" in arguments[0])) + { + in_window.org.pkijs.asn1.UTCTIME.prototype.fromDate.call(this, arguments[0].value_date); + this.value_block.value_hex = in_window.org.pkijs.asn1.UTCTIME.prototype.toBuffer.call(this); + } + // #endregion + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 23; // UTCTIME + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype = new in_window.org.pkijs.asn1.VISIBLESTRING(); + in_window.org.pkijs.asn1.UTCTIME.constructor = in_window.org.pkijs.asn1.UTCTIME; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length); + if(result_offset == (-1)) + { + this.error = this.value_block.error; + return result_offset; + } + + in_window.org.pkijs.asn1.UTCTIME.prototype.fromBuffer.call(this, this.value_block.value_hex); + + if(this.id_block.error.length == 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length == 0) + this.block_length += this.len_block.block_length; + + if(this.value_block.error.length == 0) + this.block_length += this.value_block.block_length; + + return result_offset; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype.fromBuffer = + function(input_buffer) + { + in_window.org.pkijs.asn1.UTCTIME.prototype.fromString.call(this, String.fromCharCode.apply(null, new Uint8Array(input_buffer))); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype.toBuffer = + function() + { + var str = in_window.org.pkijs.asn1.UTCTIME.prototype.toString.call(this); + + var buffer = new ArrayBuffer(str.length); + var view = new Uint8Array(buffer); + + for(var i = 0; i < str.length; i++) + view[i] = str.charCodeAt(i); + + return buffer; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype.fromDate = + function(input_date) + { + /// Create "UTCTime" ASN.1 type from JavaScript "Date" type + + this.year = input_date.getUTCFullYear(); + this.month = input_date.getUTCMonth() + 1; + this.day = input_date.getUTCDate(); + this.hour = input_date.getUTCHours(); + this.minute = input_date.getUTCMinutes(); + this.second = input_date.getUTCSeconds(); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype.toDate = + function() + { + return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second))); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype.fromString = + function(input_string) + { + /// Create "UTCTime" ASN.1 type from JavaScript "String" type + + // #region Parse input string + var parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig; + var parser_array = parser.exec(input_string); + if(parser_array === null) + { + this.error = "Wrong input string for convertion"; + return; + } + // #endregion + + // #region Store parsed values + var year = parseInt(parser_array[1], 10); + if(year >= 50) + this.year = 1900 + year; + else + this.year = 2000 + year; + + this.month = parseInt(parser_array[2], 10); + this.day = parseInt(parser_array[3], 10); + this.hour = parseInt(parser_array[4], 10); + this.minute = parseInt(parser_array[5], 10); + this.second = parseInt(parser_array[6], 10); + // #endregion + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype.toString = + function() + { + var output_array = new Array(7); + + output_array[0] = in_window.org.pkijs.padNumber(((this.year < 2000) ? (this.year - 1900) : (this.year - 2000)), 2); + output_array[1] = in_window.org.pkijs.padNumber(this.month, 2); + output_array[2] = in_window.org.pkijs.padNumber(this.day, 2); + output_array[3] = in_window.org.pkijs.padNumber(this.hour, 2); + output_array[4] = in_window.org.pkijs.padNumber(this.minute, 2); + output_array[5] = in_window.org.pkijs.padNumber(this.second, 2); + output_array[6] = "Z"; + + return output_array.join(''); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "UTCTIME"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.UTCTIME.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.VISIBLESTRING.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.UTCTIME.prototype.block_name.call(this); + _object.year = this.year; + _object.month = this.month; + _object.day = this.day; + _object.hour = this.hour; + _object.minute = this.minute; + _object.second = this.second; + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME = + function() + { + in_window.org.pkijs.asn1.VISIBLESTRING.call(this, arguments[0]); + + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + this.millisecond = 0; + + // #region Create GeneralizedTime from ASN.1 string value + if((arguments[0] instanceof Object) && ("value" in arguments[0])) + { + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromString.call(this, arguments[0].value); + + this.value_block.value_hex = new ArrayBuffer(arguments[0].value.length); + var view = new Uint8Array(this.value_block.value_hex); + + for(var i = 0; i < arguments[0].value.length; i++) + view[i] = arguments[0].value.charCodeAt(i); + } + // #endregion + // #region Create GeneralizedTime from JavaScript Date type + if((arguments[0] instanceof Object) && ("value_date" in arguments[0])) + { + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromDate.call(this, arguments[0].value_date); + this.value_block.value_hex = in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toBuffer.call(this); + } + // #endregion + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 24; // GENERALIZEDTIME + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype = new in_window.org.pkijs.asn1.VISIBLESTRING(); + in_window.org.pkijs.asn1.GENERALIZEDTIME.constructor = in_window.org.pkijs.asn1.GENERALIZEDTIME; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromBER = + function(input_buffer, input_offset, input_length) + { + /// Base function for converting block from BER encoded array of bytes + /// ASN.1 BER encoded array + /// Offset in ASN.1 BER encoded array where decoding should be started + /// Maximum length of array of bytes which can be using in this function + + var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length); + if(result_offset == (-1)) + { + this.error = this.value_block.error; + return result_offset; + } + + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromBuffer.call(this, this.value_block.value_hex); + + if(this.id_block.error.length == 0) + this.block_length += this.id_block.block_length; + + if(this.len_block.error.length == 0) + this.block_length += this.len_block.block_length; + + if(this.value_block.error.length == 0) + this.block_length += this.value_block.block_length; + + return result_offset; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromBuffer = + function(input_buffer) + { + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromString.call(this, String.fromCharCode.apply(null, new Uint8Array(input_buffer))); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toBuffer = + function() + { + var str = in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toString.call(this); + + var buffer = new ArrayBuffer(str.length); + var view = new Uint8Array(buffer); + + for(var i = 0; i < str.length; i++) + view[i] = str.charCodeAt(i); + + return buffer; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromDate = + function(input_date) + { + /// Create "GeneralizedTime" ASN.1 type from JavaScript "Date" type + + this.year = input_date.getUTCFullYear(); + this.month = input_date.getUTCMonth(); + this.day = input_date.getUTCDate(); + this.hour = input_date.getUTCHours(); + this.minute = input_date.getUTCMinutes(); + this.second = input_date.getUTCSeconds(); + this.millisecond = input_date.getUTCMilliseconds(); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toDate = + function() + { + return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond))); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromString = + function(input_string) + { + /// Create "GeneralizedTime" ASN.1 type from JavaScript "String" type + + // #region Initial variables + var isUTC = false; + + var timeString = ""; + var dateTimeString = ""; + var fractionPart = 0; + + var parser; + + var hourDifference = 0; + var minuteDifference = 0; + // #endregion + + // #region Convert as UTC time + if(input_string[input_string.length - 1] == "Z") + { + timeString = input_string.substr(0, input_string.length - 1); + + isUTC = true; + } + // #endregion + // #region Convert as local time + else + { + var number = new Number(input_string[input_string.length - 1]); + + if(isNaN(number.valueOf())) + throw new Error("Wrong input string for convertion"); + + timeString = input_string; + } + // #endregion + + // #region Check that we do not have a "+" and "-" symbols inside UTC time + if(isUTC) + { + if(timeString.indexOf("+") != (-1)) + throw new Error("Wrong input string for convertion"); + + if(timeString.indexOf("-") != (-1)) + throw new Error("Wrong input string for convertion"); + } + // #endregion + // #region Get "UTC time difference" in case of local time + else + { + var multiplier = 1; + var differencePosition = timeString.indexOf("+"); + var differenceString = ""; + + if(differencePosition == (-1)) + { + differencePosition = timeString.indexOf("-"); + multiplier = (-1); + } + + if(differencePosition != (-1)) + { + differenceString = timeString.substr(differencePosition + 1); + timeString = timeString.substr(0, differencePosition); + + if((differenceString.length != 2) && (differenceString.length != 4)) + throw new Error("Wrong input string for convertion"); + + var number = new Number(differenceString.substr(0, 2)); + + if(isNaN(number.valueOf())) + throw new Error("Wrong input string for convertion"); + + hourDifference = multiplier * number; + + if(differenceString.length == 4) + { + number = new Number(differenceString.substr(2, 2)); + + if(isNaN(number.valueOf())) + throw new Error("Wrong input string for convertion"); + + minuteDifference = multiplier * number; + } + } + } + // #endregion + + // #region Get position of fraction point + var fractionPointPosition = timeString.indexOf("."); // Check for "full stop" symbol + if(fractionPointPosition == (-1)) + fractionPointPosition = timeString.indexOf(","); // Check for "comma" symbol + // #endregion + + // #region Get fraction part + if(fractionPointPosition != (-1)) + { + var fractionPartCheck = new Number("0" + timeString.substr(fractionPointPosition)); + + if(isNaN(fractionPartCheck.valueOf())) + throw new Error("Wrong input string for convertion"); + + fractionPart = fractionPartCheck.valueOf(); + + dateTimeString = timeString.substr(0, fractionPointPosition); + } + else + dateTimeString = timeString; + // #endregion + + // #region Parse internal date + switch(true) + { + case (dateTimeString.length == 8): // "YYYYMMDD" + parser = /(\d{4})(\d{2})(\d{2})/ig; + if(fractionPointPosition !== (-1)) + throw new Error("Wrong input string for convertion"); // Here we should not have a "fraction point" + break; + case (dateTimeString.length == 10): // "YYYYMMDDHH" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig; + + if(fractionPointPosition !== (-1)) + { + var fractionResult = 60 * fractionPart; + this.minute = Math.floor(fractionResult); + + fractionResult = 60 * (fractionResult - this.minute); + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case (dateTimeString.length == 12): // "YYYYMMDDHHMM" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if(fractionPointPosition !== (-1)) + { + var fractionResult = 60 * fractionPart; + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case (dateTimeString.length == 14): // "YYYYMMDDHHMMSS" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if(fractionPointPosition !== (-1)) + { + var fractionResult = 1000 * fractionPart; + this.millisecond = Math.floor(fractionResult); + } + break; + default: + throw new Error("Wrong input string for convertion"); + } + // #endregion + + // #region Put parsed values at right places + var parser_array = parser.exec(dateTimeString); + if(parser_array == null) + throw new Error("Wrong input string for convertion"); + + for(var j = 1; j < parser_array.length; j++) + { + switch(j) + { + case 1: + this.year = parseInt(parser_array[j], 10); + break; + case 2: + this.month = parseInt(parser_array[j], 10) - 1; // In JavaScript we have month range as "0 - 11" + break; + case 3: + this.day = parseInt(parser_array[j], 10); + break; + case 4: + this.hour = parseInt(parser_array[j], 10) + hourDifference; + break; + case 5: + this.minute = parseInt(parser_array[j], 10) + minuteDifference; + break; + case 6: + this.second = parseInt(parser_array[j], 10); + break; + default: + throw new Error("Wrong input string for convertion"); + } + } + // #endregion + + // #region Get final date + if(isUTC == false) + { + var tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond); + + this.year = tempDate.getUTCFullYear(); + this.month = tempDate.getUTCMonth(); + this.day = tempDate.getUTCDay(); + this.hour = tempDate.getUTCHours(); + this.minute = tempDate.getUTCMinutes(); + this.second = tempDate.getUTCSeconds(); + this.millisecond = tempDate.getUTCMilliseconds(); + } + // #endregion + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toString = + function() + { + var output_array = new Array(); + + output_array.push(in_window.org.pkijs.padNumber(this.year, 4)); + output_array.push(in_window.org.pkijs.padNumber(this.month, 2)); + output_array.push(in_window.org.pkijs.padNumber(this.day, 2)); + output_array.push(in_window.org.pkijs.padNumber(this.hour, 2)); + output_array.push(in_window.org.pkijs.padNumber(this.minute, 2)); + output_array.push(in_window.org.pkijs.padNumber(this.second, 2)); + if(this.millisecond != 0) + { + output_array.push("."); + output_array.push(in_window.org.pkijs.padNumber(this.millisecond, 3)); + } + output_array.push("Z"); + + return output_array.join(''); + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "GENERALIZEDTIME"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.VISIBLESTRING.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.block_name.call(this); + _object.year = this.year; + _object.month = this.month; + _object.day = this.day; + _object.hour = this.hour; + _object.minute = this.minute; + _object.second = this.second; + _object.millisecond = this.millisecond; + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.DATE = + function() + { + in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 31; // DATE + }; + //************************************************************************************** + in_window.org.pkijs.asn1.DATE.prototype = new in_window.org.pkijs.asn1.UTF8STRING(); + in_window.org.pkijs.asn1.DATE.constructor = in_window.org.pkijs.asn1.DATE; + //************************************************************************************** + in_window.org.pkijs.asn1.DATE.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "DATE"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.DATE.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.DATE.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.TIMEOFDAY = + function() + { + in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 32; // TIMEOFDAY + }; + //************************************************************************************** + in_window.org.pkijs.asn1.TIMEOFDAY.prototype = new in_window.org.pkijs.asn1.UTF8STRING(); + in_window.org.pkijs.asn1.TIMEOFDAY.constructor = in_window.org.pkijs.asn1.TIMEOFDAY; + //************************************************************************************** + in_window.org.pkijs.asn1.TIMEOFDAY.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "TIMEOFDAY"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.TIMEOFDAY.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.TIMEOFDAY.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.DATETIME = + function() + { + in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 33; // DATETIME + }; + //************************************************************************************** + in_window.org.pkijs.asn1.DATETIME.prototype = new in_window.org.pkijs.asn1.UTF8STRING(); + in_window.org.pkijs.asn1.DATETIME.constructor = in_window.org.pkijs.asn1.DATETIME; + //************************************************************************************** + in_window.org.pkijs.asn1.DATETIME.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "DATETIME"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.DATETIME.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.DATETIME.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.DURATION = + function() + { + in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 34; // DURATION + }; + //************************************************************************************** + in_window.org.pkijs.asn1.DURATION.prototype = new in_window.org.pkijs.asn1.UTF8STRING(); + in_window.org.pkijs.asn1.DURATION.constructor = in_window.org.pkijs.asn1.DURATION; + //************************************************************************************** + in_window.org.pkijs.asn1.DURATION.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "DURATION"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.DURATION.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.DURATION.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.TIME = + function() + { + in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]); + + this.id_block.tag_class = 1; // UNIVERSAL + this.id_block.tag_number = 14; // TIME + }; + //************************************************************************************** + in_window.org.pkijs.asn1.TIME.prototype = new in_window.org.pkijs.asn1.UTF8STRING(); + in_window.org.pkijs.asn1.TIME.constructor = in_window.org.pkijs.asn1.TIME; + //************************************************************************************** + in_window.org.pkijs.asn1.TIME.prototype.block_name = + function() + { + /// Aux function, need to get a block name. Need to have it here for inhiritence + + return "TIME"; + }; + //************************************************************************************** + in_window.org.pkijs.asn1.TIME.prototype.toJSON = + function() + { + /// Convertion for the block to JSON object + + var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this); + + _object.block_name = in_window.org.pkijs.asn1.TIME.prototype.block_name.call(this); + + return _object; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of special ASN.1 schema type CHOICE + //************************************************************************************** + in_window.org.pkijs.asn1.CHOICE = + function() + { + if(arguments[0] instanceof Object) + { + this.value = in_window.org.pkijs.getValue(arguments[0], "value", new Array()); // Array of ASN.1 types for make a choice from + this.optional = in_window.org.pkijs.getValue(arguments[0], "optional", false); + } + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of special ASN.1 schema type ANY + //************************************************************************************** + in_window.org.pkijs.asn1.ANY = + function() + { + if(arguments[0] instanceof Object) + { + this.name = in_window.org.pkijs.getValue(arguments[0], "name", ""); + this.optional = in_window.org.pkijs.getValue(arguments[0], "optional", false); + } + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of special ASN.1 schema type REPEATED + //************************************************************************************** + in_window.org.pkijs.asn1.REPEATED = + function() + { + if(arguments[0] instanceof Object) + { + this.name = in_window.org.pkijs.getValue(arguments[0], "name", ""); + this.optional = in_window.org.pkijs.getValue(arguments[0], "optional", false); + this.value = in_window.org.pkijs.getValue(arguments[0], "value", new in_window.org.pkijs.asn1.ANY()); + this.local = in_window.org.pkijs.getValue(arguments[0], "local", false); // Could local or global array to store elements + } + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Major ASN.1 BER decoding function + //************************************************************************************** + function fromBER_raw(input_buffer, input_offset, input_length) + { + var incoming_offset = input_offset; // Need to store initial offset since "input_offset" is changing in the function + + // #region Local function changing a type for ASN.1 classes + function local_change_type(input_object, new_type) + { + if(input_object instanceof new_type) + return input_object; + + var new_object = new new_type(); + new_object.id_block = input_object.id_block; + new_object.len_block = input_object.len_block; + new_object.warnings = input_object.warnings; + new_object.value_before_decode = util_copybuf(input_object.value_before_decode); + + return new_object; + } + // #endregion + + // #region Create a basic ASN.1 type since we need to return errors and warnings from the function + var return_object = new in_window.org.pkijs.asn1.ASN1_block(); + // #endregion + + // #region Basic check for parameters + if(check_buffer_params(input_buffer, input_offset, input_length) === false) + { + return_object.error = "Wrong input parameters"; + return { + offset: (-1), + result: return_object + }; + } + // #endregion + + // #region Getting Uint8Array from ArrayBuffer + var int_buffer = new Uint8Array(input_buffer, input_offset, input_length); + // #endregion + + // #region Initial checks + if(int_buffer.length == 0) + { + this.error = "Zero buffer length"; + return { + offset: (-1), + result: return_object + }; + } + // #endregion + + // #region Decode indentifcation block of ASN.1 BER structure + var result_offset = return_object.id_block.fromBER(input_buffer, input_offset, input_length); + return_object.warnings.concat(return_object.id_block.warnings); + if(result_offset == (-1)) + { + return_object.error = return_object.id_block.error; + return { + offset: (-1), + result: return_object + }; + } + + input_offset = result_offset; + input_length -= return_object.id_block.block_length; + // #endregion + + // #region Decode length block of ASN.1 BER structure + result_offset = return_object.len_block.fromBER(input_buffer, input_offset, input_length); + return_object.warnings.concat(return_object.len_block.warnings); + if(result_offset == (-1)) + { + return_object.error = return_object.len_block.error; + return { + offset: (-1), + result: return_object + }; + } + + input_offset = result_offset; + input_length -= return_object.len_block.block_length; + // #endregion + + // #region Check for usign indefinite length form in encoding for primitive types + if((return_object.id_block.is_constructed == false) && + (return_object.len_block.is_indefinite_form == true)) + { + return_object.error = new String("Indefinite length form used for primitive encoding form"); + return { + offset: (-1), + result: return_object + }; + } + // #endregion + + // #region Switch ASN.1 block type + var new_asn1_type = in_window.org.pkijs.asn1.ASN1_block; + + switch(return_object.id_block.tag_class) + { + // #region UNIVERSAL + case 1: + // #region Check for reserved tag numbers + if((return_object.id_block.tag_number >= 37) && + (return_object.id_block.is_hex_only == false)) + { + return_object.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard"; + return { + offset: (-1), + result: return_object + }; + } + // #endregion + + switch(return_object.id_block.tag_number) + { + // #region EOC type + case 0: + // #region Check for EOC type + if((return_object.id_block.is_constructed == true) && + (return_object.len_block.length > 0)) + { + return_object.error = "Type [UNIVERSAL 0] is reserved"; + return { + offset: (-1), + result: return_object + }; + } + // #endregion + + new_asn1_type = in_window.org.pkijs.asn1.EOC; + + break; + // #endregion + // #region BOOLEAN type + case 1: + new_asn1_type = in_window.org.pkijs.asn1.BOOLEAN; + break; + // #endregion + // #region INTEGER type + case 2: + new_asn1_type = in_window.org.pkijs.asn1.INTEGER; + break; + // #endregion + // #region BITSTRING type + case 3: + new_asn1_type = in_window.org.pkijs.asn1.BITSTRING; + break; + // #endregion + // #region OCTETSTRING type + case 4: + new_asn1_type = in_window.org.pkijs.asn1.OCTETSTRING; + break; + // #endregion + // #region NULL type + case 5: + new_asn1_type = in_window.org.pkijs.asn1.NULL; + break; + // #endregion + // #region OBJECT IDENTIFIER type + case 6: + new_asn1_type = in_window.org.pkijs.asn1.OID; + break; + // #endregion + // #region ENUMERATED type + case 10: + new_asn1_type = in_window.org.pkijs.asn1.ENUMERATED; + break; + // #endregion + // #region UTF8STRING type + case 12: + new_asn1_type = in_window.org.pkijs.asn1.UTF8STRING; + break; + // #endregion + // #region TIME type + case 14: + new_asn1_type = in_window.org.pkijs.asn1.TIME; + break; + // #endregion + // #region ASN.1 reserved type + case 15: + return_object.error = "[UNIVERSAL 15] is reserved by ASN.1 standard"; + return { + offset: (-1), + result: return_object + }; + break; + // #endregion + // #region SEQUENCE type + case 16: + new_asn1_type = in_window.org.pkijs.asn1.SEQUENCE; + break; + // #endregion + // #region SET type + case 17: + new_asn1_type = in_window.org.pkijs.asn1.SET; + break; + // #endregion + // #region NUMERICSTRING type + case 18: + new_asn1_type = in_window.org.pkijs.asn1.NUMERICSTRING; + break; + // #endregion + // #region PRINTABLESTRING type + case 19: + new_asn1_type = in_window.org.pkijs.asn1.PRINTABLESTRING; + break; + // #endregion + // #region TELETEXSTRING type + case 20: + new_asn1_type = in_window.org.pkijs.asn1.TELETEXSTRING; + break; + // #endregion + // #region VIDEOTEXSTRING type + case 21: + new_asn1_type = in_window.org.pkijs.asn1.VIDEOTEXSTRING; + break; + // #endregion + // #region IA5STRING type + case 22: + new_asn1_type = in_window.org.pkijs.asn1.IA5STRING; + break; + // #endregion + // #region UTCTIME type + case 23: + new_asn1_type = in_window.org.pkijs.asn1.UTCTIME; + break; + // #endregion + // #region GENERALIZEDTIME type + case 24: + new_asn1_type = in_window.org.pkijs.asn1.GENERALIZEDTIME; + break; + // #endregion + // #region GRAPHICSTRING type + case 25: + new_asn1_type = in_window.org.pkijs.asn1.GRAPHICSTRING; + break; + // #endregion + // #region VISIBLESTRING type + case 26: + new_asn1_type = in_window.org.pkijs.asn1.VISIBLESTRING; + break; + // #endregion + // #region GENERALSTRING type + case 27: + new_asn1_type = in_window.org.pkijs.asn1.GENERALSTRING; + break; + // #endregion + // #region UNIVERSALSTRING type + case 28: + new_asn1_type = in_window.org.pkijs.asn1.UNIVERSALSTRING; + break; + // #endregion + // #region CHARACTERSTRING type + case 29: + new_asn1_type = in_window.org.pkijs.asn1.CHARACTERSTRING; + break; + // #endregion + // #region BMPSTRING type + case 30: + new_asn1_type = in_window.org.pkijs.asn1.BMPSTRING; + break; + // #endregion + // #region DATE type + case 31: + new_asn1_type = in_window.org.pkijs.asn1.DATE; + break; + // #endregion + // #region TIMEOFDAY type + case 32: + new_asn1_type = in_window.org.pkijs.asn1.TIMEOFDAY; + break; + // #endregion + // #region DATE-TIME type + case 33: + new_asn1_type = in_window.org.pkijs.asn1.DATETIME; + break; + // #endregion + // #region DURATION type + case 34: + new_asn1_type = in_window.org.pkijs.asn1.DURATION; + break; + // #endregion + // #region default + default: + { + var new_object; + + if(return_object.id_block.is_constructed == true) + new_object = new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED(); + else + new_object = new in_window.org.pkijs.asn1.ASN1_PRIMITIVE(); + + new_object.id_block = return_object.id_block; + new_object.len_block = return_object.len_block; + new_object.warnings = return_object.warnings; + + return_object = new_object; + + result_offset = return_object.fromBER(input_buffer, input_offset, input_length); + } + // #endregion + } + break; + // #endregion + // #region All other tag classes + case 2: // APPLICATION + case 3: // CONTEXT-SPECIFIC + case 4: // PRIVATE + default: + { + if(return_object.id_block.is_constructed == true) + new_asn1_type = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED; + else + new_asn1_type = in_window.org.pkijs.asn1.ASN1_PRIMITIVE; + } + // #endregion + } + // #endregion + + // #region Change type and perform BER decoding + return_object = local_change_type(return_object, new_asn1_type); + result_offset = return_object.fromBER(input_buffer, input_offset, (return_object.len_block.is_indefinite_form == true) ? input_length : return_object.len_block.length); + // #endregion + + // #region Coping incoming buffer for entire ASN.1 block + return_object.value_before_decode = util_copybuf_offset(input_buffer, incoming_offset, return_object.block_length); + // #endregion + + return { + offset: result_offset, + result: return_object + }; + } + //************************************************************************************** + in_window.org.pkijs.fromBER = + function(input_buffer) + { + /// Major function for decoding ASN.1 BER array into internal library structuries + /// ASN.1 BER encoded array of bytes + + if(input_buffer.byteLength == 0) + { + var result = new in_window.org.pkijs.asn1.ASN1_block(); + result.error = "Input buffer has zero length"; + + return { + offset: (-1), + result: result + }; + } + + return fromBER_raw(input_buffer, 0, input_buffer.byteLength); + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Major scheme verification function + //************************************************************************************** + in_window.org.pkijs.compareSchema = + function(root, input_asn1_data, input_asn1_schema) + { + // #region Special case for CHOICE schema element type + if(input_asn1_schema instanceof in_window.org.pkijs.asn1.CHOICE) + { + var choice_result = false; + + for(var j = 0; j < input_asn1_schema.value.length; j++) + { + var result = in_window.org.pkijs.compareSchema(root, input_asn1_data, input_asn1_schema.value[j]); + if(result.verified === true) + return { + verified: true, + result: root + }; + } + + if(choice_result === false) + { + var _result = { + verified: false, + result: { + error: "Wrong values for CHOICE type" + } + }; + + if(input_asn1_schema.hasOwnProperty('name')) + _result.name = input_asn1_schema.name; + + return _result; + } + } + // #endregion + + // #region Special case for ANY schema element type + if(input_asn1_schema instanceof in_window.org.pkijs.asn1.ANY) + { + // #region Add named component of ASN.1 schema + if(input_asn1_schema.hasOwnProperty('name')) + root[input_asn1_schema.name] = input_asn1_data; + // #endregion + + return { + verified: true, + result: root + }; + } + // #endregion + + // #region Initial check + if((root instanceof Object) === false) + return { + verified: false, + result: { error: "Wrong root object" } + }; + + if((input_asn1_data instanceof Object) === false) + return { + verified: false, + result: { error: "Wrong ASN.1 data" } + }; + + if((input_asn1_schema instanceof Object) === false) + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + + if(('id_block' in input_asn1_schema) === false) + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + // #endregion + + // #region Comparing id_block properties in ASN.1 data and ASN.1 schema + // #region Encode and decode ASN.1 schema id_block + /// This encoding/decoding is neccessary because could be an errors in schema definition + if(('fromBER' in input_asn1_schema.id_block) === false) + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + + if(('toBER' in input_asn1_schema.id_block) === false) + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + + var encoded_id = input_asn1_schema.id_block.toBER(false); + if(encoded_id.byteLength === 0) + return { + verified: false, + result: { error: "Error encoding id_block for ASN.1 schema" } + }; + + var decoded_offset = input_asn1_schema.id_block.fromBER(encoded_id, 0, encoded_id.byteLength); + if(decoded_offset === (-1)) + return { + verified: false, + result: { error: "Error decoding id_block for ASN.1 schema" } + }; + // #endregion + + // #region tag_class + if(input_asn1_schema.id_block.hasOwnProperty('tag_class') === false) + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + + if(input_asn1_schema.id_block.tag_class !== input_asn1_data.id_block.tag_class) + return { + verified: false, + result: root + }; + // #endregion + // #region tag_number + if(input_asn1_schema.id_block.hasOwnProperty('tag_number') === false) + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + + if(input_asn1_schema.id_block.tag_number !== input_asn1_data.id_block.tag_number) + return { + verified: false, + result: root + }; + // #endregion + // #region is_constructed + if(input_asn1_schema.id_block.hasOwnProperty('is_constructed') === false) + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + + if(input_asn1_schema.id_block.is_constructed !== input_asn1_data.id_block.is_constructed) + return { + verified: false, + result: root + }; + // #endregion + // #region is_hex_only + if(('is_hex_only' in input_asn1_schema.id_block) === false) // Since 'is_hex_only' is an inhirited property + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + + if(input_asn1_schema.id_block.is_hex_only !== input_asn1_data.id_block.is_hex_only) + return { + verified: false, + result: root + }; + // #endregion + // #region value_hex + if(input_asn1_schema.id_block.is_hex_only === true) + { + if(('value_hex' in input_asn1_schema.id_block) === false) // Since 'value_hex' is an inhirited property + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + + var schema_view = new Uint8Array(input_asn1_schema.id_block.value_hex); + var asn1_view = new Uint8Array(input_asn1_data.id_block.value_hex); + + if(schema_view.length !== asn1_view.length) + return { + verified: false, + result: root + }; + + for(var i = 0; i < schema_view.length; i++) + { + if(schema_view[i] !== asn1_view[1]) + return { + verified: false, + result: root + }; + } + } + // #endregion + // #endregion + + // #region Add named component of ASN.1 schema + if(input_asn1_schema.hasOwnProperty('name')) + { + input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, ''); + if(input_asn1_schema.name !== "") + root[input_asn1_schema.name] = input_asn1_data; + } + // #endregion + + // #region Getting next ASN.1 block for comparition + if(input_asn1_schema.id_block.is_constructed === true) + { + var admission = 0; + var result = { verified: false }; + + var max_length = input_asn1_schema.value_block.value.length; + + if(max_length > 0) + { + if(input_asn1_schema.value_block.value[0] instanceof in_window.org.pkijs.asn1.REPEATED) + max_length = input_asn1_data.value_block.value.length; + } + + // #region Special case when constructive value has no elements + if(max_length === 0) + return { + verified: true, + result: root + }; + // #endregion + + // #region Special case when "input_asn1_data" has no values and "input_asn1_schema" has all optional values + if((input_asn1_data.value_block.value.length === 0) && + (input_asn1_schema.value_block.value.length !== 0)) + { + var _optional = true; + + for(var i = 0; i < input_asn1_schema.value_block.value.length; i++) + _optional = _optional && (input_asn1_schema.value_block.value[i].optional || false); + + if(_optional === true) + { + return { + verified: true, + result: root + }; + } + else + { + // #region Delete early added name of block + if(input_asn1_schema.hasOwnProperty('name')) + { + input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, ''); + if(input_asn1_schema.name !== "") + delete root[input_asn1_schema.name]; + } + // #endregion + + root.error = "Inconsistent object length"; + + return { + verified: false, + result: root + }; + } + } + // #endregion + + for(var i = 0; i < max_length; i++) + { + // #region Special case when there is an "optional" element of ASN.1 schema at the end + if((i - admission) >= input_asn1_data.value_block.value.length) + { + if(input_asn1_schema.value_block.value[i].optional === false) + { + var _result = { + verified: false, + result: root + }; + + root.error = "Inconsistent length between ASN.1 data and schema"; + + // #region Delete early added name of block + if(input_asn1_schema.hasOwnProperty('name')) + { + input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, ''); + if(input_asn1_schema.name !== "") + { + delete root[input_asn1_schema.name]; + _result.name = input_asn1_schema.name; + } + } + // #endregion + + return _result; + } + } + // #endregion + else + { + // #region Special case for REPEATED type of ASN.1 schema element + if(input_asn1_schema.value_block.value[0] instanceof in_window.org.pkijs.asn1.REPEATED) + { + result = in_window.org.pkijs.compareSchema(root, input_asn1_data.value_block.value[i], input_asn1_schema.value_block.value[0].value); + if(result.verified === false) + { + if(input_asn1_schema.value_block.value[0].optional === true) + admission++; + else + { + // #region Delete early added name of block + if(input_asn1_schema.hasOwnProperty('name')) + { + input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, ''); + if(input_asn1_schema.name !== "") + delete root[input_asn1_schema.name]; + } + // #endregion + + return result; + } + } + + if(("name" in input_asn1_schema.value_block.value[0]) && (input_asn1_schema.value_block.value[0].name.length > 0)) + { + var array_root = {}; + + if(("local" in input_asn1_schema.value_block.value[0]) && (input_asn1_schema.value_block.value[0].local === true)) + array_root = input_asn1_data; + else + array_root = root; + + if(typeof array_root[input_asn1_schema.value_block.value[0].name] === "undefined") + array_root[input_asn1_schema.value_block.value[0].name] = new Array(); + + array_root[input_asn1_schema.value_block.value[0].name].push(input_asn1_data.value_block.value[i]); + } + } + // #endregion + else + { + result = in_window.org.pkijs.compareSchema(root, input_asn1_data.value_block.value[i - admission], input_asn1_schema.value_block.value[i]); + if(result.verified === false) + { + if(input_asn1_schema.value_block.value[i].optional === true) + admission++; + else + { + // #region Delete early added name of block + if(input_asn1_schema.hasOwnProperty('name')) + { + input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, ''); + if(input_asn1_schema.name !== "") + delete root[input_asn1_schema.name]; + } + // #endregion + + return result; + } + } + } + } + } + + if(result.verified === false) // The situation may take place if last element is "optional" and verification failed + { + var _result = { + verified: false, + result: root + }; + + // #region Delete early added name of block + if(input_asn1_schema.hasOwnProperty('name')) + { + input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, ''); + if(input_asn1_schema.name !== "") + { + delete root[input_asn1_schema.name]; + _result.name = input_asn1_schema.name; + } + } + // #endregion + + return _result; + } + + return { + verified: true, + result: root + }; + } + // #endregion + // #region Ability to parse internal value for primitive-encoded value (value of OCTETSTRING, for example) + else + { + if( ("primitive_schema" in input_asn1_schema) && + ("value_hex" in input_asn1_data.value_block) ) + { + // #region Decoding of raw ASN.1 data + var asn1 = in_window.org.pkijs.fromBER(input_asn1_data.value_block.value_hex); + if(asn1.offset === (-1)) + { + var _result = { + verified: false, + result: asn1.result + }; + + // #region Delete early added name of block + if(input_asn1_schema.hasOwnProperty('name')) + { + input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, ''); + if(input_asn1_schema.name !== "") + { + delete root[input_asn1_schema.name]; + _result.name = input_asn1_schema.name; + } + } + // #endregion + + return _result; + } + // #endregion + + return in_window.org.pkijs.compareSchema(root, asn1.result, input_asn1_schema.primitive_schema); + } + else + return { + verified: true, + result: root + }; + } + // #endregion + }; + //************************************************************************************** + in_window.org.pkijs.verifySchema = + function(input_buffer, input_schema) + { + // #region Initial check + if((input_schema instanceof Object) === false) + return { + verified: false, + result: { error: "Wrong ASN.1 schema type" } + }; + // #endregion + + // #region Decoding of raw ASN.1 data + var asn1 = in_window.org.pkijs.fromBER(input_buffer); + if(asn1.offset === (-1)) + return { + verified: false, + result: asn1.result + }; + // #endregion + + // #region Compare ASN.1 struct with input schema + return in_window.org.pkijs.compareSchema(asn1.result, asn1.result, input_schema); + // #endregion + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Major function converting JSON to ASN.1 objects + //************************************************************************************** + in_window.org.pkijs.fromJSON = + function(json) + { + /// Converting from JSON to ASN.1 objects + /// JSON string or object to convert to ASN.1 objects + }; + //************************************************************************************** + // #endregion + //************************************************************************************** +} +)(typeof exports !== "undefined" ? exports : window); \ No newline at end of file -- cgit v1.2.3