diff options
Diffstat (limited to 'dom/webauthn/tests/pkijs/common.js')
-rw-r--r-- | dom/webauthn/tests/pkijs/common.js | 1542 |
1 files changed, 1542 insertions, 0 deletions
diff --git a/dom/webauthn/tests/pkijs/common.js b/dom/webauthn/tests/pkijs/common.js new file mode 100644 index 0000000000..1bc9eda7f8 --- /dev/null +++ b/dom/webauthn/tests/pkijs/common.js @@ -0,0 +1,1542 @@ +/* + * Copyright (c) 2014, GMO GlobalSign + * Copyright (c) 2015, Peculiar Ventures + * All rights reserved. + * + * Author 2014-2015, Yury Strozhevsky <www.strozhevsky.com>. + * + * 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 "local" namespace + var local = {}; + // #endregion + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Settings for "crypto engine" + //************************************************************************************** + local.engine = { + name: "none", + crypto: null, + subtle: null + }; + + if(typeof window != "undefined") + { + if("crypto" in window) + { + var engineName = "webcrypto"; + var cryptoObject = window.crypto; + var subtleObject = null; + + // Apple Safari support + if("webkitSubtle" in window.crypto) + subtleObject = window.crypto.webkitSubtle; + + if("subtle" in window.crypto) + subtleObject = window.crypto.subtle; + + local.engine = { + name: engineName, + crypto: cryptoObject, + subtle: subtleObject + }; + } + } + //************************************************************************************** + in_window.org.pkijs.setEngine = + function(name, crypto, subtle) + { + /// <summary>Setting the global "crypto engine" parameters</summary> + /// <param name="name" type="String">Auxiliary name for "crypto engine"</param> + /// <param name="crypto" type="Object">Object handling all root cryptographic requests (in fact currently it must handle only "getRandomValues")</param> + /// <param name="subtle" type="Object">Object handling all main cryptographic requests</param> + + local.engine = { + name: name, + crypto: crypto, + subtle: subtle + }; + }; + //************************************************************************************** + in_window.org.pkijs.getEngine = + function() + { + return local.engine; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** + // #region Declaration of common functions + //************************************************************************************** + in_window.org.pkijs.emptyObject = + function() + { + this.toJSON = function() + { + return {}; + }; + this.toSchema = function() + { + return {}; + }; + }; + //************************************************************************************** + in_window.org.pkijs.getNames = + function(arg) + { + /// <summary>Get correct "names" array for all "schema" objects</summary> + + var names = {}; + + if(arg instanceof Object) + names = (arg.names || {}); + + return names; + }; + //************************************************************************************** + in_window.org.pkijs.inheriteObjectFields = + function(from) + { + for(var i in from.prototype) + { + if(typeof from.prototype[i] === "function") + continue; + + this[i] = from.prototype[i]; + } + }; + //************************************************************************************** + in_window.org.pkijs.getUTCDate = + function(date) + { + /// <summary>Making UTC date from local date</summary> + /// <param name="date" type="Date">Date to convert from</param> + + var current_date = date; + return new Date(current_date.getTime() + (current_date.getTimezoneOffset() * 60000)); + }; + //************************************************************************************** + in_window.org.pkijs.padNumber = + function(input_number, full_length) + { + var str = input_number.toString(10); + var dif = full_length - str.length; + + var padding = new Array(dif); + for(var i = 0; i < dif; i++) + padding[i] = '0'; + + var padding_string = padding.join(''); + + return padding_string.concat(str); + }; + //************************************************************************************** + in_window.org.pkijs.getValue = + function(args, item, default_value) + { + if(item in args) + return args[item]; + else + return default_value; + }; + //************************************************************************************** + in_window.org.pkijs.isEqual_view = + function(input_view1, input_view2) + { + /// <summary>Compare two Uint8Arrays</summary> + /// <param name="input_view1" type="Uint8Array">First Uint8Array for comparision</param> + /// <param name="input_view2" type="Uint8Array">Second Uint8Array for comparision</param> + + if(input_view1.length !== input_view2.length) + return false; + + for(var i = 0; i < input_view1.length; i++) + { + if(input_view1[i] != input_view2[i]) + return false; + } + + return true; + }; + //************************************************************************************** + in_window.org.pkijs.isEqual_buffer = + function(input_buffer1, input_buffer2) + { + /// <summary>Compare two array buffers</summary> + /// <param name="input_buffer1" type="ArrayBuffer">First ArrayBuffer for comparision</param> + /// <param name="input_buffer2" type="ArrayBuffer">Second ArrayBuffer for comparision</param> + + if(input_buffer1.byteLength != input_buffer2.byteLength) + return false; + + var view1 = new Uint8Array(input_buffer1); + var view2 = new Uint8Array(input_buffer2); + + return in_window.org.pkijs.isEqual_view(view1, view2); + }; + //************************************************************************************** + in_window.org.pkijs.concat_buffers = + function(input_buf1, input_buf2) + { + /// <summary>Concatenate two ArrayBuffers</summary> + /// <param name="input_buf1" type="ArrayBuffer">First ArrayBuffer (first part of concatenated array)</param> + /// <param name="input_buf2" type="ArrayBuffer">Second ArrayBuffer (second part of concatenated array)</param> + + 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; + }; + //************************************************************************************** + in_window.org.pkijs.copyBuffer = + function(input_buffer) + { + var result = new ArrayBuffer(input_buffer.byteLength); + + var resultView = new Uint8Array(result); + var inputView = new Uint8Array(input_buffer); + + for(var i = 0; i < inputView.length; i++) + resultView[i] = inputView[i]; + + return result; + }; + //************************************************************************************** + in_window.org.pkijs.getCrypto = + function() + { + var crypto_temp; + + if(local.engine.subtle !== null) + crypto_temp = local.engine.subtle; + + return crypto_temp; + }; + //************************************************************************************** + in_window.org.pkijs.stringPrep = + function(input_string) + { + /// <summary>String preparation function. In a future here will be realization of algorithm from RFC4518.</summary> + /// <param name="input_string" type="String">JavaScript string. As soon as for each ASN.1 string type we have a specific transformation function here we will work with pure JavaScript string</param> + /// <returns type="String">Formated string</returns> + + var result = input_string.replace(/^\s+|\s+$/g, ""); // Trim input string + result = result.replace(/\s+/g, " "); // Change all sequence of SPACE down to SPACE char + result = result.toLowerCase(); + + return result; + }; + //************************************************************************************** + in_window.org.pkijs.bufferToHexCodes = + function(input_buffer, input_offset, input_lenght) + { + 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; + }; + //************************************************************************************** + in_window.org.pkijs.bufferFromHexCodes = + function(hexString) + { + /// <summary>Create an ArrayBuffer from string having hexdecimal codes</summary> + /// <param name="hexString" type="String">String to create ArrayBuffer from</param> + + // #region Initial variables + var stringLength = hexString.length; + + var resultBuffer = new ArrayBuffer(stringLength >> 1); + var resultView = new Uint8Array(resultBuffer); + + var hex_map = {}; + + hex_map['0'] = 0x00; + hex_map['1'] = 0x01; + hex_map['2'] = 0x02; + hex_map['3'] = 0x03; + hex_map['4'] = 0x04; + hex_map['5'] = 0x05; + hex_map['6'] = 0x06; + hex_map['7'] = 0x07; + hex_map['8'] = 0x08; + hex_map['9'] = 0x09; + hex_map['A'] = 0x0A; + hex_map['a'] = 0x0A; + hex_map['B'] = 0x0B; + hex_map['b'] = 0x0B; + hex_map['C'] = 0x0C; + hex_map['c'] = 0x0C; + hex_map['D'] = 0x0D; + hex_map['d'] = 0x0D; + hex_map['E'] = 0x0E; + hex_map['e'] = 0x0E; + hex_map['F'] = 0x0F; + hex_map['f'] = 0x0F; + + var j = 0; + var temp = 0x00; + // #endregion + + // #region Convert char-by-char + for(var i = 0; i < stringLength; i++) + { + if(!(i % 2)) + temp = hex_map[hexString.charAt(i)] << 4; + else + { + temp |= hex_map[hexString.charAt(i)]; + + resultView[j] = temp; + j++; + } + } + // #endregion + + return resultBuffer; + }; + //************************************************************************************** + in_window.org.pkijs.getRandomValues = + function(view) + { + /// <param name="view" type="Uint8Array">New array which gives a length for random value</param> + + if(local.engine.crypto !== null) + return local.engine.crypto.getRandomValues(view); + else + throw new Error("No support for Web Cryptography API"); + }; + //************************************************************************************** + in_window.org.pkijs.getAlgorithmParameters = + function(algorithmName, operation) + { + /// <param name="algorithmName" type="String">Algorithm name to get common parameters for</param> + /// <param name="operation" type="String">Kind of operation: "sign", "encrypt", "generatekey", "importkey", "exportkey", "verify"</param> + + var result = { + algorithm: {}, + usages: [] + }; + + switch(algorithmName.toUpperCase()) + { + case "RSASSA-PKCS1-V1_5": + switch(operation.toLowerCase()) + { + case "generatekey": + result = { + algorithm: { + name: "RSASSA-PKCS1-v1_5", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { + name: "SHA-256" + } + }, + usages: ["sign", "verify"] + }; + break; + case "verify": + case "sign": + case "importkey": + result = { + algorithm: { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-256" + } + }, + usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only + }; + break; + case "exportkey": + default: + return { + algorithm: { + name: "RSASSA-PKCS1-v1_5" + }, + usages: [] + }; + } + break; + case "RSA-PSS": + switch(operation.toLowerCase()) + { + case "sign": + case "verify": + result = { + algorithm: { + name: "RSA-PSS", + hash: { + name: "SHA-1" + }, + saltLength: 20 + }, + usages: ["sign", "verify"] + }; + break; + case "generatekey": + result = { + algorithm: { + name: "RSA-PSS", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { + name: "SHA-1" + } + }, + usages: ["sign", "verify"] + }; + break; + case "importkey": + result = { + algorithm: { + name: "RSA-PSS", + hash: { + name: "SHA-1" + } + }, + usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only + }; + break; + case "exportkey": + default: + return { + algorithm: { + name: "RSA-PSS" + }, + usages: [] + }; + } + break; + case "RSA-OAEP": + switch(operation.toLowerCase()) + { + case "encrypt": + case "decrypt": + result = { + algorithm: { + name: "RSA-OAEP" + }, + usages: ["encrypt", "decrypt"] + }; + break; + break; + case "generatekey": + result = { + algorithm: { + name: "RSA-OAEP", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { + name: "SHA-256" + } + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + case "importkey": + result = { + algorithm: { + name: "RSA-OAEP", + hash: { + name: "SHA-256" + } + }, + usages: ["encrypt"] // encrypt for "spki" and decrypt for "pkcs8" + }; + break; + case "exportkey": + default: + return { + algorithm: { + name: "RSA-OAEP" + }, + usages: [] + }; + } + break; + case "ECDSA": + switch(operation.toLowerCase()) + { + case "generatekey": + result = { + algorithm: { + name: "ECDSA", + namedCurve: "P-256" + }, + usages: ["sign", "verify"] + }; + break; + case "importkey": + result = { + algorithm: { + name: "ECDSA", + namedCurve: "P-256" + }, + usages: ["verify"] // "sign" for "pkcs8" + }; + break; + case "verify": + case "sign": + result = { + algorithm: { + name: "ECDSA", + hash: { + name: "SHA-256" + } + }, + usages: ["sign"] + }; + break; + default: + return { + algorithm: { + name: "ECDSA" + }, + usages: [] + }; + } + break; + case "ECDH": + switch(operation.toLowerCase()) + { + case "exportkey": + case "importkey": + case "generatekey": + result = { + algorithm: { + name: "ECDH", + namedCurve: "P-256" + }, + usages: ["deriveKey", "deriveBits"] + }; + break; + case "derivekey": + case "derivebits": + result = { + algorithm: { + name: "ECDH", + namedCurve: "P-256", + public: [] // Must be a "publicKey" + }, + usages: ["encrypt", "decrypt"] + }; + break; + default: + return { + algorithm: { + name: "ECDH" + }, + usages: [] + }; + } + break; + case "AES-CTR": + switch(operation.toLowerCase()) + { + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "AES-CTR", + length: 256 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + case "decrypt": + case "encrypt": + result = { + algorithm: { + name: "AES-CTR", + counter: new Uint8Array(16), + length: 10 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + default: + return { + algorithm: { + name: "AES-CTR" + }, + usages: [] + }; + } + break; + case "AES-CBC": + switch(operation.toLowerCase()) + { + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "AES-CBC", + length: 256 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + case "decrypt": + case "encrypt": + result = { + algorithm: { + name: "AES-CBC", + iv: in_window.org.pkijs.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + default: + return { + algorithm: { + name: "AES-CBC" + }, + usages: [] + }; + } + break; + case "AES-GCM": + switch(operation.toLowerCase()) + { + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "AES-GCM", + length: 256 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + case "decrypt": + case "encrypt": + result = { + algorithm: { + name: "AES-GCM", + iv: in_window.org.pkijs.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + default: + return { + algorithm: { + name: "AES-GCM" + }, + usages: [] + }; + } + break; + case "AES-KW": + switch(operation.toLowerCase()) + { + case "importkey": + case "exportkey": + case "generatekey": + case "wrapkey": + case "unwrapkey": + result = { + algorithm: { + name: "AES-KW", + length: 256 + }, + usages: ["wrapKey", "unwrapKey"] + }; + break; + default: + return { + algorithm: { + name: "AES-KW" + }, + usages: [] + }; + } + break; + case "HMAC": + switch(operation.toLowerCase()) + { + case "sign": + case "verify": + result = { + algorithm: { + name: "HMAC" + }, + usages: ["sign", "verify"] + }; + break; + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "HMAC", + length: 32, + hash: { + name: "SHA-256" + } + }, + usages: ["sign", "verify"] + }; + break; + default: + return { + algorithm: { + name: "HMAC" + }, + usages: [] + }; + } + break; + case "HKDF": + switch(operation.toLowerCase()) + { + case "derivekey": + result = { + algorithm: { + name: "HKDF", + hash: "SHA-256", + salt: new Uint8Array(), + info: new Uint8Array() + }, + usages: ["encrypt", "decrypt"] + }; + break; + default: + return { + algorithm: { + name: "HKDF" + }, + usages: [] + }; + } + break; + case "PBKDF2": + switch(operation.toLowerCase()) + { + case "derivekey": + result = { + algorithm: { + name: "PBKDF2", + hash: { name: "SHA-256" }, + salt: new Uint8Array(), + iterations: 1000 + }, + usages: ["encrypt", "decrypt"] + }; + break; + default: + return { + algorithm: { + name: "PBKDF2" + }, + usages: [] + }; + } + break; + default: + } + + return result; + }; + //************************************************************************************** + in_window.org.pkijs.getOIDByAlgorithm = + function(algorithm) + { + /// <summary>Get OID for each specific WebCrypto algorithm</summary> + /// <param name="algorithm" type="Object">WebCrypto algorithm</param> + + var result = ""; + + switch(algorithm.name.toUpperCase()) + { + case "RSASSA-PKCS1-V1_5": + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + result = "1.2.840.113549.1.1.5"; + break; + case "SHA-256": + result = "1.2.840.113549.1.1.11"; + break; + case "SHA-384": + result = "1.2.840.113549.1.1.12"; + break; + case "SHA-512": + result = "1.2.840.113549.1.1.13"; + break; + default: + } + break; + case "RSA-PSS": + result = "1.2.840.113549.1.1.10"; + break; + case "RSA-OAEP": + result = "1.2.840.113549.1.1.7"; + break; + case "ECDSA": + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + result = "1.2.840.10045.4.1"; + break; + case "SHA-256": + result = "1.2.840.10045.4.3.2"; + break; + case "SHA-384": + result = "1.2.840.10045.4.3.3"; + break; + case "SHA-512": + result = "1.2.840.10045.4.3.4"; + break; + default: + } + break; + case "ECDH": + switch(algorithm.kdf.toUpperCase()) // Non-standard addition - hash algorithm of KDF function + { + case "SHA-1": + result = "1.3.133.16.840.63.0.2"; // dhSinglePass-stdDH-sha1kdf-scheme + break; + case "SHA-256": + result = "1.3.132.1.11.1"; // dhSinglePass-stdDH-sha256kdf-scheme + break; + case "SHA-384": + result = "1.3.132.1.11.2"; // dhSinglePass-stdDH-sha384kdf-scheme + break; + case "SHA-512": + result = "1.3.132.1.11.3"; // dhSinglePass-stdDH-sha512kdf-scheme + break; + default: + } + break; + case "AES-CTR": + break; + case "AES-CBC": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.2"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.22"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.42"; + break; + default: + } + break; + case "AES-CMAC": + break; + case "AES-GCM": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.6"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.26"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.46"; + break; + default: + } + break; + case "AES-CFB": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.4"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.24"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.44"; + break; + default: + } + break; + case "AES-KW": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.5"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.25"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.45"; + break; + default: + } + break; + case "HMAC": + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + result = "1.2.840.113549.2.7"; + break; + case "SHA-256": + result = "1.2.840.113549.2.9"; + break; + case "SHA-384": + result = "1.2.840.113549.2.10"; + break; + case "SHA-512": + result = "1.2.840.113549.2.11"; + break; + default: + } + break; + case "DH": + result = "1.2.840.113549.1.9.16.3.5"; + break; + case "SHA-1": + result = "1.3.14.3.2.26"; + break; + case "SHA-256": + result = "2.16.840.1.101.3.4.2.1"; + break; + case "SHA-384": + result = "2.16.840.1.101.3.4.2.2"; + break; + case "SHA-512": + result = "2.16.840.1.101.3.4.2.3"; + break; + case "CONCAT": + break; + case "HKDF": + break; + case "PBKDF2": + result = "1.2.840.113549.1.5.12"; + break; + // #region Special case - OIDs for ECC curves + case "P-256": + result = "1.2.840.10045.3.1.7"; + break; + case "P-384": + result = "1.3.132.0.34"; + break; + case "P-521": + result = "1.3.132.0.35"; + break; + // #endregion + + default: + } + + return result; + }; + //************************************************************************************** + in_window.org.pkijs.getAlgorithmByOID = + function(oid) + { + /// <summary>Get WebCrypto algorithm by wel-known OID</summary> + /// <param name="oid" type="String">Wel-known OID to search for</param> + + var result = {}; + + switch(oid) + { + case "1.2.840.113549.1.1.5": + result = { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-1" + } + }; + break; + case "1.2.840.113549.1.1.11": + result = { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-256" + } + }; + break; + case "1.2.840.113549.1.1.12": + result = { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-384" + } + }; + break; + case "1.2.840.113549.1.1.13": + result = { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-512" + } + }; + break; + case "1.2.840.113549.1.1.10": + result = { + name: "RSA-PSS" + }; + break; + case "1.2.840.113549.1.1.7": + result = { + name: "RSA-OAEP" + }; + break; + case "1.2.840.10045.4.1": + result = { + name: "ECDSA", + hash: { + name: "SHA-1" + } + }; + break; + case "1.2.840.10045.4.3.2": + result = { + name: "ECDSA", + hash: { + name: "SHA-256" + } + }; + break; + case "1.2.840.10045.4.3.3": + result = { + name: "ECDSA", + hash: { + name: "SHA-384" + } + }; + break; + case "1.2.840.10045.4.3.4": + result = { + name: "ECDSA", + hash: { + name: "SHA-512" + } + }; + break; + case "1.3.133.16.840.63.0.2": + result = { + name: "ECDH", + kdf: "SHA-1" + }; + break; + case "1.3.132.1.11.1": + result = { + name: "ECDH", + kdf: "SHA-256" + }; + break; + case "1.3.132.1.11.2": + result = { + name: "ECDH", + kdf: "SHA-384" + }; + break; + case "1.3.132.1.11.3": + result = { + name: "ECDH", + kdf: "SHA-512" + }; + break; + case "2.16.840.1.101.3.4.1.2": + result = { + name: "AES-CBC", + length: 128 + }; + break; + case "2.16.840.1.101.3.4.1.22": + result = { + name: "AES-CBC", + length: 192 + }; + break; + case "2.16.840.1.101.3.4.1.42": + result = { + name: "AES-CBC", + length: 256 + }; + break; + case "2.16.840.1.101.3.4.1.6": + result = { + name: "AES-GCM", + length: 128 + }; + break; + case "2.16.840.1.101.3.4.1.26": + result = { + name: "AES-GCM", + length: 192 + }; + break; + case "2.16.840.1.101.3.4.1.46": + result = { + name: "AES-GCM", + length: 256 + }; + break; + case "2.16.840.1.101.3.4.1.4": + result = { + name: "AES-CFB", + length: 128 + }; + break; + case "2.16.840.1.101.3.4.1.24": + result = { + name: "AES-CFB", + length: 192 + }; + break; + case "2.16.840.1.101.3.4.1.44": + result = { + name: "AES-CFB", + length: 256 + }; + break; + case "2.16.840.1.101.3.4.1.5": + result = { + name: "AES-KW", + length: 128 + }; + break; + case "2.16.840.1.101.3.4.1.25": + result = { + name: "AES-KW", + length: 192 + }; + break; + case "2.16.840.1.101.3.4.1.45": + result = { + name: "AES-KW", + length: 256 + }; + break; + case "1.2.840.113549.2.7": + result = { + name: "HMAC", + hash: { + name: "SHA-1" + } + }; + break; + case "1.2.840.113549.2.9": + result = { + name: "HMAC", + hash: { + name: "SHA-256" + } + }; + break; + case "1.2.840.113549.2.10": + result = { + name: "HMAC", + hash: { + name: "SHA-384" + } + }; + break; + case "1.2.840.113549.2.11": + result = { + name: "HMAC", + hash: { + name: "SHA-512" + } + }; + break; + case "1.2.840.113549.1.9.16.3.5": + result = { + name: "DH" + }; + break; + case "1.3.14.3.2.26": + result = { + name: "SHA-1" + }; + break; + case "2.16.840.1.101.3.4.2.1": + result = { + name: "SHA-256" + }; + break; + case "2.16.840.1.101.3.4.2.2": + result = { + name: "SHA-384" + }; + break; + case "2.16.840.1.101.3.4.2.3": + result = { + name: "SHA-512" + }; + break; + case "1.2.840.113549.1.5.12": + result = { + name: "PBKDF2" + }; + break; + // #region Special case - OIDs for ECC curves + case "1.2.840.10045.3.1.7": + result = { + name: "P-256" + }; + break; + case "1.3.132.0.34": + result = { + name: "P-384" + }; + break; + case "1.3.132.0.35": + result = { + name: "P-521" + }; + break; + // #endregion + + default: + } + + return result; + }; + //************************************************************************************** + in_window.org.pkijs.getHashAlgorithm = + function(signatureAlgorithm) + { + /// <summary>Getting hash algorithm by signature algorithm</summary> + /// <param name="signatureAlgorithm" type="in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER">Signature algorithm</param> + + var result = ""; + + switch(signatureAlgorithm.algorithm_id) + { + case "1.2.840.10045.4.1": // ecdsa-with-SHA1 + case "1.2.840.113549.1.1.5": + result = "SHA-1"; + break; + case "1.2.840.10045.4.3.2": // ecdsa-with-SHA256 + case "1.2.840.113549.1.1.11": + result = "SHA-256"; + break; + case "1.2.840.10045.4.3.3": // ecdsa-with-SHA384 + case "1.2.840.113549.1.1.12": + result = "SHA-384"; + break; + case "1.2.840.10045.4.3.4": // ecdsa-with-SHA512 + case "1.2.840.113549.1.1.13": + result = "SHA-512"; + break; + case "1.2.840.113549.1.1.10": // RSA-PSS + { + var params; + + try + { + params = new in_window.org.pkijs.simpl.x509.RSASSA_PSS_params({ schema: signatureAlgorithm.algorithm_params }); + if("hashAlgorithm" in params) + { + var algorithm = in_window.org.pkijs.getAlgorithmByOID(params.hashAlgorithm.algorithm_id); + if(("name" in algorithm) === false) + return ""; + + result = algorithm.name; + } + else + result = "SHA-1"; + } + catch(ex) + { + } + } + break; + default: + } + + return result; + }; + //************************************************************************************** + in_window.org.pkijs.createCMSECDSASignature = + function(signatureBuffer) + { + /// <summary>Create CMS ECDSA signature from WebCrypto ECDSA signature</summary> + /// <param name="signatureBuffer" type="ArrayBuffer">WebCrypto result of "sign" function</param> + + // #region Initial check for correct length + if((signatureBuffer.byteLength % 2) != 0) + return new ArrayBuffer(0); + // #endregion + + // #region Initial variables + var i = 0; + var length = signatureBuffer.byteLength / 2; // There are two equal parts inside incoming ArrayBuffer + + var signatureView = new Uint8Array(signatureBuffer); + + var r_buffer = new ArrayBuffer(length); + var r_view = new Uint8Array(r_buffer); + var r_corrected_buffer; + var r_corrected_view; + + var s_buffer = new ArrayBuffer(length); + var s_view = new Uint8Array(s_buffer); + var s_corrected_buffer; + var s_corrected_view; + // #endregion + + // #region Get "r" part of ECDSA signature + for(; i < length; i++) + r_view[i] = signatureView[i]; + + if(r_view[0] & 0x80) + { + r_corrected_buffer = new ArrayBuffer(length + 1); + r_corrected_view = new Uint8Array(r_corrected_buffer); + + r_corrected_view[0] = 0x00; + + for(var j = 0; j < length; j++) + r_corrected_view[j + 1] = r_view[j]; + } + else + { + r_corrected_buffer = r_buffer; + r_corrected_view = r_view; + } + // #endregion + + // #region Get "s" part of ECDSA signature + for(; i < signatureBuffer.byteLength; i++) + s_view[i - length] = signatureView[i]; + + + if(s_view[0] & 0x80) + { + s_corrected_buffer = new ArrayBuffer(length + 1); + s_corrected_view = new Uint8Array(s_corrected_buffer); + + s_corrected_view[0] = 0x00; + + for(var j = 0; j < length; j++) + s_corrected_view[j + 1] = s_view[j]; + } + else + { + s_corrected_buffer = s_buffer; + s_corrected_view = s_view; + } + // #endregion + + // #region Create ASN.1 structure of CMS ECDSA signature + var r_integer = new in_window.org.pkijs.asn1.INTEGER(); + r_integer.value_block.is_hex_only = true; + r_integer.value_block.value_hex = in_window.org.pkijs.copyBuffer(r_corrected_buffer); + + var s_integer = new in_window.org.pkijs.asn1.INTEGER(); + s_integer.value_block.is_hex_only = true; + s_integer.value_block.value_hex = in_window.org.pkijs.copyBuffer(s_corrected_buffer); + + var asn1 = new in_window.org.pkijs.asn1.SEQUENCE({ + value: [ + r_integer, + s_integer + ] + }); + // #endregion + + return asn1.toBER(false); + }; + //************************************************************************************** + in_window.org.pkijs.createECDSASignatureFromCMS = + function(cmsSignature) + { + /// <summary>Create a single ArrayBuffer from CMS ECDSA signature</summary> + /// <param name="cmsSignature" type="in_window.org.pkijs.asn1.SEQUENCE">ASN.1 SEQUENCE contains CMS ECDSA signature</param> + + // #region Initial variables + var length = 0; + + var r_start = 0; + var s_start = 0; + + var r_length = cmsSignature.value_block.value[0].value_block.value_hex.byteLength; + var s_length = cmsSignature.value_block.value[1].value_block.value_hex.byteLength; + // #endregion + + // #region Get length of final "ArrayBuffer" + var r_view = new Uint8Array(cmsSignature.value_block.value[0].value_block.value_hex); + if((r_view[0] === 0x00) && (r_view[1] & 0x80)) + { + length = r_length - 1; + r_start = 1; + } + else + length = r_length; + + var s_view = new Uint8Array(cmsSignature.value_block.value[1].value_block.value_hex); + if((s_view[0] === 0x00) && (s_view[1] & 0x80)) + { + length += s_length - 1; + s_start = 1; + } + else + length += s_length; + // #endregion + + // #region Copy values from CMS ECDSA signature + var result = new ArrayBuffer(length); + var result_view = new Uint8Array(result); + + for(var i = r_start; i < r_length; i++) + result_view[i - r_start] = r_view[i]; + + for(var i = s_start; i < s_length; i++) + result_view[i - s_start + r_length - r_start] = s_view[i]; + // #endregion + + return result; + }; + //************************************************************************************** + in_window.org.pkijs.getEncryptionAlgorithm = + function(algorithm) + { + /// <summary>Get encryption algorithm OID by WebCrypto algorithm's object</summary> + /// <param name="algorithm" type="WebCryptoAlgorithm">WebCrypto algorithm object</param> + + var result = ""; + + switch(algorithm.name.toUpperCase()) + { + case "AES-CBC": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.2"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.22"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.42"; + break; + default: + } + break; + case "AES-GCM": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.6"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.26"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.46"; + break; + default: + } + break; + default: + } + + return result; + }; + //************************************************************************************** + in_window.org.pkijs.getAlgorithmByEncryptionOID = + function(oid) + { + /// <summary>Get encryption algorithm name by OID</summary> + /// <param name="oid" type="String">OID of encryption algorithm</param> + + var result = ""; + + switch(oid) + { + case "2.16.840.1.101.3.4.1.2": + case "2.16.840.1.101.3.4.1.22": + case "2.16.840.1.101.3.4.1.42": + result = "AES-CBC"; + break; + case "2.16.840.1.101.3.4.1.6": + case "2.16.840.1.101.3.4.1.26": + case "2.16.840.1.101.3.4.1.46": + result = "AES-GCM"; + break; + default: + } + + return result; + }; + //************************************************************************************** + // #endregion + //************************************************************************************** +} +)(typeof exports !== "undefined" ? exports : window);
\ No newline at end of file |