Como verificar atestados

Para uma chave que é criada no Cloud HSM, é possível solicitar um atestado para fornecer evidência de que a chave está realmente protegida por HSM. A declaração é um token criptograficamente assinado de modo direto pelo hardware físico e pode ser verificado pelo usuário. Neste tópico, descrevemos como verificar a assinatura da declaração de atestado e determinar se ela corresponde à versão da chave.

Os exemplos neste tópico são para ambientes Linux.

Antes de começar

Script para verificar um atestado

Para ajudar a verificar um atestado, na linha de comando em que essa verificação será feita, crie verify.py. Se você estiver usando o Cloud Shell, poderá usar o editor de códigos para criar esse arquivo. Use o conteúdo a seguir para este arquivo.

#!/usr/bin/env python

from OpenSSL import crypto
import gzip,sys

_END_DELIM = "-----END CERTIFICATE-----"
def verify(blob, signature, certs_file):
  with open(certs_file, 'r') as cert_data:
    certs = [cert + _END_DELIM for cert in cert_data.read().split(_END_DELIM)
             if cert.strip(' \t\n\r')]
    for cert in certs:
      cert_obj = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
      try:
        crypto.verify(cert_obj, signature, blob, 'sha256')
        return True
      except crypto.Error as er:
        continue
    return False

attest_unzipped = gzip.open(sys.argv.pop(), 'rb').read()
certs_file = sys.argv.pop()
blob, signature = attest_unzipped[:-256], attest_unzipped[-256:]
verified = verify(blob, signature, certs_file)
print('Signature verified!' if verified else 'Signature failed!')

Script para analisar um atestado

Há dois tipos de atestado, CAVIUM_V1_COMPRESSED e CAVIUM_V2_COMPRESSED. Por isso, existe um script para analisar cada tipo.

<pre class="devsite-click-to-copy">
pip install --user "pyopenssl"
</pre>

Como fazer o download dos artefatos

Antes de atestar uma chave, faça o download dos certificados e da declaração de atestado.

Como fazer o download dos certificados

A assinatura de um atestado pode ser verificada usando um pacote de certificado que leva aos certificados raiz do Google e do fabricante HSM e assinado pelas autoridade de certificação (CAs, na sila em inglês) do Google e do fabricante HSM.

  1. Faça o download do pacote de certificado que leva o certificado raiz do Google.

    curl -O "https://www.gstatic.com/cloudhsm/cloud-kms-prod-location-google.pem"
    
  2. Faça o download do pacote de certificado que leva até o certificado raiz do fabricante do HSM.

    curl -O "https://www.gstatic.com/cloudhsm/cloud-kms-prod-location-cavium.pem"
    
  3. Faça o download do certificado raiz do Google.

    curl -O "https://www.gstatic.com/cloudhsm/roots/global_1498867200.pem"
    
  4. Faça o download e extraia o certificado raiz e a chave pública do fabricante do HSM.

    curl -O "https://www.marvell.com/content/dam/marvell/en/public-collateral/security-solutions/liquid_security_certificate.zip"
    
    unzip liquid_security_certificate.zip
    

    O certificado é extraído para liquid_security_certificate.crt e a chave pública é extraída para liquid_security_certificate.txt.

Como fazer o download da declaração de atestado

Você pode recuperar o atestado para uma versão de chave criptográfica.

IU da Web

  1. Acesse a página Chaves criptográficas no Console do Cloud.

    Acessar a página "Chaves criptográficas"

  2. Clique no keyring que contém a chave que você quer atestar.

  3. Clique na chave que você quer atestar.

  4. Clique em Ver maismore_vert para a versão da chave que você quer atestar e selecione Receber atestado.

  5. Na caixa de diálogo Conseguir atestado, clique em Fazer o download. O download do arquivo de atestado é feito no sistema local.

    O formato do nome do arquivo de atestado é [key-ring-name]-[key-name]-[key-version]-[attestation-format]-attestation.dat. Cada parte do nome do arquivo é separada por um hífen. Por esse motivo, o texto do marcador é delimitado por colchetes ([ e ]).

Linha de comando

