

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Implementações personalizadas da validação da integridade do arquivo de CloudTrail log
<a name="cloudtrail-log-file-custom-validation"></a>

Como CloudTrail usa algoritmos criptográficos e funções de hash padrão do setor e disponíveis abertamente, você pode criar suas próprias ferramentas para validar a integridade dos arquivos de log. CloudTrail Quando a validação da integridade do arquivo de log está habilitada, CloudTrail entrega os arquivos de resumo para o seu bucket do Amazon S3. Você pode usar esses arquivos para implementar sua própria solução de validação. Para obter mais informações sobre os arquivos de resumo, consulte [CloudTrail estrutura do arquivo digest](cloudtrail-log-file-validation-digest-file-structure.md). 

Este tópico descreve como os arquivos de resumo são assinados e explica detalhadamente as etapas que você precisará seguir para implementar uma solução que valida os arquivos de resumo e os arquivos de log aos quais eles fazem referência.

## Entendendo como os arquivos de CloudTrail resumo são assinados
<a name="cloudtrail-log-file-custom-validation-how-cloudtrail-digest-files-are-signed"></a>

CloudTrail os arquivos de resumo são assinados com assinaturas digitais RSA. Para cada arquivo de resumo, o CloudTrail faz o seguinte: 

1. Cria uma string para assinatura de dados com base em campos de arquivos de resumo designados (descritos na próxima seção). 

1. Obtém uma chave privada exclusiva para a região.

1. Transmite o hash SHA-256 da string e a chave privada ao algoritmo de assinatura RSA, que produz uma assinatura digital.

1. Codifica o código de byte da assinatura em formato hexadecimal.

1. Insere a assinatura digital na propriedade de metadados `x-amz-meta-signature` do objeto do arquivo de resumo do Amazon S3.

### Conteúdo da string de assinatura de dados
<a name="cloudtrail-log-file-custom-validation-data-signing-string-summary"></a>

Os seguintes CloudTrail objetos são incluídos na string para assinatura de dados: 
+ O carimbo de data e hora final do arquivo de resumo no formato estendido UTC (por exemplo, `2015-05-08T07:19:37Z`)
+ O caminho atual do arquivo de resumo do S3
+ O hash SHA-256 com codificação hexadecimal do arquivo de resumo atual
+ A assinatura com codificação hexadecimal do arquivo de resumo anterior

O formato para calcular essa string e uma string de exemplo são fornecidos posteriormente neste documento.

## Etapas da implementação da validação personalizada
<a name="cloudtrail-log-file-custom-validation-steps"></a>

Ao implementar uma solução de validação personalizada, você precisará validar o arquivo de resumo primeiro e os arquivos de log aos quais ele faz referência. 

### Validar o arquivo de resumo
<a name="cloudtrail-log-file-custom-validation-steps-digest"></a>

Para validar um arquivo de resumo, você precisa da assinatura dele, da chave pública cuja chave privada foi usada para assiná-lo e de uma string de assinatura de dados computada. 

1. Obtenha o arquivo de resumo.

1. Verifique se o arquivo de resumo foi recuperado de seu local original. 

1. Obtenha a assinatura com codificação hexadecimal do arquivo de resumo.

1. Obtenha a impressão digital com codificação hexadecimal da chave pública cuja chave privada foi usada para assinar o arquivo de resumo.

1. Recupere as chaves públicas do período correspondente ao arquivo de resumo.

1. Entre as chaves públicas recuperadas, escolha aquela cuja impressão digital corresponde à impressão digital do arquivo de resumo.

1. Usando o hash do arquivo de resumo e outros campos de arquivos de resumo, recrie a string de assinatura de dados usada para verificar a assinatura do arquivo de resumo.

1. Para validar a assinatura, transmita o hash SHA-256 da string, a chave pública e a assinatura como parâmetros ao algoritmo de verificação de assinatura RSA. Se o resultado for verdadeiro, o arquivo de resumo será válido. 

### Validar os arquivos de log
<a name="cloudtrail-log-file-custom-validation-steps-logs"></a>

Se o arquivo de resumo for válido, valide cada um dos arquivos de log aos quais o arquivo de resumo faz referência.

1. Para validar a integridade de um arquivo de log, compute o valor de hash SHA-256 dele em seu conteúdo não compactado e compare os resultados com o hash do arquivo de log gravado em formato hexadecimal na compilação. Se os hashes forem correspondentes, o arquivo de log será válido.

