diff --git a/deps/verifier/src/hygon_tpm/mod.rs b/deps/verifier/src/hygon_tpm/mod.rs index 6e9cecd..a0c93cb 100644 --- a/deps/verifier/src/hygon_tpm/mod.rs +++ b/deps/verifier/src/hygon_tpm/mod.rs @@ -10,11 +10,8 @@ use eventlog_rs::{BiosEventlog, Eventlog}; use log::{debug, info}; use openssl::bn::{BigNum, BigNumContext}; use openssl::ec::{EcGroup, EcKey, EcPoint}; -use openssl::ecdsa::EcdsaSig; -use openssl::hash::MessageDigest; use openssl::nid::Nid; use openssl::pkey::PKey; -use openssl::sign::Verifier as OpenSslVerifier; use openssl::x509::X509; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -94,7 +91,7 @@ fn create_sm2_pkey(ak_pubkey: &HygonSm2PublicKey) -> Result Result> { +fn extract_sm2_signature_components(sig_b64: &str) -> Result<(BigNum, BigNum)> { let sig_bytes = base64::engine::general_purpose::STANDARD.decode(sig_b64)?; let signature = Signature::unmarshall(&sig_bytes)?; let Signature::Sm2(sm2_sig) = signature else { @@ -103,8 +100,7 @@ fn signature_to_der(sig_b64: &str) -> Result> { let r = BigNum::from_slice(sm2_sig.signature_r().value())?; let s = BigNum::from_slice(sm2_sig.signature_s().value())?; - let sig = EcdsaSig::from_private_components(r, s)?; - Ok(sig.to_der()?) + Ok((r, s)) } async fn verify_registrar_binding(evidence: &HygonTpmEvidence, uuid: &str) -> Result<()> { @@ -420,17 +416,52 @@ fn parse_measurements_from_event( impl HygonTpmQuote { fn verify_signature(&self, ak_pubkey: &HygonSm2PublicKey) -> Result<()> { - let pkey = create_sm2_pkey(ak_pubkey)?; - let signature_der = signature_to_der(&self.attest_sig)?; + let (sig_r, sig_s) = extract_sm2_signature_components(&self.attest_sig)?; let attest_body = base64::engine::general_purpose::STANDARD.decode(&self.attest_body)?; - // Reuse OpenSSL's current SM2-capable verification path that works with - // the crate version in this workspace. If real hardware shows a different - // distinguishing-ID requirement, we can narrow it on-device without - // changing the evidence schema or policy surface. - let mut verifier = OpenSslVerifier::new(MessageDigest::sm3(), &pkey)?; - verifier.update(&attest_body)?; - if !verifier.verify(&signature_der)? { + // TPM2 SM2 quotes sign SM3(attest_body) directly per the TPM2 spec — + // there is no GB/T 32918 ZA pre-processing. OpenSSL's EVP_DigestVerify + // path either applies ZA (digest mismatch) or, on a plain EC PKey, + // dispatches to ECDSA verify (wrong algorithm). Run the SM2 verify + // equation (GB/T 32918.2 §7.1) directly against e = SM3(attest_body). + let mut hasher = Sm3::new(); + hasher.update(&attest_body); + let e_bytes = hasher.finalize(); + let e = BigNum::from_slice(&e_bytes)?; + + let nid = Nid::from_raw(openssl_sys::NID_sm2); + let group = EcGroup::from_curve_name(nid)?; + let mut ctx = BigNumContext::new()?; + let mut order = BigNum::new()?; + group.order(&mut order, &mut ctx)?; + + let one = BigNum::from_u32(1)?; + if sig_r < one || sig_r >= order || sig_s < one || sig_s >= order { + bail!("Verify Hygon TPM quote signature failed"); + } + + let mut t = BigNum::new()?; + t.mod_add(&sig_r, &sig_s, &order, &mut ctx)?; + if t.num_bits() == 0 { + bail!("Verify Hygon TPM quote signature failed"); + } + + let bx = BigNum::from_hex_str(&ak_pubkey.x)?; + let by = BigNum::from_hex_str(&ak_pubkey.y)?; + let mut q = EcPoint::new(&group)?; + q.set_affine_coordinates_gfp(&group, &bx, &by, &mut ctx)?; + + let mut p = EcPoint::new(&group)?; + p.mul_full(&group, &sig_s, &q, &t, &mut ctx)?; + + let mut x1 = BigNum::new()?; + let mut y1 = BigNum::new()?; + p.affine_coordinates_gfp(&group, &mut x1, &mut y1, &mut ctx)?; + + let mut r_check = BigNum::new()?; + r_check.mod_add(&e, &x1, &order, &mut ctx)?; + + if r_check != sig_r { bail!("Verify Hygon TPM quote signature failed"); } diff --git a/rpm/trustee.spec b/rpm/trustee.spec index b66e903..f2a644c 100644 --- a/rpm/trustee.spec +++ b/rpm/trustee.spec @@ -4,7 +4,7 @@ %global __brp_mangle_shebangs %{nil} Name: trustee -Version: 1.8.3 +Version: 1.8.4 Release: %{alinux_release}%{?dist} Summary: Daemon services for attestation and secret distribution Group: Applications/System @@ -148,6 +148,18 @@ fi /var/lib/attestation/token/ear/policies/opa/default.rego %changelog +* Mon May 18 2026 Jiale Zhang -1.8.4-1 +- KBS: support private cloud Aliyun KMS endpoints +- AS: add signer transparency support +- Verifier: add Hygon TPM verifier with sm2/sm3 keylime support +- Verifier/TDX: expose TCB verification result and supplemental data in claims +- Verifier: make eventlog a required dependency +- RVPS: export types for external use, add release manifest Rekor support +- Gateway: prefer instance info IP in audit records +- Gateway: fix AA instance heartbeat deduplication +- Rekor v2: unify provenance metadata schema and add OCI-based RVPS verification path +- Release: keep SLSA provenance in release workflow + * Thu Mar 26 2026 Jiale Zhang -1.8.3-1 - fix(slsa): generate and upload DSSE envelope for Rekor intoto - chore(slsa): upgrade cosign/rekor-cli and align generator with v3 APIs diff --git a/trustee-gateway/internal/persistence/storage/database.go b/trustee-gateway/internal/persistence/storage/database.go index 64e59b5..d48d1c1 100644 --- a/trustee-gateway/internal/persistence/storage/database.go +++ b/trustee-gateway/internal/persistence/storage/database.go @@ -238,7 +238,9 @@ func (d *Database) migrateAAInstanceHeartbeatIndexMySQL() error { logrus.Info("Cleaned up duplicate instance_id records in aa_instance_heartbeats") } - if err := d.DB.Exec("CREATE UNIQUE INDEX idx_aa_heartbeat_instance_id ON aa_instance_heartbeats(instance_id)").Error; err != nil { + // Use a 191-char prefix to stay under MySQL InnoDB's 767-byte index key + // limit when instance_id is VARCHAR(255) utf8mb4 (4 bytes/char → 1020 bytes). + if err := d.DB.Exec("CREATE UNIQUE INDEX idx_aa_heartbeat_instance_id ON aa_instance_heartbeats(instance_id(191))").Error; err != nil { return fmt.Errorf("failed to create unique index on instance_id: %w", err) }