Para usar o Cloud KMS na linha de comando, primeiro instale ou faça upgrade para a versão mais recente do SDK do Cloud.

gcloud kms keys versions describe key-version \
    --key key-name \
    --location location \
    --keyring key-ring-name \
    --attestation-file attestation-path \

Substitua as variáveis pelos seus próprios valores:

  • key-version. Versão da chave para receber o atestado (por exemplo, "1").

  • key-name. Nome da chave em que a versão existe (por exemplo, "my-key").

  • location. Nome do local do Cloud KMS onde está o keyring (por exemplo, "us-east1").

  • key-ring-name. Nome do keyring em que a chave existe (por exemplo, "my-key-ring").

  • attestation-path. Caminho para salvar o arquivo de atestado salvo (por exemplo, "my-attestation.dat").

Para informações sobre todas as sinalizações e valores possíveis, execute o comando com a sinalização --help.

C#

Para executar esse código, primeiro configure um ambiente de desenvolvimento C# e instale o SDK do Cloud KMS para C#.


using Google.Cloud.Kms.V1;
using System;

public class GetKeyVersionAttestationSample
{
    public byte[] GetKeyVersionAttestation(
      string projectId = "my-project", string locationId = "us-east1", string keyRingId = "my-key-ring", string keyId = "my-key", string keyVersionId = "123")
    {
        // Create the client.
        KeyManagementServiceClient client = KeyManagementServiceClient.Create();

        // Build the key name.
        CryptoKeyVersionName keyVersionName = new CryptoKeyVersionName(projectId, locationId, keyRingId, keyId, keyVersionId);

        // Call the API.
        CryptoKeyVersion result = client.GetCryptoKeyVersion(keyVersionName);

        // Only HSM keys have an attestation. For other key types, the attestion
        // will be nil.
        KeyOperationAttestation attestation = result.Attestation;
        if (attestation == null)
        {
            throw new InvalidOperationException("no attestation");
        }

        // Return the attestation.
        return attestation.Content.ToByteArray();
    }
}

Go

Para executar esse código, primeiro configure um ambiente de desenvolvimento Go e instale o SDK do Cloud KMS para Go.

import (
	"context"
	"fmt"
	"io"

	kms "cloud.google.com/go/kms/apiv1"
	kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
)

// getKeyVersionAttestation gets the attestation on a key version, if one
// exists.
func getKeyVersionAttestation(w io.Writer, name string) error {
	// name := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/123"

	// Create the client.
	ctx := context.Background()
	client, err := kms.NewKeyManagementClient(ctx)
	if err != nil {
		return fmt.Errorf("failed to create kms client: %v", err)
	}

	// Build the request.
	req := &kmspb.GetCryptoKeyVersionRequest{
		Name: name,
	}

	// Call the API.
	result, err := client.GetCryptoKeyVersion(ctx, req)
	if err != nil {
		return fmt.Errorf("failed to get key: %v", err)
	}

	// Only HSM keys have an attestation. For other key types, the attestion will
	// be nil.
	attestation := result.Attestation
	if attestation == nil {
		return fmt.Errorf("no attestation for %s", name)
	}

	// Print the attestation, hex-encoded.
	fmt.Fprintf(w, "%s: %x", attestation.Format, attestation.Content)
	return nil
}

Java

Para executar esse código, primeiro configure um ambiente de desenvolvimento Java e instale o SDK do Cloud KMS para Java.

import com.google.cloud.kms.v1.CryptoKeyVersion;
import com.google.cloud.kms.v1.CryptoKeyVersionName;
import com.google.cloud.kms.v1.KeyManagementServiceClient;
import com.google.cloud.kms.v1.KeyOperationAttestation;
import java.io.IOException;
import java.util.Base64;

public class GetKeyVersionAttestation {

