From bce1a05d1a59a25ba2ca367b659de87dfd40cb6d Mon Sep 17 00:00:00 2001 From: Jiale Zhang Date: Mon, 18 May 2026 11:10:33 +0800 Subject: [PATCH 1/3] Release v1.8.4 RPM Signed-off-by: Jiale Zhang --- rpm/trustee.spec | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) 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 From 174aa9b2dce9a8028394e990fa260db94980c7ca Mon Sep 17 00:00:00 2001 From: Jiale Zhang Date: Fri, 22 May 2026 15:28:32 +0800 Subject: [PATCH 2/3] gateway: use 191-char prefix index on aa_instance_heartbeats.instance_id The unique index on `instance_id` (VARCHAR(255), utf8mb4) overflowed MySQL InnoDB's 767-byte key length limit (255 * 4 = 1020 bytes), causing `CREATE UNIQUE INDEX ... ON aa_instance_heartbeats(instance_id)` to fail with "Specified key was too long" during gateway startup and aborting the migration. Switch the MySQL DDL to a 191-char prefix index, which keeps the index key under 767 bytes (191 * 4 = 764) while remaining longer than any realistic instance_id value. SQLite path is unaffected. Signed-off-by: Jiale Zhang --- trustee-gateway/internal/persistence/storage/database.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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) } From 5b22ad4de7328d30ab2ac69db46c74418d2b9572 Mon Sep 17 00:00:00 2001 From: Jiale Zhang Date: Mon, 25 May 2026 15:35:15 +0800 Subject: [PATCH 3/3] verifier: fix Hygon TPM SM2 quote signature verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous verify path built an SM2 PKey and ran the signature through OpenSSL's EVP_DigestVerify (effectively `Verifier::new(SM3, pkey)`). That path either applies the GB/T 32918 ZA pre-processing (SM3(ENTL || ID || a || b || xG || yG || xA || yA) prepended to the message) or, on a plain EC PKey, silently dispatches to ECDSA verify. Neither matches what TPM2 produces: per the TPM 2.0 spec the SM2 quote signs SM3(attestBody) directly, with no ZA mixing and no DER wrapping. End-to-end attestation against a real Hygon TPM therefore failed with "Verify Hygon TPM quote signature failed" even when the AK, evidence body, and signature were all correct. Drop the OpenSSL high-level verifier and implement the SM2 verify equation from GB/T 32918.2-2016 §7.1 directly using BigNum/EcPoint: e = SM3(attestBody) t = (r + s) mod n with t != 0 P = s * G + t * Q ok iff (e + P.x) mod n == r Range-check r and s against [1, n-1] up front and reject t == 0 to match the spec. Reuse the existing extracted (r, s) from the marshalled TPM signature; create_sm2_pkey is left in place because it is still used to compare AK pubkeys against the keylime registrar. Signed-off-by: Jiale Zhang --- deps/verifier/src/hygon_tpm/mod.rs | 61 ++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 15 deletions(-) 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"); }