1. Com as informações sobre o arquivo de resumo anterior que está incluído no arquivo de resumo atual, valide os arquivos de resumo anteriores e seus arquivos de log correspondentes de maneira consecutiva.

As seções a seguir descrevem essas etapas em detalhes.

### A. Obter o arquivo de resumo
<a name="cloudtrail-log-file-custom-validation-steps-get-the-digest-file"></a>

As primeiras etapas são: obter o arquivo de resumo mais recente, verificar se você o recuperou do local original dele, verificar sua assinatura digital e obter a impressão digital da chave pública.

1. Usando o S3 [https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) ou a classe AmazonS3Client (por exemplo), obtenha o arquivo de resumo mais recente do bucket do Amazon S3 para o período que você deseja validar. 

1. Verifique se o bucket e o objeto do S3 usados para recuperar o arquivo correspondem aos locais do bucket e do objeto do S3 que são registrados no próprio arquivo de resumo. 

1. Em seguida, obtenha a assinatura digital do arquivo de resumo da propriedade de metadados `x-amz-meta-signature` do objeto do arquivo de resumo no Amazon S3.

1. No arquivo de resumo, obtenha a impressão digital da chave pública cuja chave privada foi usada para assinar o arquivo de resumo do campo `digestPublicKeyFingerprint`. 

### B. Recupere a chave pública para validar o arquivo de resumo
<a name="cloudtrail-log-file-custom-validation-steps-retrieve-public-key"></a>

Para obter a chave pública para validar o arquivo de resumo, você pode usar a API AWS CLI ou a CloudTrail API. Em ambos os casos, você especifica um período (ou seja, um horário de início e de término) para os arquivos de resumo que você deseja validar. Uma ou mais chaves públicas podem ser retornadas para o período que você especificar. As chaves retornadas podem ter períodos de validade que se sobrepõem.

**nota**  
Como CloudTrail usa pares de private/public chaves diferentes por região, cada arquivo de resumo é assinado com uma chave privada exclusiva para sua região. Portanto, quando você valida um arquivo de resumo de uma região específica, precisa recuperar a chave pública da mesma região.

#### Use o AWS CLI para recuperar chaves públicas
<a name="cloudtrail-log-file-custom-validation-steps-retrieve-public-key-cli"></a>

Para recuperar chaves públicas para arquivos de resumo usando o AWS CLI, use o `cloudtrail list-public-keys` comando. O comando tem o formato a seguir: 

 `aws cloudtrail list-public-keys [--start-time <start-time>] [--end-time <end-time>]` 

Os parâmetros de horário de início e de término são carimbos de data e hora UTC opcionais. Se eles não forem especificados, a hora atual será usada, e a chave ou as chaves públicas atualmente ativas serão retornadas.

 **Exemplo de resposta** 

A resposta será uma lista de objetos JSON que representam a chave ou as chaves retornadas: 

