{"record":{"id":"cb3214e5bdb2323c","repo":"OpenNHP/opennhp","slug":"failed-to-verify-signature","errorCode":null,"errorMessage":"failed to verify signature","messagePattern":"failed to verify signature","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nhp/core/verifier/csv/csv.go","lineNumber":288,"sourceCode":"\t\treturn err\n\t}\n\n\txBig := new(big.Int).SetBytes(qx)\n\tyBig := new(big.Int).SetBytes(qy)\n\n\tpubKey := &ecdsa.PublicKey{\n\t\tCurve: sm2.P256(),\n\t\tX:     xBig,\n\t\tY:     yBig,\n\t}\n\n\trBig := new(big.Int).SetBytes(r)\n\tsBig := new(big.Int).SetBytes(s)\n\n\tif VerifySignature(pubKey, msgAllDigest, rBig, sBig) {\n\t\treturn nil\n\t} else {\n\t\treturn fmt.Errorf(\"failed to verify signature\")\n\t}\n}\n\nfunc (a *Attestation) verifyCertChain(chipId string) error {\n\t// Download HRK from Hygon's certificate server\n\tif a.hrk == nil {\n\t\tresp, err := http.Get(\"https://cert.hygon.cn/hrk\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to download HRK: %v\", err)\n\t\t}\n\t\tdefer resp.Body.Close()\n\n\t\tif resp.StatusCode != http.StatusOK {\n\t\t\treturn fmt.Errorf(\"unexpected status code when download HRK: %d\", resp.StatusCode)\n\t\t}\n\n\t\t// Read the response body (HRK content)\n\t\thrkData, err := io.ReadAll(resp.Body)","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/core/verifier/csv/csv.go#L270-L306","documentation":"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.","triggerScenarios":"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].","commonSituations":"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.","solutions":["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).","Confirm the blob actually comes from a Hygon CSV-capable chip and the remote attestation report corresponds to the chipId being verified.","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.","Confirm byte reversal (ReverseBytes) conventions match the producer of the signature (little- vs big-endian r/s/coordinates).","If you control the signing side, re-sign with the same SM2 signer ID and message framing used here (buildIDMsg with ECKEY)."],"exampleFix":"// before: slicing ID with unvalidated length\nhrkIdLen := int(binary.LittleEndian.Uint16(a.hrk[0xd4:0xd6]))\nif err := a.verifySm2SignatureWithId(\n\ta.hrk[0x44:0x64], a.hrk[0x8c:0xac],\n\ta.hrk[0x240:0x260], a.hrk[0x288:0x2a8],\n\ta.hrk[0xd6:0xd6+hrkIdLen], a.hrk[:0x240],\n); err != nil {\n\treturn err\n}\n// after: sanity-check length/bounds first\nhrkIdLen := int(binary.LittleEndian.Uint16(a.hrk[0xd4:0xd6]))\nif hrkIdLen <= 0 || 0xd6+hrkIdLen > len(a.hrk) {\n\treturn fmt.Errorf(\"invalid HRK signer ID length: %d\", hrkIdLen)\n}","handlingStrategy":"validation","validationCode":"// verify blob shape and signer-ID length before calling Verify/attestation APIs\nif len(blob) < 0x2a8 {\n\treturn fmt.Errorf(\"attestation blob too small: %d\", len(blob))\n}\nidLen := int(binary.LittleEndian.Uint16(blob[0xd4:0xd6]))\nif idLen <= 0 || 0xd6+idLen > len(blob) {\n\treturn fmt.Errorf(\"invalid signer ID length %d in blob\", idLen)\n}","typeGuard":"func isValidCSVBlob(blob []byte) bool {\n\treturn len(blob) >= 0x2a8 &&\n\t\tbinary.LittleEndian.Uint16(blob[0xd4:0xd6]) > 0 &&\n\t\t0xd6+int(binary.LittleEndian.Uint16(blob[0xd4:0xd6])) <= len(blob)\n}","tryCatchPattern":"err := att.Verify(chipId)\nif err != nil {\n\tif strings.Contains(err.Error(), \"failed to verify signature\") {\n\t\t// treat as untrusted attestation: reject the workload, log blob fingerprint\n\t\treturn ErrAttestationUntrusted\n\t}\n\treturn err\n}","preventionTips":["Checksum attestation blobs end-to-end in transit (TLS, signed channels) so corruption is detected before verification.","Keep the verifier and any blob producer on the same Hygon CSV format version.","Log the blob's key fields (sizes, ID length) on failure to speed diagnosis of offset drift."],"tags":["crypto","sm2","signature-verification","attestation"],"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"}