OpenNHP/opennhp · critical

HRK digest verification failed: got

Error message

HRK digest verification failed: got %x, want %x

What it means

After downloading (or reusing) the HRK, verifyCertChain computes its SM3 digest and compares it to a hard-coded expected digest (f5a46663...). This error means the HRK blob obtained from cert.hygon.cn does not match the library's pinned root key — the downloaded data is not the expected Hygon Root Key.

Solutions

  1. Inspect what was actually downloaded (hexdump the body) — if it is HTML/JSON, a proxy or error page was served with status 200.
  2. Update this library/package to the latest version that pins the current Hygon root key digest.
  3. Confirm the host can reach the genuine cert.hygon.cn endpoint (no DNS hijack or MITM proxy).
  4. Pin a known-good HRK file locally and load it (set a.hrk) after verifying it with an independently obtained digest.
  5. Compare the got digest in the message against Hygon's published HRK fingerprint to distinguish rotation from corruption.

Example fix

// before: silently proceeding with untrusted HRK is prevented by the digest check
expectedDigest, _ := hex.DecodeString("f5a46663059fdb4cdd06d097ed21782142923bb3430b3b938f23d54292094e3a")
// after: make the stale-digest case diagnosable
if !bytes.Equal(digest, expectedDigest) {
	if http.DetectContentType(a.hrk) != "application/octet-stream" {
		return fmt.Errorf("HRK download returned non-binary content (proxy/error page?), digest got %x want %x", digest, expectedDigest)
	}
	return fmt.Errorf("HRK digest verification failed: got %x, want %x", digest, expectedDigest)
}
Defensive patterns

Strategy: fallback

Validate before calling

// validate a locally pinned HRK before loading it
func validateHRK(hrk []byte) error {
	digest, err := Sm3Digest(hrk)
	if err != nil {
		return err
	}
	expected, _ := hex.DecodeString("f5a46663059fdb4cdd06d097ed21782142923bb3430b3b938f23d54292094e3a")
	if !bytes.Equal(digest, expected) {
		return fmt.Errorf("pinned HRK digest mismatch: %x", digest)
	}
	return nil
}

Type guard

func isTrustedHRK(digest []byte) bool {
	return bytes.Equal(digest, mustHexDecode("f5a46663059fdb4cdd06d097ed21782142923bb3430b3b938f23d54292094e3a"))
}

Try / catch

if err := att.Verify(chipId); err != nil {
	if strings.Contains(err.Error(), "HRK digest verification failed") {
		// digest mismatch: suspect proxy-intercepted or rotated HRK
		if updated := tryFetchPublishedHRKFingerprint(); updated {
			return att.Verify(chipId) // after updating pinned digest/library
		}
		return ErrUntrustedRoot
	}
	return err
}

Prevention

When it happens

Trigger: First verifyCertChain call when a.hrk is nil and the SM3 digest of the fetched hrk body differs from the hex constant at line 319: server returns an HTML error page with 200, an updated/rotated HRK the code does not know, a truncated body, or an intercepting proxy serving wrong content.

Common situations: Hygon rotates the root key and this hard-coded digest becomes stale (library version lag); proxy/firewall substitutes a block page with HTTP 200; caching layer serves corrupted content; manual edits to a locally pinned HRK file.

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/aa4c16579b01e2e3. Report an issue: GitHub.

Appendix: source

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

		}

		// Read the response body (HRK content)
		hrkData, err := io.ReadAll(resp.Body)
		if err != nil {
			return fmt.Errorf("failed to read HRK data: %v", err)
		}

		a.hrk = hrkData
	}

	digest, err := Sm3Digest(a.hrk)
	if err != nil {
		return err
	}

	expectedDigest, _ := hex.DecodeString("f5a46663059fdb4cdd06d097ed21782142923bb3430b3b938f23d54292094e3a")
	if !bytes.Equal(digest, expectedDigest) {
		return fmt.Errorf("HRK digest verification failed: got %x, want %x", digest, expectedDigest)
	}

	if err := a.verifyHygonCertInfo(a.hrk, 0x03, 0, a.hrk[0x04:0x14]); err != nil {
		return err
	}

	// verify hrk cert signature (self-signed)
	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
	}

	if _, ok := a.hskCek[chipId]; !ok {
		resp, err := http.Get(fmt.Sprintf("https://cert.hygon.cn/hsk_cek?snumber=%s", chipId))

View on GitHub (pinned to 6e04ca5ff0)