```
{
    "publicKeyList": [
        {
            "ValidityStartTime": "1436317441.0",
            "ValidityEndTime": "1438909441.0",
            "Value": "MIIBCgKCAQEAn11L2YZ9h7onug2ILi1MWyHiMRsTQjfWE+pHVRLk1QjfWhirG+lpOa8NrwQ/r7Ah5bNL6HepznOU9XTDSfmmnP97mqyc7z/upfZdS/AHhYcGaz7n6Wc/RRBU6VmiPCrAUojuSk6/GjvA8iOPFsYDuBtviXarvuLPlrT9kAd4Lb+rFfR5peEgBEkhlzc5HuWO7S0y+KunqxX6jQBnXGMtxmPBPP0FylgWGNdFtks/4YSKcgqwH0YDcawP9GGGDAeCIqPWIXDLG1jOjRRzWfCmD0iJUkz8vTsn4hq/5ZxRFE7UBAUiVcGbdnDdvVfhF9C3dQiDq3k7adQIziLT0cShgQIDAQAB",
            "Fingerprint": "8eba5db5bea9b640d1c96a77256fe7f2"
        },
        {
            "ValidityStartTime": "1434589460.0",
            "ValidityEndTime": "1437181460.0",
            "Value": "MIIBCgKCAQEApfYL2FiZhpN74LNWVUzhR+VheYhwhYm8w0n5Gf6i95ylW5kBAWKVEmnAQG7BvS5g9SMqFDQx52fW7NWV44IvfJ2xGXT+wT+DgR6ZQ+6yxskQNqV5YcXj4Aa5Zz4jJfsYjDuO2MDTZNIzNvBNzaBJ+r2WIWAJ/Xq54kyF63B6WE38vKuDE7nSd1FqQuEoNBFLPInvgggYe2Ym1Refe2z71wNcJ2kY+q0h1BSHrSM8RWuJIw7MXwF9iQncg9jYzUlNJomozQzAG5wSRfbplcCYNY40xvGd/aAmO0m+Y+XFMrKwtLCwseHPvj843qVno6x4BJN9bpWnoPo9sdsbGoiK3QIDAQAB",
            "Fingerprint": "8933b39ddc64d26d8e14ffbf6566fee4"
        },
        {
            "ValidityStartTime": "1434589370.0",
            "ValidityEndTime": "1437181370.0",
            "Value": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqlzPJbvZJ42UdcmLfPUqXYNfOs6I8lCfao/tOs8CmzPOEdtLWugB9xoIUz78qVHdKIqxbaG4jWHfJBiOSSFBM0lt8cdVo4TnRa7oG9io5pysS6DJhBBAeXsicufsiFJR+wrUNh8RSLxL4k6G1+BhLX20tJkZ/erT97tDGBujAelqseGg3vPZbTx9SMfOLN65PdLFudLP7Gat0Z9p5jw/rjpclKfo9Bfc3heeBxWGKwBBOKnFAaN9V57pOaosCvPKmHd9bg7jsQkI9Xp22IzGLsTFJZYVA3KiTAElDMu80iFXPHEq9hKNbt9e4URFam+1utKVEiLkR2disdCmPTK0VQIDAQAB",
            "Fingerprint": "31e8b5433410dfb61a9dc45cc65b22ff"
        }
    ]
}
```

#### Use a CloudTrail API para recuperar chaves públicas
<a name="cloudtrail-log-file-custom-validation-steps-retrieve-public-key-api"></a>

Para recuperar chaves públicas para arquivos de resumo usando a CloudTrail API, transmita os valores de hora de início e hora de término para a `ListPublicKeys` API. A API `ListPublicKeys` retorna as chaves públicas cujas chaves privadas foram usadas para assinar arquivos de resumo dentro do período especificado. Para cada chave pública, a API também retorna a impressão digital correspondente.

##### `ListPublicKeys`
<a name="cloudtrail-log-file-custom-validation-steps-list-public-keys"></a>

Esta seção descreve os parâmetros de solicitação e os elementos de resposta da API `ListPublicKeys`.

**nota**  
A codificação dos campos binários de `ListPublicKeys` está sujeita a alterações. 

 **Parâmetros de solicitação** 


****  

| Name (Nome) | Description | 
| --- | --- | 
|  StartTime  | Opcionalmente, especifica, em UTC, o início do intervalo de tempo para pesquisar chaves públicas para arquivos de resumo. CloudTrail Se não StartTime for especificado, a hora atual será usada e a chave pública atual será retornada. <br />Tipo: DateTime  | 
|  EndTime  | Opcionalmente, especifica, em UTC, o final do intervalo de tempo para pesquisar chaves públicas para arquivos de resumo. CloudTrail Se não EndTime for especificado, a hora atual será usada. <br />Tipo: DateTime  | 

 **Elementos de resposta** 

`PublicKeyList`, um conjunto de `PublicKey` objetos que contém: 


****  

|  |  | 
| --- |--- |
|  Name (Nome)  |  Descrição  | 
|  Value  | O valor de chave pública codificado DER no formato PKCS \#1. <br />Tipo: Blob  | 
|  ValidityStartTime  | O horário de início da validade da chave pública.<br />Tipo: DateTime  | 
|  ValidityEndTime  | O horário de término da validade da chave pública.<br />Tipo: DateTime  | 
|  Fingerprint  | A impressão digital da chave pública. A impressão digital pode ser usada para identificar a chave pública que você precisa usar para validar o arquivo de resumo.<br />Tipo: string  | 

### C. Escolha a chave pública a ser usada para a validação
<a name="cloudtrail-log-file-custom-validation-steps-choose-public-key"></a>

