diff --git a/cli/tests/testdata/webcrypto/id_rsassaPss_default.pem b/cli/tests/testdata/webcrypto/id_rsassaPss_default.pem new file mode 100644 index 00000000000000..b2b8dee5c542d6 --- /dev/null +++ b/cli/tests/testdata/webcrypto/id_rsassaPss_default.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEwwIBADASBgkqhkiG9w0BAQowBaIDAgEABIIEqDCCBKQCAQACggEBAMPqex5m +1JO1SOxN6F+yNN9AV1bhoGHpx7rqvOAjIadTSmK9g17GA8r5vYk/J/wVdPLOnVG2 +ARAzk9T554rYd4fAN3uL9CzsK2eBb7CD/OAbq1a3RLGhFrNILot7rK2QnTPuDbAh +HUWGwsW+PQYhPW1JzdnOvfRD4DEZfzz5in6SZWmHvXCMdpewgWdjzQ9O1+MxNVe4 +diw43q3fvDEZSGGgnV3eVp+adQxIq0pfNq6jB71CE82vZYMXAJ+MeypX6+xn9OG0 +NzXXUsYTQjchNUALZTG4YM5ErGJCB/cikEwqscktirmU3l1lAN193wgykYUDGV8a +JdlMUwRe68vsoI8CAwEAAQKCAQABnH0Uu+3FpTkLUHy3xMRwjZvqSALEq2KMJAAX +q9JMCQBUnZBmCCTh13n6lf1jMl363T4n/OI3WuU9XCzOVIdvI2KRbo48jFizCjp7 +7in3QeL/3JQBDf0czlwro4HBD65rTero5uzRtJEHhVAFK+LQcknyH6QqTSCb5sTI +IJlF/zSMc596zLsSdo/CdNBSvdlOXLoypJ7APW/dKs0nQ58dJ2yhNVkFfqnsckg1 +i1M12WMVUlwQDyqb7OlodLr45SN9CM4EVXES6/D1I4WTHQQgVK+nyVv/1UgGWn8w +ZJv7z5WbA+fdCPRXNf9VRkVpL2TDF32Aouu9Ck729U/KesghAoGBAOl2SBiyeK+Y +z5G/XXNOUWvVoLKv70Fy8pevvv9uyIOvxriADLRFRxcObG0rgLrCYQhjsWzhXBss +5lY8Cnm4dBFxZsAMHYBB5C99bT/OX+D4Gh7JG302wehp/2nrl9Wqs5NV6p9r0nyH +PQdPzGTBRnHG2uzor9pawU6Sb7FoIfxfAoGBANbUS4zLRqiBqjXw5TVkxGetm6St +GM+gA0JuYDqXM53a6p6/brwTO2u2hQPIphTGc+ZQzjaimUQeX4cRRm7cs7Nzvb0U +iiwYCf4zDEKzhGvdKsA/SOyGR3a5yyV1jWZdRvNra1kL08bsUYMpMOomPlDoTtZv +kJaOMblGlRskWcnRAoGBAMOeqraXBO0N/A9B7Anr++mBbU+Mf8u1h3R2fHIH39gH +91ktYnfC/Nhi65NmOk1DBo9DCa4T/1t9+dsUICrx1b+v58rP3ABWNd9dF6e5Qzl8 +alaVaIU41q3p82xLTkRo7mNsQFYowIw7vXVc9gUOtfosB9Eu//rUxNkTdqeOe7u9 +AoGBAMEW9YTp3GtuiCeNiubP2Hx7nU6JSqirYOKfxJxE9N7oOkNPOt+OxbTNy4aY +HTbFHL0hWgffY7THPANxsoXIlzgvSpYdVQfG34x8I4P8SISOuHMtLoVxN+BtpDra +Cqq8Ih5+KXFS4RmFpMooBtAeaZpdAydYBXRdADJQT4qixJVRAoGAOIF7KIGi0TBs +nr/u4Hqyj+wc0DkQFJa9ILvLV7r+k33KYjiVZeBfbDKDLMSXCHMyTSfLjmDI9ZVd +HCo6+cUw4dwXsquKn3i+nmjMc4G82o48EQYfGoRlNb7fnyBVdULIV0lwRRsXn29A +dfNGr0wbasKwbrjL6XZerA0saoNdEOw= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/cli/tests/testdata/webcrypto/id_rsassaPss_saltLen_30.pem b/cli/tests/testdata/webcrypto/id_rsassaPss_saltLen_30.pem new file mode 100644 index 00000000000000..3d34cb0133161b --- /dev/null +++ b/cli/tests/testdata/webcrypto/id_rsassaPss_saltLen_30.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEwQIBADASBgkqhkiG9w0BAQowBaIDAgEeBIIEpjCCBKICAQACggEBAMEWS3x9 +dCE5KWAoh5UAXeq2E0uPWBJ2UrtX7asgrOX1Sj4Boak/zxpsgPGQeA3kQPlcD9xi +wxnlBMFqrMwoY1Trb5quX1ZU8NVE/w3kWkF2EhHKgbWt9LyoNsNkj7liw5Aez4fN +O2v+IIsqeVJslXa6+6jfe1xWSEcRLOpfjCQ76bA9I5i9wls/ThvPnlEuYD7jFaXb +EJiKcaYxQ+L+Ys0CC5lPLGnLb3NRgeQhtBjmaTOMh2PrXoaZ9RuuzpDHJ7Iw3Inl +qh9AbH5um2TEh0ZpIhPaC5grwlbMpoTLW46MAYynme2+FsD20paszPQL9afiuUll +9PjLO3Lr3JNWxyECAwEAAQKCAQAhdReHbsWcrCb7Poqfyvx7GymkwiXkrRQQ2l+Y +c4UCI8rFi8rTZPciAQMm2H21CoQnsUgeTA66gfCdAzsF9UmhAVrJVsW2U+mXSulX +IuZwyWDALHLlZEswFYXHvbkZyn9QjcYwJePSBqrk8msrWR1dAXFyBad+jIThq5w4 +0G2cKWh1sHKTcIa3UZ6jnAB0WC/Fkv3hjybVn601Axq9YdVTbKAxfBPdfTmBXqc5 +P98ghRqPrjnFkDET8LZsDJjAuwSL9S79QAQmPmOlKuNCWB2gQ7/4aIcgtiyGOTvK +3sD4f3aL+E8caTpJQQDQanQO7DRghci+grb2bVDAkhg7/cdBAoGBAOQRDc3KSQlT +Jl8W2pa8PvtTYcK+QQ0GCKMDeFyAMqvtFo216NjgTh92WZArTTQVFMzorXNSWUbq +tAqMa9lc6f7CtM/hhuxkKL1o93Hbb69pk4eohzhk5uAleQ9jhOi4ABTwONV9HDt6 +xl8CDoZiBpqjR1hlHFSfVLDGKtG+8I/NAoGBANi8eHWMvYicyND21Kf9s4RZuVVT +sf2xj1wCv8M3Or72PRtINOGdH2ASELpyyU9nLwzPaEnQ9nwmAI3YUs9j7lqkyFv0 +aHK/F9JZ8IZi7paRsIl2lXkXBAWICG5eoBVvpl3KWzh50n0rEDaXhTJuToBVQ0BV +MiX1or6pcZUEanilAoGASg2/jbLBRGXbb8Tb9VXqnXDVrYZZWQE8jLHzwxVdXrX9 +PMZ0dPdgZpbnPgjRaLfvqRlkOK3kj0Jmc4Zk/o9M64wNafKw/NEI6XfL4Qx/l1WQ +sdvnDEi3LtD8HiMSZP5aCHJ4Ado98JJNF0xzqu7pdgzOfcVXDaMuvLeb778wHYEC +gYA0bjN9zFQ1biguVOfQ09DPnZz2BU8znfaePZQCN6QgehUCOo+AXLAwX25ojEgi +y0VYhfwmj0RxeAf+SGyP+w64ItDNXey+hXfPzS4gdGJfTlM0jdlO98BjTisr9/wl +82J9oew7V00SNo6vhiwUrRaUeQvRzkpZYHjEQt1VPUI8eQKBgFkjt/rEEgpojPIR +iC4qR35yRoTvFjOLj5WQPZmgEjeqWoE/xXMg58UXo74ViSavEP+8xQH+uSXXAG4q +G4298Uc9jNF0jTekEKI8yyi2MBThDOtQOTNZb/exAgrXkff/g1RG+XIbgHgx8qRR +XII4DFaG+/+toV/27x4mfuddXWNu +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts index ab7b46574d1997..56a23bfb5ff0a2 100644 --- a/cli/tests/unit/webcrypto_test.ts +++ b/cli/tests/unit/webcrypto_test.ts @@ -379,19 +379,32 @@ unitTest(async function generateImportHmacJwk() { // 2048-bits publicExponent=65537 const pkcs8TestVectors = [ // rsaEncryption - "cli/tests/testdata/webcrypto/id_rsaEncryption.pem", - // id-RSASSA-PSS - "cli/tests/testdata/webcrypto/id_rsassaPss.pem", + { pem: "cli/tests/testdata/webcrypto/id_rsaEncryption.pem", hash: "SHA-256" }, + // id-RSASSA-PSS (sha256) + // `openssl genpkey -algorithm rsa-pss -pkeyopt rsa_pss_keygen_md:sha256 -out id_rsassaPss.pem` + { pem: "cli/tests/testdata/webcrypto/id_rsassaPss.pem", hash: "SHA-256" }, + // id-RSASSA-PSS (default parameters) + // `openssl genpkey -algorithm rsa-pss -out id_rsassaPss.pem` + { + pem: "cli/tests/testdata/webcrypto/id_rsassaPss_default.pem", + hash: "SHA-1", + }, + // id-RSASSA-PSS (default hash) + // `openssl genpkey -algorithm rsa-pss -pkeyopt rsa_pss_keygen_saltlen:30 -out rsaPss_saltLen_30.pem` + { + pem: "cli/tests/testdata/webcrypto/id_rsassaPss_saltLen_30.pem", + hash: "SHA-1", + }, ]; unitTest({ permissions: { read: true } }, async function importRsaPkcs8() { const pemHeader = "-----BEGIN PRIVATE KEY-----"; const pemFooter = "-----END PRIVATE KEY-----"; - for (const keyFile of pkcs8TestVectors) { - const pem = await Deno.readTextFile(keyFile); - const pemContents = pem.substring( + for (const { pem, hash } of pkcs8TestVectors) { + const keyFile = await Deno.readTextFile(pem); + const pemContents = keyFile.substring( pemHeader.length, - pem.length - pemFooter.length, + keyFile.length - pemFooter.length, ); const binaryDerString = atob(pemContents); const binaryDer = new Uint8Array(binaryDerString.length); @@ -402,7 +415,7 @@ unitTest({ permissions: { read: true } }, async function importRsaPkcs8() { const key = await crypto.subtle.importKey( "pkcs8", binaryDer, - { name: "RSA-PSS", hash: "SHA-256" }, + { name: "RSA-PSS", hash }, true, ["sign"], ); @@ -413,7 +426,7 @@ unitTest({ permissions: { read: true } }, async function importRsaPkcs8() { assertEquals(key.usages, ["sign"]); const algorithm = key.algorithm as RsaHashedKeyAlgorithm; assertEquals(algorithm.name, "RSA-PSS"); - assertEquals(algorithm.hash.name, "SHA-256"); + assertEquals(algorithm.hash.name, hash); assertEquals(algorithm.modulusLength, 2048); assertEquals(algorithm.publicExponent, new Uint8Array([1, 0, 1])); } diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index 0cb8ed99422cf8..d990bf2a42230d 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -874,6 +874,38 @@ const MASK_GEN_ALGORITHM_TAG: rsa::pkcs8::der::TagNumber = const SALT_LENGTH_TAG: rsa::pkcs8::der::TagNumber = rsa::pkcs8::der::TagNumber::new(2); +lazy_static! { + // Default HashAlgorithm for RSASSA-PSS-params (sha1) + // + // sha1 HashAlgorithm ::= { + // algorithm id-sha1, + // parameters SHA1Parameters : NULL + // } + // + // SHA1Parameters ::= NULL + static ref SHA1_HASH_ALGORITHM: rsa::pkcs8::AlgorithmIdentifier<'static> = rsa::pkcs8::AlgorithmIdentifier { + // id-sha1 + oid: ID_SHA1_OID, + // NULL + parameters: Some(asn1::Any::from(asn1::Null)), + }; + + // TODO(@littledivy): `pkcs8` should provide AlgorithmIdentifier to Any conversion. + static ref ENCODED_SHA1_HASH_ALGORITHM: Vec = SHA1_HASH_ALGORITHM.to_vec().unwrap(); + // Default MaskGenAlgrithm for RSASSA-PSS-params (mgf1SHA1) + // + // mgf1SHA1 MaskGenAlgorithm ::= { + // algorithm id-mgf1, + // parameters HashAlgorithm : sha1 + // } + static ref MGF1_SHA1_MASK_ALGORITHM: rsa::pkcs8::AlgorithmIdentifier<'static> = rsa::pkcs8::AlgorithmIdentifier { + // id-mgf1 + oid: ID_MFG1, + // sha1 + parameters: Some(asn1::Any::from_der(&ENCODED_SHA1_HASH_ALGORITHM).unwrap()), + }; +} + impl<'a> TryFrom> for PssPrivateKeyParameters<'a> { @@ -887,13 +919,13 @@ impl<'a> TryFrom> .context_specific(HASH_ALGORITHM_TAG)? .map(TryInto::try_into) .transpose()? - .unwrap(); + .unwrap_or(*SHA1_HASH_ALGORITHM); let mask_gen_algorithm = decoder .context_specific(MASK_GEN_ALGORITHM_TAG)? .map(TryInto::try_into) .transpose()? - .unwrap(); + .unwrap_or(*MGF1_SHA1_MASK_ALGORITHM); let salt_length = decoder .context_specific(SALT_LENGTH_TAG)?