  public void getKeyVersionAttestation() throws IOException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String locationId = "us-east1";
    String keyRingId = "my-key-ring";
    String keyId = "my-key";
    String keyVersionId = "123";
    getKeyVersionAttestation(projectId, locationId, keyRingId, keyId, keyVersionId);
  }

  // Get the attestations for a key version
  public void getKeyVersionAttestation(
      String projectId, String locationId, String keyRingId, String keyId, String keyVersionId)
      throws IOException {
    // Initialize client that will be used to send requests. This client only
    // needs to be created once, and can be reused for multiple requests. After
    // completing all of your requests, call the "close" method on the client to
    // safely clean up any remaining background resources.
    try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
      // Build the name from the project, location, key ring, and keyId.
      CryptoKeyVersionName keyVersionName =
          CryptoKeyVersionName.of(projectId, locationId, keyRingId, keyId, keyVersionId);

      // Get the key version.
      CryptoKeyVersion keyVersion = client.getCryptoKeyVersion(keyVersionName);

      // Only HSM keys have an attestation. For other key types, the attestion
      // will be nil.
      if (!keyVersion.hasAttestation()) {
        System.out.println("no attestation");
        return;
      }

      // Print the attestation, base64-encoded.
      KeyOperationAttestation attestation = keyVersion.getAttestation();
      String format = attestation.getFormat().toString();
      byte[] content = attestation.getContent().toByteArray();
      System.out.printf("%s: %s", format, Base64.getEncoder().encodeToString(content));
    }
  }
}

Node.js

Para executar esse código, primeiro configure um ambiente de desenvolvimento do Node.js e instale o SDK do Cloud KMS para Node.js.

//
// TODO(developer): Uncomment these variables before running the sample.
//
// const projectId = 'my-project';
// const locationId = 'us-east1';
// const keyRingId = 'my-key-ring';
// const keyId = 'my-key';
// const versionId = '123';

// Imports the Cloud KMS library
const {KeyManagementServiceClient} = require('@google-cloud/kms');

// Instantiates a client
const client = new KeyManagementServiceClient();

// Build the key version name
const versionName = client.cryptoKeyVersionPath(
  projectId,
  locationId,
  keyRingId,
  keyId,
  versionId
);

async function getKeyVersionAttestation() {
  const [version] = await client.getCryptoKeyVersion({
    name: versionName,
  });

  // Only HSM keys have an attestation. For other key types, the attestion
  // will be nil.
  const attestation = version.attestation;
  if (!attestation) {
    throw new Error('no attestation');
  }

  console.log(`Attestation: ${attestation.toString('base64')}`);
  return attestation.content;
}

return getKeyVersionAttestation();

PHP

Para executar esse código, primeiro saiba como usar o PHP no Google Cloud e instalar o SDK do Cloud KMS para PHP.

use Google\Cloud\Kms\V1\KeyManagementServiceClient;

function get_key_version_attestation_sample(
    string $projectId = 'my-project',
    string $locationId = 'us-east1',
    string $keyRingId = 'my-key-ring',
    string $keyId = 'my-key',
    string $versionId = '123'
) {
    // Create the Cloud KMS client.
    $client = new KeyManagementServiceClient();

    // Build the key name.
    $keyVersionName = $client->cryptokeyVersionName($projectId, $locationId, $keyRingId, $keyId, $versionId);

    // Call the API.
    $version = $client->getCryptoKeyVersion($keyVersionName);

    // Only HSM keys have an attestation. For other key types, the attestion
    // will be NULL.
    $attestation = $version->getAttestation();
    if (!$attestation) {
        throw new Exception('no attestation - attestations only exist on HSM keys');
    }

    printf('Got key attestation: %s' . PHP_EOL, $attestation->getContent());
    return $attestation;
}

Python

Para executar esse código, primeiro configure um ambiente de desenvolvimento Python e instale o SDK do Cloud KMS para Python.

def get_key_version_attestation(project_id, location_id, key_ring_id, key_id, version_id):
    """
    Get an HSM-backend key's attestation.

    Args:
        project_id (string): Google Cloud project ID (e.g. 'my-project').
        location_id (string): Cloud KMS location (e.g. 'us-east1').
        key_ring_id (string): ID of the Cloud KMS key ring (e.g. 'my-key-ring').
        key_id (string): ID of the key to use (e.g. 'my-key').
        version_id (string): ID of the version to use (e.g. '1').

    Returns:
        Attestation: Cloud KMS key attestation.

    """

    # Import the client library.
    from google.cloud import kms

    # Import base64 for printing the attestation.
    import base64

    # Create the client.
    client = kms.KeyManagementServiceClient()

    # Build the key version name.
    key_version_name = client.crypto_key_version_path(project_id, location_id, key_ring_id, key_id, version_id)

    # Call the API.
    version = client.get_crypto_key_version(key_version_name)

    # Only HSM keys have an attestation. For other key types, the attestion
    # will be None.
    attestation = version.attestation
    if not attestation:
        raise 'no attestation - attestations only exist on HSM keys'

    encoded_attestation = base64.b64encode(attestation.content)
    print('Got key attestation: {}'.format(encoded_attestation))
    return attestation

