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 ajudá-lo a verificar um atestado, na linha de comando em que você vai verificá-lo, 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.

Script para analisar um atestado CAVIUM_V1_COMPRESSED

Crie um arquivo chamado parse_v1.py com o seguinte conteúdo:

#!/usr/bin/python
import io, gzip, sys, struct

HEADER = ">III"
TLV = ">II"
_CAVIUM_ATTESTATION_ASYM_OFFSET = 984
_CAVIUM_ATTESTATION_SYM_OFFSET = 24

def parse(attestation):
  # Parse Object (Cavium stores its structures in big endian)
  obj_handle, attr_count, obj_size = struct.unpack_from(HEADER, attestation, 0)
  obj_header_size = struct.calcsize(HEADER)
  attestation = attestation[obj_header_size:]
  while attr_count > 0:
    # Parse each Attribute.
    attr_type, attr_len = struct.unpack_from(TLV, attestation, 0)
    attestation = attestation[struct.calcsize(TLV):]
    print '0x%04x: %r' % (attr_type, attestation[:attr_len])
    attr_count -= 1
    attestation = attestation[attr_len:]
  return obj_header_size + obj_size

attest_unzipped = gzip.open(sys.argv.pop(), 'rb').read()
key_type = sys.argv.pop()
if key_type == 'symmetric':
  print "Symmetric Key Attestation"
  parse(attest_unzipped[_CAVIUM_ATTESTATION_SYM_OFFSET:])
else:
  print "Public Key Attestation"
  offset = parse(attest_unzipped[_CAVIUM_ATTESTATION_ASYM_OFFSET:])
  print 'Private Key Attestation'
  parse(attest_unzipped[(_CAVIUM_ATTESTATION_ASYM_OFFSET + offset):])

Script para analisar um atestado CAVIUM_V2_COMPRESSED

Crie um arquivo chamado parse_v2.py com o seguinte conteúdo.

#!/usr/bin/python
import io, gzip, sys, struct

RESPONSE_HEADER = ">IIII"
INFO_HEADER = ">HHHH"
OBJ_HEADER = ">III"
TLV = ">II"
SIGNATURE_SIZE = 256

def parse(attestation):
  # Parse Object
  obj_handle, attr_count, obj_size = struct.unpack_from(OBJ_HEADER, attestation, 0)
  obj_header_size = struct.calcsize(OBJ_HEADER)
  attestation = attestation[obj_header_size:]
  while attr_count > 0:
    # Parse each Attribute.
    attr_type, attr_len = struct.unpack_from(TLV, attestation, 0)
    attestation = attestation[struct.calcsize(TLV):]
    print '0x%04x: %r' % (attr_type, attestation[:attr_len])
    attr_count -= 1
    attestation = attestation[attr_len:]
  return obj_header_size + obj_size

attest_unzipped = gzip.open(attest_filename, 'rb').read()

# Parse headers (Cavium stores its structures in big endian)
_, _, totalsize, bufsize = struct.unpack_from(RESPONSE_HEADER, attest_unzipped, 0)
attribute_offset = totalsize - (bufsize + SIGNATURE_SIZE)
attestation = attest_unzipped[attribute_offset:]
version, _, offset1, offset2 = struct.unpack_from(INFO_HEADER, attestation, 0)

if offset2 > 0:
  print "Public Key Attestation"
  parse(attestation[offset1:])
  print "Private Key Attestation"
  parse(attestation[offset2:])
else:
  print "Symmetric Key Attestation"
  parse(attestation[offset1:])

Script para verificar uma chave pública

Para ajudá-lo a verificar uma chave pública, crie um arquivo chamado verify_pubkey.py com o conteúdo a seguir.

#!/usr/bin/env python
import sys

public_key_file = sys.argv.pop()
parsed_attest_file = sys.argv.pop()
with open(public_key_file, 'r') as public_key_data:
  # remove the "BEGIN" and "END" line.
  publickey = "".join(public_key_data.read().split('\n')[1:-2])
  publickey = base64.b64decode(publickey)
  # KCV is the first 6 bytes of the SHA1 digest of the key.
  kcv = hashlib.sha1(publickey).hexdigest()[:6]
  # EKCV is the SHA256 digest of the key
  ekcv = hashlib.sha256(publickey).hexdigest()

  with open(parsed_attest_file, 'r') as parsed_attest_data:
    if kcv in parsed_attest_data.read() and ekcv in parsed_attest_data.read():
      print 'Public key matched with attestation.'
    else:
      print 'Public key not matched with attestation.'
      attest_lines = parsed_attest_data.readlines()
      # field 0x0173 corresponds to KCV,
      # field 1003 (Custom Cavium) corresponds to EKCV
      kcv_lines = [line for line in attest_lines (if line.startswith('0x0173:') or if line.startswith('0x1003:'))]
      print(kcv_lines)

Recuperar o arquivo de atestado

Você pode recuperar o atestado para uma versão de chave criptográfica usando o console do Google Cloud Platform ou a linha de comando.

