OpenNHP/opennhp · error

failed to verify signature

Error message

failed to verify signature

What it means

verifySm2SignatureWithId fails when an SM2 signature does not verify against the given public key, message, and signer ID. It builds the ZA/SM3 digest per the SM2 signing standard and calls VerifySignature; a mismatch means the signature bytes were not produced by the holder of the private key over this message+ID. In the CSV attestation flow this indicates a corrupted, truncated, or forged certificate/blob, or a bad signer-ID/public-key extraction.

Solutions

  1. Verify the attestation blob is intact and matches the Hygon CSV certificate layout expected by this code (check size and byte offsets for hrk/hsk_cek fields).
  2. Confirm the blob actually comes from a Hygon CSV-capable chip and the remote attestation report corresponds to the chipId being verified.
  3. Check the hrkIdLen little-endian field at offset 0xd4-0xd6 is sane before slicing the ID; a corrupt length misaligns the signer ID and breaks verification.
  4. Confirm byte reversal (ReverseBytes) conventions match the producer of the signature (little- vs big-endian r/s/coordinates).
  5. If you control the signing side, re-sign with the same SM2 signer ID and message framing used here (buildIDMsg with ECKEY).

Example fix

// before: slicing ID with unvalidated length
hrkIdLen := int(binary.LittleEndian.Uint16(a.hrk[0xd4:0xd6]))
if err := a.verifySm2SignatureWithId(
	a.hrk[0x44:0x64], a.hrk[0x8c:0xac],
	a.hrk[0x240:0x260], a.hrk[0x288:0x2a8],
	a.hrk[0xd6:0xd6+hrkIdLen], a.hrk[:0x240],
); err != nil {
	return err
}
// after: sanity-check length/bounds first
hrkIdLen := int(binary.LittleEndian.Uint16(a.hrk[0xd4:0xd6]))
if hrkIdLen <= 0 || 0xd6+hrkIdLen > len(a.hrk) {
	return fmt.Errorf("invalid HRK signer ID length: %d", hrkIdLen)
}
Defensive patterns

Strategy: validation

Validate before calling

// verify blob shape and signer-ID length before calling Verify/attestation APIs
if len(blob) < 0x2a8 {
	return fmt.Errorf("attestation blob too small: %d", len(blob))
}
idLen := int(binary.LittleEndian.Uint16(blob[0xd4:0xd6]))
if idLen <= 0 || 0xd6+idLen > len(blob) {
	return fmt.Errorf("invalid signer ID length %d in blob", idLen)
}

Type guard

func isValidCSVBlob(blob []byte) bool {
	return len(blob) >= 0x2a8 &&
		binary.LittleEndian.Uint16(blob[0xd4:0xd6]) > 0 &&
		0xd6+int(binary.LittleEndian.Uint16(blob[0xd4:0xd6])) <= len(blob)
}

Try / catch

err := att.Verify(chipId)
if err != nil {
	if strings.Contains(err.Error(), "failed to verify signature") {
		// treat as untrusted attestation: reject the workload, log blob fingerprint
		return ErrAttestationUntrusted
	}
	return err
}

Prevention

When it happens

Trigger: Called from verifyCertChain (self-signed HRK verification, HSK/CEK chain verification) and from Attestation.Verify. Triggered when the SM2 signature extracted from the certificate blob (e.g. hrk[0x240:0x260], hrk[0x288:0x2a8]) does not match the SM3 digest of the message hashed with the extracted public key and the ID at hrk[0xd6:0xd6+hrkIdLen].

Common situations: Guest quote/certificate blobs are corrupted or truncated in transit; the wrong certificate (non-Hygon, wrong chip generation) is passed; byte offsets change in a newer Hygon CSV format so the signature region sliced is stale; reverse-byte-order handling of r/s or coordinates differs from the producer; verifying a blob whose signer ID length field (0xd4:0xd6) is wrong so the ID slice is misaligned.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/cb3214e5bdb2323c. Report an issue: GitHub.

Appendix: source

Thrown at nhp/core/verifier/csv/csv.go:288

		return err
	}

	xBig := new(big.Int).SetBytes(qx)
	yBig := new(big.Int).SetBytes(qy)

	pubKey := &ecdsa.PublicKey{
		Curve: sm2.P256(),
		X:     xBig,
		Y:     yBig,
	}

	rBig := new(big.Int).SetBytes(r)
	sBig := new(big.Int).SetBytes(s)

	if VerifySignature(pubKey, msgAllDigest, rBig, sBig) {
		return nil
	} else {
		return fmt.Errorf("failed to verify signature")
	}
}

func (a *Attestation) verifyCertChain(chipId string) error {
	// Download HRK from Hygon's certificate server
	if a.hrk == nil {
		resp, err := http.Get("https://cert.hygon.cn/hrk")
		if err != nil {
			return fmt.Errorf("failed to download HRK: %v", err)
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			return fmt.Errorf("unexpected status code when download HRK: %d", resp.StatusCode)
		}

		// Read the response body (HRK content)
		hrkData, err := io.ReadAll(resp.Body)

View on GitHub (pinned to 6e04ca5ff0)