Entre as chaves públicas recuperadas por `list-public-keys` ou `ListPublicKeys`, escolha a chave retornada cuja impressão digital corresponde à impressão digital gravada no campo `digestPublicKeyFingerprint` do arquivo de resumo. Esta é a chave pública que você usará para validar o arquivo de resumo. 

### D. Recrie a string de assinatura de dados
<a name="cloudtrail-log-file-custom-validation-steps-recreate-data-signing-string"></a>

Agora que você tem a assinatura do arquivo de resumo e a chave pública associada, precisa calcular a string de assinatura de dados. Depois que você calcular a string de assinatura de dados, terá o necessário para verificar a assinatura.

A string de assinatura de dados tem o seguinte formato: 

```
Data_To_Sign_String = 
  Digest_End_Timestamp_in_UTC_Extended_format + '\n' +
  Current_Digest_File_S3_Path + '\n' +
  Hex(Sha256(current-digest-file-content)) + '\n' +
  Previous_digest_signature_in_hex
```

Veja a seguir um exemplo de `Data_To_Sign_String`.

```
2015-08-12T04:01:31Z
amzn-s3-demo-bucket/AWSLogs/111122223333/CloudTrail-Digest/us-east-2/2015/08/12/111122223333_us-east-2_CloudTrail-Digest_us-east-2_20150812T040131Z.json.gz
4ff08d7c6ecd6eb313257e839645d20363ee3784a2328a7d76b99b53cc9bcacd
6e8540b83c3ac86a0312d971a225361d28ed0af20d70c211a2d405e32abf529a8145c2966e3bb47362383a52441545ed091fb81
d4c7c09dd152b84e79099ce7a9ec35d2b264eb92eb6e090f1e5ec5d40ec8a0729c02ff57f9e30d5343a8591638f8b794972ce15bb3063a01972
98b0aee2c1c8af74ec620261529265e83a9834ebef6054979d3e9a6767dfa6fdb4ae153436c567d6ae208f988047ccfc8e5e41f7d0121e54ed66b1b904f80fb2ce304458a2a6b91685b699434b946c52589e9438f8ebe5a0d80522b2f043b3710b87d2cda43e5c1e0db921d8d540b9ad5f6d4$31b1f4a8ef2d758424329583897339493a082bb36e782143ee5464b4e3eb4ef6
```

Depois que você recriar essa string, poderá validar o arquivo de resumo.

### E. Valide o arquivo de resumo
<a name="cloudtrail-log-file-custom-validation-steps-validate-digest-file"></a>

Transmita o hash SHA-256 da string de assinatura de dados recriada, a assinatura digital e a chave pública ao algoritmo de verificação de assinatura RSA. Se o resultado for verdadeiro, a assinatura do arquivo de resumo será verificada, e o arquivo de resumo será válido. 

### F. Valide os arquivos de log
<a name="cloudtrail-log-file-custom-validation-steps-validate-log-files"></a>

Depois que você validar o arquivo de resumo, poderá validar os arquivos de log aos quais ele faz referência. O arquivo de resumo contém os hashes SHA-256 dos arquivos de log. Se um dos arquivos de log for modificado após a CloudTrail entrega, os hashes SHA-256 serão alterados e a assinatura do arquivo de resumo não corresponderá. 

Veja a seguir como validar os arquivos de log:

1. Faça um `S3 Get` do arquivo de log usando as informações de local do S3 nos campos `logFiles.s3Bucket` e `logFiles.s3Object` do arquivo de resumo.

1. Se a operação `S3 Get` for bem-sucedida, percorra os arquivos de log listados no conjunto de arquivos de log seguindo estas etapas:

   1. Recupere o hash original do arquivo no campo `logFiles.hashValue` do log correspondente no arquivo de resumo.

   1. Faça hash do conteúdo descompactado do arquivo de log com o algoritmo de hashing especificado em `logFiles.hashAlgorithm`.

   1. Compare o valor de hash que você gerou com o valor do log no arquivo de resumo. Se os hashes forem correspondentes, o arquivo de log será válido.

### G. Valide arquivos de log e de compilação adicionais
<a name="cloudtrail-log-file-custom-validation-steps-validate-additional-files"></a>

