blob: aee8388113fefaa0120323fc44a5146f04faa2e5 [file] [log] [blame]
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from recipe_engine import recipe_api
class CloudKMSApi(recipe_api.RecipeApi):
"""API for interacting with CloudKMS using the LUCI cloudkms tool."""
def __init__(self, **kwargs):
super(CloudKMSApi, self).__init__(**kwargs)
self._cloudkms_bin = None
@property
def cloudkms_path(self):
"""Returns the path to LUCI cloudkms binary.
When the property is accessed the first time, cloudkms will be installed
using cipd.
"""
if self._cloudkms_bin is None:
cloudkms_dir = self.m.path.start_dir / 'cloudkms'
ensure_file = self.m.cipd.EnsureFile().add_package(
'infra/tools/luci/cloudkms/${platform}', 'latest')
self.m.cipd.ensure(cloudkms_dir, ensure_file)
self._cloudkms_bin = cloudkms_dir / 'cloudkms'
return self._cloudkms_bin
def decrypt(self, kms_crypto_key, input_file, output_file):
"""Decrypt a ciphertext file with a CloudKMS key.
Args:
* kms_crypto_key (str) - The name of the encryption key, e.g.
projects/chops-kms/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY]
* input_file (Path) - The path to the input (ciphertext) file.
* output_file (Path) - The path to the output (plaintext) file. It is
recommended that this is inside api.path.cleanup_dir to ensure the
plaintext file will be cleaned up by recipe.
"""
self.m.step('decrypt', [
self.cloudkms_path, 'decrypt',
'-input', input_file,
'-output', output_file,
kms_crypto_key,
])
def sign(self,
kms_crypto_key,
input_file,
output_file,
service_account_creds_file=None):
"""Processes a plaintext and uploads the digest for signing by Cloud KMS.
Args:
* kms_crypto_key (str) - The name of the cryptographic key, e.g.
projects/[PROJECT]/locations/[LOC]/keyRings/[KEYRING]/cryptoKeys/[KEY]
* input_file (Path) - Path to file with data to operate on. Data for sign
and verify cannot be larger than 64KiB.
* output_file (Path) - Path to write output signature to a json file.
* service_account_creds_file (str) - Path to JSON file with service
account credentials to use.
"""
args = [
self.cloudkms_path,
'sign',
'-input',
input_file,
'-output',
output_file,
kms_crypto_key,
]
if service_account_creds_file:
args.append('-service-account-json')
args.append(service_account_creds_file)
self.m.step('sign', args)
def verify(self,
kms_crypto_key,
input_file,
signature_file,
output_file='-',
service_account_creds_file=None):
"""Verifies a signature that was previously created with a key stored in
CloudKMS.
Args:
* kms_crypto_key (str)- The name of the cryptographic public key,
e.g.
projects/[PROJECT]/locations/[LOC]/keyRings/[KEYRING]/cryptoKeys/[KEY]
* input_file (Path) - Path to file with data to operate on. Data for sign
and verify cannot be larger than 64KiB.
* signature_file (Path) - Path to read signature from.
* output_file (Path) - Path to write operation results
(successful verification or signature mismatch)to (use '-' for stdout).
* service_account_creds_file (str) - Path to JSON file with service
account credentials to use.
"""
args = [
self.cloudkms_path,
'verify',
'-input-sig',
signature_file,
'-input',
input_file,
'-output',
output_file,
kms_crypto_key,
]
if service_account_creds_file:
args.append('-service-account-json')
args.append(service_account_creds_file)
self.m.step('verify', args)