releasetools: Support using payload_signer.

For A/B OTAs, by default it calls 'openssl pkeyutl' to sign the payload
and metadata with the package private key. If the private key cannot be
accessed directly, a payload signer that knows how to do that should be
supplied via "--payload_signer <signer>".

The signer will be called with "-inkey <path_to_private_key>",
"-in <input_file>" and "-out <output_file>" parameters.

Test: Use a dummy signer, call 'ota_from_target_files.py --payload_signer <signer> <target_files.zip> <ota.zip>' and verify the signatures in the generated package.
Bug: 28701652
Change-Id: I26cfdd3fdba6fc90799221741b75426988e46fd3
(cherry picked from commit dea0f8bfed)
This commit is contained in:
Tao Bao
2016-06-20 17:55:06 -07:00
parent 35c9b1243f
commit 1a5e1d18a7

View File

@@ -108,6 +108,14 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package
Generate a log file that shows the differences in the source and target Generate a log file that shows the differences in the source and target
builds for an incremental package. This option is only meaningful when builds for an incremental package. This option is only meaningful when
-i is specified. -i is specified.
--payload_signer <signer>
Specify the signer when signing the payload and metadata for A/B OTAs.
By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
with the package private key. If the private key cannot be accessed
directly, a payload signer that knows how to do that should be specified.
The signer will be supplied with "-inkey <path_to_key>",
"-in <input_file>" and "-out <output_file>" parameters.
""" """
import sys import sys
@@ -154,6 +162,7 @@ OPTIONS.cache_size = None
OPTIONS.stash_threshold = 0.8 OPTIONS.stash_threshold = 0.8
OPTIONS.gen_verify = False OPTIONS.gen_verify = False
OPTIONS.log_diff = None OPTIONS.log_diff = None
OPTIONS.payload_signer = None
def MostPopularKey(d, default): def MostPopularKey(d, default):
"""Given a dict, return the key corresponding to the largest """Given a dict, return the key corresponding to the largest
@@ -1155,7 +1164,9 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
"default_system_dev_certificate", "default_system_dev_certificate",
"build/target/product/security/testkey") "build/target/product/security/testkey")
# A/B updater expects key in RSA format. # A/B updater expects a signing key in RSA format. Gets the key ready for
# later use in step 3, unless a payload_signer has been specified.
if OPTIONS.payload_signer is None:
cmd = ["openssl", "pkcs8", cmd = ["openssl", "pkcs8",
"-in", OPTIONS.package_key + OPTIONS.private_key_suffix, "-in", OPTIONS.package_key + OPTIONS.private_key_suffix,
"-inform", "DER", "-nocrypt"] "-inform", "DER", "-nocrypt"]
@@ -1165,7 +1176,7 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
p1.communicate() p1.communicate()
assert p1.returncode == 0, "openssl pkcs8 failed" assert p1.returncode == 0, "openssl pkcs8 failed"
# Stage the output zip package for signing. # Stage the output zip package for package signing.
temp_zip_file = tempfile.NamedTemporaryFile() temp_zip_file = tempfile.NamedTemporaryFile()
output_zip = zipfile.ZipFile(temp_zip_file, "w", output_zip = zipfile.ZipFile(temp_zip_file, "w",
compression=zipfile.ZIP_DEFLATED) compression=zipfile.ZIP_DEFLATED)
@@ -1222,21 +1233,29 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
signed_metadata_sig_file = common.MakeTempFile(prefix="signed-sig-", signed_metadata_sig_file = common.MakeTempFile(prefix="signed-sig-",
suffix=".bin") suffix=".bin")
# 3a. Sign the payload hash. # 3a. Sign the payload hash.
if OPTIONS.payload_signer is not None:
cmd = [OPTIONS.payload_signer,
"-inkey", OPTIONS.package_key + OPTIONS.private_key_suffix]
else:
cmd = ["openssl", "pkeyutl", "-sign", cmd = ["openssl", "pkeyutl", "-sign",
"-inkey", rsa_key, "-inkey", rsa_key,
"-pkeyopt", "digest:sha256", "-pkeyopt", "digest:sha256"]
"-in", payload_sig_file, cmd.extend(["-in", payload_sig_file,
"-out", signed_payload_sig_file] "-out", signed_payload_sig_file])
p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT) p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
p1.communicate() p1.communicate()
assert p1.returncode == 0, "openssl sign payload failed" assert p1.returncode == 0, "openssl sign payload failed"
# 3b. Sign the metadata hash. # 3b. Sign the metadata hash.
if OPTIONS.payload_signer is not None:
cmd = [OPTIONS.payload_signer,
"-inkey", OPTIONS.package_key + OPTIONS.private_key_suffix]
else:
cmd = ["openssl", "pkeyutl", "-sign", cmd = ["openssl", "pkeyutl", "-sign",
"-inkey", rsa_key, "-inkey", rsa_key,
"-pkeyopt", "digest:sha256", "-pkeyopt", "digest:sha256"]
"-in", metadata_sig_file, cmd.extend(["-in", metadata_sig_file,
"-out", signed_metadata_sig_file] "-out", signed_metadata_sig_file])
p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT) p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
p1.communicate() p1.communicate()
assert p1.returncode == 0, "openssl sign metadata failed" assert p1.returncode == 0, "openssl sign metadata failed"
@@ -1896,6 +1915,8 @@ def main(argv):
OPTIONS.gen_verify = True OPTIONS.gen_verify = True
elif o == "--log_diff": elif o == "--log_diff":
OPTIONS.log_diff = a OPTIONS.log_diff = a
elif o == "--payload_signer":
OPTIONS.payload_signer = a
else: else:
return False return False
return True return True
@@ -1924,6 +1945,7 @@ def main(argv):
"stash_threshold=", "stash_threshold=",
"gen_verify", "gen_verify",
"log_diff=", "log_diff=",
"payload_signer=",
], extra_option_handler=option_handler) ], extra_option_handler=option_handler)
if len(args) != 2: if len(args) != 2: