对证明进行验证

对于在 Cloud HSM 中创建的密钥,您可以选择请求证明语句,以提供密钥确实受 HSM 保护的证据。该语句是由物理硬件直接加密签名的令牌,可由用户进行验证。本主题介绍如何对证明语句签名进行验证并确定证明语句是否与密钥版本相匹配。

本主题中的示例适用于 Linux 环境。

准备工作

用于对证明进行验证的脚本

为了便于您对证明进行验证,请在要在其中验证证明的命令行创建 verify.py。如果您使用的是 Cloud Shell,则可以使用代码编辑器创建此文件。对此文件使用以下内容。

#!/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!')

用于解析证明的脚本

因为证明有两种格式:CAVIUM_V1_COMPRESSEDCAVIUM_V2_COMPRESSED,所以有两种不同的脚本可用于解析证明。

用于解析 CAVIUM_V1_COMPRESSED 证明的脚本

使用以下内容创建名为 parse_v1.py 的文件。

#!/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):])

用于解析 CAVIUM_V2_COMPRESSED 证明的脚本

使用以下内容创建名为 parse_v2.py 的文件。

#!/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:])

用于验证公钥的脚本

为了便于您验证公钥,请使用以下内容创建名为 verify_pubkey.py 的文件。

#!/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)

检索证明文件

您可以使用 Google Cloud Platform Console 或命令行来检索加密密钥版本的证明。

Console

  1. 转到 GCP Console 中的加密密钥页面。
    转到“加密密钥”页面

  2. 点击密钥环的名称,该密钥环包含您要证明其密钥版本的密钥。

  3. 点击您要证明其密钥版本的密钥。

  4. 对于要证明的密钥版本,点击更多图标(3 个垂直点)。

  5. 点击获取证明

  6. 获取证明对话框中,点击下载。证明文件将下载到您的计算机。

证明文件名称的格式为 [KEYRING]-[KEY]-[KEYVERSION]-[ATTESTATION-FORMAT]-attestation.dat

命令行

  1. 点击控制台窗口顶部的 Activate Cloud Shell 按钮。 Activate Google Cloud Shell一个 Cloud Shell 会话随即会在控制台底部的新框内打开,并显示命令行提示符。该 Shell 会话可能需要几秒钟才能完成初始化。 Cloud Shell 会话

  2. 在 Cloud Shell 命令行提示符处,使用 gcloud alpha kms keys version describe 命令检索要证明的密钥的证明格式。

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

    此命令的输出显示密钥版本的证明格式,您将在下一步中使用该格式。

  3. 在 Cloud Shell 命令行提示符处,使用 gcloud alpha kms keys version describe 命令检索要证明的密钥的证明,将 [ATTESTATION-FORMAT] 替换为您在上一步中检索到的证明格式。--attestation-file 标志为检索到的证明指定路径地址和文件名格式。

    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
    

对密钥进行证明

证明的签名可以通过两种证书进行验证。其中一个证书通向 Google 证书授权机构 (CA),另一个证书通向 Cavium CA.

  1. 检索要使用的 CA 的证书链。

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

    [LOCATION] 替换为 Cloud HSM 支持的区域之一。将 [google|cavium] 替换为 googlecavium。以下是 us-west 位置和 Google CA 的示例:

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

    要显示证书的内容,请运行以下命令:

    openssl x509 -in cloud-kms-prod-[LOCATION]-[google|cavium].pem -text
    
  2. 安装 OpenSSL 的 Python 封装容器。

    pip install --user pyopenssl
    
  3. 在 Cloud Shell 命令行提示符处,运行验证工具。

    python verify.py \
      cloud-kms-prod-[LOCATION]-[google|cavium].pem \
      [KEYRING]-[KEY]-[KEYVERSION]-[ATTESTATION-FORMAT]-attestation.dat
    

    验证工具使用 HSM 证书软件包中提供的公钥验证包含在证明文件末尾的签名。该软件包当前包含来自所有 HSM 的所有证书链,但不包括证书授权机构 (CA) 证书。

对证明文件中的值进行验证

除了对证明的签名进行验证之外,您还可以对证明的其他部分进行验证。例如,您可以使用可在 Cloud KMS 中查看的密钥版本 ID,对证明中的密钥版本 ID 进行验证。

如果要解析 CAVIUM_V1_COMPRESSED 格式的证明,请运行以下命令:

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

如果要解析 CAVIUM_V2_COMPRESSED 格式的证明,请运行以下命令:

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

parsed.dat 文件将在以下部分进行使用。

验证密钥版本 ID

您可以验证证明中是否存在密钥版本资源 ID 的 SHA-256 哈希。

  1. 获取密钥版本的密钥版本资源 ID。您可以使用 GCP Console 或运行以下 gcloud 命令来获取密钥版本资源 ID

    gcloud alpha kms keys versions list \
      --location [LOCATION] \
      --keyring [KEY_RING] --key [KEY]
    
  2. 在命令行中,将 resource_name 分配给刚刚检索的密钥版本资源 ID。

    resource_name=projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]/cryptoKeyVersions/[VERSION]
    
  3. 运行证明脚本,以将您在步骤 1 中检索到的密钥版本资源 ID 的 SHA-256 哈希与证明中存在的密钥版本资源 ID 相匹配。

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

对密钥属性进行验证

您可以查看各种密钥属性,例如密钥是否不可提取,以及密钥支持哪些加密操作。这些属性对应于 PKCS#11 标准中的相应字段。

要确定密钥是否可提取,请检查 0x0162 字段:

grep '0x0162:' parsed.dat

要确定密钥类型,请检查 0x0100 字段。密钥类型在 PCKS#11 标准中枚举,前缀为 CKK_*

grep '0x0100:' parsed.dat

验证公钥

对于非对称密钥,您可以验证生成的密钥对是否与公钥匹配。您可以比较公钥的密钥校验和值 (KCV) 和扩展 (EKCV),并将它们与证明中的相应值进行匹配。

  1. 在本地检索公钥。

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

    除了使用 gcloud,您还可以使用 GCP Console 和 Cloud KMS API 来检索公钥

  2. 运行脚本以验证公钥。

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

其他信息

  • 您可以对证明进行验证,以确定 HSM 内是否创建了密钥版本。由于验证有意独立于 Google 构建,因此您无法使用 Google Cloud Platform Console、Cloud KMS API 或 gcloud 命令行对证明进行验证。
此页内容是否有用?请给出您的反馈和评价:

发送以下问题的反馈:

此网页
Cloud KMS