fix: fully identify signature algorithm (#1015)

This commit is contained in:
sinu.eth
2025-10-13 00:57:34 -07:00
committed by GitHub
parent 0a68837d0a
commit 2e7e3db11d
4 changed files with 158 additions and 94 deletions

View File

@@ -116,84 +116,75 @@ pub enum KeyType {
SECP256R1 = 0x0017,
}
/// Signature scheme on the key exchange parameters.
/// Signature algorithm used on the key exchange parameters.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[allow(non_camel_case_types, missing_docs)]
pub enum SignatureScheme {
RSA_PKCS1_SHA1 = 0x0201,
ECDSA_SHA1_Legacy = 0x0203,
RSA_PKCS1_SHA256 = 0x0401,
ECDSA_NISTP256_SHA256 = 0x0403,
RSA_PKCS1_SHA384 = 0x0501,
ECDSA_NISTP384_SHA384 = 0x0503,
RSA_PKCS1_SHA512 = 0x0601,
ECDSA_NISTP521_SHA512 = 0x0603,
RSA_PSS_SHA256 = 0x0804,
RSA_PSS_SHA384 = 0x0805,
RSA_PSS_SHA512 = 0x0806,
ED25519 = 0x0807,
pub enum SignatureAlgorithm {
ECDSA_NISTP256_SHA256,
ECDSA_NISTP256_SHA384,
ECDSA_NISTP384_SHA256,
ECDSA_NISTP384_SHA384,
ED25519,
RSA_PKCS1_2048_8192_SHA256,
RSA_PKCS1_2048_8192_SHA384,
RSA_PKCS1_2048_8192_SHA512,
RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
}
impl fmt::Display for SignatureScheme {
impl fmt::Display for SignatureAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SignatureScheme::RSA_PKCS1_SHA1 => write!(f, "RSA_PKCS1_SHA1"),
SignatureScheme::ECDSA_SHA1_Legacy => write!(f, "ECDSA_SHA1_Legacy"),
SignatureScheme::RSA_PKCS1_SHA256 => write!(f, "RSA_PKCS1_SHA256"),
SignatureScheme::ECDSA_NISTP256_SHA256 => write!(f, "ECDSA_NISTP256_SHA256"),
SignatureScheme::RSA_PKCS1_SHA384 => write!(f, "RSA_PKCS1_SHA384"),
SignatureScheme::ECDSA_NISTP384_SHA384 => write!(f, "ECDSA_NISTP384_SHA384"),
SignatureScheme::RSA_PKCS1_SHA512 => write!(f, "RSA_PKCS1_SHA512"),
SignatureScheme::ECDSA_NISTP521_SHA512 => write!(f, "ECDSA_NISTP521_SHA512"),
SignatureScheme::RSA_PSS_SHA256 => write!(f, "RSA_PSS_SHA256"),
SignatureScheme::RSA_PSS_SHA384 => write!(f, "RSA_PSS_SHA384"),
SignatureScheme::RSA_PSS_SHA512 => write!(f, "RSA_PSS_SHA512"),
SignatureScheme::ED25519 => write!(f, "ED25519"),
SignatureAlgorithm::ECDSA_NISTP256_SHA256 => write!(f, "ECDSA_NISTP256_SHA256"),
SignatureAlgorithm::ECDSA_NISTP256_SHA384 => write!(f, "ECDSA_NISTP256_SHA384"),
SignatureAlgorithm::ECDSA_NISTP384_SHA256 => write!(f, "ECDSA_NISTP384_SHA256"),
SignatureAlgorithm::ECDSA_NISTP384_SHA384 => write!(f, "ECDSA_NISTP384_SHA384"),
SignatureAlgorithm::ED25519 => write!(f, "ED25519"),
SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256 => {
write!(f, "RSA_PKCS1_2048_8192_SHA256")
}
SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA384 => {
write!(f, "RSA_PKCS1_2048_8192_SHA384")
}
SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA512 => {
write!(f, "RSA_PKCS1_2048_8192_SHA512")
}
SignatureAlgorithm::RSA_PSS_2048_8192_SHA256_LEGACY_KEY => {
write!(f, "RSA_PSS_2048_8192_SHA256_LEGACY_KEY")
}
SignatureAlgorithm::RSA_PSS_2048_8192_SHA384_LEGACY_KEY => {
write!(f, "RSA_PSS_2048_8192_SHA384_LEGACY_KEY")
}
SignatureAlgorithm::RSA_PSS_2048_8192_SHA512_LEGACY_KEY => {
write!(f, "RSA_PSS_2048_8192_SHA512_LEGACY_KEY")
}
}
}
}
impl TryFrom<tls_core::msgs::enums::SignatureScheme> for SignatureScheme {
type Error = &'static str;
fn try_from(value: tls_core::msgs::enums::SignatureScheme) -> Result<Self, Self::Error> {
use tls_core::msgs::enums::SignatureScheme as Core;
use SignatureScheme::*;
Ok(match value {
Core::RSA_PKCS1_SHA1 => RSA_PKCS1_SHA1,
Core::ECDSA_SHA1_Legacy => ECDSA_SHA1_Legacy,
Core::RSA_PKCS1_SHA256 => RSA_PKCS1_SHA256,
Core::ECDSA_NISTP256_SHA256 => ECDSA_NISTP256_SHA256,
Core::RSA_PKCS1_SHA384 => RSA_PKCS1_SHA384,
Core::ECDSA_NISTP384_SHA384 => ECDSA_NISTP384_SHA384,
Core::RSA_PKCS1_SHA512 => RSA_PKCS1_SHA512,
Core::ECDSA_NISTP521_SHA512 => ECDSA_NISTP521_SHA512,
Core::RSA_PSS_SHA256 => RSA_PSS_SHA256,
Core::RSA_PSS_SHA384 => RSA_PSS_SHA384,
Core::RSA_PSS_SHA512 => RSA_PSS_SHA512,
Core::ED25519 => ED25519,
_ => return Err("unsupported signature scheme"),
})
}
}
impl From<SignatureScheme> for tls_core::msgs::enums::SignatureScheme {
fn from(value: SignatureScheme) -> Self {
use tls_core::msgs::enums::SignatureScheme::*;
impl From<tls_core::verify::SignatureAlgorithm> for SignatureAlgorithm {
fn from(value: tls_core::verify::SignatureAlgorithm) -> Self {
use tls_core::verify::SignatureAlgorithm as Core;
match value {
SignatureScheme::RSA_PKCS1_SHA1 => RSA_PKCS1_SHA1,
SignatureScheme::ECDSA_SHA1_Legacy => ECDSA_SHA1_Legacy,
SignatureScheme::RSA_PKCS1_SHA256 => RSA_PKCS1_SHA256,
SignatureScheme::ECDSA_NISTP256_SHA256 => ECDSA_NISTP256_SHA256,
SignatureScheme::RSA_PKCS1_SHA384 => RSA_PKCS1_SHA384,
SignatureScheme::ECDSA_NISTP384_SHA384 => ECDSA_NISTP384_SHA384,
SignatureScheme::RSA_PKCS1_SHA512 => RSA_PKCS1_SHA512,
SignatureScheme::ECDSA_NISTP521_SHA512 => ECDSA_NISTP521_SHA512,
SignatureScheme::RSA_PSS_SHA256 => RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384 => RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512 => RSA_PSS_SHA512,
SignatureScheme::ED25519 => ED25519,
Core::ECDSA_NISTP256_SHA256 => SignatureAlgorithm::ECDSA_NISTP256_SHA256,
Core::ECDSA_NISTP256_SHA384 => SignatureAlgorithm::ECDSA_NISTP256_SHA384,
Core::ECDSA_NISTP384_SHA256 => SignatureAlgorithm::ECDSA_NISTP384_SHA256,
Core::ECDSA_NISTP384_SHA384 => SignatureAlgorithm::ECDSA_NISTP384_SHA384,
Core::ED25519 => SignatureAlgorithm::ED25519,
Core::RSA_PKCS1_2048_8192_SHA256 => SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256,
Core::RSA_PKCS1_2048_8192_SHA384 => SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA384,
Core::RSA_PKCS1_2048_8192_SHA512 => SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA512,
Core::RSA_PSS_2048_8192_SHA256_LEGACY_KEY => {
SignatureAlgorithm::RSA_PSS_2048_8192_SHA256_LEGACY_KEY
}
Core::RSA_PSS_2048_8192_SHA384_LEGACY_KEY => {
SignatureAlgorithm::RSA_PSS_2048_8192_SHA384_LEGACY_KEY
}
Core::RSA_PSS_2048_8192_SHA512_LEGACY_KEY => {
SignatureAlgorithm::RSA_PSS_2048_8192_SHA512_LEGACY_KEY
}
}
}
}
@@ -201,8 +192,8 @@ impl From<SignatureScheme> for tls_core::msgs::enums::SignatureScheme {
/// Server's signature of the key exchange parameters.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerSignature {
/// Signature scheme.
pub scheme: SignatureScheme,
/// Signature algorithm.
pub alg: SignatureAlgorithm,
/// Signature data.
pub sig: Vec<u8>,
}
@@ -359,20 +350,23 @@ impl HandshakeData {
message.extend_from_slice(&server_ephemeral_key.kx_params());
use webpki::ring as alg;
let sig_alg = match self.sig.scheme {
SignatureScheme::RSA_PKCS1_SHA256 => alg::RSA_PKCS1_2048_8192_SHA256,
SignatureScheme::RSA_PKCS1_SHA384 => alg::RSA_PKCS1_2048_8192_SHA384,
SignatureScheme::RSA_PKCS1_SHA512 => alg::RSA_PKCS1_2048_8192_SHA512,
SignatureScheme::RSA_PSS_SHA256 => alg::RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
SignatureScheme::RSA_PSS_SHA384 => alg::RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
SignatureScheme::RSA_PSS_SHA512 => alg::RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
SignatureScheme::ECDSA_NISTP256_SHA256 => alg::ECDSA_P256_SHA256,
SignatureScheme::ECDSA_NISTP384_SHA384 => alg::ECDSA_P384_SHA384,
SignatureScheme::ED25519 => alg::ED25519,
scheme => {
return Err(HandshakeVerificationError::UnsupportedSignatureScheme(
scheme,
))
let sig_alg = match self.sig.alg {
SignatureAlgorithm::ECDSA_NISTP256_SHA256 => alg::ECDSA_P256_SHA256,
SignatureAlgorithm::ECDSA_NISTP256_SHA384 => alg::ECDSA_P256_SHA384,
SignatureAlgorithm::ECDSA_NISTP384_SHA256 => alg::ECDSA_P384_SHA256,
SignatureAlgorithm::ECDSA_NISTP384_SHA384 => alg::ECDSA_P384_SHA384,
SignatureAlgorithm::ED25519 => alg::ED25519,
SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256 => alg::RSA_PKCS1_2048_8192_SHA256,
SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA384 => alg::RSA_PKCS1_2048_8192_SHA384,
SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA512 => alg::RSA_PKCS1_2048_8192_SHA512,
SignatureAlgorithm::RSA_PSS_2048_8192_SHA256_LEGACY_KEY => {
alg::RSA_PSS_2048_8192_SHA256_LEGACY_KEY
}
SignatureAlgorithm::RSA_PSS_2048_8192_SHA384_LEGACY_KEY => {
alg::RSA_PSS_2048_8192_SHA384_LEGACY_KEY
}
SignatureAlgorithm::RSA_PSS_2048_8192_SHA512_LEGACY_KEY => {
alg::RSA_PSS_2048_8192_SHA512_LEGACY_KEY
}
};
@@ -402,8 +396,6 @@ pub enum HandshakeVerificationError {
InvalidServerEphemeralKey,
#[error("server certificate verification failed: {0}")]
ServerCert(ServerCertVerifierError),
#[error("unsupported signature scheme: {0}")]
UnsupportedSignatureScheme(SignatureScheme),
}
#[cfg(test)]

View File

@@ -10,7 +10,8 @@ use hex::FromHex;
use crate::{
connection::{
CertBinding, CertBindingV1_2, ConnectionInfo, DnsName, HandshakeData, KeyType,
ServerEphemKey, ServerName, ServerSignature, SignatureScheme, TlsVersion, TranscriptLength,
ServerEphemKey, ServerName, ServerSignature, SignatureAlgorithm, TlsVersion,
TranscriptLength,
},
transcript::{
encoding::{EncoderSecret, EncodingProvider},
@@ -47,7 +48,7 @@ impl ConnectionFixture {
CertificateDer(include_bytes!("fixtures/data/tlsnotary.org/ca.der").to_vec()),
],
sig: ServerSignature {
scheme: SignatureScheme::RSA_PKCS1_SHA256,
alg: SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256,
sig: Vec::<u8>::from_hex(include_bytes!(
"fixtures/data/tlsnotary.org/signature"
))
@@ -92,7 +93,7 @@ impl ConnectionFixture {
CertificateDer(include_bytes!("fixtures/data/appliedzkp.org/ca.der").to_vec()),
],
sig: ServerSignature {
scheme: SignatureScheme::ECDSA_NISTP256_SHA256,
alg: SignatureAlgorithm::ECDSA_NISTP256_SHA256,
sig: Vec::<u8>::from_hex(include_bytes!(
"fixtures/data/appliedzkp.org/signature"
))

View File

@@ -41,6 +41,7 @@ use tls_core::{
message::{OpaqueMessage, PlainMessage},
},
suites::SupportedCipherSuite,
verify::verify_sig_determine_alg,
};
use tlsn_core::{
connection::{CertBinding, CertBindingV1_2, ServerSignature, TlsVersion, VerifyData},
@@ -327,12 +328,20 @@ impl MpcTlsLeader {
.map(|cert| CertificateDer(cert.0.clone()))
.collect();
let mut sig_msg = Vec::new();
sig_msg.extend_from_slice(&client_random.0);
sig_msg.extend_from_slice(&server_random.0);
sig_msg.extend_from_slice(server_kx_details.kx_params());
let server_signature_alg = verify_sig_determine_alg(
&server_cert_details.cert_chain()[0],
&sig_msg,
server_kx_details.kx_sig(),
)
.expect("only supported signature should have been accepted");
let server_signature = ServerSignature {
scheme: server_kx_details
.kx_sig()
.scheme
.try_into()
.expect("only supported signature scheme should have been accepted"),
alg: server_signature_alg.into(),
sig: server_kx_details.kx_sig().sig.0.clone(),
};

View File

@@ -465,19 +465,81 @@ fn convert_scheme(scheme: SignatureScheme) -> Result<SignatureAlgorithms, Error>
}
}
/// Signature algorithm.
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(non_camel_case_types)]
pub enum SignatureAlgorithm {
ECDSA_NISTP256_SHA256,
ECDSA_NISTP256_SHA384,
ECDSA_NISTP384_SHA256,
ECDSA_NISTP384_SHA384,
ED25519,
RSA_PKCS1_2048_8192_SHA256,
RSA_PKCS1_2048_8192_SHA384,
RSA_PKCS1_2048_8192_SHA512,
RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
}
impl SignatureAlgorithm {
pub fn from_alg(alg: &dyn pki_types::SignatureVerificationAlgorithm) -> Self {
let id = alg.signature_alg_id();
if id == webpki::ring::ECDSA_P256_SHA256.signature_alg_id() {
SignatureAlgorithm::ECDSA_NISTP256_SHA256
} else if id == webpki::ring::ECDSA_P256_SHA384.signature_alg_id() {
SignatureAlgorithm::ECDSA_NISTP256_SHA384
} else if id == webpki::ring::ECDSA_P384_SHA256.signature_alg_id() {
SignatureAlgorithm::ECDSA_NISTP384_SHA256
} else if id == webpki::ring::ECDSA_P384_SHA384.signature_alg_id() {
SignatureAlgorithm::ECDSA_NISTP384_SHA384
} else if id == webpki::ring::ED25519.signature_alg_id() {
SignatureAlgorithm::ED25519
} else if id == webpki::ring::RSA_PKCS1_2048_8192_SHA256.signature_alg_id() {
SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA256
} else if id == webpki::ring::RSA_PKCS1_2048_8192_SHA384.signature_alg_id() {
SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA384
} else if id == webpki::ring::RSA_PKCS1_2048_8192_SHA512.signature_alg_id() {
SignatureAlgorithm::RSA_PKCS1_2048_8192_SHA512
} else if id == webpki::ring::RSA_PSS_2048_8192_SHA256_LEGACY_KEY.signature_alg_id() {
SignatureAlgorithm::RSA_PSS_2048_8192_SHA256_LEGACY_KEY
} else if id == webpki::ring::RSA_PSS_2048_8192_SHA384_LEGACY_KEY.signature_alg_id() {
SignatureAlgorithm::RSA_PSS_2048_8192_SHA384_LEGACY_KEY
} else if id == webpki::ring::RSA_PSS_2048_8192_SHA512_LEGACY_KEY.signature_alg_id() {
SignatureAlgorithm::RSA_PSS_2048_8192_SHA512_LEGACY_KEY
} else {
unreachable!()
}
}
}
/// Verify the signature and return the algorithm which passed verification.
pub fn verify_sig_determine_alg(
cert: &Certificate,
message: &[u8],
dss: &DigitallySignedStruct,
) -> Result<SignatureAlgorithm, Error> {
let cert = pki_types::CertificateDer::from(cert.0.as_slice());
let cert = webpki::EndEntityCert::try_from(&cert).map_err(pki_error)?;
verify_sig_using_any_alg(&cert, convert_scheme(dss.scheme)?, message, &dss.sig.0)
.map_err(pki_error)
}
fn verify_sig_using_any_alg(
cert: &webpki::EndEntityCert,
algs: SignatureAlgorithms,
message: &[u8],
sig: &[u8],
) -> Result<(), webpki::Error> {
) -> Result<SignatureAlgorithm, webpki::Error> {
// TLS doesn't itself give us enough info to map to a single
// webpki::SignatureAlgorithm. Therefore, convert_algs maps to several and
// we try them all.
for alg in algs {
match cert.verify_signature(*alg, message, sig) {
Ok(_) => return Ok(SignatureAlgorithm::from_alg(*alg)),
Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKeyContext(_)) => continue,
res => return res,
Err(e) => return Err(e),
}
}