Ruby

Para executar esse código, primeiro configure um ambiente de desenvolvimento Ruby e instale o SDK do Cloud KMS para Ruby.

# TODO(developer): uncomment these values before running the sample.
# project_id  = "my-project"
# location_id = "us-east1"
# key_ring_id = "my-key-ring"
# key_id      = "my-key"
# version_id  = "123"

# Require the library.
require "google/cloud/kms"

# Create the client.
client = Google::Cloud::Kms.new

# Build the key version name.
key_version_name = client.crypto_key_version_path project_id, location_id, key_ring_id, key_id, version_id

# Call the API.
version = client.get_crypto_key_version key_version_name

# Only HSM keys have an attestation. For other key types, the attestion will
# be nil.
attestation = version.attestation
unless attestation
  raise "no attestation"
end

puts "Attestation: #{Base64.strict_encode64 attestation.content}"

Atestar uma chave

A assinatura de um atestado pode ser verificada por dois certificados. Um dos certificados leva até a autoridade de certificação (CA, na sigla em inglês) do Google, e o outro certificado leva à CA do Cavium.

  1. Recupere a cadeia de certificados da CA que você quer usar.

    curl -O https://www.gstatic.com/cloudhsm/cloud-kms-prod-[location]-[google-or-cavium].pem
    

    Substitua location por uma das regiões compatíveis com o Cloud HSM. Substitua [google-or-cavium] por google ou cavium. Veja a seguir um exemplo de local us-west1 e de CA do Google:

    curl -O https://www.gstatic.com/cloudhsm/cloud-kms-prod-us-west1-google.pem
    

    Para exibir o conteúdo do certificado, execute:

    openssl x509 \
      -in cloud-kms-prod-[location]-[google-or-cavium].pem \
      -text
    

    Cada parte do nome do arquivo é separada por um hífen. Por esse motivo, o texto do marcador é delimitado por colchetes ([ e ]).

  2. Instale o wrapper do Python para o OpenSSL.

    pip install --user pyopenssl
    
  3. No prompt de linha de comando do Cloud Shell, execute a ferramenta de verificação. Cada parte do nome do arquivo é separada por um hífen. Por esse motivo, o texto do marcador é delimitado por colchetes ([ e ]).

    python verify.py \
     cloud-kms-prod-[location]-[google-or-cavium].pem \
     [key-ring-name]-[key-name]-[key-version]-[attestation-format]-attestation.dat
    

    Essa ferramenta verifica a assinatura incluída no final do arquivo de atestado com a chave pública fornecida no pacote de certificado do HSM. Atualmente, o pacote contém todas as cadeias de certificados de todos os HSMs, mas não inclui o certificado da autoridade de certificação (CA).

Como verificar valores no arquivo de atestado

Além de verificar a assinatura do atestado, você pode verificar outras partes do dele. Por exemplo, é possível verificar o código da versão da chave no atestado com o código da versão da chave visível no Cloud Key Management Service.

Cada parte do nome do arquivo é separada por um hífen. Por esse motivo, o texto do marcador está entre colchetes ([ e ]) nos exemplos abaixo.

Se estiver analisando um atestado no formato CAVIUM_V1_COMPRESSED, execute o seguinte comando:

python parse_v1.py symmetric-or-asymmetric \
  [key-ring-name]-[key-name]-[key-version]-[attestation-format]-attestation.dat > parsed.dat

Se estiver analisando um atestado no formato CAVIUM_V2_COMPRESSED, execute o seguinte comando:

