For a key that is created in Cloud HSM, you can optionally request an attestation statement to provide evidence that the key is actually HSM-protected. The statement is a token that is cryptographically signed directly by the physical hardware and can be verified by the user. This topic describes how to verify the attestation statement signature and determine whether the attestation statement matches the key version.
The examples in this topic are for Linux environments.
Before you begin
Create the Python scripts shown below.
Script for verifying an attestation
To help you verify an attestation, at the command line where you are going to
verify the attestation, create
verify.py. If you are using the
Cloud Shell, you can use the Code editor to create this file. Use
the following contents for this file.
#!/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 for parsing an attestation
To help you parse an attestation, create a file named
parse.py with the
#!/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 "Private 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 for verifying a public key
To help you verify a public key, create a file named
verify_pubkey.py with the
#!/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)
Retrieve the attestation file
You can retrieve the attestation for a cryptographic key version using the Google Cloud Platform Console or the command line.
Go to the Cryptographic Keys page in the GCP Console.
Go to the Cryptographic Keys page
Click the name of the key ring that contains the key whose key version you want to attest.
Click the key whose key version you want to attest.
For the key version that you want to attest, click the More icon (3 vertical dots).
Click Get attestation.
In the Get attestation dialog, click Download. The attestation file is downloaded to your computer.
The format for the name of the attestation file is
[KEYRING]-[KEY]-[KEYVERSION]-attestation.dat. When you run the example
commands in the remainder of this topic, replace
attestation.dat with the
name of the file that you downloaded.
Click the Activate Google Cloud Shell button at the top of the console window. A Cloud Shell session opens inside a new frame at the bottom of the console and displays a command-line prompt. It can take a few seconds for the shell session to be initialized.
At the Cloud Shell command-line prompt, use the
gcloud alpha kms keys version describecommand to retrieve the attestation for the key that you want to attest. The
--attestation-fileflag specifies the path and filename destination for the retrieved attestation.
gcloud alpha kms keys versions describe [KEY_VERSION] \ --key [KEY_NAME] \ --location [LOCATION] \ --keyring [KEY_RING] \ --attestation-file attestation.dat
Attest a key
The signature of an attestation can be verified by two certificates. One of the certificates leads up to the Google certificate authority (CA), and the other certificate leads up to the Cavium CA.
Retrieve the certificate chain for the CA that you want to use.
curl -O https://www.gstatic.com/cloudhsm/cloud-kms-prod-[LOCATION]-[google|cavium].pem
[LOCATION]with one of the regions supported by Cloud HSM. Replace
cavium. Here's an example for the
us-westlocation and the Google CA:
curl -O https://www.gstatic.com/cloudhsm/cloud-kms-prod-us-west1-google.pem
To display the contents of the certificate, run:
openssl x509 -in cloud-kms-prod-[LOCATION]-[google|cavium].pem -text
Install the Python wrapper for OpenSSL.
pip install --user pyopenssl
At the Cloud Shell command-line prompt, run the verification tool.
python verify.py \ cloud-kms-prod-[LOCATION]-[google|cavium].pem attestation.dat
The verification tool verifies the signature included at the end of the attestation file with the public key provided in the HSM certificate bundle. The bundle currently contains all certificate chains from all HSMs up to but not including the certificate authority (CA) certificate.
Verifying values in the attestation file
In addition to verifying the signature for the attestation, you can verify other parts of the attestation. For example, you can verify the key version ID in the attestation with the key version ID that is viewable in Cloud KMS.
Run the following to parse the attestation file.
python parse.py [symmetric|asymmetric] attestation.dat > parsed.dat
parsed.dat file will be used for the following sections.
To verify the key version ID
You can verify whether the SHA-256 hash of the key version resource ID is present in the attestation.
Get the key version resource ID for the key version. You can use the GCP Console to get the key version resource ID or you can run the following
gcloud alpha kms keys versions list \ --location [LOCATION] \ --keyring [KEY_RING] --key [KEY]
At the command line, assign
resource_nameto the key version resource ID that you just retrieved.
Run the attestation script to match the SHA-256 hash of the key version resource ID that you retrieved in Step 1 with what is present in the attestation.
echo -n $resource_name | sha256sum | cut -d ' ' -f 1 | grep -f - parsed.dat
To verify key properties
You can view key properties such as whether the key is not extractable, whether it can be parked, and what cryptographic operations are supported by the key. These properties correspond to fields in the PKCS #11 standard.
To determine whether a key is extractable, examine the
grep '0x0162:' parsed.dat
To determine whether a key can be parked, examine the
grep '0x0002:' parsed.dat
To determine the key type, examine the
0x0100 field. Key types are also
enumerated in the PCKS#11 standard with prefix
grep '0x0100:' parsed.dat
To verify the public key
For asymmetric keys, you can verify that the key pair generated matches the public key. You can compare the Key Checksum Value (KCV) and Extended KCV (EKCV) of the public key and match them with what is present in the attestation.
Retrieve the public key locally.
gcloud alpha kms keys versions get-public-key \ [KEY_VERSION] --location [LOCATION] \ --keyring [KEY_RING] --key [KEY] \ --output-file /tmp/key.pub
In addition to using
gcloud, you can retrieve the public key using the GCP Console and the Cloud KMS API.
Run the script to verify the public key.
python verify_pubkey.py parsed.dat /tmp/key.pub
- You verify an attestation to determine whether a key version was created
inside an HSM. Because the verification is intentionally independent of Google,
you cannot verify an attestation using the Google Cloud Platform Console, the
Cloud KMS API, or the