parse dnssec public keys
This commit is contained in:
parent
8811d79744
commit
3b0d1ea1fb
31
Cargo.lock
generated
31
Cargo.lock
generated
@ -196,6 +196,7 @@ dependencies = [
|
|||||||
"gost94 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gost94 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -394,6 +395,33 @@ name = "nodrop"
|
|||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
@ -932,6 +960,9 @@ dependencies = [
|
|||||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||||
|
"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"
|
||||||
|
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
||||||
|
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||||
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
|
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
|
||||||
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||||
|
@ -16,8 +16,9 @@ smallvec = "0.6.10"
|
|||||||
sha-1 = { version = "0.8.1", optional = true }
|
sha-1 = { version = "0.8.1", optional = true }
|
||||||
sha2 = { version = "0.8.0", optional = true }
|
sha2 = { version = "0.8.0", optional = true }
|
||||||
gost94 = { version = "0.7.0", optional = true }
|
gost94 = { version = "0.7.0", optional = true }
|
||||||
|
num-bigint = { version = "0.2.3", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
no-unsafe = []
|
no-unsafe = []
|
||||||
default = ['crypto']
|
default = ['crypto']
|
||||||
crypto = ['sha-1', 'sha2', 'gost94']
|
crypto = ['sha-1', 'sha2', 'gost94', 'num-bigint']
|
||||||
|
31
lib/dnsbox-base/src/crypto/ds.rs
Normal file
31
lib/dnsbox-base/src/crypto/ds.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use crate::common_types::DnsSecDigestAlgorithmKnown;
|
||||||
|
|
||||||
|
pub fn sha1(data: &[u8]) -> Vec<u8> {
|
||||||
|
use sha1::Digest;
|
||||||
|
sha1::Sha1::digest(data).as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sha256(data: &[u8]) -> Vec<u8> {
|
||||||
|
use sha2::Digest;
|
||||||
|
sha2::Sha256::digest(data).as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sha384(data: &[u8]) -> Vec<u8> {
|
||||||
|
use sha2::Digest;
|
||||||
|
sha2::Sha384::digest(data).as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
// gostR3411
|
||||||
|
pub fn gost_r3411(data: &[u8]) -> Vec<u8> {
|
||||||
|
use gost94::Digest;
|
||||||
|
gost94::Gost94CryptoPro::digest(data).as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ds_hash(alg: DnsSecDigestAlgorithmKnown, data: &[u8]) -> Vec<u8> {
|
||||||
|
match alg {
|
||||||
|
DnsSecDigestAlgorithmKnown::SHA1 => sha1(data),
|
||||||
|
DnsSecDigestAlgorithmKnown::SHA256 => sha256(data),
|
||||||
|
DnsSecDigestAlgorithmKnown::GOST_R_34_11_94 => gost_r3411(data),
|
||||||
|
DnsSecDigestAlgorithmKnown::SHA384 => sha384(data),
|
||||||
|
}
|
||||||
|
}
|
@ -1,31 +1,5 @@
|
|||||||
use crate::common_types::DnsSecDigestAlgorithmKnown;
|
mod ds;
|
||||||
|
mod pubkey;
|
||||||
|
|
||||||
pub fn sha1(data: &[u8]) -> Vec<u8> {
|
pub(crate) use self::ds::ds_hash;
|
||||||
use sha1::Digest;
|
pub use self::pubkey::PublicKey;
|
||||||
sha1::Sha1::digest(data).as_slice().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sha256(data: &[u8]) -> Vec<u8> {
|
|
||||||
use sha2::Digest;
|
|
||||||
sha2::Sha256::digest(data).as_slice().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sha384(data: &[u8]) -> Vec<u8> {
|
|
||||||
use sha2::Digest;
|
|
||||||
sha2::Sha384::digest(data).as_slice().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
// gostR3411
|
|
||||||
pub fn gost_r3411(data: &[u8]) -> Vec<u8> {
|
|
||||||
use gost94::Digest;
|
|
||||||
gost94::Gost94CryptoPro::digest(data).as_slice().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ds_hash(alg: DnsSecDigestAlgorithmKnown, data: &[u8]) -> Vec<u8> {
|
|
||||||
match alg {
|
|
||||||
DnsSecDigestAlgorithmKnown::SHA1 => sha1(data),
|
|
||||||
DnsSecDigestAlgorithmKnown::SHA256 => sha256(data),
|
|
||||||
DnsSecDigestAlgorithmKnown::GOST_R_34_11_94 => gost_r3411(data),
|
|
||||||
DnsSecDigestAlgorithmKnown::SHA384 => sha384(data),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
115
lib/dnsbox-base/src/crypto/pubkey.rs
Normal file
115
lib/dnsbox-base/src/crypto/pubkey.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
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<PublicKey> {
|
||||||
|
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<Self> {
|
||||||
|
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<u32> {
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ extern crate self as dnsbox_base;
|
|||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
|
||||||
#[cfg(feature = "crypto")]
|
#[cfg(feature = "crypto")]
|
||||||
mod crypto;
|
pub mod crypto;
|
||||||
pub mod common_types;
|
pub mod common_types;
|
||||||
pub mod ser;
|
pub mod ser;
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
|
@ -415,6 +415,11 @@ impl DNSKEY {
|
|||||||
digest: HexRemainingBlob::new(crate::crypto::ds_hash(*alg, &bin)),
|
digest: HexRemainingBlob::new(crate::crypto::ds_hash(*alg, &bin)),
|
||||||
}).collect())
|
}).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "crypto")]
|
||||||
|
pub fn parse_public_key(&self) -> Result<crate::crypto::PublicKey> {
|
||||||
|
crate::crypto::PublicKey::parse(self.algorithm, &self.public_key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
|
||||||
|
Loading…
Reference in New Issue
Block a user