use num_bigint::BigUint; use crate::common_types::{DnsSecAlgorithm, DnsSecAlgorithmKnown}; // ECC_GOST [RFC5933] // RFC5702 still confirms this const RSA_BITS_LIMIT: usize = 4096; const RSA_BYTES_LIMIT: usize = RSA_BITS_LIMIT / 8; fn parse_rsa(data: &[u8]) -> crate::errors::Result { failure::ensure!(!data.is_empty(), "RSA public key must be non-empty"); let exp_len: usize; let offset: usize; if data[0] == 0 { failure::ensure!( data.len() >= 3, "RSA public key: unexpected end of data when decoding exponent length" ); exp_len = (data[1] as usize) << 8 + (data[2] as usize); offset = 3; failure::ensure!( exp_len >= 256, "RSA public key: exponent length in long form but too small" ); } else { exp_len = data[0] as usize; offset = 1; } assert!(exp_len > 0); // should be unreachable: 0 means two bytes, which are checked for >= 256 failure::ensure!( exp_len <= RSA_BYTES_LIMIT, "RSA public key: exponent too long (limit: {} bits)", RSA_BITS_LIMIT ); failure::ensure!( data.len() >= offset + exp_len, "RSA public key: unexpected end of data when reading exponent" ); failure::ensure!( data[offset] != 0, "RSA public key: leading zero in exponent" ); let exponent = BigUint::from_bytes_be(&data[offset..][..exp_len]); let modulus_data = &data[offset..][exp_len..]; failure::ensure!( modulus_data.len() <= RSA_BYTES_LIMIT, "RSA public key: modulus too long (limit: {} bits)", RSA_BITS_LIMIT ); failure::ensure!(!modulus_data.is_empty(), "RSA public key: modulus empty"); failure::ensure!( modulus_data[offset] != 0, "RSA public key: leading zero in modulus" ); let modulus = BigUint::from_bytes_be(modulus_data); Ok(PublicKey::RSA { exponent, modulus }) } #[allow(non_camel_case_types)] pub enum PublicKey { RSA { exponent: BigUint, modulus: BigUint }, ECDSAP256 { xy: Box<([u8; 32], [u8; 32])> }, ECDSAP384 { xy: Box<([u8; 48], [u8; 48])> }, ECC_GOST { xy: Box<([u8; 32], [u8; 32])> }, ED25519 { key: Box<[u8; 32]> }, ED448 { key: Box<[u8; 57]> }, } impl PublicKey { pub fn parse(algorithm: DnsSecAlgorithm, data: &[u8]) -> crate::errors::Result { use DnsSecAlgorithmKnown::*; let algorithm = algorithm .into_known() .ok_or_else(|| failure::format_err!("Unknown algorithm"))?; match algorithm { DELETE | INDIRECT | PRIVATEDNS | PRIVATEOID => { failure::bail!("Algorithm {:?} not used with actual key", algorithm) }, RSAMD5 | RSASHA1 | RSASHA1_NSEC3_SHA1 | RSASHA256 | RSASHA512 => parse_rsa(data), DH | DSA | DSA_NSEC3_SHA1 => failure::bail!("Algorithm {:?} not supported", algorithm), ECDSAP256SHA256 => { failure::ensure!( data.len() == 64, "Expected 64 bytes public key for ECDSAP256" ); let mut x = [0u8; 32]; x.copy_from_slice(&data[..32]); let mut y = [0u8; 32]; y.copy_from_slice(&data[32..]); Ok(PublicKey::ECDSAP256 { xy: Box::new((x, y)), }) }, ECDSAP384SHA384 => { failure::ensure!( data.len() == 96, "Expected 96 bytes public key for ECDSAP384" ); let mut x = [0u8; 48]; x.copy_from_slice(&data[..48]); let mut y = [0u8; 48]; y.copy_from_slice(&data[48..]); Ok(PublicKey::ECDSAP384 { xy: Box::new((x, y)), }) }, ECC_GOST => { failure::ensure!( data.len() == 64, "Expected 64 bytes public key for ECC_GOST" ); let mut x = [0u8; 32]; x.copy_from_slice(&data[..32]); let mut y = [0u8; 32]; y.copy_from_slice(&data[32..]); Ok(PublicKey::ECC_GOST { xy: Box::new((x, y)), }) }, ED25519 => { failure::ensure!(data.len() == 32, "Expected 32 bytes public key for ED25519"); let mut key = [0u8; 32]; key.copy_from_slice(data); Ok(PublicKey::ED25519 { key: Box::new(key) }) }, ED448 => { failure::ensure!(data.len() == 57, "Expected 57 bytes public key for ED448"); let mut key = [0u8; 57]; key.copy_from_slice(data); Ok(PublicKey::ED448 { key: Box::new(key) }) }, } } pub fn bits(&self) -> Option { match self { PublicKey::RSA { modulus, .. } => Some(modulus.bits() as u32), PublicKey::ECDSAP256 { .. } => Some(32 * 8), PublicKey::ECDSAP384 { .. } => Some(48 * 8), PublicKey::ECC_GOST { .. } => Some(32 * 8), PublicKey::ED25519 { .. } => Some(32 * 8), PublicKey::ED448 { .. } => Some(57 * 8), } } }