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
- Inspect what was actually downloaded (hexdump the body) — if it is HTML/JSON, a proxy or error page was served with status 200.
- Update this library/package to the latest version that pins the current Hygon root key digest.
- Confirm the host can reach the genuine cert.hygon.cn endpoint (no DNS hijack or MITM proxy).
- Pin a known-good HRK file locally and load it (set a.hrk) after verifying it with an independently obtained digest.
- 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
- Never accept a 200 response at face value — the library enforces a digest check; keep it and log got/want digests.
- Track Hygon root key rotation and update the library/pinned digest promptly.
- Block or detect MITM proxies that rewrite cert.hygon.cn responses.
- Ship a known-good HRK with your deployment and validate it before first attestation.
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
- failed to write HRK data to SM3
- invalid public key length: got
- invalid signature length: got
- failed to verify signature
- unsupported key type, expect RSA
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)