mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-10-28 08:20:49 +08:00
refactor: 将 DTLS 本地依赖迁移到 libs 目录
This commit is contained in:
215
libs/dtls/src/signature_hash_algorithm/mod.rs
Normal file
215
libs/dtls/src/signature_hash_algorithm/mod.rs
Normal file
@@ -0,0 +1,215 @@
|
||||
#[cfg(test)]
|
||||
mod signature_hash_algorithm_test;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use crate::crypto::*;
|
||||
use crate::error::*;
|
||||
|
||||
// HashAlgorithm is used to indicate the hash algorithm used
|
||||
// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-18
|
||||
// Supported hash hash algorithms
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum HashAlgorithm {
|
||||
Md2 = 0, // Blacklisted
|
||||
Md5 = 1, // Blacklisted
|
||||
Sha1 = 2, // Blacklisted
|
||||
Sha224 = 3,
|
||||
Sha256 = 4,
|
||||
Sha384 = 5,
|
||||
Sha512 = 6,
|
||||
Ed25519 = 8,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
impl From<u8> for HashAlgorithm {
|
||||
fn from(val: u8) -> Self {
|
||||
match val {
|
||||
0 => HashAlgorithm::Md2,
|
||||
1 => HashAlgorithm::Md5,
|
||||
2 => HashAlgorithm::Sha1,
|
||||
3 => HashAlgorithm::Sha224,
|
||||
4 => HashAlgorithm::Sha256,
|
||||
5 => HashAlgorithm::Sha384,
|
||||
6 => HashAlgorithm::Sha512,
|
||||
8 => HashAlgorithm::Ed25519,
|
||||
_ => HashAlgorithm::Unsupported,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HashAlgorithm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
HashAlgorithm::Md2 => write!(f, "md2"),
|
||||
HashAlgorithm::Md5 => write!(f, "md5"), // [RFC3279]
|
||||
HashAlgorithm::Sha1 => write!(f, "sha-1"), // [RFC3279]
|
||||
HashAlgorithm::Sha224 => write!(f, "sha-224"), // [RFC4055]
|
||||
HashAlgorithm::Sha256 => write!(f, "sha-256"), // [RFC4055]
|
||||
HashAlgorithm::Sha384 => write!(f, "sha-384"), // [RFC4055]
|
||||
HashAlgorithm::Sha512 => write!(f, "sha-512"), // [RFC4055]
|
||||
HashAlgorithm::Ed25519 => write!(f, "null"), // [RFC4055]
|
||||
_ => write!(f, "unknown or unsupported hash algorithm"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HashAlgorithm {
|
||||
pub(crate) fn insecure(&self) -> bool {
|
||||
matches!(
|
||||
*self,
|
||||
HashAlgorithm::Md2 | HashAlgorithm::Md5 | HashAlgorithm::Sha1
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn invalid(&self) -> bool {
|
||||
matches!(*self, HashAlgorithm::Md2)
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum SignatureAlgorithm {
|
||||
Rsa = 1,
|
||||
Ecdsa = 3,
|
||||
Ed25519 = 7,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
impl From<u8> for SignatureAlgorithm {
|
||||
fn from(val: u8) -> Self {
|
||||
match val {
|
||||
1 => SignatureAlgorithm::Rsa,
|
||||
3 => SignatureAlgorithm::Ecdsa,
|
||||
7 => SignatureAlgorithm::Ed25519,
|
||||
_ => SignatureAlgorithm::Unsupported,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SignatureHashAlgorithm {
|
||||
pub hash: HashAlgorithm,
|
||||
pub signature: SignatureAlgorithm,
|
||||
}
|
||||
|
||||
impl SignatureHashAlgorithm {
|
||||
// is_compatible checks that given private key is compatible with the signature scheme.
|
||||
pub(crate) fn is_compatible(&self, private_key: &CryptoPrivateKey) -> bool {
|
||||
match &private_key.kind {
|
||||
CryptoPrivateKeyKind::Ed25519(_) => self.signature == SignatureAlgorithm::Ed25519,
|
||||
CryptoPrivateKeyKind::Ecdsa256(_) => self.signature == SignatureAlgorithm::Ecdsa,
|
||||
CryptoPrivateKeyKind::Rsa256(_) => self.signature == SignatureAlgorithm::Rsa,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_signature_schemes() -> Vec<SignatureHashAlgorithm> {
|
||||
vec![
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha256,
|
||||
signature: SignatureAlgorithm::Ecdsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha384,
|
||||
signature: SignatureAlgorithm::Ecdsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha512,
|
||||
signature: SignatureAlgorithm::Ecdsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha256,
|
||||
signature: SignatureAlgorithm::Rsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha384,
|
||||
signature: SignatureAlgorithm::Rsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha512,
|
||||
signature: SignatureAlgorithm::Rsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Ed25519,
|
||||
signature: SignatureAlgorithm::Ed25519,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// select Signature Scheme returns most preferred and compatible scheme.
|
||||
pub(crate) fn select_signature_scheme(
|
||||
sigs: &[SignatureHashAlgorithm],
|
||||
private_key: &CryptoPrivateKey,
|
||||
) -> Result<SignatureHashAlgorithm> {
|
||||
for ss in sigs {
|
||||
if ss.is_compatible(private_key) {
|
||||
return Ok(*ss);
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::ErrNoAvailableSignatureSchemes)
|
||||
}
|
||||
|
||||
// SignatureScheme identifies a signature algorithm supported by TLS. See
|
||||
// RFC 8446, Section 4.2.3.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum SignatureScheme {
|
||||
// RSASSA-PKCS1-v1_5 algorithms.
|
||||
Pkcs1WithSha256 = 0x0401,
|
||||
Pkcs1WithSha384 = 0x0501,
|
||||
Pkcs1WithSha512 = 0x0601,
|
||||
|
||||
// RSASSA-PSS algorithms with public key OID rsaEncryption.
|
||||
PssWithSha256 = 0x0804,
|
||||
PssWithSha384 = 0x0805,
|
||||
PssWithSha512 = 0x0806,
|
||||
|
||||
// ECDSA algorithms. Only constrained to a specific curve in TLS 1.3.
|
||||
EcdsaWithP256AndSha256 = 0x0403,
|
||||
EcdsaWithP384AndSha384 = 0x0503,
|
||||
EcdsaWithP521AndSha512 = 0x0603,
|
||||
|
||||
// EdDSA algorithms.
|
||||
Ed25519 = 0x0807,
|
||||
|
||||
// Legacy signature and hash algorithms for TLS 1.2.
|
||||
Pkcs1WithSha1 = 0x0201,
|
||||
EcdsaWithSha1 = 0x0203,
|
||||
}
|
||||
|
||||
// parse_signature_schemes translates []tls.SignatureScheme to []signatureHashAlgorithm.
|
||||
// It returns default signature scheme list if no SignatureScheme is passed.
|
||||
pub(crate) fn parse_signature_schemes(
|
||||
sigs: &[u16],
|
||||
insecure_hashes: bool,
|
||||
) -> Result<Vec<SignatureHashAlgorithm>> {
|
||||
if sigs.is_empty() {
|
||||
return Ok(default_signature_schemes());
|
||||
}
|
||||
|
||||
let mut out = vec![];
|
||||
for ss in sigs {
|
||||
let sig: SignatureAlgorithm = ((*ss & 0xFF) as u8).into();
|
||||
if sig == SignatureAlgorithm::Unsupported {
|
||||
return Err(Error::ErrInvalidSignatureAlgorithm);
|
||||
}
|
||||
let h: HashAlgorithm = (((*ss >> 8) & 0xFF) as u8).into();
|
||||
if h == HashAlgorithm::Unsupported || h.invalid() {
|
||||
return Err(Error::ErrInvalidHashAlgorithm);
|
||||
}
|
||||
if h.insecure() && !insecure_hashes {
|
||||
continue;
|
||||
}
|
||||
out.push(SignatureHashAlgorithm {
|
||||
hash: h,
|
||||
signature: sig,
|
||||
})
|
||||
}
|
||||
|
||||
if out.is_empty() {
|
||||
Err(Error::ErrNoAvailableSignatureSchemes)
|
||||
} else {
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_signature_schemes() -> Result<()> {
|
||||
let tests = vec![
|
||||
(
|
||||
"Translate",
|
||||
vec![
|
||||
SignatureScheme::EcdsaWithP256AndSha256 as u16,
|
||||
SignatureScheme::EcdsaWithP384AndSha384 as u16,
|
||||
SignatureScheme::EcdsaWithP521AndSha512 as u16,
|
||||
SignatureScheme::Pkcs1WithSha256 as u16,
|
||||
SignatureScheme::Pkcs1WithSha384 as u16,
|
||||
SignatureScheme::Pkcs1WithSha512 as u16,
|
||||
],
|
||||
vec![
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha256,
|
||||
signature: SignatureAlgorithm::Ecdsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha384,
|
||||
signature: SignatureAlgorithm::Ecdsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha512,
|
||||
signature: SignatureAlgorithm::Ecdsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha256,
|
||||
signature: SignatureAlgorithm::Rsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha384,
|
||||
signature: SignatureAlgorithm::Rsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha512,
|
||||
signature: SignatureAlgorithm::Rsa,
|
||||
},
|
||||
],
|
||||
false,
|
||||
None,
|
||||
),
|
||||
(
|
||||
"InvalidSignatureAlgorithm",
|
||||
vec![
|
||||
SignatureScheme::EcdsaWithP256AndSha256 as u16, // Valid
|
||||
0x04FF, // Invalid: unknown signature with SHA-256
|
||||
],
|
||||
vec![],
|
||||
false,
|
||||
Some(Error::ErrInvalidSignatureAlgorithm),
|
||||
),
|
||||
(
|
||||
"InvalidHashAlgorithm",
|
||||
vec![
|
||||
SignatureScheme::EcdsaWithP256AndSha256 as u16, // Valid
|
||||
0x0003, // Invalid: ECDSA with MD2
|
||||
],
|
||||
vec![],
|
||||
false,
|
||||
Some(Error::ErrInvalidHashAlgorithm),
|
||||
),
|
||||
(
|
||||
"InsecureHashAlgorithmDenied",
|
||||
vec![
|
||||
SignatureScheme::EcdsaWithP256AndSha256 as u16, // Valid
|
||||
SignatureScheme::EcdsaWithSha1 as u16, // Insecure
|
||||
],
|
||||
vec![SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha256,
|
||||
signature: SignatureAlgorithm::Ecdsa,
|
||||
}],
|
||||
false,
|
||||
None,
|
||||
),
|
||||
(
|
||||
"InsecureHashAlgorithmAllowed",
|
||||
vec![
|
||||
SignatureScheme::EcdsaWithP256AndSha256 as u16, // Valid
|
||||
SignatureScheme::EcdsaWithSha1 as u16, // Insecure
|
||||
],
|
||||
vec![
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha256,
|
||||
signature: SignatureAlgorithm::Ecdsa,
|
||||
},
|
||||
SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Sha1,
|
||||
signature: SignatureAlgorithm::Ecdsa,
|
||||
},
|
||||
],
|
||||
true,
|
||||
None,
|
||||
),
|
||||
(
|
||||
"OnlyInsecureHashAlgorithm",
|
||||
vec![
|
||||
SignatureScheme::EcdsaWithSha1 as u16, // Insecure
|
||||
],
|
||||
vec![],
|
||||
false,
|
||||
Some(Error::ErrNoAvailableSignatureSchemes),
|
||||
),
|
||||
(
|
||||
"Translate",
|
||||
vec![SignatureScheme::Ed25519 as u16],
|
||||
vec![SignatureHashAlgorithm {
|
||||
hash: HashAlgorithm::Ed25519,
|
||||
signature: SignatureAlgorithm::Ed25519,
|
||||
}],
|
||||
false,
|
||||
None,
|
||||
),
|
||||
];
|
||||
|
||||
for (name, inputs, expected, insecure_hashes, want_err) in tests {
|
||||
let output = parse_signature_schemes(&inputs, insecure_hashes);
|
||||
if let Some(err) = want_err {
|
||||
if let Err(output_err) = output {
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
output_err.to_string(),
|
||||
"Expected error: {err:?}, got: {output_err:?}"
|
||||
);
|
||||
} else {
|
||||
panic!("expect err, but got non-err for {name}");
|
||||
}
|
||||
} else if let Ok(output_val) = output {
|
||||
assert_eq!(
|
||||
expected, output_val,
|
||||
"Expected signatureHashAlgorithm:\n{expected:?}\ngot:\n{output_val:?}",
|
||||
);
|
||||
} else {
|
||||
panic!("expect non-err, but got err for {name}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user