Console

  1. Acesse a página Chaves criptográficas no console do GCP.
    Acessar a página "Chaves criptográficas"

  2. Clique no nome do keyring que contém a chave com a versão que você quer atestar.

  3. Clique na chave com a versão que você quer atestar.

  4. Para a versão da chave que você quer atestar, clique no ícone Mais (três pontos verticais).

  5. Clique em Conseguir atestado.

  6. Na caixa de diálogo Conseguir atestado, clique em Fazer o download. O download do arquivo de atestado é feito no seu computador.

O formato do nome do arquivo de atestado é [KEYRING]-[KEY]-[KEYVERSION]-[ATTESTATION-FORMAT]-attestation.dat.

Linha de comando

  1. Clique no botão Ativar o Google Cloud Shell na parte superior da janela do console. Ativar o Google Cloud Shell Uma sessão do Cloud Shell é aberta em um novo frame na parte inferior do console e é exibido um prompt de linha de comando. A inicialização da sessão do shell pode levar alguns segundos. Seção do Cloud Shell

  2. Para recuperar o formato de atestado da chave a ser atestada, use o comando gcloud alpha kms keys version describe no prompt da linha de comando do Cloud Shell.

    gcloud alpha kms keys versions describe [KEY_VERSION] \
      --key [KEY_NAME] \
      --location [LOCATION] \
      --keyring [KEY_RING]
    

    A saída deste comando mostra o formato de atestado da versão da chave, necessária para a próxima etapa.

  3. Para recuperar o atestado para a chave a ser atestada, use o comando gcloud alpha kms keys version describe, no prompt da linha de comando do Cloud Shell, substituindo [ATTESTATION-FORMAT] pelo formato de atestado recuperado na etapa anterior. A sinalização --attestation-file especifica o caminho e o destino do nome do arquivo para o atestado recuperado.

    gcloud alpha kms keys versions describe [KEY_VERSION] \
      --key [KEY_NAME] \
      --location [LOCATION] \
      --keyring [KEY_RING] \
      --attestation-file \
      [KEYRING]-[KEY]-[KEYVERSION]-[ATTESTATION-FORMAT]-attestation.dat
    

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|cavium].pem
    

    Substitua [LOCATION] por uma das regiões compatíveis com o Cloud HSM. Substitua [google|cavium] por google ou cavium. Veja um exemplo para o local us-west e a 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|cavium].pem -text
    
  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.

    python verify.py \
      cloud-kms-prod-[LOCATION]-[google|cavium].pem \
      [KEYRING]-[KEY]-[KEYVERSION]-[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 que pode ser visualizado no Cloud KMS.

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

python parse_v1.py [symmetric|asymmetric] \
[KEYRING]-[KEY]-[KEYVERSION]-[ATTESTATION-FORMAT]-attestation.dat > parsed.dat

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

python parse_v2.py \
[KEYRING]-[KEY]-[KEYVERSION]-[ATTESTATION-FORMAT]-attestation.dat > parsed.dat

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

Para verificar o código da versão da chave

Você pode verificar se o hash SHA-256 do código do recurso da versão-chave está no atestado.

  1. Consiga o código do recurso da versão da chave para a versão da chave. É possível usar o Console do GCP para conseguir o código do recurso da versão da chave ou executar o comando gcloud a seguir:

    gcloud alpha kms keys versions list \
      --location [LOCATION] \
      --keyring [KEY_RING] --key [KEY]
    
  2. Na linha de comando, atribua resource_name ao código do recurso da versão da chave que você acabou de recuperar.

    resource_name=projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]/cryptoKeyVersions/[VERSION]
    
  3. Execute o script de atestado para corresponder o hash SHA-256 do código do recurso da versão da chave que você recuperou na Etapa 1 ao que está no atestado.

    echo -n $resource_name | sha256sum | cut -d ' ' -f 1 | grep -f - parsed.dat
    

Para verificar as propriedades das chaves

É possível ver as propriedades das chaves. Por exemplo, se a chave pode ou não ser extraída, ou quais operações criptográficas são compatíveis com ela. Essas propriedades correspondem aos campos no padrão PKCS#11.

Para determinar se uma chave é extraível, examine o campo 0x0162:

grep '0x0162:' parsed.dat

Para determinar o tipo de chave, examine o campo 0x0100. Os tipos de chave também são enumerados no padrão PCKS#11 com o prefixo CKK_*.

grep '0x0100:' parsed.dat

Para verificar a chave pública

Para chaves assimétricas, você pode verificar se o par de chaves gerado corresponde à chave pública. Você pode comparar o Key Checksum Value (KCV, na sigla em inglês) e o Extended KCV (EKCV, na sigla em inglês) da chave pública e combiná-los com o que está no atestado.

  1. Recupere a chave pública no local.

    gcloud alpha kms keys versions get-public-key \
      [KEY_VERSION] --location [LOCATION] \
      --keyring [KEY_RING] --key [KEY] \
      --output-file /tmp/key.pub
    

    Além de usar o gcloud, é possível recuperar a chave pública usando o Console do GCP e a API do Cloud KMS.

  2. Execute o script para verificar a chave pública.

    python verify_pubkey.py parsed.dat /tmp/key.pub
    

Mais informações

  • Verifique um atestado para determinar se uma versão de chave foi criada dentro de um HSM. Como a verificação é intencionalmente independente do Google, não é possível confirmar um atestado usando o console do Google Cloud Platform, a API Cloud KMS ou a linha de comando gcloud.
Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…