diff --git a/README.md b/README.md index 66165e965..4896de127 100644 --- a/README.md +++ b/README.md @@ -15,24 +15,28 @@ Public Key Infrastructure (PKI) is the basis of how identity and key management ## Features of the library -* Fully object-oriented library. Inhiritence is using everywhere inside the lib;. -* Working with HTML5 data objects (ArrayBuffer, Uint8Array, Promises, WebCrypto, etc.). +* Fully object-oriented library. Inhiritence is using everywhere inside the lib; +* Working with HTML5 data objects (ArrayBuffer, Uint8Array, Promises, WebCrypto, etc.); * Has a complete set of helpers for working with types like: * GeneralName; * RelativeDistinguishedName; * Time; * AlgorithmIdentifier; * All types of ASN.1 strings, including "international" like UniversalString, UTF8String and BMPString (with help from [ASN1js][]); - * All extension types of X.509 certificates (BasicConstraints, CertificatePolicies, AuthorityKeyIdentifier etc.) + * All extension types of X.509 certificates (BasicConstraints, CertificatePolicies, AuthorityKeyIdentifier etc.); * All "support types" for OCSP requests and responces; - * All "support types" for Time-Stamping Protocol (TSP) requests and responces. -* Has own certification chain verification engine, purelly made on JavaScript with help from Promises and WebCrypto latest standard implementation; + * All "support types" for Time-Stamping Protocol (TSP) requests and responces; +* **Has own certification chain verification engine, purelly made on JavaScript with help from Promises and WebCrypto latest standard implementation;** +* Working with **all** WebCrypto signature algorithms: + * RSASSA-PKCS1-v1_5; + * RSA-PSS; + * ECDSA; * Working with all major PKI-related types ("minor" types are not mentioned here but there are huge number of such "minor types"): * X.509 certificates: * Parsing internal values; * Getting/setting any internal values; * Creatiion of a new X.509 certificate "from scratch"; - * Internal certificate chain validation engine. + * **Internal certificate chain validation engine**; * X.509 "certificate revocation lists" (CRLs): * Parsing internal values; * Getting/setting any internal values; diff --git a/examples/CMS Signed complex example/CMSSigned_complex_example.html b/examples/CMS Signed complex example/CMSSigned_complex_example.html index 0d765204c..920b0e914 100644 --- a/examples/CMS Signed complex example/CMSSigned_complex_example.html +++ b/examples/CMS Signed complex example/CMSSigned_complex_example.html @@ -248,32 +248,37 @@ var publicKey; var privateKey; - var hash_algorithm = "sha-1"; - var hash_algorithm_oid = "1.3.14.3.2.26"; - var signature_algorithm = "1.2.840.113549.1.1.5"; - + var hash_algorithm; var hash_option = document.getElementById("hash_alg").value; switch(hash_option) { case "alg_SHA1": hash_algorithm = "sha-1"; - hash_algorithm_oid = "1.3.14.3.2.26"; - signature_algorithm = "1.2.840.113549.1.1.5"; break; case "alg_SHA256": hash_algorithm = "sha-256"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.1"; - signature_algorithm = "1.2.840.113549.1.1.11"; break; case "alg_SHA384": hash_algorithm = "sha-384"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.2"; - signature_algorithm = "1.2.840.113549.1.1.12"; break; case "alg_SHA512": hash_algorithm = "sha-512"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.3"; - signature_algorithm = "1.2.840.113549.1.1.13"; + break; + default:; + } + + var signature_algorithm_name; + var sign_option = document.getElementById("sign_alg").value; + switch(sign_option) + { + case "alg_RSA15": + signature_algorithm_name = "RSASSA-PKCS1-V1_5"; + break; + case "alg_RSA2": + signature_algorithm_name = "RSA-PSS"; + break; + case "alg_ECDSA": + signature_algorithm_name = "ECDSA"; break; default:; } @@ -343,16 +348,19 @@ parsedValue: key_usage // Parsed value for well-known extensions })); // #endregion - - cert_simpl.signatureAlgorithm.algorithm_id = signature_algorithm; - cert_simpl.signature.algorithm_id = cert_simpl.signatureAlgorithm.algorithm_id; // Must be the same value // #endregion // #region Create a new key pair sequence = sequence.then( function() { - return crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: hash_algorithm } }, true, ["sign", "verify"]); + // #region Get default algorithm parameters for key generation + var algorithm = org.pkijs.getAlgorithmParameters(signature_algorithm_name, "generatekey"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = hash_algorithm; + // #endregion + + return crypto.generateKey(algorithm.algorithm, true, algorithm.usages); } ); // #endregion @@ -384,7 +392,7 @@ sequence = sequence.then( function() { - return cert_simpl.sign(privateKey); + return cert_simpl.sign(privateKey, hash_algorithm); }, function(error) { @@ -498,12 +506,6 @@ { cms_signed_simpl = new org.pkijs.simpl.CMS_SIGNED_DATA({ version: 1, - digestAlgorithms: [ - new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ - algorithm_id: hash_algorithm_oid, - algorithm_params: new org.pkijs.asn1.NULL() - }) // SHA-1 - ], encapContentInfo: new org.pkijs.simpl.cms.EncapsulatedContentInfo({ eContentType: "1.2.840.113549.1.7.1", // "data" content type eContent: new org.pkijs.asn1.OCTETSTRING({ value_hex: buffer }) @@ -514,15 +516,7 @@ sid: new org.pkijs.simpl.cms.IssuerAndSerialNumber({ issuer: cert_simpl.issuer, serialNumber: cert_simpl.serialNumber - }), - digestAlgorithm: new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ - algorithm_id: hash_algorithm_oid, - algorithm_params: new org.pkijs.asn1.NULL() - }), // SHA-1 - signatureAlgorithm: new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ - algorithm_id: "1.2.840.113549.1.1.1", - algorithm_params: new org.pkijs.asn1.NULL() - }), // RSA (PKCS #1 v1.5) key transport algorithm + }) }) ], certificates: [cert_simpl] @@ -536,7 +530,7 @@ }); } - return cms_signed_simpl.sign(privateKey, 0); + return cms_signed_simpl.sign(privateKey, 0, hash_algorithm); } ); // #endregion @@ -932,6 +926,14 @@
++ + +
diff --git a/examples/CRL complex example/CRL_complex_example.html b/examples/CRL complex example/CRL_complex_example.html index c8b5ca6e9..10b0fc274 100644 --- a/examples/CRL complex example/CRL_complex_example.html +++ b/examples/CRL complex example/CRL_complex_example.html @@ -241,32 +241,37 @@ var publicKey; var privateKey; - var hash_algorithm = "sha-1"; - var hash_algorithm_oid = "1.3.14.3.2.26"; - var signature_algorithm = "1.2.840.113549.1.1.5"; - + var hash_algorithm; var hash_option = document.getElementById("hash_alg").value; switch(hash_option) { case "alg_SHA1": hash_algorithm = "sha-1"; - hash_algorithm_oid = "1.3.14.3.2.26"; - signature_algorithm = "1.2.840.113549.1.1.5"; break; case "alg_SHA256": hash_algorithm = "sha-256"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.1"; - signature_algorithm = "1.2.840.113549.1.1.11"; break; case "alg_SHA384": hash_algorithm = "sha-384"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.2"; - signature_algorithm = "1.2.840.113549.1.1.12"; break; case "alg_SHA512": hash_algorithm = "sha-512"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.3"; - signature_algorithm = "1.2.840.113549.1.1.13"; + break; + default:; + } + + var signature_algorithm_name; + var sign_option = document.getElementById("sign_alg").value; + switch(sign_option) + { + case "alg_RSA15": + signature_algorithm_name = "RSASSA-PKCS1-V1_5"; + break; + case "alg_RSA2": + signature_algorithm_name = "RSA-PSS"; + break; + case "alg_ECDSA": + signature_algorithm_name = "ECDSA"; break; default:; } @@ -318,16 +323,19 @@ extnID: "2.5.29.20", // cRLNumber extnValue: (new org.pkijs.asn1.INTEGER({ value: 2 })).toBER(false) })]; - - crl_simpl.signatureAlgorithm.algorithm_id = signature_algorithm; - crl_simpl.signature.algorithm_id = signature_algorithm; // #endregion // #region Create a new key pair sequence = sequence.then( function() { - return crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: hash_algorithm } }, true, ["sign", "verify"]); + // #region Get default algorithm parameters for key generation + var algorithm = org.pkijs.getAlgorithmParameters(signature_algorithm_name, "generatekey"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = hash_algorithm; + // #endregion + + return crypto.generateKey(algorithm.algorithm, true, algorithm.usages); } ); // #endregion @@ -353,7 +361,7 @@ sequence = sequence.then( function() { - return crl_simpl.sign(privateKey); + return crl_simpl.sign(privateKey, hash_algorithm); }, function(error) { @@ -630,6 +638,14 @@ ++ + +
Create diff --git a/examples/Certificate complex example/X509_cert_complex_example.html b/examples/Certificate complex example/X509_cert_complex_example.html index 2644336ab..b2c517b6e 100644 --- a/examples/Certificate complex example/X509_cert_complex_example.html +++ b/examples/Certificate complex example/X509_cert_complex_example.html @@ -340,32 +340,37 @@ var publicKey; var privateKey; - var hash_algorithm = "sha-1"; - var hash_algorithm_oid = "1.3.14.3.2.26"; - var signature_algorithm = "1.2.840.113549.1.1.5"; - + var hash_algorithm; var hash_option = document.getElementById("hash_alg").value; switch(hash_option) { case "alg_SHA1": hash_algorithm = "sha-1"; - hash_algorithm_oid = "1.3.14.3.2.26"; - signature_algorithm = "1.2.840.113549.1.1.5"; break; case "alg_SHA256": hash_algorithm = "sha-256"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.1"; - signature_algorithm = "1.2.840.113549.1.1.11"; break; case "alg_SHA384": hash_algorithm = "sha-384"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.2"; - signature_algorithm = "1.2.840.113549.1.1.12"; break; case "alg_SHA512": hash_algorithm = "sha-512"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.3"; - signature_algorithm = "1.2.840.113549.1.1.13"; + break; + default:; + } + + var signature_algorithm_name; + var sign_option = document.getElementById("sign_alg").value; + switch(sign_option) + { + case "alg_RSA15": + signature_algorithm_name = "RSASSA-PKCS1-V1_5"; + break; + case "alg_RSA2": + signature_algorithm_name = "RSA-PSS"; + break; + case "alg_ECDSA": + signature_algorithm_name = "ECDSA"; break; default:; } @@ -435,16 +440,19 @@ parsedValue: key_usage // Parsed value for well-known extensions })); // #endregion - - cert_simpl.signatureAlgorithm.algorithm_id = signature_algorithm; - cert_simpl.signature.algorithm_id = cert_simpl.signatureAlgorithm.algorithm_id; // Must be the same value // #endregion // #region Create a new key pair sequence = sequence.then( function() { - return crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: hash_algorithm } }, true, ["sign", "verify"]); + // #region Get default algorithm parameters for key generation + var algorithm = org.pkijs.getAlgorithmParameters(signature_algorithm_name, "generatekey"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = hash_algorithm; + // #endregion + + return crypto.generateKey(algorithm.algorithm, true, algorithm.usages); } ); // #endregion @@ -476,7 +484,7 @@ sequence = sequence.then( function() { - return cert_simpl.sign(privateKey); + return cert_simpl.sign(privateKey, hash_algorithm); }, function(error) { @@ -668,21 +676,18 @@ // #region Put information about signature algorithm var algomap = { - "1.2.840.113549.2.1": "MD2", "1.2.840.113549.1.1.2": "MD2 with RSA", - "1.2.840.113549.2.5": "MD5", "1.2.840.113549.1.1.4": "MD5 with RSA", - "1.3.14.3.2.26": "SHA1", "1.2.840.10040.4.3": "SHA1 with DSA", "1.2.840.10045.4.1": "SHA1 with ECDSA", + "1.2.840.10045.4.3.2": "SHA256 with ECDSA", + "1.2.840.10045.4.3.3": "SHA384 with ECDSA", + "1.2.840.10045.4.3.4": "SHA512 with ECDSA", + "1.2.840.113549.1.1.10": "RSA-PSS", "1.2.840.113549.1.1.5": "SHA1 with RSA", - "2.16.840.1.101.3.4.2.4": "SHA224", "1.2.840.113549.1.1.14": "SHA224 with RSA", - "2.16.840.1.101.3.4.2.1": "SHA256", "1.2.840.113549.1.1.11": "SHA256 with RSA", - "2.16.840.1.101.3.4.2.2": "SHA384", "1.2.840.113549.1.1.12": "SHA384 with RSA", - "2.16.840.1.101.3.4.2.3": "SHA512", "1.2.840.113549.1.1.13": "SHA512 with RSA" }; // array mapping of common algorithm OIDs and corresponding types @@ -905,6 +910,14 @@ ++ + +
Create diff --git a/examples/Create new CMS Signed data/CreateCMSSignedData.html b/examples/Create new CMS Signed data/CreateCMSSignedData.html index 3aa973609..2f9ea2c24 100644 --- a/examples/Create new CMS Signed data/CreateCMSSignedData.html +++ b/examples/Create new CMS Signed data/CreateCMSSignedData.html @@ -86,32 +86,37 @@ var publicKey; var privateKey; - var hash_algorithm = "sha-1"; - var hash_algorithm_oid = "1.3.14.3.2.26"; - var signature_algorithm = "1.2.840.113549.1.1.5"; - + var hash_algorithm; var hash_option = document.getElementById("hash_alg").value; switch(hash_option) { case "alg_SHA1": hash_algorithm = "sha-1"; - hash_algorithm_oid = "1.3.14.3.2.26"; - signature_algorithm = "1.2.840.113549.1.1.5"; break; case "alg_SHA256": hash_algorithm = "sha-256"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.1"; - signature_algorithm = "1.2.840.113549.1.1.11"; break; case "alg_SHA384": hash_algorithm = "sha-384"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.2"; - signature_algorithm = "1.2.840.113549.1.1.12"; break; case "alg_SHA512": hash_algorithm = "sha-512"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.3"; - signature_algorithm = "1.2.840.113549.1.1.13"; + break; + default:; + } + + var signature_algorithm_name; + var sign_option = document.getElementById("sign_alg").value; + switch(sign_option) + { + case "alg_RSA15": + signature_algorithm_name = "RSASSA-PKCS1-V1_5"; + break; + case "alg_RSA2": + signature_algorithm_name = "RSA-PSS"; + break; + case "alg_ECDSA": + signature_algorithm_name = "ECDSA"; break; default:; } @@ -126,7 +131,7 @@ } // #endregion - // #region Put a static values + // #region Put a static values into certificate "helper" object cert_simpl.version = 2; cert_simpl.serialNumber = new org.pkijs.asn1.INTEGER({ value: 1 }); cert_simpl.issuer.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({ @@ -151,26 +156,11 @@ cert_simpl.extensions = new Array(); // Extensions are not a part of certificate by default, it's an optional array - // #region "BasicConstraints" extension - var basic_constr = new org.pkijs.simpl.x509.BasicConstraints({ - cA: true, - pathLenConstraint: 3 - }); - - cert_simpl.extensions.push(new org.pkijs.simpl.EXTENSION({ - extnID: "2.5.29.19", - critical: false, - extnValue: basic_constr.toSchema().toBER(false), - parsedValue: basic_constr // Parsed value for well-known extensions - })); - // #endregion - // #region "KeyUsage" extension var bit_array = new ArrayBuffer(1); var bit_view = new Uint8Array(bit_array); bit_view[0] = bit_view[0] | 0x02; // Key usage "cRLSign" flag - bit_view[0] = bit_view[0] | 0x04; // Key usage "keyCertSign" flag var key_usage = new org.pkijs.asn1.BITSTRING({ value_hex: bit_array }); @@ -181,16 +171,19 @@ parsedValue: key_usage // Parsed value for well-known extensions })); // #endregion - - cert_simpl.signatureAlgorithm.algorithm_id = signature_algorithm; - cert_simpl.signature.algorithm_id = cert_simpl.signatureAlgorithm.algorithm_id; // Must be the same value // #endregion // #region Create a new key pair sequence = sequence.then( function() { - return crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: hash_algorithm } }, true, ["sign", "verify"]); + // #region Get default algorithm parameters for key generation + var algorithm = org.pkijs.getAlgorithmParameters(signature_algorithm_name, "generatekey"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = hash_algorithm; + // #endregion + + return crypto.generateKey(algorithm.algorithm, true, algorithm.usages); } ); // #endregion @@ -222,7 +215,7 @@ sequence = sequence.then( function() { - return cert_simpl.sign(privateKey); + return cert_simpl.sign(privateKey, hash_algorithm); }, function(error) { @@ -336,12 +329,6 @@ { cms_signed_simpl = new org.pkijs.simpl.CMS_SIGNED_DATA({ version: 1, - digestAlgorithms: [ - new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ - algorithm_id: hash_algorithm_oid, - algorithm_params: new org.pkijs.asn1.NULL() - }) // SHA-1 - ], encapContentInfo: new org.pkijs.simpl.cms.EncapsulatedContentInfo({ eContentType: "1.2.840.113549.1.7.1", // "data" content type eContent: new org.pkijs.asn1.OCTETSTRING({ value_hex: buffer }) @@ -352,15 +339,7 @@ sid: new org.pkijs.simpl.cms.IssuerAndSerialNumber({ issuer: cert_simpl.issuer, serialNumber: cert_simpl.serialNumber - }), - digestAlgorithm: new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ - algorithm_id: hash_algorithm_oid, - algorithm_params: new org.pkijs.asn1.NULL() - }), // SHA-1 - signatureAlgorithm: new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ - algorithm_id: "1.2.840.113549.1.1.1", - algorithm_params: new org.pkijs.asn1.NULL() - }), // RSA (PKCS #1 v1.5) key transport algorithm + }) }) ], certificates: [cert_simpl] @@ -374,7 +353,7 @@ }); } - return cms_signed_simpl.sign(privateKey, 0); + return cms_signed_simpl.sign(privateKey, 0, hash_algorithm); } ); // #endregion @@ -385,7 +364,7 @@ var cms_signed_schema = cms_signed_simpl.toSchema(true); var cms_content_simp = new org.pkijs.simpl.CMS_CONTENT_INFO({ - contentType: "1.2.840.113549.1.7.2", + contentType: "1.2.840.113549.1.7.2", // CMS Signed Data content: cms_signed_schema }); @@ -470,6 +449,14 @@ ++ + +
diff --git a/examples/Create new X.509 certificate/CreateNewX509Certificate.html b/examples/Create new X.509 certificate/CreateNewX509Certificate.html index 7bd2df7d2..993caa799 100644 --- a/examples/Create new X.509 certificate/CreateNewX509Certificate.html +++ b/examples/Create new X.509 certificate/CreateNewX509Certificate.html @@ -1,35 +1,4 @@ - - + @@ -179,16 +148,19 @@ parsedValue: key_usage // Parsed value for well-known extensions })); // #endregion - - cert_simpl.signatureAlgorithm.algorithm_id = "1.2.840.113549.1.1.5"; // RSA + SHA-1 - cert_simpl.signature.algorithm_id = cert_simpl.signatureAlgorithm.algorithm_id; // Must be the same value // #endregion // #region Create a new key pair sequence = sequence.then( function() { - return crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: "sha-1" } }, true, ["encrypt", "decrypt", "sign", "verify"]); + // #region Get default algorithm parameters for key generation + var algorithm = org.pkijs.getAlgorithmParameters("RSASSA-PKCS1-v1_5", "generatekey"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = "SHA-1"; + // #endregion + + return crypto.generateKey(algorithm.algorithm, true, algorithm.usages); } ); // #endregion @@ -220,7 +192,7 @@ sequence = sequence.then( function() { - return cert_simpl.sign(privateKey); + return cert_simpl.sign(privateKey, "SHA-1"); }, function(error) { diff --git a/examples/OCSP response complex example/OCSP_resp_complex_example.html b/examples/OCSP response complex example/OCSP_resp_complex_example.html index f899d6dc2..ca0f6bb63 100644 --- a/examples/OCSP response complex example/OCSP_resp_complex_example.html +++ b/examples/OCSP response complex example/OCSP_resp_complex_example.html @@ -237,32 +237,37 @@ var publicKey; var privateKey; - var hash_algorithm = "sha-1"; - var hash_algorithm_oid = "1.3.14.3.2.26"; - var signature_algorithm = "1.2.840.113549.1.1.5"; - + var hash_algorithm; var hash_option = document.getElementById("hash_alg").value; switch(hash_option) { case "alg_SHA1": hash_algorithm = "sha-1"; - hash_algorithm_oid = "1.3.14.3.2.26"; - signature_algorithm = "1.2.840.113549.1.1.5"; break; case "alg_SHA256": hash_algorithm = "sha-256"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.1"; - signature_algorithm = "1.2.840.113549.1.1.11"; break; case "alg_SHA384": hash_algorithm = "sha-384"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.2"; - signature_algorithm = "1.2.840.113549.1.1.12"; break; case "alg_SHA512": hash_algorithm = "sha-512"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.3"; - signature_algorithm = "1.2.840.113549.1.1.13"; + break; + default:; + } + + var signature_algorithm_name; + var sign_option = document.getElementById("sign_alg").value; + switch(sign_option) + { + case "alg_RSA15": + signature_algorithm_name = "RSASSA-PKCS1-V1_5"; + break; + case "alg_RSA2": + signature_algorithm_name = "RSA-PSS"; + break; + case "alg_ECDSA": + signature_algorithm_name = "ECDSA"; break; default:; } @@ -332,16 +337,19 @@ parsedValue: key_usage // Parsed value for well-known extensions })); // #endregion - - cert_simpl.signatureAlgorithm.algorithm_id = signature_algorithm; - cert_simpl.signature.algorithm_id = cert_simpl.signatureAlgorithm.algorithm_id; // Must be the same value // #endregion // #region Create a new key pair sequence = sequence.then( function() { - return crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: hash_algorithm } }, true, ["sign", "verify"]); + // #region Get default algorithm parameters for key generation + var algorithm = org.pkijs.getAlgorithmParameters(signature_algorithm_name, "generatekey"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = hash_algorithm; + // #endregion + + return crypto.generateKey(algorithm.algorithm, true, algorithm.usages); } ); // #endregion @@ -373,7 +381,7 @@ sequence = sequence.then( function() { - return cert_simpl.sign(privateKey); + return cert_simpl.sign(privateKey, hash_algorithm); }, function(error) { @@ -468,10 +476,9 @@ ocsp_basic_resp.tbsResponseData.responses.push(response); - ocsp_basic_resp.signatureAlgorithm.algorithm_id = "1.2.840.113549.1.1.5"; // RSA + SHA-1 ocsp_basic_resp.certs = [cert_simpl]; - return ocsp_basic_resp.sign(privateKey); + return ocsp_basic_resp.sign(privateKey, hash_algorithm); } ); // #endregion @@ -908,6 +915,14 @@ ++ + +
Create diff --git a/examples/PKCS#10 complex example/PKCS10_complex_example.html b/examples/PKCS#10 complex example/PKCS10_complex_example.html index 1b11b1228..645c37760 100644 --- a/examples/PKCS#10 complex example/PKCS10_complex_example.html +++ b/examples/PKCS#10 complex example/PKCS10_complex_example.html @@ -178,6 +178,41 @@ var publicKey; var privateKey; + + var hash_algorithm; + var hash_option = document.getElementById("hash_alg").value; + switch(hash_option) + { + case "alg_SHA1": + hash_algorithm = "sha-1"; + break; + case "alg_SHA256": + hash_algorithm = "sha-256"; + break; + case "alg_SHA384": + hash_algorithm = "sha-384"; + break; + case "alg_SHA512": + hash_algorithm = "sha-512"; + break; + default:; + } + + var signature_algorithm_name; + var sign_option = document.getElementById("sign_alg").value; + switch(sign_option) + { + case "alg_RSA15": + signature_algorithm_name = "RSASSA-PKCS1-V1_5"; + break; + case "alg_RSA2": + signature_algorithm_name = "RSA-PSS"; + break; + case "alg_ECDSA": + signature_algorithm_name = "ECDSA"; + break; + default:; + } // #endregion // #region Get a "crypto" extension @@ -193,16 +228,19 @@ pkcs10_simpl.version = 0; pkcs10_simpl.subject.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({ type: "2.5.4.6", value: new org.pkijs.asn1.PRINTABLESTRING({ value: "RU" }) })); pkcs10_simpl.subject.types_and_values.push(new org.pkijs.simpl.ATTR_TYPE_AND_VALUE({ type: "2.5.4.3", value: new org.pkijs.asn1.UTF8STRING({ value: "Simple test (простой тест)" }) })); - - pkcs10_simpl.signatureAlgorithm.algorithm_id = "1.2.840.113549.1.1.5"; // RSA + SHA-1 // #endregion // #region Create a new key pair sequence = sequence.then( function() { - return crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: "sha-1" } }, true, ["sign", "verify"]); + // #region Get default algorithm parameters for key generation + var algorithm = org.pkijs.getAlgorithmParameters(signature_algorithm_name, "generatekey"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = hash_algorithm; + // #endregion + return crypto.generateKey(algorithm.algorithm, true, algorithm.usages); } ); // #endregion @@ -234,7 +272,7 @@ sequence = sequence.then( function() { - return pkcs10_simpl.sign(privateKey); + return pkcs10_simpl.sign(privateKey, hash_algorithm); }, function(error) { @@ -314,42 +352,50 @@ // #endregion // #region Put information about public key size - var asn1_publicKey = org.pkijs.fromBER(pkcs10_simpl.subjectPublicKeyInfo.subjectPublicKey.value_block.value_hex), - rsa_publicKey_simple = new org.pkijs.simpl.x509.RSAPublicKey({ schema: asn1_publicKey.result }), - modulus_view = new Uint8Array(rsa_publicKey_simple.modulus.value_block.value_hex), - modulus_bit_length = 0; + var publicKeySize = "< unknown >"; - if(modulus_view[0] === 0x00) - modulus_bit_length = (rsa_publicKey_simple.modulus.value_block.value_hex.byteLength - 1) * 8; - else - modulus_bit_length = rsa_publicKey_simple.modulus.value_block.value_hex.byteLength * 8; + if(pkcs10_simpl.subjectPublicKeyInfo.algorithm.algorithm_id.indexOf("1.2.840.113549") !== (-1)) + { + var asn1_publicKey = org.pkijs.fromBER(pkcs10_simpl.subjectPublicKeyInfo.subjectPublicKey.value_block.value_hex); + var rsa_publicKey_simple = new org.pkijs.simpl.x509.RSAPublicKey({ schema: asn1_publicKey.result }); + var modulus_view = new Uint8Array(rsa_publicKey_simple.modulus.value_block.value_hex); + var modulus_bit_length = 0; + + if(modulus_view[0] === 0x00) + modulus_bit_length = (rsa_publicKey_simple.modulus.value_block.value_hex.byteLength - 1) * 8; + else + modulus_bit_length = rsa_publicKey_simple.modulus.value_block.value_hex.byteLength * 8; - var publicExponent_bit_length = rsa_publicKey_simple.publicExponent.value_block.value_hex.byteLength * 8; + publicKeySize = modulus_bit_length.toString(); + } - document.getElementById("keysize").innerHTML = modulus_bit_length; + document.getElementById("keysize").innerHTML = publicKeySize; // #endregion // #region Put information about signature algorithm var algomap = { - "1.2.840.113549.2.1": "MD2", "1.2.840.113549.1.1.2": "MD2 with RSA", - "1.2.840.113549.2.5": "MD5", "1.2.840.113549.1.1.4": "MD5 with RSA", - "1.3.14.3.2.26": "SHA1", "1.2.840.10040.4.3": "SHA1 with DSA", "1.2.840.10045.4.1": "SHA1 with ECDSA", + "1.2.840.10045.4.3.2": "SHA256 with ECDSA", + "1.2.840.10045.4.3.3": "SHA384 with ECDSA", + "1.2.840.10045.4.3.4": "SHA512 with ECDSA", + "1.2.840.113549.1.1.10": "RSA-PSS", "1.2.840.113549.1.1.5": "SHA1 with RSA", - "2.16.840.1.101.3.4.2.4": "SHA224", "1.2.840.113549.1.1.14": "SHA224 with RSA", - "2.16.840.1.101.3.4.2.1": "SHA256", "1.2.840.113549.1.1.11": "SHA256 with RSA", - "2.16.840.1.101.3.4.2.2": "SHA384", "1.2.840.113549.1.1.12": "SHA384 with RSA", - "2.16.840.1.101.3.4.2.3": "SHA512", "1.2.840.113549.1.1.13": "SHA512 with RSA" }; - document.getElementById("sig-algo").innerHTML = algomap[pkcs10_simpl.signatureAlgorithm.algorithm_id]; + var signatureAlgorithm = algomap[pkcs10_simpl.signatureAlgorithm.algorithm_id]; + if(typeof signatureAlgorithm === "undefined") + signatureAlgorithm = pkcs10_simpl.signatureAlgorithm.algorithm_id; + else + signatureAlgorithm = signatureAlgorithm + " (" + pkcs10_simpl.signatureAlgorithm.algorithm_id + ")"; + + document.getElementById("sig-algo").innerHTML = signatureAlgorithm; // #endregion // #region Put information about PKCS#10 attributes @@ -430,6 +476,23 @@+ + +
++ + +
Create diff --git a/examples/TSP response complex example/TSP_resp_complex_example.html b/examples/TSP response complex example/TSP_resp_complex_example.html index 9fd230bea..8f1321ae1 100644 --- a/examples/TSP response complex example/TSP_resp_complex_example.html +++ b/examples/TSP response complex example/TSP_resp_complex_example.html @@ -234,32 +234,37 @@ var publicKey; var privateKey; - var hash_algorithm = "sha-1"; - var hash_algorithm_oid = "1.3.14.3.2.26"; - var signature_algorithm = "1.2.840.113549.1.1.5"; - + var hash_algorithm; var hash_option = document.getElementById("hash_alg").value; switch(hash_option) { case "alg_SHA1": hash_algorithm = "sha-1"; - hash_algorithm_oid = "1.3.14.3.2.26"; - signature_algorithm = "1.2.840.113549.1.1.5"; break; case "alg_SHA256": hash_algorithm = "sha-256"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.1"; - signature_algorithm = "1.2.840.113549.1.1.11"; break; case "alg_SHA384": hash_algorithm = "sha-384"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.2"; - signature_algorithm = "1.2.840.113549.1.1.12"; break; case "alg_SHA512": hash_algorithm = "sha-512"; - hash_algorithm_oid = "2.16.840.1.101.3.4.2.3"; - signature_algorithm = "1.2.840.113549.1.1.13"; + break; + default:; + } + + var signature_algorithm_name; + var sign_option = document.getElementById("sign_alg").value; + switch(sign_option) + { + case "alg_RSA15": + signature_algorithm_name = "RSASSA-PKCS1-V1_5"; + break; + case "alg_RSA2": + signature_algorithm_name = "RSA-PSS"; + break; + case "alg_ECDSA": + signature_algorithm_name = "ECDSA"; break; default:; } @@ -329,16 +334,19 @@ parsedValue: key_usage // Parsed value for well-known extensions })); // #endregion - - cert_simpl.signatureAlgorithm.algorithm_id = signature_algorithm; - cert_simpl.signature.algorithm_id = cert_simpl.signatureAlgorithm.algorithm_id; // Must be the same value // #endregion // #region Create a new key pair sequence = sequence.then( function() { - return crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: hash_algorithm } }, true, ["sign", "verify"]); + // #region Get default algorithm parameters for key generation + var algorithm = org.pkijs.getAlgorithmParameters(signature_algorithm_name, "generatekey"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = hash_algorithm; + // #endregion + + return crypto.generateKey(algorithm.algorithm, true, algorithm.usages); } ); // #endregion @@ -370,7 +378,7 @@ sequence = sequence.then( function() { - return cert_simpl.sign(privateKey); + return cert_simpl.sign(privateKey, hash_algorithm); }, function(error) { @@ -478,12 +486,6 @@ cms_signed_simpl = new org.pkijs.simpl.CMS_SIGNED_DATA({ version: 3, - digestAlgorithms: [ - new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ - algorithm_id: hash_algorithm_oid, - algorithm_params: new org.pkijs.asn1.NULL() - }) // SHA-1 - ], encapContentInfo: encapContent, signerInfos: [ new org.pkijs.simpl.CMS_SIGNER_INFO({ @@ -491,21 +493,13 @@ sid: new org.pkijs.simpl.cms.IssuerAndSerialNumber({ issuer: cert_simpl.issuer, serialNumber: cert_simpl.serialNumber - }), - digestAlgorithm: new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ - algorithm_id: hash_algorithm_oid, - algorithm_params: new org.pkijs.asn1.NULL() - }), // SHA-1 - signatureAlgorithm: new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ - algorithm_id: "1.2.840.113549.1.1.1", - algorithm_params: new org.pkijs.asn1.NULL() - }), // RSA (PKCS #1 v1.5) key transport algorithm + }) }) ], certificates: [cert_simpl] }); - return cms_signed_simpl.sign(privateKey, 0); + return cms_signed_simpl.sign(privateKey, 0, hash_algorithm); } ); // #endregion @@ -963,6 +957,14 @@ ++ + +
Create diff --git a/examples/Use WebCrypto/HowToUseWebCrypto.js b/examples/Use WebCrypto/HowToUseWebCrypto.js index 94bb7d0ec..fb8292526 100644 --- a/examples/Use WebCrypto/HowToUseWebCrypto.js +++ b/examples/Use WebCrypto/HowToUseWebCrypto.js @@ -58,9 +58,9 @@ function test_web_crypto() var crypto = window.crypto.subtle; // #endregion - crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: "sha-1" }}, + crypto.generateKey({ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: "sha-1" } }, true, - ["encrypt", "decrypt", "sign", "verify"]). + ["sign", "verify"]). then( function(result) // result of generating key pair { @@ -68,11 +68,20 @@ function test_web_crypto() privateKey = result.privateKey; return crypto.exportKey("spki", publicKey); - }). + }, + function(error) + { + console.log("ERROR #1: " + error); + } + ). then( function(result) // result of exporting public key { - return crypto.importKey("spki", new Uint8Array(result), { name: "RSASSA-PKCS1-v1_5", hash: { name: "sha-1" } }, true, ["sign", "verify"]); + return crypto.importKey("spki", new Uint8Array(result), { name: "RSASSA-PKCS1-v1_5", hash: { name: "sha-1" } }, true, ["verify"]); + }, + function(error) + { + console.log("ERROR #2: " + error); } ). then( @@ -80,12 +89,20 @@ function test_web_crypto() { publicKey = result; return crypto.exportKey("pkcs8", privateKey); + }, + function(error) + { + console.log("ERROR #3: " + error); } ). then( function(result) // result of exporting private key { - return crypto.importKey("pkcs8", new Uint8Array(result), { name: "RSASSA-PKCS1-v1_5", hash: { name: "sha-1" } }, true, ["sign", "verify"]); + return crypto.importKey("pkcs8", new Uint8Array(result), { name: "RSASSA-PKCS1-v1_5", hash: { name: "sha-1" } }, true, ["sign"]); + }, + function(error) + { + console.log("ERROR #4: " + error); } ). then( @@ -93,18 +110,30 @@ function test_web_crypto() { privateKey = result; return crypto.sign({ name: "RSASSA-PKCS1-v1_5", hash: { name: "sha-512" } }, result, value_hex_view); + }, + function(error) + { + console.log("ERROR #5: " + error); } ). then( function(result) // result of signing test data { return crypto.verify({ name: "RSASSA-PKCS1-v1_5", hash: { name: "sha-512" } }, publicKey, new Uint8Array(result), value_hex_view); + }, + function(error) + { + console.log("ERROR #6: " + error); } ). then( function(result) // result of verifying test signature { alert("Message verified: " + result); + }, + function(error) + { + console.log("ERROR #7: " + error); } ); } diff --git a/org/pkijs/cms_schema.js b/org/pkijs/cms_schema.js index c4e764e38..4d8504c1e 100644 --- a/org/pkijs/cms_schema.js +++ b/org/pkijs/cms_schema.js @@ -286,6 +286,52 @@ function(in_window) //************************************************************************************** // #endregion //************************************************************************************** + // #region ASN.1 schema definition for "RSAES-OAEP-params" type (RFC3447) + //************************************************************************************** + in_window.org.pkijs.schema.x509.RSAES_OAEP_params = + function() + { + //RSAES-OAEP-params ::= SEQUENCE { + // hashAlgorithm [0] HashAlgorithm DEFAULT sha1, + // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, + // pSourceAlgorithm [2] PSourceAlgorithm DEFAULT pSpecifiedEmpty + //} + + var names = in_window.org.pkijs.getNames(arguments[0]); + + return (new in_window.org.pkijs.asn1.SEQUENCE({ + name: (names.block_name || ""), + value: [ + new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED({ + id_block: { + tag_class: 3, // CONTEXT-SPECIFIC + tag_number: 0 // [0] + }, + optional: true, + value: [in_window.org.pkijs.schema.ALGORITHM_IDENTIFIER(names.hashAlgorithm || {})] + }), + new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED({ + id_block: { + tag_class: 3, // CONTEXT-SPECIFIC + tag_number: 1 // [1] + }, + optional: true, + value: [in_window.org.pkijs.schema.ALGORITHM_IDENTIFIER(names.maskGenAlgorithm || {})] + }), + new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED({ + id_block: { + tag_class: 3, // CONTEXT-SPECIFIC + tag_number: 2 // [2] + }, + optional: true, + value: [in_window.org.pkijs.schema.ALGORITHM_IDENTIFIER(names.pSourceAlgorithm || {})] + }) + ] + })); + } + //************************************************************************************** + // #endregion + //************************************************************************************** // #region ASN.1 schema for CMS "SignedAttributes" and "UnsignedAttributes" types //************************************************************************************** in_window.org.pkijs.schema.cms.SignedUnsignedAttributes = @@ -964,13 +1010,30 @@ function(in_window) value: [ new in_window.org.pkijs.asn1.OID({ name: (names.contentType || "") }), in_window.org.pkijs.schema.ALGORITHM_IDENTIFIER(names.contentEncryptionAlgorithm || {}), - new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED({ - name: (names.encryptedContent || ""), - id_block: { - tag_class: 3, // CONTEXT-SPECIFIC - tag_number: 0 // [0] - }, - value: [new in_window.org.pkijs.asn1.OCTETSTRING()] + // The CHOICE we need because "EncryptedContent" could have either "constructive" + // or "primitive" form of encoding and we need to handle both variants + new in_window.org.pkijs.asn1.CHOICE({ + value: [ + new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED({ + name: (names.encryptedContent || ""), + id_block: { + tag_class: 3, // CONTEXT-SPECIFIC + tag_number: 0 // [0] + }, + value: [ + new in_window.org.pkijs.asn1.REPEATED({ + value: new in_window.org.pkijs.asn1.OCTETSTRING() + }) + ] + }), + new in_window.org.pkijs.asn1.ASN1_PRIMITIVE({ + name: (names.encryptedContent || ""), + id_block: { + tag_class: 3, // CONTEXT-SPECIFIC + tag_number: 0 // [0] + } + }) + ] }) ] })); diff --git a/org/pkijs/cms_simpl.js b/org/pkijs/cms_simpl.js index 34eac7b62..46921127a 100644 --- a/org/pkijs/cms_simpl.js +++ b/org/pkijs/cms_simpl.js @@ -638,6 +638,142 @@ function(in_window) //************************************************************************************** // #endregion //************************************************************************************** + // #region Simplified structure for "RSAES_OAEP_params" type (RFC3447) + //************************************************************************************** + in_window.org.pkijs.simpl.x509.RSAES_OAEP_params = + function() + { + // #region Internal properties of the object + // OPTIONAL this.hashAlgorithm = new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER(); + // OPTIONAL this.maskGenAlgorithm = new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER(); + // OPTIONAL this.pSourceAlgorithm = new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER(); + // #endregion + + // #region If input argument array contains "schema" for this object + if((arguments[0] instanceof Object) && ("schema" in arguments[0])) + in_window.org.pkijs.simpl.x509.RSAES_OAEP_params.prototype.fromSchema.call(this, arguments[0].schema); + // #endregion + // #region If input argument array contains "native" values for internal properties + else + { + if(arguments[0] instanceof Object) + { + if("hashAlgorithm" in arguments[0]) + this.hashAlgorithm = arguments[0].hashAlgorithm; + + if("maskGenAlgorithm" in arguments[0]) + this.maskGenAlgorithm = arguments[0].maskGenAlgorithm; + + if("pSourceAlgorithm" in arguments[0]) + this.pSourceAlgorithm = arguments[0].pSourceAlgorithm; + } + } + // #endregion + } + //************************************************************************************** + in_window.org.pkijs.simpl.x509.RSAES_OAEP_params.prototype.fromSchema = + function(schema) + { + // #region Check the schema is valid + var asn1 = in_window.org.pkijs.compareSchema(schema, + schema, + in_window.org.pkijs.schema.x509.RSAES_OAEP_params({ + names: { + hashAlgorithm: { + names: { + block_name: "hashAlgorithm" + } + }, + maskGenAlgorithm: { + names: { + block_name: "maskGenAlgorithm" + } + }, + pSourceAlgorithm: { + names: { + block_name: "pSourceAlgorithm" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RSAES_OAEP_params"); + // #endregion + + // #region Get internal properties from parsed schema + if("hashAlgorithm" in asn1.result) + this.hashAlgorithm = new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER({ schema: asn1.result["hashAlgorithm"] }); + + if("maskGenAlgorithm" in asn1.result) + this.maskGenAlgorithm = new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER({ schema: asn1.result["maskGenAlgorithm"] }); + + if("pSourceAlgorithm" in asn1.result) + this.pSourceAlgorithm = new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER({ schema: asn1.result["pSourceAlgorithm"] }); + // #endregion + } + //************************************************************************************** + in_window.org.pkijs.simpl.x509.RSAES_OAEP_params.prototype.toSchema = + function() + { + // #region Create array for output sequence + var output_array = new Array(); + + if("hashAlgorithm" in this) + output_array.push(new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED({ + id_block: { + tag_class: 3, // CONTEXT-SPECIFIC + tag_number: 0 // [0] + }, + value: [this.hashAlgorithm.toSchema()] + })); + + if("maskGenAlgorithm" in this) + output_array.push(new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED({ + id_block: { + tag_class: 3, // CONTEXT-SPECIFIC + tag_number: 1 // [1] + }, + value: [this.maskGenAlgorithm.toSchema()] + })); + + if("pSourceAlgorithm" in this) + output_array.push(new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED({ + id_block: { + tag_class: 3, // CONTEXT-SPECIFIC + tag_number: 2 // [2] + }, + value: [this.pSourceAlgorithm.toSchema()] + })); + // #endregion + + // #region Construct and return new ASN.1 schema for this object + return (new in_window.org.pkijs.asn1.SEQUENCE({ + value: output_array + })); + // #endregion + } + //************************************************************************************** + in_window.org.pkijs.simpl.x509.RSAES_OAEP_params.prototype.toJSON = + function() + { + var _object = {}; + + if("hashAlgorithm" in this) + _object.hashAlgorithm = this.hashAlgorithm.toJSON(); + + if("maskGenAlgorithm" in this) + _object.maskGenAlgorithm = this.maskGenAlgorithm.toJSON(); + + if("pSourceAlgorithm" in this) + _object.pSourceAlgorithm = this.pSourceAlgorithm.toJSON(); + + return _object; + } + //************************************************************************************** + // #endregion + //************************************************************************************** // #region Simplified structure for "SignedUnsignedAttributes" type //************************************************************************************** in_window.org.pkijs.simpl.cms.SignedUnsignedAttributes = @@ -1360,23 +1496,9 @@ function(in_window) sequence = sequence.then( function() { - switch(signerInfos[signerIndex].digestAlgorithm.algorithm_id) - { - case "1.3.14.3.2.26": - sha_algorithm = "sha-1"; - break; - case "2.16.840.1.101.3.4.2.1": - sha_algorithm = "sha-256"; - break; - case "2.16.840.1.101.3.4.2.2": - sha_algorithm = "sha-384"; - break; - case "2.16.840.1.101.3.4.2.3": - sha_algorithm = "sha-512"; - break; - default: - return new Promise(function(resolve, reject) { reject("Unsupported signature algorithm: " + _this.signerInfos[signerIndex].digestAlgorithm.algorithm_id); }); - } + sha_algorithm = in_window.org.pkijs.getHashAlgorithmByOID(signerInfos[signerIndex].digestAlgorithm.algorithm_id); + if(sha_algorithm === "") + return new Promise(function(resolve, reject) { reject("Unsupported signature algorithm: " + _this.signerInfos[signerIndex].digestAlgorithm.algorithm_id); }); return new Promise(function(resolve, reject) { resolve(); }); } @@ -1421,11 +1543,21 @@ function(in_window) sequence = sequence.then( function() { + // #region Get information about public key algorithm and default parameters for import + var algorithm_name = in_window.org.pkijs.getAlgorithmNameBySignature(signer_cert.signatureAlgorithm.algorithm_id); + if(algorithm_name === "") + return new Promise(function(resolve, reject) { reject("Unsupported public key algorithm: " + signer_cert.signatureAlgorithm.algorithm_id); }); + + var algorithm = in_window.org.pkijs.getAlgorithmParameters(algorithm_name, "importkey"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = sha_algorithm; + // #endregion + var publicKeyInfo_schema = signer_cert.subjectPublicKeyInfo.toSchema(); var publicKeyInfo_buffer = publicKeyInfo_schema.toBER(false); var publicKeyInfo_view = new Uint8Array(publicKeyInfo_buffer); - return crypto.importKey("spki", publicKeyInfo_view, { name: "RSASSA-PKCS1-v1_5", hash: { name: sha_algorithm } }, true, ["verify"]); + return crypto.importKey("spki", publicKeyInfo_view, algorithm.algorithm, true, algorithm.usages); } ); // #endregion @@ -1434,10 +1566,62 @@ function(in_window) sequence = sequence.then( function(publicKey) { - return crypto.verify({ name: publicKey.algorithm.name, hash: { name: sha_algorithm } }, + // #region Get default algorithm parameters for verification + var algorithm = in_window.org.pkijs.getAlgorithmParameters(publicKey.algorithm.name, "verify"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = sha_algorithm; + // #endregion + + // #region Special case for ECDSA signatures + var signature_value = signerInfos[signerIndex].signature.value_block.value_hex; + + if(publicKey.algorithm.name === "ECDSA") + { + var asn1 = in_window.org.pkijs.fromBER(signature_value); + signature_value = in_window.org.pkijs.createECDSASignatureFromCMS(asn1.result); + } + // #endregion + + // #region Special case for RSA-PSS + if(publicKey.algorithm.name === "RSA-PSS") + { + var pssParameters; + + try + { + pssParameters = new in_window.org.pkijs.simpl.x509.RSASSA_PSS_params({ schema: signerInfos[signerIndex].signatureAlgorithm.algorithm_params }); + } + catch(ex) + { + return new Promise(function(resolve, reject) { reject(ex); }); + } + + if("saltLength" in pssParameters) + algorithm.algorithm.saltLength = pssParameters.saltLength; + else + algorithm.algorithm.saltLength = 20; + + var hash_algo = "SHA-1"; + + if("hashAlgorithm" in pssParameters) + { + hash_algo = in_window.org.pkijs.getHashAlgorithmByOID(pssParameters.hashAlgorithm.algorithm_id); + if(hash_algo === "") + return new Promise(function(resolve, reject) { reject("Unrecognized hash algorithm: " + pssParameters.hashAlgorithm.algorithm_id); }); + } + + algorithm.algorithm.hash.name = hash_algo; + } + // #endregion + + return crypto.verify(algorithm.algorithm, publicKey, - new Uint8Array(signerInfos[signerIndex].signature.value_block.value_hex), + new Uint8Array(signature_value), new Uint8Array(data)); + }, + function(error) + { + return new Promise(function(resolve, reject) { reject(error); }); } ); // #endregion @@ -1446,15 +1630,16 @@ function(in_window) } //************************************************************************************** in_window.org.pkijs.simpl.CMS_SIGNED_DATA.prototype.sign = - function(privateKey, signerIndex) + function(privateKey, signerIndex, hashAlgorithm) { /// Private key for "subjectPublicKeyInfo" structure /// Index number (starting from 0) of signer index to make signature for + /// Hashing algorithm. Default SHA-1 // #region Initial variables var _this = this; var data = new ArrayBuffer(0); - var sha_algorithm = ""; + var hashAlgorithmOID = ""; // #endregion // #region Get a private key from function parameter @@ -1462,23 +1647,109 @@ function(in_window) return new Promise(function(resolve, reject) { reject("Need to provide a private key for signing"); }); // #endregion - // #region Find a correct hashing algorithm - switch(_this.signerInfos[signerIndex].digestAlgorithm.algorithm_id) + // #region Get hashing algorithm + if(typeof hashAlgorithm === "undefined") + hashAlgorithm = "SHA-1"; + + // #region Simple check for supported algorithm + hashAlgorithmOID = in_window.org.pkijs.getHashAlgorithmOID(hashAlgorithm); + if(hashAlgorithmOID === "") + return new Promise(function(resolve, reject) { reject("Unsupported hash algorithm: " + hashAlgorithm); }); + // #endregion + // #endregion + + // #region Append information about hash algorithm + var found = false; + + for(var i = 0; i < _this.digestAlgorithms.length; i++) { - case "1.3.14.3.2.26": - sha_algorithm = "sha-1"; - break; - case "2.16.840.1.101.3.4.2.1": - sha_algorithm = "sha-256"; + if(_this.digestAlgorithms[i].algorithm_id === hashAlgorithmOID) + { + found = true; break; - case "2.16.840.1.101.3.4.2.2": - sha_algorithm = "sha-384"; + } + } + + if(found === false) + { + _this.digestAlgorithms.push(new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ + algorithm_id: hashAlgorithmOID, + algorithm_params: new org.pkijs.asn1.NULL() + })); + } + + _this.signerInfos[signerIndex].digestAlgorithm = new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ + algorithm_id: hashAlgorithmOID, + algorithm_params: new org.pkijs.asn1.NULL() + }); + // #endregion + + // #region Get a "default parameters" for current algorithm + var defParams = in_window.org.pkijs.getAlgorithmParameters(privateKey.algorithm.name, "sign"); + defParams.algorithm.hash.name = hashAlgorithm; + // #endregion + + // #region Fill internal structures base on "privateKey" and "hashAlgorithm" + switch(privateKey.algorithm.name.toUpperCase()) + { + case "RSASSA-PKCS1-V1_5": + case "ECDSA": + _this.signerInfos[signerIndex].signatureAlgorithm.algorithm_id = in_window.org.pkijs.getSignatureAlgorithm(defParams.algorithm); break; - case "2.16.840.1.101.3.4.2.3": - sha_algorithm = "sha-512"; + case "RSA-PSS": + { + // #region Set "saltLength" as a length (in octets) of hash function result + switch(hashAlgorithm.toUpperCase()) + { + case "SHA-256": + defParams.algorithm.saltLength = 32; + break; + case "SHA-384": + defParams.algorithm.saltLength = 48; + break; + case "SHA-512": + defParams.algorithm.saltLength = 64; + break; + default:; + } + // #endregion + + // #region Fill "RSASSA_PSS_params" object + var paramsObject = {}; + + if(hashAlgorithm.toUpperCase() !== "SHA-1") + { + hashAlgorithmOID = in_window.org.pkijs.getHashAlgorithmOID(hashAlgorithm); + if(hashAlgorithmOID === "") + return new Promise(function(resolve, reject) { reject("Unsupported hash algorithm: " + hashAlgorithm); }); + + paramsObject.hashAlgorithm = new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ + algorithm_id: hashAlgorithmOID, + algorithm_params: new org.pkijs.asn1.NULL() + }); + + paramsObject.maskGenAlgorithm = new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ + algorithm_id: "1.2.840.113549.1.1.8", // MGF1 + algorithm_params: paramsObject.hashAlgorithm.toSchema() + }) + } + + if(defParams.algorithm.saltLength !== 20) + paramsObject.saltLength = defParams.algorithm.saltLength; + + var pssParameters = new in_window.org.pkijs.simpl.x509.RSASSA_PSS_params(paramsObject); + // #endregion + + // #region Automatically set signature algorithm + _this.signerInfos[signerIndex].signatureAlgorithm = new org.pkijs.simpl.ALGORITHM_IDENTIFIER({ + algorithm_id: "1.2.840.113549.1.1.10", + algorithm_params: pssParameters.toSchema() + }); + // #endregion + } break; default: - return new Promise(function(resolve, reject) { reject("Unsupported signature algorithm: " + this.signature.signatureAlgorithm.algorithm_id); }); + return new Promise(function(resolve, reject) { reject("Unsupported signature algorithm: " + privateKey.algorithm.name); }); } // #endregion @@ -1530,11 +1801,16 @@ function(in_window) // #endregion // #region Signing TBS data on provided private key - return crypto.sign({ name: privateKey.algorithm.name, hash: { name: sha_algorithm } }, + return crypto.sign(defParams.algorithm, privateKey, new Uint8Array(data)).then( function(result) { + // #region Special case for ECDSA algorithm + if(defParams.algorithm.name === "ECDSA") + result = in_window.org.pkijs.createCMSECDSASignature(result); + // #endregion + _this.signerInfos[signerIndex].signature = new in_window.org.pkijs.asn1.OCTETSTRING({ value_hex: result }); return new Promise(function(resolve, reject) { resolve(result); }); }, @@ -1693,12 +1969,7 @@ function(in_window) { // #region Internal properties of the object this.version = -1; - this.rid = { - toJSON: function() - { - return {}; - } - }; + this.rid = new in_window.org.pkijs.emptyObject(); this.keyEncryptionAlgorithm = new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER(); this.encryptedKey = new in_window.org.pkijs.asn1.OCTETSTRING(); // #endregion @@ -1713,7 +1984,7 @@ function(in_window) if(arguments[0] instanceof Object) { this.version = arguments[0].version || -1; - this.rid = arguments[0].rid || {}; + this.rid = arguments[0].rid || new in_window.org.pkijs.emptyObject(); this.keyEncryptionAlgorithm = arguments[0].keyEncryptionAlgorithm || new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER(); this.encryptedKey = arguments[0].encryptedKey || new in_window.org.pkijs.asn1.OCTETSTRING(); } @@ -3168,7 +3439,7 @@ function(in_window) // #region Internal properties of the object this.contentType = ""; this.contentEncryptionAlgorithm = new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER(); - // OPTIONAL this.encryptedContent + // OPTIONAL this.encryptedContent // new in_window.org.pkijs.asn1.OCTETSTRING - (!!!) could be contructive or primitive value (!!!) // #endregion // #region If input argument array contains "schema" for this object @@ -3184,7 +3455,43 @@ function(in_window) this.contentEncryptionAlgorithm = arguments[0].contentEncryptionAlgorithm || new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER(); if("encryptedContent" in arguments[0]) + { this.encryptedContent = arguments[0].encryptedContent; + + if((this.encryptedContent.id_block.tag_class === 1) && + (this.encryptedContent.id_block.tag_number === 4)) + { + // #region Divide OCTETSTRING value down to small pieces + if(this.encryptedContent.id_block.is_constructed === false) + { + var constr_string = new in_window.org.pkijs.asn1.OCTETSTRING({ + id_block: { is_constructed: true }, + is_constructed: true + }); + + var offset = 0; + var length = this.encryptedContent.value_block.value_hex.byteLength; + + while(length > 0) + { + var piece_view = new Uint8Array(this.encryptedContent.value_block.value_hex, offset, ((offset + 65536) > this.encryptedContent.value_block.value_hex.byteLength) ? (this.encryptedContent.value_block.value_hex.byteLength - offset) : 65536); + var _array = new ArrayBuffer(piece_view.length); + var _view = new Uint8Array(_array); + + for(var i = 0; i < _view.length; i++) + _view[i] = piece_view[i]; + + constr_string.value_block.value.push(new in_window.org.pkijs.asn1.OCTETSTRING({ value_hex: _array })); + + length -= piece_view.length; + offset += piece_view.length; + } + + this.encryptedContent = constr_string; + } + // #endregion + } + } } } // #endregion @@ -3218,7 +3525,12 @@ function(in_window) this.contentEncryptionAlgorithm = new in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER({ schema: asn1.result["contentEncryptionAlgorithm"] }); if("encryptedContent" in asn1.result) - this.encryptedContent = asn1.result["encryptedContent"].value_block.value[0]; + { + this.encryptedContent = asn1.result["encryptedContent"]; + + this.encryptedContent.id_block.tag_class = 1; // UNIVERSAL + this.encryptedContent.id_block.tag_number = 4; // OCTETSTRING (!!!) The value still has instance of "in_window.org.pkijs.asn1.ASN1_CONSTRUCTED / ASN1_PRIMITIVE" + } // #endregion } //************************************************************************************** @@ -3232,13 +3544,14 @@ function(in_window) output_array.push(this.contentEncryptionAlgorithm.toSchema()); if("encryptedContent" in this) - output_array.push(new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED({ - id_block: { - tag_class: 3, // CONTEXT-SPECIFIC - tag_number: 0 // [0] - }, - value: [this.encryptedContent] - })); + { + var encryptedValue = this.encryptedContent; + + encryptedValue.id_block.tag_class = 3; // CONTEXT-SPECIFIC + encryptedValue.id_block.tag_number = 0; // [0] + + output_array.push(encryptedValue); + } // #endregion // #region Construct and return new ASN.1 schema for this object @@ -3437,6 +3750,48 @@ function(in_window) return _object; } //************************************************************************************** + in_window.org.pkijs.simpl.CMS_ENVELOPED_DATA.prototype.encrypt = + function() + { + ///