diff --git a/src/crypto/openssl.rs b/src/crypto/openssl.rs index 9ae32fd9..fdb94a09 100644 --- a/src/crypto/openssl.rs +++ b/src/crypto/openssl.rs @@ -446,7 +446,8 @@ pub mod sign { } let pkey = match secret { - SecretKeyBytes::RsaSha256(s) => { + SecretKeyBytes::RsaSha256(s) + | SecretKeyBytes::RsaSha512(s) => { let n = num(&s.n)?; let e = num(&s.e)?; @@ -458,12 +459,20 @@ pub mod sign { .expect("should not fail"); let rsa_public = PKey::from_rsa(rsa_public).expect("should not fail"); - let p = PublicKey::Rsa( - MessageDigest::sha256(), - rsa_public, - public.flags(), - ) - .dnskey(); + let digest = + if matches!(secret, SecretKeyBytes::RsaSha256(_)) { + MessageDigest::sha256() + } else if matches!( + secret, + SecretKeyBytes::RsaSha512(_) + ) { + MessageDigest::sha512() + } else { + unreachable!(); + }; + let p = + PublicKey::Rsa(digest, rsa_public, public.flags()) + .dnskey(); if p != *public { return Err(FromBytesError::InvalidKey); } @@ -585,9 +594,10 @@ pub mod sign { pub fn to_bytes(&self) -> SecretKeyBytes { // TODO: Consider security implications of secret data in 'Vec's. match self.algorithm { - SecurityAlgorithm::RSASHA256 => { + SecurityAlgorithm::RSASHA256 + | SecurityAlgorithm::RSASHA512 => { let key = self.pkey.rsa().unwrap(); - SecretKeyBytes::RsaSha256(RsaSecretKeyBytes { + let secret_key_bytes = RsaSecretKeyBytes { n: key.n().to_vec().into(), e: key.e().to_vec().into(), d: key.d().to_vec().into(), @@ -596,7 +606,14 @@ pub mod sign { d_p: key.dmp1().unwrap().to_vec().into(), d_q: key.dmq1().unwrap().to_vec().into(), q_i: key.iqmp().unwrap().to_vec().into(), - }) + }; + if self.algorithm == SecurityAlgorithm::RSASHA256 { + SecretKeyBytes::RsaSha256(secret_key_bytes) + } else if self.algorithm == SecurityAlgorithm::RSASHA512 { + SecretKeyBytes::RsaSha512(secret_key_bytes) + } else { + unreachable!(); + } } SecurityAlgorithm::ECDSAP256SHA256 => { let key = self.pkey.ec_key().unwrap(); @@ -641,6 +658,13 @@ pub mod sign { s.sign_oneshot_to_vec(data) } + SecurityAlgorithm::RSASHA512 => { + let mut s = + Signer::new(MessageDigest::sha512(), &self.pkey)?; + s.set_rsa_padding(openssl::rsa::Padding::PKCS1)?; + s.sign_oneshot_to_vec(data) + } + SecurityAlgorithm::ECDSAP256SHA256 => { let mut s = Signer::new(MessageDigest::sha256(), &self.pkey)?; @@ -687,18 +711,24 @@ pub mod sign { fn dnskey(&self) -> Dnskey> { match self.algorithm { - SecurityAlgorithm::RSASHA256 => { + SecurityAlgorithm::RSASHA256 + | SecurityAlgorithm::RSASHA512 => { let key = self.pkey.rsa().expect("should not fail"); let n = key.n().to_owned().expect("should not fail"); let e = key.e().to_owned().expect("should not fail"); let key = Rsa::from_public_components(n, e) .expect("should not fail"); let key = PKey::from_rsa(key).expect("should not fail"); - let public = PublicKey::Rsa( - MessageDigest::sha256(), - key, - self.flags, - ); + let digest = if self.algorithm + == SecurityAlgorithm::RSASHA256 + { + MessageDigest::sha256() + } else if self.algorithm == SecurityAlgorithm::RSASHA512 { + MessageDigest::sha512() + } else { + unreachable!(); + }; + let public = PublicKey::Rsa(digest, key, self.flags); public.dnskey() } SecurityAlgorithm::ECDSAP256SHA256 @@ -756,6 +786,10 @@ pub mod sign { Ok(Signature::RsaSha256(signature)) } + SecurityAlgorithm::RSASHA512 => { + Ok(Signature::RsaSha512(signature)) + } + SecurityAlgorithm::ECDSAP256SHA256 => signature .try_into() .map(Signature::EcdsaP256Sha256) @@ -827,6 +861,7 @@ pub mod sign { const KEYS: &[(SecurityAlgorithm, u16)] = &[ (SecurityAlgorithm::RSASHA256, 60616), + (SecurityAlgorithm::RSASHA512, 46731), (SecurityAlgorithm::ECDSAP256SHA256, 42253), (SecurityAlgorithm::ECDSAP384SHA384, 33566), (SecurityAlgorithm::ED25519, 56037), @@ -840,6 +875,9 @@ pub mod sign { SecurityAlgorithm::RSASHA256 => { GenerateParams::RsaSha256 { bits: 3072 } } + SecurityAlgorithm::RSASHA512 => { + GenerateParams::RsaSha512 { bits: 3072 } + } SecurityAlgorithm::ECDSAP256SHA256 => { GenerateParams::EcdsaP256Sha256 } @@ -862,6 +900,9 @@ pub mod sign { SecurityAlgorithm::RSASHA256 => { GenerateParams::RsaSha256 { bits: 3072 } } + SecurityAlgorithm::RSASHA512 => { + GenerateParams::RsaSha512 { bits: 3072 } + } SecurityAlgorithm::ECDSAP256SHA256 => { GenerateParams::EcdsaP256Sha256 } diff --git a/src/crypto/ring.rs b/src/crypto/ring.rs index 318bd9b1..c4085693 100644 --- a/src/crypto/ring.rs +++ b/src/crypto/ring.rs @@ -329,6 +329,18 @@ pub mod sign { rng: Arc, }, + /// An RSA/SHA-512 keypair. + RsaSha512 { + /// They RSA key. + key: RsaKeyPair, + + /// Flags from [`Dnskey`]. + flags: u16, + + /// Random number generator. + rng: Arc, + }, + /// An ECDSA P-256/SHA-256 keypair. EcdsaP256Sha256 { /// The ECDSA key. @@ -370,12 +382,20 @@ pub mod sign { { let rng = Arc::new(SystemRandom::new()); match secret { - SecretKeyBytes::RsaSha256(s) => { + SecretKeyBytes::RsaSha256(s) + | SecretKeyBytes::RsaSha512(s) => { let rsa_public = signature::RsaPublicKeyComponents { n: s.n.to_vec(), e: s.e.to_vec(), }; - let p = PublicKey::Rsa(&signature::RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY, rsa_public).dnskey(public.flags()); + let p = if matches!(secret, SecretKeyBytes::RsaSha256(_)) + { + PublicKey::Rsa(&signature::RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY, rsa_public).dnskey(public.flags()) + } else if matches!(secret, SecretKeyBytes::RsaSha512(_)) { + PublicKey::Rsa(&signature::RSA_PKCS1_1024_8192_SHA512_FOR_LEGACY_USE_ONLY, rsa_public).dnskey(public.flags()) + } else { + unreachable!(); + }; // Ensure that the public and private key match. if p != *public { return Err(FromBytesError::InvalidKey); @@ -398,13 +418,26 @@ pub mod sign { dQ: s.d_q.expose_secret(), qInv: s.q_i.expose_secret(), }; - ring::signature::RsaKeyPair::from_components(&components) - .map_err(|_| FromBytesError::InvalidKey) - .map(|key| Self::RsaSha256 { + let key_pair = + ring::signature::RsaKeyPair::from_components( + &components, + ) + .map_err(|_| FromBytesError::InvalidKey); + if matches!(secret, SecretKeyBytes::RsaSha256(_)) { + key_pair.map(|key| Self::RsaSha256 { key, flags: public.flags(), rng, }) + } else if matches!(secret, SecretKeyBytes::RsaSha512(_)) { + key_pair.map(|key| Self::RsaSha512 { + key, + flags: public.flags(), + rng, + }) + } else { + unreachable!(); + } } SecretKeyBytes::EcdsaP256Sha256(s) => { @@ -477,6 +510,7 @@ pub mod sign { fn algorithm(&self) -> SecurityAlgorithm { match self { Self::RsaSha256 { .. } => SecurityAlgorithm::RSASHA256, + Self::RsaSha512 { .. } => SecurityAlgorithm::RSASHA512, Self::EcdsaP256Sha256 { .. } => { SecurityAlgorithm::ECDSAP256SHA256 } @@ -489,14 +523,21 @@ pub mod sign { fn dnskey(&self) -> Dnskey> { match self { - Self::RsaSha256 { key, flags, rng: _ } => { + Self::RsaSha256 { key, flags, rng: _ } + | Self::RsaSha512 { key, flags, rng: _ } => { let components: ring::rsa::PublicKeyComponents> = key.public().into(); let n = components.n; let e = components.e; let public_key = signature::RsaPublicKeyComponents { n, e }; - let public = PublicKey::Rsa(&signature::RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY, public_key); + let public = if matches!(self, Self::RsaSha256 { .. }) { + PublicKey::Rsa(&signature::RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY, public_key) + } else if matches!(self, Self::RsaSha512 { .. }) { + PublicKey::Rsa(&signature::RSA_PKCS1_1024_8192_SHA512_FOR_LEGACY_USE_ONLY, public_key) + } else { + unreachable!(); + }; public.dnskey(*flags) } @@ -563,6 +604,16 @@ pub mod sign { .map_err(|_| SignError) } + Self::RsaSha512 { key, flags: _, rng } => { + let mut buf = vec![0u8; key.public().modulus_len()]; + let pad = &ring::signature::RSA_PKCS1_SHA512; + key.sign(pad, &**rng, data, &mut buf) + .map(|()| { + Signature::RsaSha512(buf.into_boxed_slice()) + }) + .map_err(|_| SignError) + } + Self::EcdsaP256Sha256 { key, flags: _, rng } => key .sign(&**rng, data) .map(|sig| Box::<[u8]>::from(sig.as_ref())) @@ -689,6 +740,7 @@ pub mod sign { const KEYS: &[(SecurityAlgorithm, u16)] = &[ (SecurityAlgorithm::RSASHA256, 60616), + (SecurityAlgorithm::RSASHA512, 46731), (SecurityAlgorithm::ECDSAP256SHA256, 42253), (SecurityAlgorithm::ECDSAP384SHA384, 33566), (SecurityAlgorithm::ED25519, 56037), diff --git a/src/crypto/sign.rs b/src/crypto/sign.rs index 88c1ed38..110e75b5 100644 --- a/src/crypto/sign.rs +++ b/src/crypto/sign.rs @@ -520,6 +520,9 @@ pub enum SecretKeyBytes { /// An RSA/SHA-256 keypair. RsaSha256(RsaSecretKeyBytes), + /// An RSA/SHA-256 keypair. + RsaSha512(RsaSecretKeyBytes), + /// An ECDSA P-256/SHA-256 keypair. /// /// The private key is a single 32-byte big-endian integer. @@ -548,6 +551,7 @@ impl SecretKeyBytes { pub fn algorithm(&self) -> SecurityAlgorithm { match self { Self::RsaSha256(_) => SecurityAlgorithm::RSASHA256, + Self::RsaSha512(_) => SecurityAlgorithm::RSASHA512, Self::EcdsaP256Sha256(_) => SecurityAlgorithm::ECDSAP256SHA256, Self::EcdsaP384Sha384(_) => SecurityAlgorithm::ECDSAP384SHA384, Self::Ed25519(_) => SecurityAlgorithm::ED25519, @@ -572,6 +576,11 @@ impl SecretKeyBytes { k.format_as_bind(w) } + Self::RsaSha512(k) => { + writeln!(w, "Algorithm: 10 (RSASHA512)")?; + k.format_as_bind(w) + } + Self::EcdsaP256Sha256(s) => { let s = s.expose_secret(); writeln!(w, "Algorithm: 13 (ECDSAP256SHA256)")?; @@ -675,6 +684,9 @@ impl SecretKeyBytes { (8, "(RSASHA256)") => { RsaSecretKeyBytes::parse_from_bind(data).map(Self::RsaSha256) } + (10, "(RSASHA512)") => { + RsaSecretKeyBytes::parse_from_bind(data).map(Self::RsaSha512) + } (13, "(ECDSAP256SHA256)") => { parse_pkey(data).map(Self::EcdsaP256Sha256) } @@ -1094,6 +1106,7 @@ mod tests { }; const KEYS: &[(SecurityAlgorithm, u16)] = &[ (SecurityAlgorithm::RSASHA256, 60616), + (SecurityAlgorithm::RSASHA512, 46731), (SecurityAlgorithm::ECDSAP256SHA256, 42253), (SecurityAlgorithm::ECDSAP384SHA384, 33566), (SecurityAlgorithm::ED25519, 56037), @@ -1139,6 +1152,14 @@ mod tests { continue; } } + SecurityAlgorithm::RSASHA512 => { + if cfg!(feature = "openssl") { + GenerateParams::RsaSha512 { bits: 2048 } + } else { + // No support for RSASHA256 in Ring. + continue; + } + } SecurityAlgorithm::ECDSAP256SHA256 => { GenerateParams::EcdsaP256Sha256 } diff --git a/test-data/dnssec-keys/Ktest.+010+46731.key b/test-data/dnssec-keys/Ktest.+010+46731.key new file mode 100644 index 00000000..dec7cda5 --- /dev/null +++ b/test-data/dnssec-keys/Ktest.+010+46731.key @@ -0,0 +1 @@ +test. IN DNSKEY 256 3 10 AwEAAaOjLFFjqsv8lg/FBU8LCktei3/t3+C+s42cxmUOv4xvI/NPZ35i5zqTIoi4v0+EthzbcfnDvqVPdM1MRlVYRcWewuc18rrUZB6k1+igzcj5XuuilktNkHFfBOWinEYqzv/0KDuUSk5eMVG11DEQXx7qRPjH74WJ96sBcXzXm+GEcaYXXn/forV2khWtlGxDC6I9J6Zcwf8ACk5t6yiNBmvoljNR201clsgAgg7t+52X+echuEmkAybwVtL73tFw9JUnUeBA9Pm0pvq8hTNPXs/XhCnMw1wVRyECleOvBt2lx7s3suXXOljPdgjFZZTO2Mij8I3aYAafUEBzjcYssSU= ;{id = 46731 (zsk), size = 2048b} diff --git a/test-data/dnssec-keys/Ktest.+010+46731.private b/test-data/dnssec-keys/Ktest.+010+46731.private new file mode 100644 index 00000000..361b382d --- /dev/null +++ b/test-data/dnssec-keys/Ktest.+010+46731.private @@ -0,0 +1,10 @@ +Private-key-format: v1.2 +Algorithm: 10 (RSASHA512) +Modulus: o6MsUWOqy/yWD8UFTwsKS16Lf+3f4L6zjZzGZQ6/jG8j809nfmLnOpMiiLi/T4S2HNtx+cO+pU90zUxGVVhFxZ7C5zXyutRkHqTX6KDNyPle66KWS02QcV8E5aKcRirO//QoO5RKTl4xUbXUMRBfHupE+MfvhYn3qwFxfNeb4YRxphdef9+itXaSFa2UbEMLoj0nplzB/wAKTm3rKI0Ga+iWM1HbTVyWyACCDu37nZf55yG4SaQDJvBW0vve0XD0lSdR4ED0+bSm+ryFM09ez9eEKczDXBVHIQKV468G3aXHuzey5dc6WM92CMVllM7YyKPwjdpgBp9QQHONxiyxJQ== +PublicExponent: AQAB +PrivateExponent: Bzb3CcGcsrC4xwo3QTRp6EfLW8EXqVePIBPE9YiwblcqHRynof1nV4BMOf33RWDDDMOqI0p7mdtGeZS+1x10uhFVY49P2+foYCeBc3q/h/hitH3vJXPOhgkb9Kn2POu/Q662pWXU3t6tSv561Az2PK00jEl4aIlcN5hxMgFpmIhFt8/oeT+4Z/h9N66jBM1e6z8TqM6jkqyJQ96hEtElDw+hZyxL84qJcfqPAraADJh1M9J5VzAauFhcKZ2LeUaDcb2DNiWhgMAbW7gfvx9QB58udavUSSAA3iqxo3aIMqvYqbxPnKb5KGvpNRTERgNPgNuF9Elzs2/6QNCyuYSYww== +Prime1: 5KIn8oSsNA22EJvzhWq0Hx+jMI4bPvGOrBfmD42FKvClPtA1sAMqsabQrE2t0lYzRBnHa7ad/TpQRBTFsydy8IFTHEDeISxo3Dch8Hr+Q474TCNTEHduX3pkniTZMMdzkcC9jD9d4NGKufMz57DVejoCjEao0ZyD/WATjGd1OCM= +Prime2: tzlkY2ryyYncIZlHtPP374MWzmUWSZHimZTDOP3Al6R87q7uWoa1G518049p//v/PZiT6rR5QFBgxS3H3B7Dhc4Ew8MED1lyO71+AvTpY/8/VsgIkJDnDKtOpY7jr/jd4avk7Ga4n+IpnNrJaLxGfcXHjJs8Xb2MiIpDbe0QIhc= +Exponent1: jmpvxcJc3gPYcBoko+umjWiQp3Mth5TCUXKFjRSTaf8Cf9EEUEJ4urZ1b47ngojNYFNKhE75tL45N19VEta04xk7ovLJKxLVsq7pBjom3gBVrF+ooy4x42mC+XtsitUCqTzNFWp3WM5Nwqy6nUzqfTtbUPPGvuLm2NKa+q+LNc8= +Exponent2: lf/pXK7QxwgS7HrFRrI4t5+1SxFc9qv1PFCapoyvYDYshWc3AWuo10vORpDxcb1HT5Ea/5nybiGfp618IowY+/EW24FLUJmkuJ3AjQEeFVyA6TXoNRo73ZZdU5Kwen8ef0Mvrg3GdjY8ZQqEuzbv6sXBQS5RdFjatWmkHFlozM8= +Coefficient: S/x4RWc2cB8lR4rn14cvah+lwo+opkyoumRxfoUqWKILxvMA2hRwhMtB90dP7TxzdN3VqmXZ4m4ygWEAKgrtXC1qhzKnXPJjWAgn/ElmsuVdW7azCexNN1PZxFRNIwLElrbTlLur/C9SvBBUtlUA2Z965mqjWMgd9ooYxjn3B44=