{"record":{"id":"b5455617560faa07","repo":"hashicorp/terraform","slug":"failed-to-authenticate-that-the-archive-was-signed","errorCode":null,"errorMessage":"failed to authenticate that the archive was signed by HashiCorp","messagePattern":"failed to authenticate that the archive was signed by HashiCorp","errorType":"validation","errorClass":"ErrNotSignedByHashiCorp","httpStatus":null,"severity":"critical","filePath":"internal/releaseauth/signature.go","lineNumber":32,"sourceCode":"\topenpgpErrors \"github.com/ProtonMail/go-crypto/openpgp/errors\"\n)\n\n// SignatureAuthentication is an archive Authenticator that validates that SHA256SUMS data\n// was signed by the given signing key.\ntype SignatureAuthentication struct {\n\tAuthenticator\n\n\t// This can be overridden by tests to check arbitrary keys, rather than the HashiCorp public key\n\tPublicKey string\n\tsignature []byte\n\tsigned    []byte\n}\n\nvar _ Authenticator = SignatureAuthentication{}\n\n// ErrNotSignedByHashiCorp is the error returned when there is a mismatch between the SHA256SUMS\n// signature data and the data itself.\nvar ErrNotSignedByHashiCorp = errors.New(\"failed to authenticate that the archive was signed by HashiCorp\")\n\n// NewSignatureAuthentication creates a new Authenticator given some signature data\n// (the SHA256SUMS.sig file), the signed data (the SHA256SUMS file), and a public key\nfunc NewSignatureAuthentication(signature []byte, signed []byte) *SignatureAuthentication {\n\treturn &SignatureAuthentication{\n\t\tsignature: signature,\n\t\tsigned:    signed,\n\t\tPublicKey: HashiCorpPublicKey,\n\t}\n}\n\nfunc (a SignatureAuthentication) Authenticate() error {\n\t// Verify the signature using the HashiCorp public key. If this succeeds,\n\t// this is an official provider.\n\thashicorpKeyring, err := openpgp.ReadArmoredKeyRing(strings.NewReader(a.PublicKey))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating HashiCorp keyring: %s\", err)\n\t}","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/releaseauth/signature.go#L14-L50","documentation":"ErrNotSignedByHashiCorp is returned by SignatureAuthentication.Authenticate when OpenPGP detached-signature verification of the SHA256SUMS file against the HashiCorp public key fails for any reason other than an expired key (which is tolerated and logged at WARN). It means the archive's signature cannot be attributed to HashiCorp, so the release is not authenticated as official.","triggerScenarios":"SignatureAuthentication.Authenticate at signature.go:52 calls openpgp.CheckDetachedSignature; if the resulting error is non-nil and not openpgpErrors.ErrKeyExpired, it returns ErrNotSignedByHashiCorp (signature.go:59-61).","commonSituations":"Tampered or rebuilt SHA256SUMS / .sig pair; signature made with a different (non-HashiCorp) key; corrupted .sig download; wrong public key configured (e.g. tests overriding PublicKey); third-party mirror re-signing releases.","solutions":["Re-download both the SHA256SUMS and SHA256SUMS.sig files from the official source and retry.","Verify the public key in use is the official HashiCorp key (ID 72D7468F) — do not override PublicKey except in controlled tests.","If the release genuinely is not signed by HashiCorp (community/third-party plugin), do not use SignatureAuthentication; rely on the appropriate trust mechanism for that source.","Check the [DEBUG] GPG log line for the underlying OpenPGP error to distinguish a bad signature from a bad key."],"exampleFix":"// before\nauth := releaseauth.NewSignatureAuthentication(sigBytes, sumsBytes)\nif err := auth.Authenticate(); err != nil {\n    return err\n}\n\n// after — ensure fresh, complete downloads and the official key\nif !bytes.Equal(auth.PublicKey, releaseauth.HashiCorpPublicKey) {\n    return errors.New(\"refusing to verify with a non-HashiCorp key\")\n}\nif err := auth.Authenticate(); err != nil {\n    return fmt.Errorf(\"release is NOT signed by HashiCorp; do not trust this archive: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Ensure the official key is in use and inputs are non-empty\nif len(signature) == 0 || len(signed) == 0 {\n    return errors.New(\"missing signature or SHA256SUMS data\")\n}","typeGuard":"func isNotSignedByHashiCorp(err error) bool {\n    return errors.Is(err, releaseauth.ErrNotSignedByHashiCorp)\n}","tryCatchPattern":"err := releaseauth.NewSignatureAuthentication(sig, sums).Authenticate()\nif errors.Is(err, releaseauth.ErrNotSignedByHashiCorp) {\n    // do NOT proceed; re-download official artifacts and retry once\n    return redownloadAndVerify()\n}","preventionTips":["Only trust artifacts from the official release source.","Never override PublicKey outside of controlled tests.","Pair signature verification with checksum verification in a single authenticator chain.","Check the [DEBUG] GPG log line to learn the underlying openpgp error."],"tags":["security","gpg","signature","authentication","terraform"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}