use std::sync::Arc;
use tightbeam::{
crypto::{
hash::Sha3_256,
policy::{Secp256k1Policy, VerificationPolicy},
sign::{ecdsa::Secp256k1Signature, sign_canonical},
},
der::Encode,
exactly, job,
oids::{AES_256_GCM, SIGNER_ECDSA_WITH_SHA3_256},
tb_assert_spec, tb_process_spec, tb_scenario,
testing::{ScenarioConf, SetupEnv},
trace::TraceCollector,
TightBeamError,
};
use crate::common::security::{deterministic_signing_key, expectation_failure, test_certificate};
tb_assert_spec! {
pub AlgorithmConfusionSpec,
V(1,0,0): {
mode: Accept,
gate: Ok,
assertions: [
(foreign_oid_rejected, exactly!(1u32))
]
}
}
tb_process_spec! {
pub AlgorithmConfusionProcess,
events {
observable { "foreign_oid_rejected" }
hidden { }
}
states {
Idle => { "foreign_oid_rejected" => Done },
Done => { }
}
terminal { Done }
annotations { description: "Algorithm confusion: policy must honour the advertised signature OID" }
}
tb_scenario! {
name: algorithm_confusion,
config: ScenarioConf::builder()
.with_spec(AlgorithmConfusionSpec::latest())
.with_csp(AlgorithmConfusionProcess)
.build(),
environment Bare {
exec: |SetupEnv { trace, .. }| async move {
AlgorithmConfusionScenario::run((trace.into(),)).await
}
}
}
job! {
name: AlgorithmConfusionScenario,
async fn run((trace,): (Arc<TraceCollector>,)) -> Result<(), TightBeamError> {
let signing_key = deterministic_signing_key();
let cert = test_certificate(&signing_key);
let spki_der = cert.tbs_certificate.subject_public_key_info.to_der()?;
let message: &[u8] = b"tbs-certificate-bytes";
let signature: Secp256k1Signature = sign_canonical::<Sha3_256, _>(&signing_key, message)
.map_err(|_| expectation_failure("signing failed"))?;
let signature_bytes = signature.to_bytes();
let policy = Secp256k1Policy;
policy
.verify_signature(&SIGNER_ECDSA_WITH_SHA3_256, &spki_der, message, signature_bytes.as_ref())
.map_err(|_| expectation_failure("baseline verification under the genuine OID failed"))?;
match policy.verify_signature(&AES_256_GCM, &spki_der, message, signature_bytes.as_ref()) {
Err(_) => {
trace.event(AlgorithmConfusionSpec::foreign_oid_rejected)?;
}
Ok(_) => return Err(expectation_failure("signature accepted under an unsupported algorithm OID")),
}
Ok(())
}
}