{"record":{"id":"aa4c16579b01e2e3","repo":"OpenNHP/opennhp","slug":"hrk-digest-verification-failed-got-x-want-x","errorCode":null,"errorMessage":"HRK digest verification failed: got %x, want %x","messagePattern":"HRK digest verification failed: got %x, want %x","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"nhp/core/verifier/csv/csv.go","lineNumber":321,"sourceCode":"\t\t}\n\n\t\t// Read the response body (HRK content)\n\t\thrkData, err := io.ReadAll(resp.Body)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read HRK data: %v\", err)\n\t\t}\n\n\t\ta.hrk = hrkData\n\t}\n\n\tdigest, err := Sm3Digest(a.hrk)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\texpectedDigest, _ := hex.DecodeString(\"f5a46663059fdb4cdd06d097ed21782142923bb3430b3b938f23d54292094e3a\")\n\tif !bytes.Equal(digest, expectedDigest) {\n\t\treturn fmt.Errorf(\"HRK digest verification failed: got %x, want %x\", digest, expectedDigest)\n\t}\n\n\tif err := a.verifyHygonCertInfo(a.hrk, 0x03, 0, a.hrk[0x04:0x14]); err != nil {\n\t\treturn err\n\t}\n\n\t// verify hrk cert signature (self-signed)\n\thrkIdLen := int(binary.LittleEndian.Uint16(a.hrk[0xd4:0xd6]))\n\tif err := a.verifySm2SignatureWithId(\n\t\ta.hrk[0x44:0x64], a.hrk[0x8c:0xac],\n\t\ta.hrk[0x240:0x260], a.hrk[0x288:0x2a8],\n\t\ta.hrk[0xd6:0xd6+hrkIdLen], a.hrk[:0x240],\n\t); err != nil {\n\t\treturn err\n\t}\n\n\tif _, ok := a.hskCek[chipId]; !ok {\n\t\tresp, err := http.Get(fmt.Sprintf(\"https://cert.hygon.cn/hsk_cek?snumber=%s\", chipId))","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/core/verifier/csv/csv.go#L303-L339","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: silently proceeding with untrusted HRK is prevented by the digest check\nexpectedDigest, _ := hex.DecodeString(\"f5a46663059fdb4cdd06d097ed21782142923bb3430b3b938f23d54292094e3a\")\n// after: make the stale-digest case diagnosable\nif !bytes.Equal(digest, expectedDigest) {\n\tif http.DetectContentType(a.hrk) != \"application/octet-stream\" {\n\t\treturn fmt.Errorf(\"HRK download returned non-binary content (proxy/error page?), digest got %x want %x\", digest, expectedDigest)\n\t}\n\treturn fmt.Errorf(\"HRK digest verification failed: got %x, want %x\", digest, expectedDigest)\n}","handlingStrategy":"fallback","validationCode":"// validate a locally pinned HRK before loading it\nfunc validateHRK(hrk []byte) error {\n\tdigest, err := Sm3Digest(hrk)\n\tif err != nil {\n\t\treturn err\n\t}\n\texpected, _ := hex.DecodeString(\"f5a46663059fdb4cdd06d097ed21782142923bb3430b3b938f23d54292094e3a\")\n\tif !bytes.Equal(digest, expected) {\n\t\treturn fmt.Errorf(\"pinned HRK digest mismatch: %x\", digest)\n\t}\n\treturn nil\n}","typeGuard":"func isTrustedHRK(digest []byte) bool {\n\treturn bytes.Equal(digest, mustHexDecode(\"f5a46663059fdb4cdd06d097ed21782142923bb3430b3b938f23d54292094e3a\"))\n}","tryCatchPattern":"if err := att.Verify(chipId); err != nil {\n\tif strings.Contains(err.Error(), \"HRK digest verification failed\") {\n\t\t// digest mismatch: suspect proxy-intercepted or rotated HRK\n\t\tif updated := tryFetchPublishedHRKFingerprint(); updated {\n\t\t\treturn att.Verify(chipId) // after updating pinned digest/library\n\t\t}\n\t\treturn ErrUntrustedRoot\n\t}\n\treturn err\n}","preventionTips":["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."],"tags":["crypto","attestation","trust-anchor","sm3","checksum"],"backgroundTag":"checksum-mismatch","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}