From 95801d89e9015f2f189d29c1c031b84336d5b843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gonz=C3=A1lez?= Date: Wed, 8 May 2024 16:09:30 +0100 Subject: [PATCH 1/3] Expose PKCS_RSA_PSS_SHA256 for CSR generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make PKCS_RSA_PSS_SHA256 a publicly accessible algorithm so that CSRs can be created for RSA PSS. The default salt_len value for RSA PSS SHA256 is the current value, 20. However, the only application that we currently know can use the generated RSA PSS CSRs is Parsec https://github.com/parallaxsecond/parsec which requires a salt length of 32 to work with OPENSSL. * Change this value to 32 to be compatible with OpenSSL. On this topic, the spec states: "When signing, it is RECOMMENDED that the parameters, except for possibly saltLength, remain fixed for all usages of a given RSA key pair"; and this is the value we are changing. Signed-off-by: Tomás González --- rcgen/src/oid.rs | 4 ++-- rcgen/src/sign_algo.rs | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rcgen/src/oid.rs b/rcgen/src/oid.rs index a757559c..9c989e2a 100644 --- a/rcgen/src/oid.rs +++ b/rcgen/src/oid.rs @@ -28,8 +28,8 @@ pub(crate) const EC_SECP_521_R1: &[u64] = &[1, 3, 132, 0, 35]; /// rsaEncryption in [RFC 4055](https://www.rfc-editor.org/rfc/rfc4055#section-6) pub(crate) const RSA_ENCRYPTION: &[u64] = &[1, 2, 840, 113549, 1, 1, 1]; -/// id-RSASSA-PSS in [RFC 4055](https://www.rfc-editor.org/rfc/rfc4055#section-6) -pub(crate) const RSASSA_PSS: &[u64] = &[1, 2, 840, 113549, 1, 1, 10]; +/// id-RSASSA-PSS in [RFC 4055](https://www.rfc-editor.org/rfc/rfc4055#section-6) with sha256WithRSAEncryption +pub(crate) const RSASSA_PSS_SHA256: &[u64] = &[1, 2, 840, 113549, 1, 1, 11]; /// id-ce-keyUsage in [RFC 5280](https://tools.ietf.org/html/rfc5280#appendix-A.2) pub(crate) const KEY_USAGE: &[u64] = &[2, 5, 29, 15]; diff --git a/rcgen/src/sign_algo.rs b/rcgen/src/sign_algo.rs index 5d7052ae..f34cfe22 100644 --- a/rcgen/src/sign_algo.rs +++ b/rcgen/src/sign_algo.rs @@ -88,7 +88,7 @@ impl SignatureAlgorithm { &PKCS_RSA_SHA256, &PKCS_RSA_SHA384, &PKCS_RSA_SHA512, - //&PKCS_RSA_PSS_SHA256, + &PKCS_RSA_PSS_SHA256, &PKCS_ECDSA_P256_SHA256, &PKCS_ECDSA_P384_SHA384, #[cfg(feature = "aws_lc_rs")] @@ -145,24 +145,24 @@ pub(crate) mod algo { params: SignatureAlgorithmParams::Null, }; - // TODO: not really sure whether the certs we generate actually work. - // Both openssl and webpki reject them. It *might* be possible that openssl - // accepts the certificate if the key is a proper RSA-PSS key, but ring doesn't - // support those: https://github.com/briansmith/ring/issues/1353 - // /// RSA signing with PKCS#1 2.1 RSASSA-PSS padding and SHA-256 hashing as per [RFC 4055](https://tools.ietf.org/html/rfc4055) - pub(crate) static PKCS_RSA_PSS_SHA256: SignatureAlgorithm = SignatureAlgorithm { + /// + /// Note: `*ring*` does not support this signature algorithm, and so it can not be used with the `crypto` feature + /// of `rcgen` when verifying signatures using the `ring` backend. + pub static PKCS_RSA_PSS_SHA256: SignatureAlgorithm = SignatureAlgorithm { // We could also use RSA_ENCRYPTION here, but it's recommended // to use ID-RSASSA-PSS if possible. - oids_sign_alg: &[&RSASSA_PSS], + oids_sign_alg: &[&RSASSA_PSS_SHA256], #[cfg(feature = "crypto")] sign_alg: SignAlgo::Rsa(&signature::RSA_PSS_SHA256), - oid_components: RSASSA_PSS, //&[1, 2, 840, 113549, 1, 1, 13], + oid_components: RSASSA_PSS_SHA256, //&[1, 2, 840, 113549, 1, 1, 11], // rSASSA-PSS-SHA256-Params in RFC 4055 params: SignatureAlgorithmParams::RsaPss { // id-sha256 in https://datatracker.ietf.org/doc/html/rfc4055#section-2.1 hash_algorithm: &[2, 16, 840, 1, 101, 3, 4, 2, 1], - salt_length: 20, + // It's conventional to use a salt length equal to the size of the hash algorithm's digest + // (32 bytes for the 256 bit digest produced by SHA256). + salt_length: 32, }, }; From c0405371a35d10a7b302c0cfe54a36e457e4e5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gonz=C3=A1lez?= Date: Fri, 31 May 2024 14:13:40 +0100 Subject: [PATCH 2/3] Add PKCS_RSA_PSS_SHA384 _SHA512 variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A previous commit has added PKCS_RSA_PSS_SHA256 and made it publicly available. * Replicate the same behaviour for PKCS_RSA_PSS_SHA384 and PKCS_RSA_PSS_SHA512 Signed-off-by: Tomás González --- rcgen/src/key_pair.rs | 12 +++++++++++ rcgen/src/oid.rs | 6 ++++++ rcgen/src/sign_algo.rs | 48 ++++++++++++++++++++++++++++++++++++++++++ rcgen/tests/openssl.rs | 2 ++ rcgen/tests/webpki.rs | 2 ++ 5 files changed, 70 insertions(+) diff --git a/rcgen/src/key_pair.rs b/rcgen/src/key_pair.rs index 6f5e7728..d500f524 100644 --- a/rcgen/src/key_pair.rs +++ b/rcgen/src/key_pair.rs @@ -252,6 +252,12 @@ impl KeyPair { } else if alg == &PKCS_RSA_PSS_SHA256 { let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA256) + } else if alg == &PKCS_RSA_PSS_SHA384 { + let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; + KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA384) + } else if alg == &PKCS_RSA_PSS_SHA512 { + let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; + KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA512) } else { #[cfg(feature = "aws_lc_rs")] if alg == &PKCS_ECDSA_P521_SHA512 { @@ -367,6 +373,12 @@ impl KeyPair { } else if alg == &PKCS_RSA_PSS_SHA256 { let rsakp = rsa_key_pair_from(&serialized_der)._err()?; KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA256) + } else if alg == &PKCS_RSA_PSS_SHA384 { + let rsakp = rsa_key_pair_from(&serialized_der)._err()?; + KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA384) + } else if alg == &PKCS_RSA_PSS_SHA512 { + let rsakp = rsa_key_pair_from(&serialized_der)._err()?; + KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA512) } else { panic!("Unknown SignatureAlgorithm specified!"); }; diff --git a/rcgen/src/oid.rs b/rcgen/src/oid.rs index 9c989e2a..1d75d7b8 100644 --- a/rcgen/src/oid.rs +++ b/rcgen/src/oid.rs @@ -31,6 +31,12 @@ pub(crate) const RSA_ENCRYPTION: &[u64] = &[1, 2, 840, 113549, 1, 1, 1]; /// id-RSASSA-PSS in [RFC 4055](https://www.rfc-editor.org/rfc/rfc4055#section-6) with sha256WithRSAEncryption pub(crate) const RSASSA_PSS_SHA256: &[u64] = &[1, 2, 840, 113549, 1, 1, 11]; +/// id-RSASSA-PSS in [RFC 4055](https://www.rfc-editor.org/rfc/rfc4055#section-6) with sha384WithRSAEncryption +pub(crate) const RSASSA_PSS_SHA384: &[u64] = &[1, 2, 840, 113549, 1, 1, 12]; + +/// id-RSASSA-PSS in [RFC 4055](https://www.rfc-editor.org/rfc/rfc4055#section-6) with sha512WithRSAEncryption +pub(crate) const RSASSA_PSS_SHA512: &[u64] = &[1, 2, 840, 113549, 1, 1, 13]; + /// id-ce-keyUsage in [RFC 5280](https://tools.ietf.org/html/rfc5280#appendix-A.2) pub(crate) const KEY_USAGE: &[u64] = &[2, 5, 29, 15]; diff --git a/rcgen/src/sign_algo.rs b/rcgen/src/sign_algo.rs index f34cfe22..f3632640 100644 --- a/rcgen/src/sign_algo.rs +++ b/rcgen/src/sign_algo.rs @@ -49,6 +49,10 @@ impl fmt::Debug for SignatureAlgorithm { write!(f, "PKCS_RSA_SHA512") } else if self == &PKCS_RSA_PSS_SHA256 { write!(f, "PKCS_RSA_PSS_SHA256") + } else if self == &PKCS_RSA_PSS_SHA384 { + write!(f, "PKCS_RSA_PSS_SHA384") + } else if self == &PKCS_RSA_PSS_SHA512 { + write!(f, "PKCS_RSA_PSS_SHA512") } else if self == &PKCS_ECDSA_P256_SHA256 { write!(f, "PKCS_ECDSA_P256_SHA256") } else if self == &PKCS_ECDSA_P384_SHA384 { @@ -89,6 +93,8 @@ impl SignatureAlgorithm { &PKCS_RSA_SHA384, &PKCS_RSA_SHA512, &PKCS_RSA_PSS_SHA256, + &PKCS_RSA_PSS_SHA384, + &PKCS_RSA_PSS_SHA512, &PKCS_ECDSA_P256_SHA256, &PKCS_ECDSA_P384_SHA384, #[cfg(feature = "aws_lc_rs")] @@ -166,6 +172,48 @@ pub(crate) mod algo { }, }; + /// RSA signing with PKCS#1 2.1 RSASSA-PSS padding and SHA-384 hashing as per [RFC 4055](https://tools.ietf.org/html/rfc4055) + /// + /// Note: `*ring*` does not support this signature algorithm, and so it can not be used with the `crypto` feature + /// of `rcgen` when verifying signatures using the `ring` backend. + pub static PKCS_RSA_PSS_SHA384: SignatureAlgorithm = SignatureAlgorithm { + // We could also use RSA_ENCRYPTION here, but it's recommended + // to use ID-RSASSA-PSS if possible. + oids_sign_alg: &[&RSASSA_PSS_SHA384], + #[cfg(feature = "crypto")] + sign_alg: SignAlgo::Rsa(&signature::RSA_PSS_SHA384), + oid_components: RSASSA_PSS_SHA384, //&[1, 2, 840, 113549, 1, 1, 12], + // rSASSA-PSS-SHA384-Params in RFC 4055 + params: SignatureAlgorithmParams::RsaPss { + // id-sha384 in https://datatracker.ietf.org/doc/html/rfc4055#section-2.1 + hash_algorithm: &[2, 16, 840, 1, 101, 3, 4, 2, 2], + // It's conventional to use a salt length equal to the size of the hash algorithm's digest + // (48 bytes for the 384 bit digest produced by SHA384). + salt_length: 48, + }, + }; + + /// RSA signing with PKCS#1 2.1 RSASSA-PSS padding and SHA-512 hashing as per [RFC 4055](https://tools.ietf.org/html/rfc4055) + /// + /// Note: `*ring*` does not support this signature algorithm, and so it can not be used with the `crypto` feature + /// of `rcgen` when verifying signatures using the `ring` backend. + pub static PKCS_RSA_PSS_SHA512: SignatureAlgorithm = SignatureAlgorithm { + // We could also use RSA_ENCRYPTION here, but it's recommended + // to use ID-RSASSA-PSS if possible. + oids_sign_alg: &[&RSASSA_PSS_SHA512], + #[cfg(feature = "crypto")] + sign_alg: SignAlgo::Rsa(&signature::RSA_PSS_SHA512), + oid_components: RSASSA_PSS_SHA512, //&[1, 2, 840, 113549, 1, 1, 13], + // rSASSA-PSS-SHA512-Params in RFC 4055 + params: SignatureAlgorithmParams::RsaPss { + // id-sha512 in https://datatracker.ietf.org/doc/html/rfc4055#section-2.1 + hash_algorithm: &[2, 16, 840, 1, 101, 3, 4, 2, 3], + // It's conventional to use a salt length equal to the size of the hash algorithm's digest + // (64 bytes for the 512 bit digest produced by SHA512). + salt_length: 64, + }, + }; + /// ECDSA signing using the P-256 curves and SHA-256 hashing as per [RFC 5758](https://tools.ietf.org/html/rfc5758#section-3.2) pub static PKCS_ECDSA_P256_SHA256: SignatureAlgorithm = SignatureAlgorithm { oids_sign_alg: &[&EC_PUBLIC_KEY, &EC_SECP_256_R1], diff --git a/rcgen/tests/openssl.rs b/rcgen/tests/openssl.rs index 478f565e..a1c8d0f4 100644 --- a/rcgen/tests/openssl.rs +++ b/rcgen/tests/openssl.rs @@ -289,6 +289,8 @@ fn test_openssl_rsa_combinations_given() { &rcgen::PKCS_RSA_SHA384, &rcgen::PKCS_RSA_SHA512, //&rcgen::PKCS_RSA_PSS_SHA256, + //&rcgen::PKCS_RSA_PSS_SHA384, + //&rcgen::PKCS_RSA_PSS_SHA512, ]; for (i, alg) in alg_list.iter().enumerate() { let (params, _) = util::default_params(); diff --git a/rcgen/tests/webpki.rs b/rcgen/tests/webpki.rs index 8f076952..7e4a0d75 100644 --- a/rcgen/tests/webpki.rs +++ b/rcgen/tests/webpki.rs @@ -245,6 +245,8 @@ fn test_webpki_rsa_combinations_given() { &signature::RSA_PKCS1_SHA512, ), //(&rcgen::PKCS_RSA_PSS_SHA256, &webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, &signature::RSA_PSS_SHA256), + //(&rcgen::PKCS_RSA_PSS_SHA384, &webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY, &signature::RSA_PSS_SHA384), + //(&rcgen::PKCS_RSA_PSS_SHA384, &webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, &signature::RSA_PSS_SHA512), ]; for c in configs { let (params, _) = util::default_params(); From f5717442ddbd7d1a6835e5ed42e9645ea9bbc277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gonz=C3=A1lez?= Date: Fri, 31 May 2024 14:48:37 +0100 Subject: [PATCH 3/3] [TEMP] tests/openssl: Enable PKCS_RSA_PSS_SHA256 certificate tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only enable PKCS_RSA_PSS_SHA256 and not the rest of the variants as the tests for that are currently failing. Use aws_lc_rs for testing as supposedly this one does support PSS keys while ring does not. * Fix a logic error in the test in which verify_cert_basic was being run when verify_cert should have been and viceversa. Signed-off-by: Tomás González --- rcgen/tests/openssl.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/rcgen/tests/openssl.rs b/rcgen/tests/openssl.rs index a1c8d0f4..968e11ae 100644 --- a/rcgen/tests/openssl.rs +++ b/rcgen/tests/openssl.rs @@ -288,25 +288,21 @@ fn test_openssl_rsa_combinations_given() { &rcgen::PKCS_RSA_SHA256, &rcgen::PKCS_RSA_SHA384, &rcgen::PKCS_RSA_SHA512, - //&rcgen::PKCS_RSA_PSS_SHA256, - //&rcgen::PKCS_RSA_PSS_SHA384, - //&rcgen::PKCS_RSA_PSS_SHA512, + #[cfg(feature = "aws_lc_rs")] + &rcgen::PKCS_RSA_PSS_SHA256, + // #[cfg(feature = "aws_lc_rs")] + // &rcgen::PKCS_RSA_PSS_SHA384, + // #[cfg(feature = "aws_lc_rs")] + // &rcgen::PKCS_RSA_PSS_SHA512, ]; - for (i, alg) in alg_list.iter().enumerate() { + for (_i, alg) in alg_list.iter().enumerate() { let (params, _) = util::default_params(); let key_pair = KeyPair::from_pkcs8_pem_and_sign_algo(util::RSA_TEST_KEY_PAIR_PEM, alg).unwrap(); let cert = params.self_signed(&key_pair).unwrap(); - // Now verify the certificate. - if i >= 4 { - verify_cert(&cert, &key_pair); - verify_csr(&cert, &key_pair); - } else { - // The PSS key types are not fully supported. - // An attempt to use them gives a handshake error. - verify_cert_basic(&cert); - } + verify_cert(&cert, &key_pair); + verify_csr(&cert, &key_pair); } }