{"record":{"id":"a78adb15c291c7d5","repo":"hashicorp/packer","slug":"ed25519-verification-failed","errorCode":null,"errorMessage":"Ed25519 verification failed","messagePattern":"Ed25519 verification failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/attestation/sign_key.go","lineNumber":92,"sourceCode":"\treturn s.verifier, nil\n}\n\nfunc (v *pemVerifier) Verify(_ context.Context, payloadType string, payload, signature []byte) error {\n\tpae := PreAuthEncode(payloadType, payload)\n\n\tswitch publicKey := v.publicKey.(type) {\n\tcase *rsa.PublicKey:\n\t\tdigest := sha256.Sum256(pae)\n\t\treturn rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, digest[:], signature)\n\tcase *ecdsa.PublicKey:\n\t\tdigest := sha256.Sum256(pae)\n\t\tif !ecdsa.VerifyASN1(publicKey, digest[:], signature) {\n\t\t\treturn fmt.Errorf(\"ECDSA verification failed\")\n\t\t}\n\t\treturn nil\n\tcase ed25519.PublicKey:\n\t\tif !ed25519.Verify(publicKey, pae, signature) {\n\t\t\treturn fmt.Errorf(\"Ed25519 verification failed\")\n\t\t}\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported public key type %T\", v.publicKey)\n\t}\n}\n\nfunc (v *pemVerifier) KeyID() string {\n\treturn v.keyID\n}\n\nfunc LoadPEMVerifier(path string) (Verifier, error) {\n\tcontents, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read verifier %q: %w\", path, err)\n\t}\n\n\tpublicKey, rawVerifier, err := loadPEMPublicKey(contents)","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/internal/attestation/sign_key.go#L74-L110","documentation":"pemVerifier.Verify handles ed25519.PublicKey verifiers by calling ed25519.Verify with the raw pre-auth-encoded payload (Ed25519 signs the message directly, no pre-hashing). When ed25519.Verify returns false, the verifier returns the literal error \"Ed25519 verification failed\". Like the ECDSA case, this indicates the signature does not cryptographically match the payload under this Ed25519 public key.","triggerScenarios":"Calling pemVerifier.Verify(ctx, payloadType, payload, signature) where the verifier's publicKey is ed25519.PublicKey and ed25519.Verify(publicKey, PreAuthEncode(payloadType,payload), signature) returns false — wrong key, altered payload, corrupted or wrongly encoded signature.","commonSituations":"Using an Ed25519 public key to verify a signature made by an RSA/ECDSA signer (or vice versa); passing the un-hashed or differently-encoded payload to Verify while the signer hashed it externally; signature bytes damaged by text-mode transport or bad base64 handling; key rotation leaving old signatures verified against new keys.","solutions":["Verify the Ed25519 public key PEM corresponds to the signing key — compare Signature.KeyID with verifier.KeyID() before attempting verification.","Pass the identical payloadType and payload bytes used at signing time; Ed25519 here verifies the raw PAE bytes, so any difference fails.","Ensure the signature is exactly 64 bytes of raw Ed25519 signature data and was not base64-decoded incorrectly or truncated.","If signatures come from an external Ed25519 library, confirm it signs the same message bytes (the PAE), not a pre-hash or a different canonicalization."],"exampleFix":"// before: mismatched algorithm pair\nrsaSigner, _ := attestation.NewSigner(ctx, cfgWithRSAKey) // RSA key\nedVerifier, _ := attestation.LoadPEMVerifier(\"ed25519-pub.pem\")\nerr := edVerifier.Verify(ctx, payloadType, payload, sig.Sig) // Ed25519 verification failed\n\n// after: derive the verifier from the signer so algorithms always match\nverifier, _ := signer.Verifier(ctx, cfg)\nerr := verifier.Verify(ctx, payloadType, payload, sig.Sig)","handlingStrategy":"validation","validationCode":"if verifier.KeyID() != sig.KeyID {\n\treturn fmt.Errorf(\"signature made with key %s but verifier is %s\", sig.KeyID, verifier.KeyID())\n}\nif len(sig.Sig) != ed25519.SignatureSize {\n\treturn fmt.Errorf(\"bad ed25519 signature length %d, want %d\", len(sig.Sig), ed25519.SignatureSize)\n}","typeGuard":"func isEd25519Verifier(pub crypto.PublicKey) bool {\n\t_, ok := pub.(ed25519.PublicKey)\n\treturn ok\n}","tryCatchPattern":"if err := verifier.Verify(ctx, payloadType, payload, sig.Sig); err != nil {\n\tif err.Error() == \"Ed25519 verification failed\" {\n\t\t// mismatch: check key pairing and that payload bytes are identical to signing input\n\t}\n\treturn fmt.Errorf(\"attestation verify: %w\", err)\n}","preventionTips":["Use signer.Verifier(ctx, cfg) to obtain the matching verifier rather than a separately loaded PEM.","Validate that the signature is exactly 64 bytes before verification for Ed25519 keys.","Never mix key algorithms across rotate operations: keep old verifiers available for old signatures.","Keep payloadType and payload byte-identical between sign and verify; PreAuthEncode makes any difference fatal."],"tags":["attestation","signature-verification","ed25519","crypto"],"backgroundTag":"signature-verification-failed","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}