common.js (54582B)
1 /* 2 * Copyright (c) 2014, GMO GlobalSign 3 * Copyright (c) 2015, Peculiar Ventures 4 * All rights reserved. 5 * 6 * Author 2014-2015, Yury Strozhevsky <www.strozhevsky.com>. 7 * 8 * Redistribution and use in source and binary forms, with or without modification, 9 * are permitted provided that the following conditions are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * 3. Neither the name of the copyright holder nor the names of its contributors 19 * may be used to endorse or promote products derived from this software without 20 * specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31 * OF SUCH DAMAGE. 32 * 33 */ 34 ( 35 function(in_window) 36 { 37 //************************************************************************************** 38 // #region Declaration of global variables 39 //************************************************************************************** 40 // #region "org" namespace 41 if(typeof in_window.org === "undefined") 42 in_window.org = {}; 43 else 44 { 45 if(typeof in_window.org !== "object") 46 throw new Error("Name org already exists and it's not an object"); 47 } 48 // #endregion 49 50 // #region "org.pkijs" namespace 51 if(typeof in_window.org.pkijs === "undefined") 52 in_window.org.pkijs = {}; 53 else 54 { 55 if(typeof in_window.org.pkijs !== "object") 56 throw new Error("Name org.pkijs already exists and it's not an object" + " but " + (typeof in_window.org.pkijs)); 57 } 58 // #endregion 59 60 // #region "local" namespace 61 var local = {}; 62 // #endregion 63 //************************************************************************************** 64 // #endregion 65 //************************************************************************************** 66 // #region Settings for "crypto engine" 67 //************************************************************************************** 68 local.engine = { 69 name: "none", 70 crypto: null, 71 subtle: null 72 }; 73 74 if(typeof window != "undefined") 75 { 76 if("crypto" in window) 77 { 78 var engineName = "webcrypto"; 79 var cryptoObject = window.crypto; 80 var subtleObject = null; 81 82 // Apple Safari support 83 if("webkitSubtle" in window.crypto) 84 subtleObject = window.crypto.webkitSubtle; 85 86 if("subtle" in window.crypto) 87 subtleObject = window.crypto.subtle; 88 89 local.engine = { 90 name: engineName, 91 crypto: cryptoObject, 92 subtle: subtleObject 93 }; 94 } 95 } 96 //************************************************************************************** 97 in_window.org.pkijs.setEngine = 98 function(name, crypto, subtle) 99 { 100 /// <summary>Setting the global "crypto engine" parameters</summary> 101 /// <param name="name" type="String">Auxiliary name for "crypto engine"</param> 102 /// <param name="crypto" type="Object">Object handling all root cryptographic requests (in fact currently it must handle only "getRandomValues")</param> 103 /// <param name="subtle" type="Object">Object handling all main cryptographic requests</param> 104 105 local.engine = { 106 name: name, 107 crypto: crypto, 108 subtle: subtle 109 }; 110 }; 111 //************************************************************************************** 112 in_window.org.pkijs.getEngine = 113 function() 114 { 115 return local.engine; 116 }; 117 //************************************************************************************** 118 // #endregion 119 //************************************************************************************** 120 // #region Declaration of common functions 121 //************************************************************************************** 122 in_window.org.pkijs.emptyObject = 123 function() 124 { 125 this.toJSON = function() 126 { 127 return {}; 128 }; 129 this.toSchema = function() 130 { 131 return {}; 132 }; 133 }; 134 //************************************************************************************** 135 in_window.org.pkijs.getNames = 136 function(arg) 137 { 138 /// <summary>Get correct "names" array for all "schema" objects</summary> 139 140 var names = {}; 141 142 if(arg instanceof Object) 143 names = (arg.names || {}); 144 145 return names; 146 }; 147 //************************************************************************************** 148 in_window.org.pkijs.inheriteObjectFields = 149 function(from) 150 { 151 for(var i in from.prototype) 152 { 153 if(typeof from.prototype[i] === "function") 154 continue; 155 156 this[i] = from.prototype[i]; 157 } 158 }; 159 //************************************************************************************** 160 in_window.org.pkijs.getUTCDate = 161 function(date) 162 { 163 /// <summary>Making UTC date from local date</summary> 164 /// <param name="date" type="Date">Date to convert from</param> 165 166 var current_date = date; 167 return new Date(current_date.getTime() + (current_date.getTimezoneOffset() * 60000)); 168 }; 169 //************************************************************************************** 170 in_window.org.pkijs.padNumber = 171 function(input_number, full_length) 172 { 173 var str = input_number.toString(10); 174 var dif = full_length - str.length; 175 176 var padding = new Array(dif); 177 for(var i = 0; i < dif; i++) 178 padding[i] = '0'; 179 180 var padding_string = padding.join(''); 181 182 return padding_string.concat(str); 183 }; 184 //************************************************************************************** 185 in_window.org.pkijs.getValue = 186 function(args, item, default_value) 187 { 188 if(item in args) 189 return args[item]; 190 else 191 return default_value; 192 }; 193 //************************************************************************************** 194 in_window.org.pkijs.isEqual_view = 195 function(input_view1, input_view2) 196 { 197 /// <summary>Compare two Uint8Arrays</summary> 198 /// <param name="input_view1" type="Uint8Array">First Uint8Array for comparision</param> 199 /// <param name="input_view2" type="Uint8Array">Second Uint8Array for comparision</param> 200 201 if(input_view1.length !== input_view2.length) 202 return false; 203 204 for(var i = 0; i < input_view1.length; i++) 205 { 206 if(input_view1[i] != input_view2[i]) 207 return false; 208 } 209 210 return true; 211 }; 212 //************************************************************************************** 213 in_window.org.pkijs.isEqual_buffer = 214 function(input_buffer1, input_buffer2) 215 { 216 /// <summary>Compare two array buffers</summary> 217 /// <param name="input_buffer1" type="ArrayBuffer">First ArrayBuffer for comparision</param> 218 /// <param name="input_buffer2" type="ArrayBuffer">Second ArrayBuffer for comparision</param> 219 220 if(input_buffer1.byteLength != input_buffer2.byteLength) 221 return false; 222 223 var view1 = new Uint8Array(input_buffer1); 224 var view2 = new Uint8Array(input_buffer2); 225 226 return in_window.org.pkijs.isEqual_view(view1, view2); 227 }; 228 //************************************************************************************** 229 in_window.org.pkijs.concat_buffers = 230 function(input_buf1, input_buf2) 231 { 232 /// <summary>Concatenate two ArrayBuffers</summary> 233 /// <param name="input_buf1" type="ArrayBuffer">First ArrayBuffer (first part of concatenated array)</param> 234 /// <param name="input_buf2" type="ArrayBuffer">Second ArrayBuffer (second part of concatenated array)</param> 235 236 var input_view1 = new Uint8Array(input_buf1); 237 var input_view2 = new Uint8Array(input_buf2); 238 239 var ret_buf = new ArrayBuffer(input_buf1.byteLength + input_buf2.byteLength); 240 var ret_view = new Uint8Array(ret_buf); 241 242 for(var i = 0; i < input_buf1.byteLength; i++) 243 ret_view[i] = input_view1[i]; 244 245 for(var j = 0; j < input_buf2.byteLength; j++) 246 ret_view[input_buf1.byteLength + j] = input_view2[j]; 247 248 return ret_buf; 249 }; 250 //************************************************************************************** 251 in_window.org.pkijs.copyBuffer = 252 function(input_buffer) 253 { 254 var result = new ArrayBuffer(input_buffer.byteLength); 255 256 var resultView = new Uint8Array(result); 257 var inputView = new Uint8Array(input_buffer); 258 259 for(var i = 0; i < inputView.length; i++) 260 resultView[i] = inputView[i]; 261 262 return result; 263 }; 264 //************************************************************************************** 265 in_window.org.pkijs.getCrypto = 266 function() 267 { 268 var crypto_temp; 269 270 if(local.engine.subtle !== null) 271 crypto_temp = local.engine.subtle; 272 273 return crypto_temp; 274 }; 275 //************************************************************************************** 276 in_window.org.pkijs.stringPrep = 277 function(input_string) 278 { 279 /// <summary>String preparation function. In a future here will be realization of algorithm from RFC4518.</summary> 280 /// <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> 281 /// <returns type="String">Formated string</returns> 282 283 var result = input_string.replace(/^\s+|\s+$/g, ""); // Trim input string 284 result = result.replace(/\s+/g, " "); // Change all sequence of SPACE down to SPACE char 285 result = result.toLowerCase(); 286 287 return result; 288 }; 289 //************************************************************************************** 290 in_window.org.pkijs.bufferToHexCodes = 291 function(input_buffer, input_offset, input_lenght) 292 { 293 var result = ""; 294 295 var int_buffer = new Uint8Array(input_buffer, input_offset, input_lenght); 296 297 for(var i = 0; i < int_buffer.length; i++) 298 { 299 var str = int_buffer[i].toString(16).toUpperCase(); 300 result = result + ((str.length === 1) ? "0" : "") + str; 301 } 302 303 return result; 304 }; 305 //************************************************************************************** 306 in_window.org.pkijs.bufferFromHexCodes = 307 function(hexString) 308 { 309 /// <summary>Create an ArrayBuffer from string having hexdecimal codes</summary> 310 /// <param name="hexString" type="String">String to create ArrayBuffer from</param> 311 312 // #region Initial variables 313 var stringLength = hexString.length; 314 315 var resultBuffer = new ArrayBuffer(stringLength >> 1); 316 var resultView = new Uint8Array(resultBuffer); 317 318 var hex_map = {}; 319 320 hex_map['0'] = 0x00; 321 hex_map['1'] = 0x01; 322 hex_map['2'] = 0x02; 323 hex_map['3'] = 0x03; 324 hex_map['4'] = 0x04; 325 hex_map['5'] = 0x05; 326 hex_map['6'] = 0x06; 327 hex_map['7'] = 0x07; 328 hex_map['8'] = 0x08; 329 hex_map['9'] = 0x09; 330 hex_map['A'] = 0x0A; 331 hex_map['a'] = 0x0A; 332 hex_map['B'] = 0x0B; 333 hex_map['b'] = 0x0B; 334 hex_map['C'] = 0x0C; 335 hex_map['c'] = 0x0C; 336 hex_map['D'] = 0x0D; 337 hex_map['d'] = 0x0D; 338 hex_map['E'] = 0x0E; 339 hex_map['e'] = 0x0E; 340 hex_map['F'] = 0x0F; 341 hex_map['f'] = 0x0F; 342 343 var j = 0; 344 var temp = 0x00; 345 // #endregion 346 347 // #region Convert char-by-char 348 for(var i = 0; i < stringLength; i++) 349 { 350 if(!(i % 2)) 351 temp = hex_map[hexString.charAt(i)] << 4; 352 else 353 { 354 temp |= hex_map[hexString.charAt(i)]; 355 356 resultView[j] = temp; 357 j++; 358 } 359 } 360 // #endregion 361 362 return resultBuffer; 363 }; 364 //************************************************************************************** 365 in_window.org.pkijs.getRandomValues = 366 function(view) 367 { 368 /// <param name="view" type="Uint8Array">New array which gives a length for random value</param> 369 370 if(local.engine.crypto !== null) 371 return local.engine.crypto.getRandomValues(view); 372 else 373 throw new Error("No support for Web Cryptography API"); 374 }; 375 //************************************************************************************** 376 in_window.org.pkijs.getAlgorithmParameters = 377 function(algorithmName, operation) 378 { 379 /// <param name="algorithmName" type="String">Algorithm name to get common parameters for</param> 380 /// <param name="operation" type="String">Kind of operation: "sign", "encrypt", "generatekey", "importkey", "exportkey", "verify"</param> 381 382 var result = { 383 algorithm: {}, 384 usages: [] 385 }; 386 387 switch(algorithmName.toUpperCase()) 388 { 389 case "RSASSA-PKCS1-V1_5": 390 switch(operation.toLowerCase()) 391 { 392 case "generatekey": 393 result = { 394 algorithm: { 395 name: "RSASSA-PKCS1-v1_5", 396 modulusLength: 2048, 397 publicExponent: new Uint8Array([0x01, 0x00, 0x01]), 398 hash: { 399 name: "SHA-256" 400 } 401 }, 402 usages: ["sign", "verify"] 403 }; 404 break; 405 case "verify": 406 case "sign": 407 case "importkey": 408 result = { 409 algorithm: { 410 name: "RSASSA-PKCS1-v1_5", 411 hash: { 412 name: "SHA-256" 413 } 414 }, 415 usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only 416 }; 417 break; 418 case "exportkey": 419 default: 420 return { 421 algorithm: { 422 name: "RSASSA-PKCS1-v1_5" 423 }, 424 usages: [] 425 }; 426 } 427 break; 428 case "RSA-PSS": 429 switch(operation.toLowerCase()) 430 { 431 case "sign": 432 case "verify": 433 result = { 434 algorithm: { 435 name: "RSA-PSS", 436 hash: { 437 name: "SHA-1" 438 }, 439 saltLength: 20 440 }, 441 usages: ["sign", "verify"] 442 }; 443 break; 444 case "generatekey": 445 result = { 446 algorithm: { 447 name: "RSA-PSS", 448 modulusLength: 2048, 449 publicExponent: new Uint8Array([0x01, 0x00, 0x01]), 450 hash: { 451 name: "SHA-1" 452 } 453 }, 454 usages: ["sign", "verify"] 455 }; 456 break; 457 case "importkey": 458 result = { 459 algorithm: { 460 name: "RSA-PSS", 461 hash: { 462 name: "SHA-1" 463 } 464 }, 465 usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only 466 }; 467 break; 468 case "exportkey": 469 default: 470 return { 471 algorithm: { 472 name: "RSA-PSS" 473 }, 474 usages: [] 475 }; 476 } 477 break; 478 case "RSA-OAEP": 479 switch(operation.toLowerCase()) 480 { 481 case "encrypt": 482 case "decrypt": 483 result = { 484 algorithm: { 485 name: "RSA-OAEP" 486 }, 487 usages: ["encrypt", "decrypt"] 488 }; 489 break; 490 break; 491 case "generatekey": 492 result = { 493 algorithm: { 494 name: "RSA-OAEP", 495 modulusLength: 2048, 496 publicExponent: new Uint8Array([0x01, 0x00, 0x01]), 497 hash: { 498 name: "SHA-256" 499 } 500 }, 501 usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] 502 }; 503 break; 504 case "importkey": 505 result = { 506 algorithm: { 507 name: "RSA-OAEP", 508 hash: { 509 name: "SHA-256" 510 } 511 }, 512 usages: ["encrypt"] // encrypt for "spki" and decrypt for "pkcs8" 513 }; 514 break; 515 case "exportkey": 516 default: 517 return { 518 algorithm: { 519 name: "RSA-OAEP" 520 }, 521 usages: [] 522 }; 523 } 524 break; 525 case "ECDSA": 526 switch(operation.toLowerCase()) 527 { 528 case "generatekey": 529 result = { 530 algorithm: { 531 name: "ECDSA", 532 namedCurve: "P-256" 533 }, 534 usages: ["sign", "verify"] 535 }; 536 break; 537 case "importkey": 538 result = { 539 algorithm: { 540 name: "ECDSA", 541 namedCurve: "P-256" 542 }, 543 usages: ["verify"] // "sign" for "pkcs8" 544 }; 545 break; 546 case "verify": 547 case "sign": 548 result = { 549 algorithm: { 550 name: "ECDSA", 551 hash: { 552 name: "SHA-256" 553 } 554 }, 555 usages: ["sign"] 556 }; 557 break; 558 default: 559 return { 560 algorithm: { 561 name: "ECDSA" 562 }, 563 usages: [] 564 }; 565 } 566 break; 567 case "ECDH": 568 switch(operation.toLowerCase()) 569 { 570 case "exportkey": 571 case "importkey": 572 case "generatekey": 573 result = { 574 algorithm: { 575 name: "ECDH", 576 namedCurve: "P-256" 577 }, 578 usages: ["deriveKey", "deriveBits"] 579 }; 580 break; 581 case "derivekey": 582 case "derivebits": 583 result = { 584 algorithm: { 585 name: "ECDH", 586 namedCurve: "P-256", 587 public: [] // Must be a "publicKey" 588 }, 589 usages: ["encrypt", "decrypt"] 590 }; 591 break; 592 default: 593 return { 594 algorithm: { 595 name: "ECDH" 596 }, 597 usages: [] 598 }; 599 } 600 break; 601 case "AES-CTR": 602 switch(operation.toLowerCase()) 603 { 604 case "importkey": 605 case "exportkey": 606 case "generatekey": 607 result = { 608 algorithm: { 609 name: "AES-CTR", 610 length: 256 611 }, 612 usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] 613 }; 614 break; 615 case "decrypt": 616 case "encrypt": 617 result = { 618 algorithm: { 619 name: "AES-CTR", 620 counter: new Uint8Array(16), 621 length: 10 622 }, 623 usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] 624 }; 625 break; 626 default: 627 return { 628 algorithm: { 629 name: "AES-CTR" 630 }, 631 usages: [] 632 }; 633 } 634 break; 635 case "AES-CBC": 636 switch(operation.toLowerCase()) 637 { 638 case "importkey": 639 case "exportkey": 640 case "generatekey": 641 result = { 642 algorithm: { 643 name: "AES-CBC", 644 length: 256 645 }, 646 usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] 647 }; 648 break; 649 case "decrypt": 650 case "encrypt": 651 result = { 652 algorithm: { 653 name: "AES-CBC", 654 iv: in_window.org.pkijs.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step 655 }, 656 usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] 657 }; 658 break; 659 default: 660 return { 661 algorithm: { 662 name: "AES-CBC" 663 }, 664 usages: [] 665 }; 666 } 667 break; 668 case "AES-GCM": 669 switch(operation.toLowerCase()) 670 { 671 case "importkey": 672 case "exportkey": 673 case "generatekey": 674 result = { 675 algorithm: { 676 name: "AES-GCM", 677 length: 256 678 }, 679 usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] 680 }; 681 break; 682 case "decrypt": 683 case "encrypt": 684 result = { 685 algorithm: { 686 name: "AES-GCM", 687 iv: in_window.org.pkijs.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step 688 }, 689 usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] 690 }; 691 break; 692 default: 693 return { 694 algorithm: { 695 name: "AES-GCM" 696 }, 697 usages: [] 698 }; 699 } 700 break; 701 case "AES-KW": 702 switch(operation.toLowerCase()) 703 { 704 case "importkey": 705 case "exportkey": 706 case "generatekey": 707 case "wrapkey": 708 case "unwrapkey": 709 result = { 710 algorithm: { 711 name: "AES-KW", 712 length: 256 713 }, 714 usages: ["wrapKey", "unwrapKey"] 715 }; 716 break; 717 default: 718 return { 719 algorithm: { 720 name: "AES-KW" 721 }, 722 usages: [] 723 }; 724 } 725 break; 726 case "HMAC": 727 switch(operation.toLowerCase()) 728 { 729 case "sign": 730 case "verify": 731 result = { 732 algorithm: { 733 name: "HMAC" 734 }, 735 usages: ["sign", "verify"] 736 }; 737 break; 738 case "importkey": 739 case "exportkey": 740 case "generatekey": 741 result = { 742 algorithm: { 743 name: "HMAC", 744 length: 32, 745 hash: { 746 name: "SHA-256" 747 } 748 }, 749 usages: ["sign", "verify"] 750 }; 751 break; 752 default: 753 return { 754 algorithm: { 755 name: "HMAC" 756 }, 757 usages: [] 758 }; 759 } 760 break; 761 case "HKDF": 762 switch(operation.toLowerCase()) 763 { 764 case "derivekey": 765 result = { 766 algorithm: { 767 name: "HKDF", 768 hash: "SHA-256", 769 salt: new Uint8Array(), 770 info: new Uint8Array() 771 }, 772 usages: ["encrypt", "decrypt"] 773 }; 774 break; 775 default: 776 return { 777 algorithm: { 778 name: "HKDF" 779 }, 780 usages: [] 781 }; 782 } 783 break; 784 case "PBKDF2": 785 switch(operation.toLowerCase()) 786 { 787 case "derivekey": 788 result = { 789 algorithm: { 790 name: "PBKDF2", 791 hash: { name: "SHA-256" }, 792 salt: new Uint8Array(), 793 iterations: 1000 794 }, 795 usages: ["encrypt", "decrypt"] 796 }; 797 break; 798 default: 799 return { 800 algorithm: { 801 name: "PBKDF2" 802 }, 803 usages: [] 804 }; 805 } 806 break; 807 default: 808 } 809 810 return result; 811 }; 812 //************************************************************************************** 813 in_window.org.pkijs.getOIDByAlgorithm = 814 function(algorithm) 815 { 816 /// <summary>Get OID for each specific WebCrypto algorithm</summary> 817 /// <param name="algorithm" type="Object">WebCrypto algorithm</param> 818 819 var result = ""; 820 821 switch(algorithm.name.toUpperCase()) 822 { 823 case "RSASSA-PKCS1-V1_5": 824 switch(algorithm.hash.name.toUpperCase()) 825 { 826 case "SHA-1": 827 result = "1.2.840.113549.1.1.5"; 828 break; 829 case "SHA-256": 830 result = "1.2.840.113549.1.1.11"; 831 break; 832 case "SHA-384": 833 result = "1.2.840.113549.1.1.12"; 834 break; 835 case "SHA-512": 836 result = "1.2.840.113549.1.1.13"; 837 break; 838 default: 839 } 840 break; 841 case "RSA-PSS": 842 result = "1.2.840.113549.1.1.10"; 843 break; 844 case "RSA-OAEP": 845 result = "1.2.840.113549.1.1.7"; 846 break; 847 case "ECDSA": 848 switch(algorithm.hash.name.toUpperCase()) 849 { 850 case "SHA-1": 851 result = "1.2.840.10045.4.1"; 852 break; 853 case "SHA-256": 854 result = "1.2.840.10045.4.3.2"; 855 break; 856 case "SHA-384": 857 result = "1.2.840.10045.4.3.3"; 858 break; 859 case "SHA-512": 860 result = "1.2.840.10045.4.3.4"; 861 break; 862 default: 863 } 864 break; 865 case "ECDH": 866 switch(algorithm.kdf.toUpperCase()) // Non-standard addition - hash algorithm of KDF function 867 { 868 case "SHA-1": 869 result = "1.3.133.16.840.63.0.2"; // dhSinglePass-stdDH-sha1kdf-scheme 870 break; 871 case "SHA-256": 872 result = "1.3.132.1.11.1"; // dhSinglePass-stdDH-sha256kdf-scheme 873 break; 874 case "SHA-384": 875 result = "1.3.132.1.11.2"; // dhSinglePass-stdDH-sha384kdf-scheme 876 break; 877 case "SHA-512": 878 result = "1.3.132.1.11.3"; // dhSinglePass-stdDH-sha512kdf-scheme 879 break; 880 default: 881 } 882 break; 883 case "AES-CTR": 884 break; 885 case "AES-CBC": 886 switch(algorithm.length) 887 { 888 case 128: 889 result = "2.16.840.1.101.3.4.1.2"; 890 break; 891 case 192: 892 result = "2.16.840.1.101.3.4.1.22"; 893 break; 894 case 256: 895 result = "2.16.840.1.101.3.4.1.42"; 896 break; 897 default: 898 } 899 break; 900 case "AES-CMAC": 901 break; 902 case "AES-GCM": 903 switch(algorithm.length) 904 { 905 case 128: 906 result = "2.16.840.1.101.3.4.1.6"; 907 break; 908 case 192: 909 result = "2.16.840.1.101.3.4.1.26"; 910 break; 911 case 256: 912 result = "2.16.840.1.101.3.4.1.46"; 913 break; 914 default: 915 } 916 break; 917 case "AES-CFB": 918 switch(algorithm.length) 919 { 920 case 128: 921 result = "2.16.840.1.101.3.4.1.4"; 922 break; 923 case 192: 924 result = "2.16.840.1.101.3.4.1.24"; 925 break; 926 case 256: 927 result = "2.16.840.1.101.3.4.1.44"; 928 break; 929 default: 930 } 931 break; 932 case "AES-KW": 933 switch(algorithm.length) 934 { 935 case 128: 936 result = "2.16.840.1.101.3.4.1.5"; 937 break; 938 case 192: 939 result = "2.16.840.1.101.3.4.1.25"; 940 break; 941 case 256: 942 result = "2.16.840.1.101.3.4.1.45"; 943 break; 944 default: 945 } 946 break; 947 case "HMAC": 948 switch(algorithm.hash.name.toUpperCase()) 949 { 950 case "SHA-1": 951 result = "1.2.840.113549.2.7"; 952 break; 953 case "SHA-256": 954 result = "1.2.840.113549.2.9"; 955 break; 956 case "SHA-384": 957 result = "1.2.840.113549.2.10"; 958 break; 959 case "SHA-512": 960 result = "1.2.840.113549.2.11"; 961 break; 962 default: 963 } 964 break; 965 case "DH": 966 result = "1.2.840.113549.1.9.16.3.5"; 967 break; 968 case "SHA-1": 969 result = "1.3.14.3.2.26"; 970 break; 971 case "SHA-256": 972 result = "2.16.840.1.101.3.4.2.1"; 973 break; 974 case "SHA-384": 975 result = "2.16.840.1.101.3.4.2.2"; 976 break; 977 case "SHA-512": 978 result = "2.16.840.1.101.3.4.2.3"; 979 break; 980 case "CONCAT": 981 break; 982 case "HKDF": 983 break; 984 case "PBKDF2": 985 result = "1.2.840.113549.1.5.12"; 986 break; 987 // #region Special case - OIDs for ECC curves 988 case "P-256": 989 result = "1.2.840.10045.3.1.7"; 990 break; 991 case "P-384": 992 result = "1.3.132.0.34"; 993 break; 994 case "P-521": 995 result = "1.3.132.0.35"; 996 break; 997 // #endregion 998 999 default: 1000 } 1001 1002 return result; 1003 }; 1004 //************************************************************************************** 1005 in_window.org.pkijs.getAlgorithmByOID = 1006 function(oid) 1007 { 1008 /// <summary>Get WebCrypto algorithm by wel-known OID</summary> 1009 /// <param name="oid" type="String">Wel-known OID to search for</param> 1010 1011 var result = {}; 1012 1013 switch(oid) 1014 { 1015 case "1.2.840.113549.1.1.5": 1016 result = { 1017 name: "RSASSA-PKCS1-v1_5", 1018 hash: { 1019 name: "SHA-1" 1020 } 1021 }; 1022 break; 1023 case "1.2.840.113549.1.1.11": 1024 result = { 1025 name: "RSASSA-PKCS1-v1_5", 1026 hash: { 1027 name: "SHA-256" 1028 } 1029 }; 1030 break; 1031 case "1.2.840.113549.1.1.12": 1032 result = { 1033 name: "RSASSA-PKCS1-v1_5", 1034 hash: { 1035 name: "SHA-384" 1036 } 1037 }; 1038 break; 1039 case "1.2.840.113549.1.1.13": 1040 result = { 1041 name: "RSASSA-PKCS1-v1_5", 1042 hash: { 1043 name: "SHA-512" 1044 } 1045 }; 1046 break; 1047 case "1.2.840.113549.1.1.10": 1048 result = { 1049 name: "RSA-PSS" 1050 }; 1051 break; 1052 case "1.2.840.113549.1.1.7": 1053 result = { 1054 name: "RSA-OAEP" 1055 }; 1056 break; 1057 case "1.2.840.10045.4.1": 1058 result = { 1059 name: "ECDSA", 1060 hash: { 1061 name: "SHA-1" 1062 } 1063 }; 1064 break; 1065 case "1.2.840.10045.4.3.2": 1066 result = { 1067 name: "ECDSA", 1068 hash: { 1069 name: "SHA-256" 1070 } 1071 }; 1072 break; 1073 case "1.2.840.10045.4.3.3": 1074 result = { 1075 name: "ECDSA", 1076 hash: { 1077 name: "SHA-384" 1078 } 1079 }; 1080 break; 1081 case "1.2.840.10045.4.3.4": 1082 result = { 1083 name: "ECDSA", 1084 hash: { 1085 name: "SHA-512" 1086 } 1087 }; 1088 break; 1089 case "1.3.133.16.840.63.0.2": 1090 result = { 1091 name: "ECDH", 1092 kdf: "SHA-1" 1093 }; 1094 break; 1095 case "1.3.132.1.11.1": 1096 result = { 1097 name: "ECDH", 1098 kdf: "SHA-256" 1099 }; 1100 break; 1101 case "1.3.132.1.11.2": 1102 result = { 1103 name: "ECDH", 1104 kdf: "SHA-384" 1105 }; 1106 break; 1107 case "1.3.132.1.11.3": 1108 result = { 1109 name: "ECDH", 1110 kdf: "SHA-512" 1111 }; 1112 break; 1113 case "2.16.840.1.101.3.4.1.2": 1114 result = { 1115 name: "AES-CBC", 1116 length: 128 1117 }; 1118 break; 1119 case "2.16.840.1.101.3.4.1.22": 1120 result = { 1121 name: "AES-CBC", 1122 length: 192 1123 }; 1124 break; 1125 case "2.16.840.1.101.3.4.1.42": 1126 result = { 1127 name: "AES-CBC", 1128 length: 256 1129 }; 1130 break; 1131 case "2.16.840.1.101.3.4.1.6": 1132 result = { 1133 name: "AES-GCM", 1134 length: 128 1135 }; 1136 break; 1137 case "2.16.840.1.101.3.4.1.26": 1138 result = { 1139 name: "AES-GCM", 1140 length: 192 1141 }; 1142 break; 1143 case "2.16.840.1.101.3.4.1.46": 1144 result = { 1145 name: "AES-GCM", 1146 length: 256 1147 }; 1148 break; 1149 case "2.16.840.1.101.3.4.1.4": 1150 result = { 1151 name: "AES-CFB", 1152 length: 128 1153 }; 1154 break; 1155 case "2.16.840.1.101.3.4.1.24": 1156 result = { 1157 name: "AES-CFB", 1158 length: 192 1159 }; 1160 break; 1161 case "2.16.840.1.101.3.4.1.44": 1162 result = { 1163 name: "AES-CFB", 1164 length: 256 1165 }; 1166 break; 1167 case "2.16.840.1.101.3.4.1.5": 1168 result = { 1169 name: "AES-KW", 1170 length: 128 1171 }; 1172 break; 1173 case "2.16.840.1.101.3.4.1.25": 1174 result = { 1175 name: "AES-KW", 1176 length: 192 1177 }; 1178 break; 1179 case "2.16.840.1.101.3.4.1.45": 1180 result = { 1181 name: "AES-KW", 1182 length: 256 1183 }; 1184 break; 1185 case "1.2.840.113549.2.7": 1186 result = { 1187 name: "HMAC", 1188 hash: { 1189 name: "SHA-1" 1190 } 1191 }; 1192 break; 1193 case "1.2.840.113549.2.9": 1194 result = { 1195 name: "HMAC", 1196 hash: { 1197 name: "SHA-256" 1198 } 1199 }; 1200 break; 1201 case "1.2.840.113549.2.10": 1202 result = { 1203 name: "HMAC", 1204 hash: { 1205 name: "SHA-384" 1206 } 1207 }; 1208 break; 1209 case "1.2.840.113549.2.11": 1210 result = { 1211 name: "HMAC", 1212 hash: { 1213 name: "SHA-512" 1214 } 1215 }; 1216 break; 1217 case "1.2.840.113549.1.9.16.3.5": 1218 result = { 1219 name: "DH" 1220 }; 1221 break; 1222 case "1.3.14.3.2.26": 1223 result = { 1224 name: "SHA-1" 1225 }; 1226 break; 1227 case "2.16.840.1.101.3.4.2.1": 1228 result = { 1229 name: "SHA-256" 1230 }; 1231 break; 1232 case "2.16.840.1.101.3.4.2.2": 1233 result = { 1234 name: "SHA-384" 1235 }; 1236 break; 1237 case "2.16.840.1.101.3.4.2.3": 1238 result = { 1239 name: "SHA-512" 1240 }; 1241 break; 1242 case "1.2.840.113549.1.5.12": 1243 result = { 1244 name: "PBKDF2" 1245 }; 1246 break; 1247 // #region Special case - OIDs for ECC curves 1248 case "1.2.840.10045.3.1.7": 1249 result = { 1250 name: "P-256" 1251 }; 1252 break; 1253 case "1.3.132.0.34": 1254 result = { 1255 name: "P-384" 1256 }; 1257 break; 1258 case "1.3.132.0.35": 1259 result = { 1260 name: "P-521" 1261 }; 1262 break; 1263 // #endregion 1264 1265 default: 1266 } 1267 1268 return result; 1269 }; 1270 //************************************************************************************** 1271 in_window.org.pkijs.getHashAlgorithm = 1272 function(signatureAlgorithm) 1273 { 1274 /// <summary>Getting hash algorithm by signature algorithm</summary> 1275 /// <param name="signatureAlgorithm" type="in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER">Signature algorithm</param> 1276 1277 var result = ""; 1278 1279 switch(signatureAlgorithm.algorithm_id) 1280 { 1281 case "1.2.840.10045.4.1": // ecdsa-with-SHA1 1282 case "1.2.840.113549.1.1.5": 1283 result = "SHA-1"; 1284 break; 1285 case "1.2.840.10045.4.3.2": // ecdsa-with-SHA256 1286 case "1.2.840.113549.1.1.11": 1287 result = "SHA-256"; 1288 break; 1289 case "1.2.840.10045.4.3.3": // ecdsa-with-SHA384 1290 case "1.2.840.113549.1.1.12": 1291 result = "SHA-384"; 1292 break; 1293 case "1.2.840.10045.4.3.4": // ecdsa-with-SHA512 1294 case "1.2.840.113549.1.1.13": 1295 result = "SHA-512"; 1296 break; 1297 case "1.2.840.113549.1.1.10": // RSA-PSS 1298 { 1299 var params; 1300 1301 try 1302 { 1303 params = new in_window.org.pkijs.simpl.x509.RSASSA_PSS_params({ schema: signatureAlgorithm.algorithm_params }); 1304 if("hashAlgorithm" in params) 1305 { 1306 var algorithm = in_window.org.pkijs.getAlgorithmByOID(params.hashAlgorithm.algorithm_id); 1307 if(("name" in algorithm) === false) 1308 return ""; 1309 1310 result = algorithm.name; 1311 } 1312 else 1313 result = "SHA-1"; 1314 } 1315 catch(ex) 1316 { 1317 } 1318 } 1319 break; 1320 default: 1321 } 1322 1323 return result; 1324 }; 1325 //************************************************************************************** 1326 in_window.org.pkijs.createCMSECDSASignature = 1327 function(signatureBuffer) 1328 { 1329 /// <summary>Create CMS ECDSA signature from WebCrypto ECDSA signature</summary> 1330 /// <param name="signatureBuffer" type="ArrayBuffer">WebCrypto result of "sign" function</param> 1331 1332 // #region Initial check for correct length 1333 if((signatureBuffer.byteLength % 2) != 0) 1334 return new ArrayBuffer(0); 1335 // #endregion 1336 1337 // #region Initial variables 1338 var i = 0; 1339 var length = signatureBuffer.byteLength / 2; // There are two equal parts inside incoming ArrayBuffer 1340 1341 var signatureView = new Uint8Array(signatureBuffer); 1342 1343 var r_buffer = new ArrayBuffer(length); 1344 var r_view = new Uint8Array(r_buffer); 1345 var r_corrected_buffer; 1346 var r_corrected_view; 1347 1348 var s_buffer = new ArrayBuffer(length); 1349 var s_view = new Uint8Array(s_buffer); 1350 var s_corrected_buffer; 1351 var s_corrected_view; 1352 // #endregion 1353 1354 // #region Get "r" part of ECDSA signature 1355 for(; i < length; i++) 1356 r_view[i] = signatureView[i]; 1357 1358 if(r_view[0] & 0x80) 1359 { 1360 r_corrected_buffer = new ArrayBuffer(length + 1); 1361 r_corrected_view = new Uint8Array(r_corrected_buffer); 1362 1363 r_corrected_view[0] = 0x00; 1364 1365 for(var j = 0; j < length; j++) 1366 r_corrected_view[j + 1] = r_view[j]; 1367 } 1368 else 1369 { 1370 r_corrected_buffer = r_buffer; 1371 r_corrected_view = r_view; 1372 } 1373 // #endregion 1374 1375 // #region Get "s" part of ECDSA signature 1376 for(; i < signatureBuffer.byteLength; i++) 1377 s_view[i - length] = signatureView[i]; 1378 1379 1380 if(s_view[0] & 0x80) 1381 { 1382 s_corrected_buffer = new ArrayBuffer(length + 1); 1383 s_corrected_view = new Uint8Array(s_corrected_buffer); 1384 1385 s_corrected_view[0] = 0x00; 1386 1387 for(var j = 0; j < length; j++) 1388 s_corrected_view[j + 1] = s_view[j]; 1389 } 1390 else 1391 { 1392 s_corrected_buffer = s_buffer; 1393 s_corrected_view = s_view; 1394 } 1395 // #endregion 1396 1397 // #region Create ASN.1 structure of CMS ECDSA signature 1398 var r_integer = new in_window.org.pkijs.asn1.INTEGER(); 1399 r_integer.value_block.is_hex_only = true; 1400 r_integer.value_block.value_hex = in_window.org.pkijs.copyBuffer(r_corrected_buffer); 1401 1402 var s_integer = new in_window.org.pkijs.asn1.INTEGER(); 1403 s_integer.value_block.is_hex_only = true; 1404 s_integer.value_block.value_hex = in_window.org.pkijs.copyBuffer(s_corrected_buffer); 1405 1406 var asn1 = new in_window.org.pkijs.asn1.SEQUENCE({ 1407 value: [ 1408 r_integer, 1409 s_integer 1410 ] 1411 }); 1412 // #endregion 1413 1414 return asn1.toBER(false); 1415 }; 1416 //************************************************************************************** 1417 in_window.org.pkijs.createECDSASignatureFromCMS = 1418 function(cmsSignature) 1419 { 1420 /// <summary>Create a single ArrayBuffer from CMS ECDSA signature</summary> 1421 /// <param name="cmsSignature" type="in_window.org.pkijs.asn1.SEQUENCE">ASN.1 SEQUENCE contains CMS ECDSA signature</param> 1422 1423 // #region Initial variables 1424 var length = 0; 1425 1426 var r_start = 0; 1427 var s_start = 0; 1428 1429 var r_length = cmsSignature.value_block.value[0].value_block.value_hex.byteLength; 1430 var s_length = cmsSignature.value_block.value[1].value_block.value_hex.byteLength; 1431 // #endregion 1432 1433 // #region Get length of final "ArrayBuffer" 1434 var r_view = new Uint8Array(cmsSignature.value_block.value[0].value_block.value_hex); 1435 if((r_view[0] === 0x00) && (r_view[1] & 0x80)) 1436 { 1437 length = r_length - 1; 1438 r_start = 1; 1439 } 1440 else 1441 length = r_length; 1442 1443 var s_view = new Uint8Array(cmsSignature.value_block.value[1].value_block.value_hex); 1444 if((s_view[0] === 0x00) && (s_view[1] & 0x80)) 1445 { 1446 length += s_length - 1; 1447 s_start = 1; 1448 } 1449 else 1450 length += s_length; 1451 // #endregion 1452 1453 // #region Copy values from CMS ECDSA signature 1454 var result = new ArrayBuffer(length); 1455 var result_view = new Uint8Array(result); 1456 1457 for(var i = r_start; i < r_length; i++) 1458 result_view[i - r_start] = r_view[i]; 1459 1460 for(var i = s_start; i < s_length; i++) 1461 result_view[i - s_start + r_length - r_start] = s_view[i]; 1462 // #endregion 1463 1464 return result; 1465 }; 1466 //************************************************************************************** 1467 in_window.org.pkijs.getEncryptionAlgorithm = 1468 function(algorithm) 1469 { 1470 /// <summary>Get encryption algorithm OID by WebCrypto algorithm's object</summary> 1471 /// <param name="algorithm" type="WebCryptoAlgorithm">WebCrypto algorithm object</param> 1472 1473 var result = ""; 1474 1475 switch(algorithm.name.toUpperCase()) 1476 { 1477 case "AES-CBC": 1478 switch(algorithm.length) 1479 { 1480 case 128: 1481 result = "2.16.840.1.101.3.4.1.2"; 1482 break; 1483 case 192: 1484 result = "2.16.840.1.101.3.4.1.22"; 1485 break; 1486 case 256: 1487 result = "2.16.840.1.101.3.4.1.42"; 1488 break; 1489 default: 1490 } 1491 break; 1492 case "AES-GCM": 1493 switch(algorithm.length) 1494 { 1495 case 128: 1496 result = "2.16.840.1.101.3.4.1.6"; 1497 break; 1498 case 192: 1499 result = "2.16.840.1.101.3.4.1.26"; 1500 break; 1501 case 256: 1502 result = "2.16.840.1.101.3.4.1.46"; 1503 break; 1504 default: 1505 } 1506 break; 1507 default: 1508 } 1509 1510 return result; 1511 }; 1512 //************************************************************************************** 1513 in_window.org.pkijs.getAlgorithmByEncryptionOID = 1514 function(oid) 1515 { 1516 /// <summary>Get encryption algorithm name by OID</summary> 1517 /// <param name="oid" type="String">OID of encryption algorithm</param> 1518 1519 var result = ""; 1520 1521 switch(oid) 1522 { 1523 case "2.16.840.1.101.3.4.1.2": 1524 case "2.16.840.1.101.3.4.1.22": 1525 case "2.16.840.1.101.3.4.1.42": 1526 result = "AES-CBC"; 1527 break; 1528 case "2.16.840.1.101.3.4.1.6": 1529 case "2.16.840.1.101.3.4.1.26": 1530 case "2.16.840.1.101.3.4.1.46": 1531 result = "AES-GCM"; 1532 break; 1533 default: 1534 } 1535 1536 return result; 1537 }; 1538 //************************************************************************************** 1539 // #endregion 1540 //************************************************************************************** 1541 } 1542 )(typeof exports !== "undefined" ? exports : window);