Em cada arquivo de resumo, os campos a seguir fornecem o local e a assinatura do arquivo de resumo anterior:
+  `previousDigestS3Bucket` 
+  `previousDigestS3Object` 
+  `previousDigestSignature` 

Use essas informações para acessar os arquivos de resumo anteriores em sequência, validando a assinatura de cada um deles e os arquivos de log aos quais eles fazem referência seguindo as etapas das seções anteriores. A única diferença é que, para os arquivos de resumo anteriores, você não precisa recuperar a assinatura digital das propriedades de metadados do Amazon S3 do objeto do arquivo de resumo. A assinatura do arquivo de resumo anterior é fornecida a você no campo `previousDigestSignature`. 

Você pode voltar até que o arquivo de resumo inicial seja atingido ou até que a cadeia de arquivos de resumo seja interrompida, o que ocorrer primeiro. 

## Validar arquivos de log e de resumo offline
<a name="cloudtrail-log-file-custom-validation-offline"></a>

Ao validar os arquivos de log e de compilação offline, você pode seguir os procedimentos descritos nas seções anteriores. No entanto, é necessário levar em conta as seguintes áreas:

### Processar o arquivo de resumo mais recente
<a name="cloudtrail-log-file-custom-validation-offline-most-recent-digest"></a>

A assinatura digital do arquivo de resumo mais recente (ou seja, "atual") está nas propriedades de metadados do Amazon S3 do objeto do arquivo de resumo. Em um cenário offline, a assinatura digital do arquivo de resumo atual não é disponibilizada.

Veja a seguir duas possíveis maneiras de fazer isso:
+ Como a assinatura digital do arquivo de resumo anterior está no arquivo de resumo atual, comece a validar a partir do next-to-last arquivo de resumo. Com esse método, não é possível validar o arquivo de resumo mais recente.
+ Como etapa preliminar, obtenha a assinatura do arquivo de resumo atual das propriedades de metadados do objeto do arquivo de resumo e armazene-a offline com segurança. Isso permite que o arquivo de resumo atual seja validado, além dos arquivos anteriores da cadeia.

### Resolução de caminho
<a name="cloudtrail-log-file-custom-validation-offline-path-resolution"></a>

Os campos nos arquivos de resumo obtidos por download, como `s3Object` e `previousDigestS3Object`, ainda apontarão para os locais online do Amazon S3 dos arquivos de log e de resumo. Uma solução offline precisa encontrar uma maneira de redirecioná-los para o caminho atual dos arquivos de log e de compilação baixados.

### Chaves públicas
<a name="cloudtrail-log-file-custom-validation-offline-public-keys"></a>

Para fazer a validação offline, todas as chaves públicas de que você precisa para validar os arquivos de log em um determinado período precisam primeiro ser obtidas online (ao chamar `ListPublicKeys`, por exemplo) e, depois, armazenadas offline com segurança. Essa etapa precisará ser repetida sempre que você quiser validar arquivos adicionais fora do período inicial que especificou.

## Exemplo de snippet de validação
<a name="cloudtrail-log-file-custom-validation-sample-code"></a>

