blob: c562371fc4d5e26f8dc75c9bd5374c93bb2982c5 [file] [log] [blame]
/*
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! bitmap for expressing the set of supported algorithms in edns.
use std::convert::From;
use std::fmt;
use std::fmt::{Display, Formatter};
use log::warn;
use crate::error::*;
use crate::rr::dnssec::Algorithm;
use crate::serialize::binary::{BinEncodable, BinEncoder};
/// Used to specify the set of SupportedAlgorithms between a client and server
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
pub struct SupportedAlgorithms {
// right now the number of Algorithms supported are fewer than 16..
bit_map: u8,
}
impl SupportedAlgorithms {
/// Return a new set of Supported algorithms
pub fn new() -> Self {
SupportedAlgorithms { bit_map: 0 }
}
/// Specify the entire set is supported
pub fn all() -> Self {
SupportedAlgorithms {
bit_map: 0b0111_1111,
}
}
/// Based on the set of Algorithms, return the supported set
pub fn from_vec(algorithms: &[Algorithm]) -> Self {
let mut supported = SupportedAlgorithms::new();
for a in algorithms {
supported.set(*a);
}
supported
}
fn pos(algorithm: Algorithm) -> Option<u8> {
// not using the values from the RFC's to keep the bit_map space condensed
let bit_pos: Option<u8> = match algorithm {
Algorithm::RSASHA1 => Some(0),
Algorithm::RSASHA256 => Some(1),
Algorithm::RSASHA1NSEC3SHA1 => Some(2),
Algorithm::RSASHA512 => Some(3),
Algorithm::ECDSAP256SHA256 => Some(4),
Algorithm::ECDSAP384SHA384 => Some(5),
Algorithm::ED25519 => Some(6),
Algorithm::Unknown(_) => None,
};
bit_pos.map(|b| 1u8 << b)
}
fn from_pos(pos: u8) -> Option<Algorithm> {
// TODO: should build a code generator or possibly a macro for deriving these inversions
match pos {
0 => Some(Algorithm::RSASHA1),
1 => Some(Algorithm::RSASHA256),
2 => Some(Algorithm::RSASHA1NSEC3SHA1),
3 => Some(Algorithm::RSASHA512),
4 => Some(Algorithm::ECDSAP256SHA256),
5 => Some(Algorithm::ECDSAP384SHA384),
6 => Some(Algorithm::ED25519),
_ => None,
}
}
/// Set the specified algorithm as supported
pub fn set(&mut self, algorithm: Algorithm) {
if let Some(bit_pos) = Self::pos(algorithm) {
self.bit_map |= bit_pos;
}
}
/// Returns true if the algorithm is supported
pub fn has(self, algorithm: Algorithm) -> bool {
if let Some(bit_pos) = Self::pos(algorithm) {
(bit_pos & self.bit_map) == bit_pos
} else {
false
}
}
/// Return an Iterator over the supported set.
pub fn iter(&self) -> SupportedAlgorithmsIter {
SupportedAlgorithmsIter::new(self)
}
/// Return the count of supported algorithms
pub fn len(self) -> u16 {
// this is pretty much guaranteed to be less that u16::max_value()
self.iter().count() as u16
}
/// Return true if no SupportedAlgorithms are set, this implies the option is not supported
pub fn is_empty(self) -> bool {
self.bit_map == 0
}
}
impl Default for SupportedAlgorithms {
fn default() -> SupportedAlgorithms {
SupportedAlgorithms::new()
}
}
impl Display for SupportedAlgorithms {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
for a in self.iter() {
a.fmt(f)?;
f.write_str(", ")?;
}
Ok(())
}
}
impl<'a> From<&'a [u8]> for SupportedAlgorithms {
fn from(values: &'a [u8]) -> Self {
let mut supported = SupportedAlgorithms::new();
for a in values.iter().map(|i| Algorithm::from_u8(*i)) {
match a {
Algorithm::Unknown(v) => warn!("unrecognized algorithm: {}", v),
a => supported.set(a),
}
}
supported
}
}
impl<'a> From<&'a SupportedAlgorithms> for Vec<u8> {
fn from(value: &'a SupportedAlgorithms) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::with_capacity(8); // today this is less than 8
for a in value.iter() {
bytes.push(a.into());
}
bytes.shrink_to_fit();
bytes
}
}
impl From<Algorithm> for SupportedAlgorithms {
fn from(algorithm: Algorithm) -> Self {
SupportedAlgorithms::from_vec(&[algorithm])
}
}
pub struct SupportedAlgorithmsIter<'a> {
algorithms: &'a SupportedAlgorithms,
current: usize,
}
impl<'a> SupportedAlgorithmsIter<'a> {
pub fn new(algorithms: &'a SupportedAlgorithms) -> Self {
SupportedAlgorithmsIter {
algorithms,
current: 0,
}
}
}
impl<'a> Iterator for SupportedAlgorithmsIter<'a> {
type Item = Algorithm;
fn next(&mut self) -> Option<Self::Item> {
// some quick bounds checking
if self.current > u8::max_value() as usize {
return None;
}
while let Some(algorithm) = SupportedAlgorithms::from_pos(self.current as u8) {
self.current += 1;
if self.algorithms.has(algorithm) {
return Some(algorithm);
}
}
None
}
}
impl BinEncodable for SupportedAlgorithms {
fn emit(&self, encoder: &mut BinEncoder) -> ProtoResult<()> {
for a in self.iter() {
encoder.emit_u8(a.into())?;
}
Ok(())
}
}
#[test]
fn test_has() {
let mut supported = SupportedAlgorithms::new();
supported.set(Algorithm::RSASHA1);
assert!(supported.has(Algorithm::RSASHA1));
assert!(!supported.has(Algorithm::RSASHA1NSEC3SHA1));
let mut supported = SupportedAlgorithms::new();
supported.set(Algorithm::RSASHA256);
assert!(!supported.has(Algorithm::RSASHA1));
assert!(!supported.has(Algorithm::RSASHA1NSEC3SHA1));
assert!(supported.has(Algorithm::RSASHA256));
}
#[test]
fn test_iterator() {
let supported = SupportedAlgorithms::all();
assert_eq!(supported.iter().count(), 7);
// it just so happens that the iterator has a fixed order...
let supported = SupportedAlgorithms::all();
let mut iter = supported.iter();
assert_eq!(iter.next(), Some(Algorithm::RSASHA1));
assert_eq!(iter.next(), Some(Algorithm::RSASHA256));
assert_eq!(iter.next(), Some(Algorithm::RSASHA1NSEC3SHA1));
assert_eq!(iter.next(), Some(Algorithm::RSASHA512));
assert_eq!(iter.next(), Some(Algorithm::ECDSAP256SHA256));
assert_eq!(iter.next(), Some(Algorithm::ECDSAP384SHA384));
assert_eq!(iter.next(), Some(Algorithm::ED25519));
let mut supported = SupportedAlgorithms::new();
supported.set(Algorithm::RSASHA256);
supported.set(Algorithm::RSASHA512);
let mut iter = supported.iter();
assert_eq!(iter.next(), Some(Algorithm::RSASHA256));
assert_eq!(iter.next(), Some(Algorithm::RSASHA512));
}
#[test]
fn test_vec() {
let supported = SupportedAlgorithms::all();
let array: Vec<u8> = (&supported).into();
let decoded: SupportedAlgorithms = (&array as &[_]).into();
assert_eq!(supported, decoded);
let mut supported = SupportedAlgorithms::new();
supported.set(Algorithm::RSASHA256);
supported.set(Algorithm::ECDSAP256SHA256);
supported.set(Algorithm::ECDSAP384SHA384);
supported.set(Algorithm::ED25519);
let array: Vec<u8> = (&supported).into();
let decoded: SupportedAlgorithms = (&array as &[_]).into();
assert_eq!(supported, decoded);
assert!(!supported.has(Algorithm::RSASHA1));
assert!(!supported.has(Algorithm::RSASHA1NSEC3SHA1));
assert!(supported.has(Algorithm::RSASHA256));
assert!(supported.has(Algorithm::ECDSAP256SHA256));
assert!(supported.has(Algorithm::ECDSAP384SHA384));
assert!(supported.has(Algorithm::ED25519));
}