use std::{fmt::Display, str::FromStr};
use base64ct::{Base64, Encoding};
use nethsm_sdk_rs::models::KeyPrivateData;
use pgp::composed::SignedPublicKey;
use pgp::types::KeyDetails as _;
use rsa::{
RsaPrivateKey,
pkcs8::DecodePrivateKey,
traits::PrivateKeyParts,
traits::PublicKeyParts,
};
use serde::{Deserialize, Serialize};
use crate::{
KeyMechanism,
KeyType,
OpenPgpUserId,
OpenPgpUserIdList,
OpenPgpVersion,
SignatureType,
TlsKeyType,
};
pub const MIN_RSA_BIT_LENGTH: u32 = 2048;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("PKCS#8 error: {0}")]
Pkcs8(#[from] rsa::pkcs8::Error),
#[error("No primes found")]
NoPrimes,
#[error("The {0} key type is not supported")]
UnsupportedKeyType(KeyType),
#[error(
"The key type {key_type} does not support the following key mechanisms: {invalid_mechanisms:?}"
)]
InvalidKeyMechanism {
key_type: KeyType,
invalid_mechanisms: Vec<KeyMechanism>,
},
#[error("Elliptic curve key ({key_type}) does not support setting length")]
KeyLengthUnsupported { key_type: KeyType },
#[error("Generating a key of type {key_type} requires setting a length")]
KeyLengthRequired { key_type: KeyType },
#[error(
"AES only defines key lengths of 128, 192 and 256. A key length of {key_length} is unsupported!"
)]
InvalidKeyLengthAes { key_length: u32 },
#[error(
"RSA keys shorter than {MIN_RSA_BIT_LENGTH} are not supported. A key length of {key_length} is unsafe!"
)]
InvalidKeyLengthRsa { key_length: u32 },
#[error("Elliptic curve key ({tls_key_type}) does not support setting length")]
TlsKeyLengthUnsupported { tls_key_type: TlsKeyType },
#[error("Generating a key of type {tls_key_type} requires setting a length")]
TlsKeyLengthRequired { tls_key_type: TlsKeyType },
#[error(
"RSA keys shorter than {MIN_RSA_BIT_LENGTH} are not supported. A key length of {key_length} is unsafe!"
)]
InvalidTlsKeyLengthRsa { key_length: u32 },
#[error("Invalid Key ID{}: {}", if key_ids.len() == 1 {"s"} else { " "}, key_ids.join(", "))]
InvalidKeyIds {
key_ids: Vec<String>,
},
#[error("The key type {key_type} is not compatible with signature type: {signature_type}")]
InvalidKeyTypeForSignatureType {
key_type: KeyType,
signature_type: SignatureType,
},
#[error(
"The key mechanism {required_key_mechanism} must be used with signature type {signature_type}"
)]
InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism,
signature_type: SignatureType,
},
#[error("Unable to derive a valid cryptography key use from string: {0}")]
InvalidCryptograhicKeyUse(String),
#[error(
"The key type {key_type}, key mechanisms {key_mechanisms:?} and signature type {signature_type} are incompatible with raw cryptographic signing"
)]
InvalidRawSigningKeySetup {
key_type: KeyType,
key_mechanisms: Vec<KeyMechanism>,
signature_type: SignatureType,
},
#[error(
"The key type {key_type}, key mechanisms {key_mechanisms:?} and signature type {signature_type} are incompatible with OpenPGP signing"
)]
InvalidOpenPgpSigningKeySetup {
key_type: KeyType,
key_mechanisms: Vec<KeyMechanism>,
signature_type: SignatureType,
},
#[error("An OpenPGP error occurred while {context}:\n{source}")]
OpenPgp {
context: &'static str,
source: crate::openpgp::Error,
},
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(into = "String", try_from = "String")]
pub struct KeyId(String);
impl KeyId {
pub fn new(key_id: String) -> Result<Self, Error> {
if key_id.is_empty()
|| !key_id.chars().all(|char| {
char.is_numeric() || (char.is_ascii_lowercase() && char.is_ascii_alphabetic())
})
{
return Err(Error::InvalidKeyIds {
key_ids: vec![key_id],
});
}
Ok(Self(key_id))
}
}
impl AsRef<str> for KeyId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl From<KeyId> for String {
fn from(value: KeyId) -> Self {
value.0
}
}
impl FromStr for KeyId {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s.into())
}
}
impl Display for KeyId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl TryFrom<&str> for KeyId {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::from_str(value)
}
}
impl TryFrom<&String> for KeyId {
type Error = Error;
fn try_from(value: &String) -> Result<Self, Self::Error> {
Self::from_str(value)
}
}
impl TryFrom<String> for KeyId {
type Error = Error;
fn try_from(value: String) -> Result<Self, Self::Error> {
Self::new(value)
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum CryptographicKeyContext {
#[serde(rename = "openpgp")]
OpenPgp {
user_ids: OpenPgpUserIdList,
version: OpenPgpVersion,
},
#[serde(rename = "raw")]
Raw,
}
impl CryptographicKeyContext {
pub fn validate_signing_key_setup(
&self,
key_type: KeyType,
key_mechanisms: &[KeyMechanism],
signature_type: SignatureType,
) -> Result<(), Error> {
match self {
Self::Raw => match (key_type, signature_type) {
(KeyType::Curve25519, SignatureType::EdDsa)
if key_mechanisms.contains(&KeyMechanism::EdDsaSignature) => {}
(KeyType::EcP256, SignatureType::EcdsaP256)
if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
(KeyType::EcP384, SignatureType::EcdsaP384)
if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
(KeyType::EcP521, SignatureType::EcdsaP521)
if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
(KeyType::Rsa, SignatureType::Pkcs1)
if key_mechanisms.contains(&KeyMechanism::RsaSignaturePkcs1) => {}
(KeyType::Rsa, SignatureType::PssMd5)
if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssMd5) => {}
(KeyType::Rsa, SignatureType::PssSha1)
if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha1) => {}
(KeyType::Rsa, SignatureType::PssSha224)
if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha224) => {}
(KeyType::Rsa, SignatureType::PssSha256)
if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha256) => {}
(KeyType::Rsa, SignatureType::PssSha384)
if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha384) => {}
(KeyType::Rsa, SignatureType::PssSha512)
if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha512) => {}
_ => {
return Err(Error::InvalidRawSigningKeySetup {
key_type,
key_mechanisms: key_mechanisms.to_vec(),
signature_type,
});
}
},
Self::OpenPgp {
user_ids: _,
version: _,
} => match (key_type, signature_type) {
(KeyType::Curve25519, SignatureType::EdDsa)
if key_mechanisms.contains(&KeyMechanism::EdDsaSignature) => {}
(KeyType::EcP256, SignatureType::EcdsaP256)
if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
(KeyType::EcP384, SignatureType::EcdsaP384)
if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
(KeyType::EcP521, SignatureType::EcdsaP521)
if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
(KeyType::Rsa, SignatureType::Pkcs1)
if key_mechanisms.contains(&KeyMechanism::RsaSignaturePkcs1) => {}
_ => {
return Err(Error::InvalidOpenPgpSigningKeySetup {
key_type,
key_mechanisms: key_mechanisms.to_vec(),
signature_type,
});
}
},
}
Ok(())
}
}
impl Display for CryptographicKeyContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::OpenPgp { user_ids, version } => {
write!(
f,
"OpenPGP (Version: {version}; User IDs: {})",
user_ids
.iter()
.map(|user_id| format!("\"{user_id}\""))
.collect::<Vec<String>>()
.join(", ")
)
}
Self::Raw => {
write!(f, "Raw")
}
}
}
}
impl TryFrom<SignedPublicKey> for CryptographicKeyContext {
type Error = Error;
fn try_from(value: SignedPublicKey) -> Result<Self, Self::Error> {
let user_ids: Vec<OpenPgpUserId> = value
.details
.users
.iter()
.filter_map(|signed_user| signed_user.try_into().ok())
.collect();
Ok(Self::OpenPgp {
user_ids: OpenPgpUserIdList::new(user_ids).map_err(|source| Error::OpenPgp {
context: "creating a list of OpenPGP User IDs",
source,
})?,
version: value
.primary_key
.version()
.try_into()
.map_err(|source| Error::OpenPgp {
context: "deriving an OpenPGP version from a primary key",
source,
})?,
})
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct SigningKeySetup {
key_id: KeyId,
key_type: KeyType,
key_mechanisms: Vec<KeyMechanism>,
key_length: Option<u32>,
signature_type: SignatureType,
key_context: CryptographicKeyContext,
}
impl SigningKeySetup {
pub fn new(
key_id: KeyId,
key_type: KeyType,
key_mechanisms: Vec<KeyMechanism>,
key_length: Option<u32>,
signature_type: SignatureType,
cryptographic_key_context: CryptographicKeyContext,
) -> Result<Self, Error> {
key_type_matches_mechanisms(key_type, &key_mechanisms)?;
key_type_matches_length(key_type, key_length)?;
key_type_and_mechanisms_match_signature_type(key_type, &key_mechanisms, signature_type)?;
cryptographic_key_context.validate_signing_key_setup(
key_type,
&key_mechanisms,
signature_type,
)?;
Ok(Self {
key_id,
key_type,
key_mechanisms,
key_length,
signature_type,
key_context: cryptographic_key_context,
})
}
pub fn get_key_id(&self) -> KeyId {
self.key_id.clone()
}
pub fn get_key_type(&self) -> KeyType {
self.key_type
}
pub fn get_key_mechanisms(&self) -> Vec<KeyMechanism> {
self.key_mechanisms.clone()
}
pub fn get_key_length(&self) -> Option<u32> {
self.key_length
}
pub fn get_signature_type(&self) -> SignatureType {
self.signature_type
}
pub fn get_key_context(&self) -> CryptographicKeyContext {
self.key_context.clone()
}
}
enum PrivateKeyData {
Curve25519(Vec<u8>),
EcP256(Vec<u8>),
EcP384(Vec<u8>),
EcP521(Vec<u8>),
Rsa {
prime_p: Vec<u8>,
prime_q: Vec<u8>,
public_exponent: Vec<u8>,
},
}
impl std::fmt::Debug for PrivateKeyData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
const REDACTED: &&str = &"[REDACTED]";
match self {
Self::Curve25519(_) => f.debug_tuple("Curve25519").field(REDACTED).finish(),
Self::EcP256(_) => f.debug_tuple("EcP256").field(REDACTED).finish(),
Self::EcP384(_) => f.debug_tuple("EcP384").field(REDACTED).finish(),
Self::EcP521(_) => f.debug_tuple("EcP521").field(REDACTED).finish(),
Self::Rsa {
public_exponent, ..
} => f
.debug_struct("Rsa")
.field("prime_p", REDACTED)
.field("prime_q", REDACTED)
.field("public_exponent", public_exponent)
.finish(),
}
}
}
#[derive(Debug)]
pub struct PrivateKeyImport {
key_data: PrivateKeyData,
}
fn pad(buf: &[u8], len: usize) -> Result<Vec<u8>, crate::Error> {
if len < buf.len() {
return Err(crate::Error::Default(format!(
"Input buffer should be upmost {len} bytes long but has {} bytes.",
buf.len()
)));
}
let mut v = vec![0; len];
v[len - buf.len()..].copy_from_slice(buf);
Ok(v)
}
impl PrivateKeyImport {
pub fn new(key_type: KeyType, key_data: &[u8]) -> Result<Self, Error> {
Ok(match key_type {
KeyType::Curve25519 => {
let key_pair = ed25519_dalek::pkcs8::KeypairBytes::from_pkcs8_der(key_data)?;
Self {
key_data: PrivateKeyData::Curve25519(key_pair.secret_key.to_vec()),
}
}
KeyType::EcP256 => {
let private_key = p256::SecretKey::from_pkcs8_der(key_data)?;
Self {
key_data: PrivateKeyData::EcP256(private_key.to_bytes().as_slice().to_owned()),
}
}
KeyType::EcP384 => {
let private_key = p384::SecretKey::from_pkcs8_der(key_data)?;
Self {
key_data: PrivateKeyData::EcP384(private_key.to_bytes().as_slice().to_owned()),
}
}
KeyType::EcP521 => {
let private_key = p521::SecretKey::from_pkcs8_der(key_data)?;
Self {
key_data: PrivateKeyData::EcP521(private_key.to_bytes().as_slice().to_owned()),
}
}
KeyType::Generic => return Err(Error::UnsupportedKeyType(KeyType::Generic)),
KeyType::Rsa => {
let private_key = RsaPrivateKey::from_pkcs8_der(key_data)?;
key_type_matches_length(key_type, Some(private_key.size() as u32 * 8))?;
Self {
key_data: PrivateKeyData::Rsa {
prime_p: private_key
.primes()
.first()
.ok_or(Error::NoPrimes)?
.to_bytes_be(),
prime_q: private_key
.primes()
.get(1)
.ok_or(Error::NoPrimes)?
.to_bytes_be(),
public_exponent: private_key.e().to_bytes_be(),
},
}
}
})
}
pub fn from_pkcs8_pem(key_type: KeyType, key_data: &str) -> Result<Self, Error> {
Ok(match key_type {
KeyType::Curve25519 => {
let key_pair = ed25519_dalek::pkcs8::KeypairBytes::from_pkcs8_pem(key_data)?;
Self {
key_data: PrivateKeyData::Curve25519(key_pair.secret_key.to_vec()),
}
}
KeyType::EcP256 => {
let private_key = p256::SecretKey::from_pkcs8_pem(key_data)?;
Self {
key_data: PrivateKeyData::EcP256(private_key.to_bytes().as_slice().to_owned()),
}
}
KeyType::EcP384 => {
let private_key = p384::SecretKey::from_pkcs8_pem(key_data)?;
Self {
key_data: PrivateKeyData::EcP384(private_key.to_bytes().as_slice().to_owned()),
}
}
KeyType::EcP521 => {
let private_key = p521::SecretKey::from_pkcs8_pem(key_data)?;
Self {
key_data: PrivateKeyData::EcP521(private_key.to_bytes().as_slice().to_owned()),
}
}
KeyType::Generic => return Err(Error::UnsupportedKeyType(KeyType::Generic)),
KeyType::Rsa => {
let private_key = RsaPrivateKey::from_pkcs8_pem(key_data)?;
key_type_matches_length(key_type, Some(private_key.size() as u32 * 8))?;
Self {
key_data: PrivateKeyData::Rsa {
prime_p: private_key
.primes()
.first()
.ok_or(Error::NoPrimes)?
.to_bytes_be(),
prime_q: private_key
.primes()
.get(1)
.ok_or(Error::NoPrimes)?
.to_bytes_be(),
public_exponent: private_key.e().to_bytes_be(),
},
}
}
})
}
pub fn from_rsa(prime_p: Vec<u8>, prime_q: Vec<u8>, public_exponent: Vec<u8>) -> Self {
Self {
key_data: PrivateKeyData::Rsa {
prime_p,
prime_q,
public_exponent,
},
}
}
pub fn from_raw_bytes(ec: KeyType, bytes: impl AsRef<[u8]>) -> Result<Self, crate::Error> {
let bytes = bytes.as_ref();
Ok(Self {
key_data: match ec {
KeyType::EcP256 => PrivateKeyData::EcP256(pad(bytes, 32)?),
KeyType::EcP384 => PrivateKeyData::EcP384(pad(bytes, 48)?),
KeyType::EcP521 => PrivateKeyData::EcP521(pad(bytes, 66)?),
KeyType::Curve25519 => PrivateKeyData::Curve25519(pad(bytes, 32)?),
ec => return Err(crate::Error::Default(format!("Unsupported key type: {ec}"))),
},
})
}
pub fn key_type(&self) -> KeyType {
match &self.key_data {
PrivateKeyData::Curve25519(_) => KeyType::Curve25519,
PrivateKeyData::EcP256(_) => KeyType::EcP256,
PrivateKeyData::EcP384(_) => KeyType::EcP384,
PrivateKeyData::EcP521(_) => KeyType::EcP521,
PrivateKeyData::Rsa {
prime_p: _,
prime_q: _,
public_exponent: _,
} => KeyType::Rsa,
}
}
}
impl From<PrivateKeyImport> for KeyPrivateData {
fn from(value: PrivateKeyImport) -> Self {
match value.key_data {
PrivateKeyData::Rsa {
prime_p,
prime_q,
public_exponent,
} => KeyPrivateData {
prime_p: Some(Base64::encode_string(&prime_p)),
prime_q: Some(Base64::encode_string(&prime_q)),
public_exponent: Some(Base64::encode_string(&public_exponent)),
data: None,
},
PrivateKeyData::EcP256(data)
| PrivateKeyData::EcP384(data)
| PrivateKeyData::EcP521(data)
| PrivateKeyData::Curve25519(data) => KeyPrivateData {
prime_p: None,
prime_q: None,
public_exponent: None,
data: Some(Base64::encode_string(&data)),
},
}
}
}
pub fn key_type_matches_mechanisms(
key_type: KeyType,
mechanisms: &[KeyMechanism],
) -> Result<(), Error> {
let valid_mechanisms: &[KeyMechanism] = match key_type {
KeyType::Curve25519 => &KeyMechanism::curve25519_mechanisms(),
KeyType::EcP256 | KeyType::EcP384 | KeyType::EcP521 => {
&KeyMechanism::elliptic_curve_mechanisms()
}
KeyType::Generic => &KeyMechanism::generic_mechanisms(),
KeyType::Rsa => &KeyMechanism::rsa_mechanisms(),
};
let invalid_mechanisms = mechanisms
.iter()
.filter(|mechanism| !valid_mechanisms.contains(mechanism))
.cloned()
.collect::<Vec<KeyMechanism>>();
if invalid_mechanisms.is_empty() {
Ok(())
} else {
Err(Error::InvalidKeyMechanism {
key_type,
invalid_mechanisms,
})
}
}
pub fn key_type_and_mechanisms_match_signature_type(
key_type: KeyType,
mechanisms: &[KeyMechanism],
signature_type: SignatureType,
) -> Result<(), Error> {
match signature_type {
SignatureType::EcdsaP256 => {
if key_type != KeyType::EcP256 {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::EcdsaSignature) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::EcdsaSignature,
signature_type,
});
}
}
SignatureType::EcdsaP384 => {
if key_type != KeyType::EcP384 {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::EcdsaSignature) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::EcdsaSignature,
signature_type,
});
}
}
SignatureType::EcdsaP521 => {
if key_type != KeyType::EcP521 {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::EcdsaSignature) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::EcdsaSignature,
signature_type,
});
}
}
SignatureType::EdDsa => {
if key_type != KeyType::Curve25519 {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::EdDsaSignature) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::EdDsaSignature,
signature_type,
});
}
}
SignatureType::Pkcs1 => {
if key_type != KeyType::Rsa {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::RsaSignaturePkcs1) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::RsaSignaturePkcs1,
signature_type,
});
}
}
SignatureType::PssMd5 => {
if key_type != KeyType::Rsa {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssMd5) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::RsaSignaturePssMd5,
signature_type,
});
}
}
SignatureType::PssSha1 => {
if key_type != KeyType::Rsa {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha1) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::RsaSignaturePssSha1,
signature_type,
});
}
}
SignatureType::PssSha224 => {
if key_type != KeyType::Rsa {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha224) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::RsaSignaturePssSha224,
signature_type,
});
}
}
SignatureType::PssSha256 => {
if key_type != KeyType::Rsa {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha256) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::RsaSignaturePssSha256,
signature_type,
});
}
}
SignatureType::PssSha384 => {
if key_type != KeyType::Rsa {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha384) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::RsaSignaturePssSha384,
signature_type,
});
}
}
SignatureType::PssSha512 => {
if key_type != KeyType::Rsa {
return Err(Error::InvalidKeyTypeForSignatureType {
key_type,
signature_type,
});
} else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha512) {
return Err(Error::InvalidKeyMechanismsForSignatureType {
required_key_mechanism: KeyMechanism::RsaSignaturePssSha512,
signature_type,
});
}
}
}
Ok(())
}
pub fn key_type_matches_length(key_type: KeyType, length: Option<u32>) -> Result<(), Error> {
match key_type {
KeyType::Curve25519 | KeyType::EcP256 | KeyType::EcP384 | KeyType::EcP521 => {
if length.is_some() {
Err(Error::KeyLengthUnsupported { key_type })
} else {
Ok(())
}
}
KeyType::Generic => match length {
None => Err(Error::KeyLengthRequired { key_type }),
Some(length) => {
if ![128, 192, 256].contains(&length) {
Err(Error::InvalidKeyLengthAes { key_length: length })
} else {
Ok(())
}
}
},
KeyType::Rsa => match length {
None => Err(Error::KeyLengthRequired { key_type }),
Some(length) => {
if length < MIN_RSA_BIT_LENGTH {
Err(Error::InvalidKeyLengthRsa { key_length: length })
} else {
Ok(())
}
}
},
}
}
pub fn tls_key_type_matches_length(
tls_key_type: TlsKeyType,
length: Option<u32>,
) -> Result<(), Error> {
match tls_key_type {
TlsKeyType::Curve25519
| TlsKeyType::EcP224
| TlsKeyType::EcP256
| TlsKeyType::EcP384
| TlsKeyType::EcP521 => {
if length.is_some() {
Err(Error::TlsKeyLengthUnsupported { tls_key_type })
} else {
Ok(())
}
}
TlsKeyType::Rsa => match length {
None => Err(Error::TlsKeyLengthRequired { tls_key_type }),
Some(length) => {
if length < MIN_RSA_BIT_LENGTH {
Err(Error::InvalidTlsKeyLengthRsa { key_length: length })
} else {
Ok(())
}
}
},
}
}
#[cfg(test)]
mod tests {
use rsa::RsaPrivateKey;
use rsa::pkcs8::EncodePrivateKey;
use rstest::{fixture, rstest};
use testresult::TestResult;
use super::*;
#[fixture]
fn ed25519_private_key() -> TestResult<Vec<u8>> {
use ed25519_dalek::SigningKey;
use rand::rngs::OsRng;
let mut csprng = OsRng;
let signing_key: SigningKey = SigningKey::generate(&mut csprng);
Ok(signing_key.to_pkcs8_der()?.as_bytes().to_vec())
}
#[fixture]
fn p256_private_key() -> TestResult<Vec<u8>> {
use p256::elliptic_curve::rand_core::OsRng;
let private_key = p256::SecretKey::random(&mut OsRng);
Ok(private_key.to_pkcs8_der()?.as_bytes().to_vec())
}
#[fixture]
fn p384_private_key() -> TestResult<Vec<u8>> {
use p384::elliptic_curve::rand_core::OsRng;
let private_key = p384::SecretKey::random(&mut OsRng);
Ok(private_key.to_pkcs8_der()?.as_bytes().to_vec())
}
#[fixture]
fn p521_private_key() -> TestResult<Vec<u8>> {
use p521::elliptic_curve::rand_core::OsRng;
let private_key = p521::SecretKey::random(&mut OsRng);
Ok(private_key.to_pkcs8_der()?.as_bytes().to_vec())
}
#[fixture]
fn rsa_private_key() -> TestResult<Vec<u8>> {
let mut rng = rand::thread_rng();
let private_key = RsaPrivateKey::new(&mut rng, 2048.try_into()?)?;
Ok(private_key.to_pkcs8_der()?.as_bytes().to_vec())
}
#[rstest]
fn key_data(
ed25519_private_key: TestResult<Vec<u8>>,
p256_private_key: TestResult<Vec<u8>>,
p384_private_key: TestResult<Vec<u8>>,
p521_private_key: TestResult<Vec<u8>>,
rsa_private_key: TestResult<Vec<u8>>,
) -> TestResult {
let ed25519_private_key = ed25519_private_key?;
let p256_private_key = p256_private_key?;
let p384_private_key = p384_private_key?;
let p521_private_key = p521_private_key?;
let rsa_private_key = rsa_private_key?;
assert!(PrivateKeyImport::new(KeyType::Curve25519, &ed25519_private_key).is_ok());
assert!(PrivateKeyImport::new(KeyType::Curve25519, &p256_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Curve25519, &p384_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Curve25519, &p521_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Curve25519, &rsa_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP256, &ed25519_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP256, &p256_private_key).is_ok());
assert!(PrivateKeyImport::new(KeyType::EcP256, &p384_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP256, &p521_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP256, &rsa_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP384, &ed25519_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP384, &p256_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP384, &p384_private_key).is_ok());
assert!(PrivateKeyImport::new(KeyType::EcP384, &p521_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP384, &rsa_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP521, &ed25519_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP521, &p256_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP521, &p384_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::EcP521, &p521_private_key).is_ok());
assert!(PrivateKeyImport::new(KeyType::EcP521, &rsa_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Rsa, &ed25519_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Rsa, &p256_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Rsa, &p384_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Rsa, &p521_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Rsa, &rsa_private_key).is_ok());
assert!(PrivateKeyImport::new(KeyType::Generic, &ed25519_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Generic, &p256_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Generic, &p384_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Generic, &p521_private_key).is_err());
assert!(PrivateKeyImport::new(KeyType::Generic, &rsa_private_key).is_err());
Ok(())
}
#[rstest]
#[case(KeyType::Curve25519, &[KeyMechanism::EdDsaSignature], SignatureType::EdDsa, None)]
#[case(KeyType::EcP256, &[KeyMechanism::EcdsaSignature], SignatureType::EcdsaP256, None)]
#[case(KeyType::EcP384, &[KeyMechanism::EcdsaSignature], SignatureType::EcdsaP384, None)]
#[case(KeyType::EcP521, &[KeyMechanism::EcdsaSignature], SignatureType::EcdsaP521, None)]
#[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePkcs1], SignatureType::Pkcs1, None)]
#[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssMd5], SignatureType::PssMd5, None)]
#[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha1], SignatureType::PssSha1, None)]
#[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha224], SignatureType::PssSha224, None)]
#[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha256], SignatureType::PssSha256, None)]
#[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha384], SignatureType::PssSha384, None)]
#[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha512], SignatureType::PssSha512, None)]
#[case(
KeyType::Curve25519,
&[KeyMechanism::EdDsaSignature],
SignatureType::EcdsaP256,
Some(Box::new(Error::InvalidKeyTypeForSignatureType {
key_type: KeyType::Curve25519,
signature_type: SignatureType::EcdsaP256
})
))]
#[case(
KeyType::Curve25519,
&[KeyMechanism::EcdsaSignature],
SignatureType::EdDsa,
Some(Box::new(Error::InvalidKeyMechanismsForSignatureType {
signature_type: SignatureType::EdDsa,
required_key_mechanism: KeyMechanism::EdDsaSignature,
})
))]
#[case(
KeyType::EcP256,
&[KeyMechanism::EcdsaSignature],
SignatureType::EdDsa,
Some(Box::new(Error::InvalidKeyTypeForSignatureType {
key_type: KeyType::EcP256,
signature_type: SignatureType::EdDsa,
})
))]
#[case(
KeyType::EcP256,
&[KeyMechanism::EdDsaSignature],
SignatureType::EcdsaP256,
Some(Box::new(Error::InvalidKeyMechanismsForSignatureType {
signature_type: SignatureType::EcdsaP256,
required_key_mechanism: KeyMechanism::EcdsaSignature,
})
))]
#[case(
KeyType::EcP384,
&[KeyMechanism::EcdsaSignature],
SignatureType::EdDsa,
Some(Box::new(Error::InvalidKeyTypeForSignatureType {
key_type: KeyType::EcP384,
signature_type: SignatureType::EdDsa,
})
))]
#[case(
KeyType::EcP384,
&[KeyMechanism::EdDsaSignature],
SignatureType::EcdsaP384,
Some(Box::new(Error::InvalidKeyMechanismsForSignatureType {
signature_type: SignatureType::EcdsaP384,
required_key_mechanism: KeyMechanism::EcdsaSignature,
})
))]
#[case(
KeyType::EcP521,
&[KeyMechanism::EcdsaSignature],
SignatureType::EdDsa,
Some(Box::new(Error::InvalidKeyTypeForSignatureType {
key_type: KeyType::EcP521,
signature_type: SignatureType::EdDsa,
})
))]
#[case(
KeyType::EcP521,
&[KeyMechanism::EdDsaSignature],
SignatureType::EcdsaP521,
Some(Box::new(Error::InvalidKeyMechanismsForSignatureType {
signature_type: SignatureType::EcdsaP521,
required_key_mechanism: KeyMechanism::EcdsaSignature,
})
))]
#[case(
KeyType::Rsa,
&[KeyMechanism::RsaSignaturePkcs1],
SignatureType::EdDsa,
Some(Box::new(Error::InvalidKeyTypeForSignatureType {
key_type: KeyType::Rsa,
signature_type: SignatureType::EdDsa,
})
))]
#[case(
KeyType::Rsa,
&[KeyMechanism::RsaDecryptionOaepMd5],
SignatureType::PssMd5,
Some(Box::new(Error::InvalidKeyMechanismsForSignatureType {
signature_type: SignatureType::PssMd5,
required_key_mechanism: KeyMechanism::RsaSignaturePssMd5,
})
))]
fn test_key_type_and_mechanisms_match_signature_type(
#[case] key_type: KeyType,
#[case] key_mechanisms: &[KeyMechanism],
#[case] signature_type: SignatureType,
#[case] result: Option<Box<Error>>,
) -> TestResult {
if let Some(error) = result {
if let Err(fn_error) = key_type_and_mechanisms_match_signature_type(
key_type,
key_mechanisms,
signature_type,
) {
assert_eq!(fn_error.to_string(), error.to_string());
} else {
panic!("Did not return an Error!");
}
} else {
key_type_and_mechanisms_match_signature_type(key_type, key_mechanisms, signature_type)?;
}
Ok(())
}
}