O trecho de amostra a seguir fornece código básico para validar arquivos de CloudTrail resumo e log. O código básico é online/offline agnóstico; ou seja, cabe a você decidir se deseja implementá-lo com ou sem conectividade on-line com. AWS A implementação sugerida usa [Java Cryptography Extension (JCE)](https://en.wikipedia.org/wiki/Java_Cryptography_Extension) e [Bouncy Castle](https://www.bouncycastle.org/) como um provedor de segurança. 

O exemplo de snippet mostra:
+ Como criar a string de assinatura de dados usada para validar a assinatura do arquivo de resumo. 
+ Como verificar a assinatura do arquivo de resumo.
+ Como verificar os hashes do arquivo de log.
+ Uma estrutura de código para validar uma cadeia de arquivos de resumo.

```
import java.util.Arrays;
import java.security.MessageDigest;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import org.json.JSONObject;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.apache.commons.codec.binary.Hex;

public class DigestFileValidator {

    public void validateDigestFile(String digestS3Bucket, String digestS3Object, String digestSignature) {
 
        // Using the Bouncy Castle provider as a JCE security provider - http://www.bouncycastle.org/
        Security.addProvider(new BouncyCastleProvider());
 
        // Load the digest file from S3 (using Amazon S3 Client) or from your local copy
        JSONObject digestFile = loadDigestFileInMemory(digestS3Bucket, digestS3Object);
 
        // Check that the digest file has been retrieved from its original location
        if (!digestFile.getString("digestS3Bucket").equals(digestS3Bucket) ||
                !digestFile.getString("digestS3Object").equals(digestS3Object)) {
            System.err.println("Digest file has been moved from its original location.");
        } else {
            // Compute digest file hash
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(convertToByteArray(digestFile));
            byte[] digestFileHash = messageDigest.digest();
            messageDigest.reset();
 
            // Compute the data to sign
            String dataToSign = String.format("%s%n%s/%s%n%s%n%s",
                                digestFile.getString("digestEndTime"),
                                digestFile.getString("digestS3Bucket"), digestFile.getString("digestS3Object"), // Constructing the S3 path of the digest file as part of the data to sign
                                Hex.encodeHexString(digestFileHash),
                                digestFile.getString("previousDigestSignature"));
 
            byte[] signatureContent = Hex.decodeHex(digestSignature);
 
            /*
                NOTE: 
                To find the right public key to verify the signature, call CloudTrail ListPublicKey API to get a list 
                of public keys, then match by the publicKeyFingerprint in the digest file. Also, the public key bytes 
                returned from ListPublicKey API are DER encoded in PKCS#1 format:
 
                PublicKeyInfo ::= SEQUENCE {
                    algorithm       AlgorithmIdentifier,
                    PublicKey       BIT STRING
                }
 
                AlgorithmIdentifier ::= SEQUENCE {
                    algorithm       OBJECT IDENTIFIER,
                    parameters      ANY DEFINED BY algorithm OPTIONAL
                }                
            */
            pkcs1PublicKeyBytes = getPublicKey(digestFile.getString("digestPublicKeyFingerprint")));
 
            // Transform the PKCS#1 formatted public key to x.509 format.
            RSAPublicKey rsaPublicKey = RSAPublicKey.getInstance(pkcs1PublicKeyBytes);
            AlgorithmIdentifier rsaEncryption = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, null);
            SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(rsaEncryption, rsaPublicKey);
 
            // Create the PublicKey object needed for the signature validation
            PublicKey publicKey = KeyFactory.getInstance("RSA", "BC").generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
 
            // Verify signature
            Signature signature = Signature.getInstance("SHA256withRSA", "BC");
            signature.initVerify(publicKey);
            signature.update(dataToSign.getBytes("UTF-8"));
 
            if (signature.verify(signatureContent)) {
                System.out.println("Digest file signature is valid, validating log files…");
                for (int i = 0; i < digestFile.getJSONArray("logFiles").length(); i++) {
 
                    JSONObject logFileMetadata = digestFile.getJSONArray("logFiles").getJSONObject(i);
 
                    // Compute log file hash
                    byte[] logFileContent = loadUncompressedLogFileInMemory(
                                                logFileMetadata.getString("s3Bucket"),
                                                logFileMetadata.getString("s3Object")
                                            );
                    messageDigest.update(logFileContent);
                     byte[] logFileHash = messageDigest.digest();
                    messageDigest.reset();
 
                    // Retrieve expected hash for the log file being processed
                    byte[] expectedHash = Hex.decodeHex(logFileMetadata.getString("hashValue"));
 
                    boolean signaturesMatch = Arrays.equals(expectedHash, logFileHash);
                    if (!signaturesMatch) {
                        System.err.println(String.format("Log file: %s/%s hash doesn't match.\tExpected: %s Actual: %s",
                               logFileMetadata.getString("s3Bucket"), logFileMetadata.getString("s3Object"),
                               Hex.encodeHexString(expectedHash), Hex.encodeHexString(logFileHash)));
                    } else {
                        System.out.println(String.format("Log file: %s/%s hash match",
                               logFileMetadata.getString("s3Bucket"), logFileMetadata.getString("s3Object")));
                    }
                }
 
            } else {
                System.err.println("Digest signature failed validation.");
            }
 
            System.out.println("Digest file validation completed.");
 
            if (chainValidationIsEnabled()) {
                // This enables the digests' chain validation
                validateDigestFile(
                        digestFile.getString("previousDigestS3Bucket"),
                        digestFile.getString("previousDigestS3Object"),
                        digestFile.getString("previousDigestSignature"));
            }
        }
    }
}
```