prestodb/presto · critical · TagVerificationException
Signature mismatch in plaintext footer
Error message
Signature mismatch in plaintext footer
What it means
verifyFooterIntegrity recomputes the GCM authentication tag over the serialized footer using the footer key and footer AAD, and compares it to the tag stored in the file's footer_signing_key_metadata. A mismatch means the plaintext footer was tampered with, corrupted, or signed/verified with different key/AAD material — the encrypted-column contents may not correspond to the visible footer.
Source
Thrown at presto-parquet/src/main/java/com/facebook/presto/parquet/cache/MetadataReader.java:341
private static void verifyFooterIntegrity(BasicSliceInput from, InternalFileDecryptor fileDecryptor, int combinedFooterLength)
{
byte[] nonce = new byte[NONCE_LENGTH];
from.read(nonce);
byte[] gcmTag = new byte[GCM_TAG_LENGTH];
from.read(gcmTag);
AesGcmEncryptor footerSigner = fileDecryptor.createSignedFooterEncryptor();
int footerSignatureLength = NONCE_LENGTH + GCM_TAG_LENGTH;
byte[] serializedFooter = new byte[combinedFooterLength - footerSignatureLength];
from.setPosition(0);
from.read(serializedFooter, 0, serializedFooter.length);
byte[] signedFooterAuthenticationData = AesCipher.createFooterAAD(fileDecryptor.getFileAAD());
byte[] encryptedFooterBytes = footerSigner.encrypt(false, serializedFooter, nonce, signedFooterAuthenticationData);
byte[] calculatedTag = new byte[GCM_TAG_LENGTH];
System.arraycopy(encryptedFooterBytes, encryptedFooterBytes.length - GCM_TAG_LENGTH, calculatedTag, 0, GCM_TAG_LENGTH);
if (!Arrays.equals(gcmTag, calculatedTag)) {
throw new TagVerificationException("Signature mismatch in plaintext footer");
}
}
private static MessageType readParquetSchema(List<SchemaElement> schema)
{
Iterator<SchemaElement> schemaIterator = schema.iterator();
SchemaElement rootSchema = schemaIterator.next();
Types.MessageTypeBuilder builder = Types.buildMessage();
readTypeSchema(builder, schemaIterator, rootSchema.getNum_children());
return builder.named(rootSchema.name);
}
private static void readTypeSchema(Types.GroupBuilder<?> builder, Iterator<SchemaElement> schemaIterator, int typeCount)
{
for (int i = 0; i < typeCount; i++) {
SchemaElement element = schemaIterator.next();
Types.Builder<?, ?> typeBuilder;
if (element.type == null) {View on GitHub (pinned to 55bb57d202)
Solutions
- Ensure the correct footer signing key (same as footer key at write time) is configured
- Verify file integrity end-to-end (checksum) and re-download/re-copy the file if corrupted
- Match the AAD prefix configuration used by the writer
- Do NOT bypass verification; re-write the file from a trusted source if intentional modification occurred
Example fix
// before: key mismatch across environments String key = envSpecificKey(); // after: use the key recorded for the table's encryption config String key = keyRetriever.getKey(footerSigningKeyId);
Defensive patterns
Strategy: try-catch
Try / catch
try {
readParquetMetadata(dataSource);
} catch (TagVerificationException e) {
// footer signature mismatch: possible tampering — quarantine the file, never ignore
quarantineFile(path, e);
throw e;
} Prevention
- Never edit or partially rewrite signed-encrypted Parquet files in place
- Use the same footer/signing key across writer and all readers
- Re-copy from a trusted source rather than bypassing verification
- Monitor for TagVerificationException as a tampering signal
When it happens
Trigger: Reading a file with a plaintext footer + footer signing metadata while fileDecryptor is present: encrypt(false, serializedFooter, nonce, footerAAD) produces a tag that differs from the stored gcmTag — wrong signing key, altered footer bytes, or different file AAD.
Common situations: Footer manually edited or file partially rewritten after signing; wrong key configured so the signature can't validate; AAD prefix differences between writer and reader; bit-rot or truncation of the footer region.
Related errors
- PERMISSION_DENIED
- Applying decryptor on plaintext file
- Column encrypted with footer key in file with plaintext foot
- ColumnMetaData not set in Encryption with Footer key
- Column encrypted with footer key: No keys available
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/7792eec2377de9f0.
Report an issue: GitHub.