python parse_v2.py \
[key-ring-name]-[key-name]-[key-version]-[attestation-format]-attestation.dat > parsed.dat

O arquivo parsed.dat será usado nas seções a seguir.

Para verificar o ID da versão da chave

É possível verificar se o hash SHA-256 do ID do recurso da versão da chave está presente no atestado. O nome do recurso da chave faz parte do campo 0x0102 ou do campo de ID da chave no arquivo de atestado. O ID da chave é composto de dois resumos de hash SHA-256 concatenados no formato hexadecimal. O segundo deve corresponder ao nome do recurso da chave.

  1. Consiga o ID do recurso da versão da chave para a versão da chave. Você pode usar o Console do Cloud para conseguir o código do recurso da versão da chave ou executar o seguinte comando:

    gcloud kms keys versions list \
       --location location \
       --keyring key-ring-name \
       --key key-name
    
  2. Na linha de comando, atribua resource_name ao ID do recurso da versão da chave que você acabou de recuperar.

    RESOURCE_NAME="projects/project-id/locations/location/keyRings/key-ring-name/cryptoKeys/key-name/cryptoKeyVersions/key-version"
    
  3. Como o script de análise despeja todos os campos de atestado no formato hexadecimal, o ID da chave teria sido formatado duas vezes em hexadecimal. Uma vez ao criar o ID da chave e outra ao analisar o atestado. Para verificar se o nome do recurso corresponde ao ID da chave, converta-o em um resumo hexadecimal de SHA-256, reverta uma conversão hexadecimal do ID da chave no arquivo de atestado e compare os dois.

    RESOURCE_NAME_HEX="$(echo -n ${RESOURCE_NAME} | openssl dgst -sha256 -hex | awk '{print $2}')"
    
  4. O script de análise despeja todos os campos de atestado no formato hexadecimal, e o código da chave é codificado internamente em hexadecimal. Defina a variável de ambiente KEYID_HEX como o valor do código da chave com uma camada de codificação hexadecimal decodificada:

    KEYID_HEX=$(grep -m 1 0x0102 /path/to/attestation.dat | awk '{print $2}' | xxd -p -r)
    
  5. Compare os valores de RESOURCE_NAME_HEX e KEYID_HEX como strings:

    test  ${RESOURCE_NAME_HEX} == ${KEYID_HEX} || echo "Values don't match"
    

    Se os valores forem correspondentes, nenhuma saída será retornada e o comando será encerrado com o código 0.

Como verificar outras propriedades da chave

Você pode visualizar várias propriedades de chave, que correspondem aos campos no padrão PKCS #11. Use os seguintes exemplos como guias para verificar outras propriedades da chave.

  • Se uma chave é extraível, ela é armazenada no campo 0x0102 da saída analisada. Para determinar se uma chave pode ser extraída, observe o campo 0x0162: Um valor de \x01 é true e um valor de \x00 é false.

    Chaves do Cloud HSM não podem ser extraídas.

    grep '0x0162:' /path/to/attestation.dat
    
  • Como a chave chegou ao HSM, se ela foi criada diretamente ou importada, é armazenado no campo 0x0163. Se a chave tiver sido criada localmente no HSM, o campo será definido como \x01. O campo de uma chave importada é definido como \x00.

    Você pode inferir algumas informações sobre como a chave chegou ao HSM. Se a chave foi criada no Cloud HSM, isso significa que ela nunca foi armazenada sem criptografia fora de um HSM. Se a chave foi importada, o mecanismo de importação garante que ela esteja protegida durante o processo de importação e no Cloud HSM posteriormente.

    grep '0x0163:' /path/to/attestation.dat
    
  • O tipo de chave é armazenado no campo 0x0100. Os tipos de chave são documentados no padrão PCKS#11 com o prefixo CKK_*. Por exemplo, uma chave AES tem um tipo de \x1f.

    grep '0x0100:' /path/to/attestation.dat
    

Mais informações

Verifique um atestado para determinar se uma versão de chave foi criada em um HSM. Como a verificação é intencionalmente independente do Google, não é possível verificar um atestado usando o Console do Cloud, a API Cloud KMS ou a ferramenta gcloud.