Skip to content

Commit

Permalink
core: Add helpers for checking mechanisms at compile time
Browse files Browse the repository at this point in the history
To be able to compare mechanism variants in const contexts, we use
add a const_eq function.  And to be able to indicate which mechanism
is potentially missing, we add a const panic method that includes the
mechanism variant in the panic message.

To reduce the boilerplate code, we use a macro to generate the enum.
  • Loading branch information
robin-nitrokey committed Dec 20, 2024
1 parent 5cba648 commit 872f9ab
Showing 1 changed file with 107 additions and 155 deletions.
262 changes: 107 additions & 155 deletions core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,163 +452,115 @@ impl Client {
];
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Mechanism {
#[cfg(feature = "aes256-cbc")]
Aes256Cbc,
#[cfg(feature = "chacha8-poly1305")]
Chacha8Poly1305,
#[cfg(feature = "ed255")]
Ed255,
#[cfg(feature = "hmac-blake2s")]
HmacBlake2s,
#[cfg(feature = "hmac-sha1")]
HmacSha1,
#[cfg(feature = "hmac-sha256")]
HmacSha256,
#[cfg(feature = "hmac-sha512")]
HmacSha512,
// P256XSha256,
#[cfg(feature = "p256")]
P256,
#[cfg(feature = "p256")]
P256Prehashed,
#[cfg(feature = "p384")]
P384,
#[cfg(feature = "p384")]
P384Prehashed,
#[cfg(feature = "p521")]
P521,
#[cfg(feature = "p521")]
P521Prehashed,
#[cfg(feature = "brainpoolp256r1")]
BrainpoolP256R1,
#[cfg(feature = "brainpoolp256r1")]
BrainpoolP256R1Prehashed,
#[cfg(feature = "brainpoolp384r1")]
BrainpoolP384R1,
#[cfg(feature = "brainpoolp384r1")]
BrainpoolP384R1Prehashed,
#[cfg(feature = "brainpoolp512r1")]
BrainpoolP512R1,
#[cfg(feature = "brainpoolp512r1")]
BrainpoolP512R1Prehashed,
#[cfg(feature = "secp256k1")]
Secp256k1,
#[cfg(feature = "secp256k1")]
Secp256k1Prehashed,
// clients can also do hashing by themselves
#[cfg(feature = "sha256")]
Sha256,
#[cfg(feature = "tdes")]
Tdes,
#[cfg(feature = "totp")]
Totp,
#[cfg(feature = "trng")]
Trng,
#[cfg(feature = "x255")]
X255,
/// Used to serialize the output of a diffie-hellman
#[cfg(feature = "shared-secret")]
SharedSecret,

/// Exposes the Raw RSA encryption/decryption primitive. Be aware this is dangerous.
/// Not having any padding can allow an attacker to obtain plaintexts and forge signatures.
/// It should only be used if absolutely necessary.
#[cfg(feature = "rsa2048")]
Rsa2048Raw,
/// Exposes the Raw RSA encryption/decryption primitive. Be aware this is dangerous.
/// Not having any padding can allow an attacker to obtain plaintexts and forge signatures.
/// It should only be used if absolutely necessary.
#[cfg(feature = "rsa3072")]
Rsa3072Raw,
/// Exposes the Raw RSA encryption/decryption primitive. Be aware this is dangerous.
/// Not having any padding can allow an attacker to obtain plaintexts and forge signatures.
/// It should only be used if absolutely necessary.
#[cfg(feature = "rsa4096")]
Rsa4096Raw,

#[cfg(feature = "rsa2048")]
Rsa2048Pkcs1v15,
#[cfg(feature = "rsa3072")]
Rsa3072Pkcs1v15,
#[cfg(feature = "rsa4096")]
Rsa4096Pkcs1v15,
macro_rules! generate_mechanism {
(
$(#[$outer:meta])*
$vis:vis enum $name:ident {
$(
$(#[$inner:meta])*
$feature:literal: $variant:ident,
)*
}
) => {
$(#[$outer])*
$vis enum $name {
$(
$(#[$inner])*
#[cfg(feature = $feature)]
$variant,
)*
}

impl $name {
/// All enabled mechanisms.
///
/// The contents of this constant depends on the enabled features.
pub const ENABLED: &[Self] = &[
$(
#[cfg(feature = $feature)]
Self::$variant,
)*
];

/// Check equality in a const-friendly way.
pub const fn const_eq(&self, other: Self) -> bool {
let _ = other;
match *self {
$(
#[cfg(feature = $feature)]
Self::$variant => matches!(other, Self::$variant),
)*
}
}

/// Panic with a message contain this mechanism.
///
/// This is intended for compile time checks that don’t have a direct way to indicate
/// a missing mechanism in a panic message.
pub const fn panic(&self) -> ! {
match *self {
$(
#[cfg(feature = $feature)]
Self::$variant => panic!("panic for mechanism: $variant"),
)*
}
}
}
}
}

impl Mechanism {
/// All enabled mechanisms.
///
/// The contents of this constant depends on the enabled features.
pub const ENABLED: &[Self] = &[
#[cfg(feature = "aes256-cbc")]
Self::Aes256Cbc,
#[cfg(feature = "chacha8-poly1305")]
Self::Chacha8Poly1305,
#[cfg(feature = "ed255")]
Self::Ed255,
#[cfg(feature = "hmac-blake2s")]
Self::HmacBlake2s,
#[cfg(feature = "hmac-sha1")]
Self::HmacSha1,
#[cfg(feature = "hmac-sha256")]
Self::HmacSha256,
#[cfg(feature = "hmac-sha512")]
Self::HmacSha512,
#[cfg(feature = "p256")]
Self::P256,
#[cfg(feature = "p256")]
Self::P256Prehashed,
#[cfg(feature = "p384")]
Self::P384,
#[cfg(feature = "p384")]
Self::P384Prehashed,
#[cfg(feature = "p521")]
Self::P521,
#[cfg(feature = "p521")]
Self::P521Prehashed,
#[cfg(feature = "brainpoolp256r1")]
Self::BrainpoolP256R1,
#[cfg(feature = "brainpoolp256r1")]
Self::BrainpoolP256R1Prehashed,
#[cfg(feature = "brainpoolp384r1")]
Self::BrainpoolP384R1,
#[cfg(feature = "brainpoolp384r1")]
Self::BrainpoolP384R1Prehashed,
#[cfg(feature = "brainpoolp512r1")]
Self::BrainpoolP512R1,
#[cfg(feature = "brainpoolp512r1")]
Self::BrainpoolP512R1Prehashed,
#[cfg(feature = "secp256k1")]
Self::Secp256k1,
#[cfg(feature = "secp256k1")]
Self::Secp256k1Prehashed,
#[cfg(feature = "sha256")]
Self::Sha256,
#[cfg(feature = "tdes")]
Self::Tdes,
#[cfg(feature = "totp")]
Self::Totp,
#[cfg(feature = "trng")]
Self::Trng,
#[cfg(feature = "x255")]
Self::X255,
#[cfg(feature = "shared-secret")]
Self::SharedSecret,
#[cfg(feature = "rsa2048")]
Self::Rsa2048Raw,
#[cfg(feature = "rsa3072")]
Self::Rsa3072Raw,
#[cfg(feature = "rsa4096")]
Self::Rsa4096Raw,
#[cfg(feature = "rsa2048")]
Self::Rsa2048Pkcs1v15,
#[cfg(feature = "rsa3072")]
Self::Rsa3072Pkcs1v15,
#[cfg(feature = "rsa4096")]
Self::Rsa4096Pkcs1v15,
];
generate_mechanism! {
#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Mechanism {
"aes256-cbc": Aes256Cbc,
"chacha8-poly1305": Chacha8Poly1305,
"ed255": Ed255,
"hmac-blake2s": HmacBlake2s,
"hmac-sha1": HmacSha1,
"hmac-sha256": HmacSha256,
"hmac-sha512": HmacSha512,
// P256XSha256,
"p256": P256,
"p256": P256Prehashed,
"p384": P384,
"p384": P384Prehashed,
"p521": P521,
"p521": P521Prehashed,
"brainpoolp256r1": BrainpoolP256R1,
"brainpoolp256r1": BrainpoolP256R1Prehashed,
"brainpoolp384r1": BrainpoolP384R1,
"brainpoolp384r1": BrainpoolP384R1Prehashed,
"brainpoolp512r1": BrainpoolP512R1,
"brainpoolp512r1": BrainpoolP512R1Prehashed,
"secp256k1": Secp256k1,
"secp256k1": Secp256k1Prehashed,
// clients can also do hashing by themselves
"sha256": Sha256,
"tdes": Tdes,
"totp": Totp,
"trng": Trng,
"x255": X255,
/// Used to serialize the output of a diffie-hellman
"shared-secret": SharedSecret,

/// Exposes the Raw RSA encryption/decryption primitive. Be aware this is dangerous.
/// Not having any padding can allow an attacker to obtain plaintexts and forge signatures.
/// It should only be used if absolutely necessary.
"rsa2048": Rsa2048Raw,
/// Exposes the Raw RSA encryption/decryption primitive. Be aware this is dangerous.
/// Not having any padding can allow an attacker to obtain plaintexts and forge signatures.
/// It should only be used if absolutely necessary.
"rsa3072": Rsa3072Raw,
/// Exposes the Raw RSA encryption/decryption primitive. Be aware this is dangerous.
/// Not having any padding can allow an attacker to obtain plaintexts and forge signatures.
/// It should only be used if absolutely necessary.
"rsa4096": Rsa4096Raw,

"rsa2048": Rsa2048Pkcs1v15,
"rsa3072": Rsa3072Pkcs1v15,
"rsa4096": Rsa4096Pkcs1v15,
}
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
Expand Down

0 comments on commit 872f9ab

Please sign in to comment.