#[cfg(not(any(feature = "crypto-rustcrypto", feature = "crypto-fips")))]
#[doc(hidden)]
#[allow(
dead_code,
reason = "crypto key APIs are unavailable without a backend"
)]
pub(crate) mod auth;
#[cfg(any(feature = "crypto-rustcrypto", feature = "crypto-fips"))]
pub mod auth;
mod authoritative;
mod config;
#[cfg_attr(
not(any(feature = "crypto-rustcrypto", feature = "crypto-fips")),
allow(
dead_code,
reason = "crypto provider APIs are unavailable without a backend"
)
)]
mod crypto;
pub(crate) mod encode;
mod engine;
#[cfg_attr(
not(any(feature = "crypto-rustcrypto", feature = "crypto-fips")),
doc(hidden)
)]
#[cfg_attr(
not(any(feature = "crypto-rustcrypto", feature = "crypto-fips")),
allow(
dead_code,
reason = "privacy key APIs are unavailable without a backend"
)
)]
mod privacy;
pub(crate) mod process;
mod recency_map;
mod report;
mod usm;
#[cfg(any(feature = "crypto-rustcrypto", feature = "crypto-fips"))]
pub use auth::{LocalizedKey, MasterKey, MasterKeys};
#[cfg(not(any(feature = "crypto-rustcrypto", feature = "crypto-fips")))]
pub(crate) use auth::{LocalizedKey, MasterKey, MasterKeys};
pub use authoritative::{
AuthoritativeEngine, AuthoritativeEnginePersistenceError,
AuthoritativeEnginePersistenceOperation, PersistedAuthoritativeEngine,
};
#[cfg(any(feature = "crypto-rustcrypto", feature = "crypto-fips"))]
pub use config::DerivedKeys;
#[cfg(not(any(feature = "crypto-rustcrypto", feature = "crypto-fips")))]
pub(crate) use config::DerivedKeys;
pub use config::{UsmConfig, UsmUser};
pub use crypto::{CryptoBackend, CryptoError, CryptoResult};
pub use engine::report_oids;
pub use engine::{
AuthenticatedEngineTime, DiscoveredEngine, EngineCache, EngineState, MAX_ENGINE_ID_LEN,
MAX_ENGINE_TIME, MIN_ENGINE_ID_LEN, TIME_WINDOW, compute_engine_boots_time, generate_engine_id,
in_authoritative_time_window, parse_discovery_response, parse_discovery_response_with_limits,
validate_engine_id,
};
pub(crate) use engine::{
TimelinessCandidateOutcome, TimelinessPublicationOutcome, discovered_engine_state,
};
pub(crate) use privacy::PrivacyEncryptContext;
pub use privacy::{
DesSaltPersistenceError, DesSaltPersistenceOperation, DesSaltState, DesSaltStateError,
PersistedDesSaltState, PrivacyError, PrivacyResult,
};
#[cfg(any(feature = "crypto-rustcrypto", feature = "crypto-fips"))]
pub use privacy::{DesSaltReservation, PrivKey, SaltCounter};
#[cfg(not(any(feature = "crypto-rustcrypto", feature = "crypto-fips")))]
pub(crate) use privacy::{PrivKey, SaltCounter};
pub use report::{MalformedReport, ReportStatus, classify_report};
pub use usm::UsmSecurityParams;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub(crate) enum KeyExtension {
#[default]
None,
Blumenthal,
Reeder,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseProtocolError {
input: String,
kind: ProtocolKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ProtocolKind {
Auth,
Priv,
}
impl std::fmt::Display for ParseProtocolError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.kind {
ProtocolKind::Auth => write!(
f,
"unknown authentication protocol '{}'; expected one of: MD5, SHA, SHA-224, SHA-256, SHA-384, SHA-512",
self.input
),
ProtocolKind::Priv => write!(
f,
"unknown privacy protocol '{}'; expected one of: DES, 3DES, 3DES-EDE, DES3, TDES, AES, AES-128, AES-192-BLUMENTHAL, AES-192-REEDER, AES-256-BLUMENTHAL, AES-256-REEDER",
self.input
),
}
}
}
impl std::error::Error for ParseProtocolError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AuthProtocol {
Md5,
Sha1,
Sha224,
Sha256,
Sha384,
Sha512,
}
impl std::fmt::Display for AuthProtocol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Md5 => write!(f, "MD5"),
Self::Sha1 => write!(f, "SHA"),
Self::Sha224 => write!(f, "SHA-224"),
Self::Sha256 => write!(f, "SHA-256"),
Self::Sha384 => write!(f, "SHA-384"),
Self::Sha512 => write!(f, "SHA-512"),
}
}
}
impl std::str::FromStr for AuthProtocol {
type Err = ParseProtocolError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_uppercase().as_str() {
"MD5" => Ok(Self::Md5),
"SHA" | "SHA1" | "SHA-1" => Ok(Self::Sha1),
"SHA224" | "SHA-224" => Ok(Self::Sha224),
"SHA256" | "SHA-256" => Ok(Self::Sha256),
"SHA384" | "SHA-384" => Ok(Self::Sha384),
"SHA512" | "SHA-512" => Ok(Self::Sha512),
_ => Err(ParseProtocolError {
input: s.to_string(),
kind: ProtocolKind::Auth,
}),
}
}
}
impl AuthProtocol {
#[must_use]
pub fn digest_len(self) -> usize {
match self {
Self::Md5 => 16,
Self::Sha1 => 20,
Self::Sha224 => 28,
Self::Sha256 => 32,
Self::Sha384 => 48,
Self::Sha512 => 64,
}
}
#[must_use]
pub fn mac_len(self) -> usize {
match self {
Self::Md5 | Self::Sha1 => 12, Self::Sha224 => 16, Self::Sha256 => 24, Self::Sha384 => 32, Self::Sha512 => 48, }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PrivProtocol {
Des,
Des3,
Aes128,
Aes192Blumenthal,
Aes192Reeder,
Aes256Blumenthal,
Aes256Reeder,
}
impl std::fmt::Display for PrivProtocol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Des => write!(f, "DES"),
Self::Des3 => write!(f, "3DES"),
Self::Aes128 => write!(f, "AES"),
Self::Aes192Blumenthal => write!(f, "AES-192-BLUMENTHAL"),
Self::Aes192Reeder => write!(f, "AES-192-REEDER"),
Self::Aes256Blumenthal => write!(f, "AES-256-BLUMENTHAL"),
Self::Aes256Reeder => write!(f, "AES-256-REEDER"),
}
}
}
impl std::str::FromStr for PrivProtocol {
type Err = ParseProtocolError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_uppercase().as_str() {
"DES" => Ok(Self::Des),
"3DES" | "3DES-EDE" | "DES3" | "TDES" => Ok(Self::Des3),
"AES" | "AES128" | "AES-128" => Ok(Self::Aes128),
"AES192-BLUMENTHAL" | "AES-192-BLUMENTHAL" => Ok(Self::Aes192Blumenthal),
"AES192-REEDER" | "AES-192-REEDER" | "AES192-CISCO" | "AES-192-CISCO" => {
Ok(Self::Aes192Reeder)
}
"AES256-BLUMENTHAL" | "AES-256-BLUMENTHAL" => Ok(Self::Aes256Blumenthal),
"AES256-REEDER" | "AES-256-REEDER" | "AES256-CISCO" | "AES-256-CISCO" => {
Ok(Self::Aes256Reeder)
}
_ => Err(ParseProtocolError {
input: s.to_string(),
kind: ProtocolKind::Priv,
}),
}
}
}
impl PrivProtocol {
#[must_use]
pub fn key_len(self) -> usize {
match self {
Self::Des => 16, Self::Des3 => 32, Self::Aes128 => 16,
Self::Aes192Blumenthal | Self::Aes192Reeder => 24,
Self::Aes256Blumenthal | Self::Aes256Reeder => 32,
}
}
#[must_use]
pub fn salt_len(self) -> usize {
8 }
pub(crate) fn key_extension_for(self, auth_protocol: AuthProtocol) -> KeyExtension {
let auth_len = auth_protocol.digest_len();
let priv_len = self.key_len();
if auth_len >= priv_len {
return KeyExtension::None;
}
match self {
Self::Des3 => KeyExtension::Reeder,
Self::Aes192Blumenthal | Self::Aes256Blumenthal => KeyExtension::Blumenthal,
Self::Aes192Reeder | Self::Aes256Reeder => KeyExtension::Reeder,
Self::Des | Self::Aes128 => KeyExtension::None, }
}
#[must_use]
pub const fn is_des_family(self) -> bool {
matches!(self, Self::Des | Self::Des3)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_auth_protocol_display() {
assert_eq!(format!("{}", AuthProtocol::Md5), "MD5");
assert_eq!(format!("{}", AuthProtocol::Sha1), "SHA");
assert_eq!(format!("{}", AuthProtocol::Sha224), "SHA-224");
assert_eq!(format!("{}", AuthProtocol::Sha256), "SHA-256");
assert_eq!(format!("{}", AuthProtocol::Sha384), "SHA-384");
assert_eq!(format!("{}", AuthProtocol::Sha512), "SHA-512");
}
#[test]
fn test_auth_protocol_from_str() {
assert_eq!("MD5".parse::<AuthProtocol>().unwrap(), AuthProtocol::Md5);
assert_eq!("md5".parse::<AuthProtocol>().unwrap(), AuthProtocol::Md5);
assert_eq!("SHA".parse::<AuthProtocol>().unwrap(), AuthProtocol::Sha1);
assert_eq!("sha1".parse::<AuthProtocol>().unwrap(), AuthProtocol::Sha1);
assert_eq!("SHA-1".parse::<AuthProtocol>().unwrap(), AuthProtocol::Sha1);
assert_eq!(
"sha-224".parse::<AuthProtocol>().unwrap(),
AuthProtocol::Sha224
);
assert_eq!(
"SHA256".parse::<AuthProtocol>().unwrap(),
AuthProtocol::Sha256
);
assert_eq!(
"SHA-256".parse::<AuthProtocol>().unwrap(),
AuthProtocol::Sha256
);
assert_eq!(
"sha384".parse::<AuthProtocol>().unwrap(),
AuthProtocol::Sha384
);
assert_eq!(
"SHA-512".parse::<AuthProtocol>().unwrap(),
AuthProtocol::Sha512
);
assert!("invalid".parse::<AuthProtocol>().is_err());
}
#[test]
fn test_priv_protocol_display() {
assert_eq!(format!("{}", PrivProtocol::Des), "DES");
assert_eq!(format!("{}", PrivProtocol::Des3), "3DES");
assert_eq!(format!("{}", PrivProtocol::Aes128), "AES");
assert_eq!(
format!("{}", PrivProtocol::Aes192Blumenthal),
"AES-192-BLUMENTHAL"
);
assert_eq!(format!("{}", PrivProtocol::Aes192Reeder), "AES-192-REEDER");
assert_eq!(
format!("{}", PrivProtocol::Aes256Blumenthal),
"AES-256-BLUMENTHAL"
);
assert_eq!(format!("{}", PrivProtocol::Aes256Reeder), "AES-256-REEDER");
}
#[test]
fn test_priv_protocol_from_str() {
assert_eq!("DES".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des);
assert_eq!("des".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des);
assert_eq!("3DES".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des3);
assert_eq!("3des".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des3);
assert_eq!(
"3DES-EDE".parse::<PrivProtocol>().unwrap(),
PrivProtocol::Des3
);
assert_eq!("DES3".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des3);
assert_eq!("TDES".parse::<PrivProtocol>().unwrap(), PrivProtocol::Des3);
assert_eq!("AES".parse::<PrivProtocol>().unwrap(), PrivProtocol::Aes128);
assert_eq!("aes".parse::<PrivProtocol>().unwrap(), PrivProtocol::Aes128);
assert_eq!(
"AES128".parse::<PrivProtocol>().unwrap(),
PrivProtocol::Aes128
);
assert_eq!(
"AES-128".parse::<PrivProtocol>().unwrap(),
PrivProtocol::Aes128
);
for (input, expected) in [
("aes192-blumenthal", PrivProtocol::Aes192Blumenthal),
("AES-192-BLUMENTHAL", PrivProtocol::Aes192Blumenthal),
("aes192-reeder", PrivProtocol::Aes192Reeder),
("AES-192-REEDER", PrivProtocol::Aes192Reeder),
("aes192-cisco", PrivProtocol::Aes192Reeder),
("AES-192-CISCO", PrivProtocol::Aes192Reeder),
("aes256-blumenthal", PrivProtocol::Aes256Blumenthal),
("AES-256-BLUMENTHAL", PrivProtocol::Aes256Blumenthal),
("aes256-reeder", PrivProtocol::Aes256Reeder),
("AES-256-REEDER", PrivProtocol::Aes256Reeder),
("aes256-cisco", PrivProtocol::Aes256Reeder),
("AES-256-CISCO", PrivProtocol::Aes256Reeder),
] {
assert_eq!(input.parse::<PrivProtocol>().unwrap(), expected);
}
for ambiguous in ["AES192", "AES-192", "AES256", "AES-256"] {
assert!(ambiguous.parse::<PrivProtocol>().is_err());
}
for protocol in [
PrivProtocol::Des,
PrivProtocol::Des3,
PrivProtocol::Aes128,
PrivProtocol::Aes192Blumenthal,
PrivProtocol::Aes192Reeder,
PrivProtocol::Aes256Blumenthal,
PrivProtocol::Aes256Reeder,
] {
assert_eq!(
protocol.to_string().parse::<PrivProtocol>().unwrap(),
protocol
);
}
assert!("invalid".parse::<PrivProtocol>().is_err());
}
#[test]
fn test_parse_protocol_error_display() {
let err = "bogus".parse::<AuthProtocol>().unwrap_err();
assert!(err.to_string().contains("bogus"));
assert!(err.to_string().contains("authentication protocol"));
let err = "bogus".parse::<PrivProtocol>().unwrap_err();
assert_eq!(
err.to_string(),
"unknown privacy protocol 'bogus'; expected one of: DES, 3DES, 3DES-EDE, DES3, TDES, AES, AES-128, AES-192-BLUMENTHAL, AES-192-REEDER, AES-256-BLUMENTHAL, AES-256-REEDER"
);
}
#[test]
fn aes_extension_variant_selects_only_required_extension() {
for auth in [AuthProtocol::Md5, AuthProtocol::Sha1] {
assert_eq!(
PrivProtocol::Aes192Blumenthal.key_extension_for(auth),
KeyExtension::Blumenthal
);
assert_eq!(
PrivProtocol::Aes192Reeder.key_extension_for(auth),
KeyExtension::Reeder
);
}
for auth in [AuthProtocol::Md5, AuthProtocol::Sha1, AuthProtocol::Sha224] {
assert_eq!(
PrivProtocol::Aes256Blumenthal.key_extension_for(auth),
KeyExtension::Blumenthal
);
assert_eq!(
PrivProtocol::Aes256Reeder.key_extension_for(auth),
KeyExtension::Reeder
);
}
for auth in [
AuthProtocol::Sha224,
AuthProtocol::Sha256,
AuthProtocol::Sha384,
AuthProtocol::Sha512,
] {
assert_eq!(
PrivProtocol::Aes192Blumenthal.key_extension_for(auth),
KeyExtension::None
);
assert_eq!(
PrivProtocol::Aes192Reeder.key_extension_for(auth),
KeyExtension::None
);
}
for auth in [
AuthProtocol::Sha256,
AuthProtocol::Sha384,
AuthProtocol::Sha512,
] {
assert_eq!(
PrivProtocol::Aes256Blumenthal.key_extension_for(auth),
KeyExtension::None
);
assert_eq!(
PrivProtocol::Aes256Reeder.key_extension_for(auth),
KeyExtension::None
);
}
}
}