release-request-01b39c26-bf86-40a5-a7bf-8eb15c488673-for-git_oc-mr1-release-4080221 snap-temp-L23400000072087081
Change-Id: I16046ecda761163a4315d2e7078bdb7062e284c7
diff --git a/README.md b/README.md
index df6218f..ea35f02 100644
--- a/README.md
+++ b/README.md
@@ -303,6 +303,7 @@
[--setup_rootfs_from_kernel /path/to/image.bin] \
[--chain_partition part_name:rollback_index_location:/path/to/key1.bin] \
[--signing_helper /path/to/external/signer] \
+ [--signing_helper_with_files /path/to/external/signer_with_files] \
[--print_required_libavb_version] \
[--append_to_release_string STR]
@@ -319,6 +320,7 @@
[--setup_rootfs_from_kernel /path/to/image.bin] \
[--output_vbmeta_image OUTPUT_IMAGE] [--do_not_append_vbmeta_image] \
[--signing_helper /path/to/external/signer] \
+ [--signing_helper_with_files /path/to/external/signer_with_files] \
[--print_required_libavb_version] \
[--append_to_release_string STR] \
[--calc_max_image_size]
@@ -339,6 +341,7 @@
[--output_vbmeta_image OUTPUT_IMAGE] [--do_not_append_vbmeta_image] \
[--do_not_generate_fec] [--fec_num_roots FEC_NUM_ROOTS] \
[--signing_helper /path/to/external/signer] \
+ [--signing_helper_with_files /path/to/external/signer_with_files] \
[--print_required_libavb_version] \
[--append_to_release_string STR] \
[--calc_max_image_size]
@@ -398,6 +401,18 @@
/path/to/my_signing_program SHA256_RSA2048 /path/to/publickey.pem
+The `--signing_helper_with_files` is similar to `--signing_helper`
+except that a temporary file is used to communicate with the helper
+instead of `STDIN` and `STDOUT`. This is useful in situations where
+the signing helper is using code which is outputting diagnostics on
+`STDOUT` instead of `STDERR`. Here's an example invocation
+
+ /path/to/my_signing_program_with_files SHA256_RSA2048 \
+ /path/to/publickey.pem /tmp/path/to/communication_file
+
+where the last positional argument is a file that contains the data to
+sign. The helper should write the signature in this file.
+
The `append_vbmeta_image` command can be used to append an entire
vbmeta blob to the end of another image. This is useful for cases when
not using any vbmeta partitions, for example:
diff --git a/avbtool b/avbtool
index b742acc..db7c512 100755
--- a/avbtool
+++ b/avbtool
@@ -434,12 +434,14 @@
raise AvbError('Unknown algorithm type {}'.format(alg_type))
-def raw_sign(signing_helper, algorithm_name, signature_num_bytes, key_path,
+def raw_sign(signing_helper, signing_helper_with_files,
+ algorithm_name, signature_num_bytes, key_path,
raw_data_to_sign):
"""Computes a raw RSA signature using |signing_helper| or openssl.
Arguments:
signing_helper: Program which signs a hash and returns the signature.
+ signing_helper_with_files: Same as signing_helper but uses files instead.
algorithm_name: The algorithm name as per the ALGORITHMS dict.
signature_num_bytes: Number of bytes used to store the signature.
key_path: Path to the private key file. Must be PEM format.
@@ -452,23 +454,35 @@
Exception: If an error occurs.
"""
p = None
- if signing_helper is not None:
+ if signing_helper_with_files is not None:
+ signing_file = tempfile.NamedTemporaryFile()
+ signing_file.write(str(raw_data_to_sign))
+ signing_file.flush()
p = subprocess.Popen(
- [signing_helper, algorithm_name, key_path],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ [signing_helper_with_files, algorithm_name, key_path, signing_file.name])
+ retcode = p.wait()
+ if retcode != 0:
+ raise AvbError('Error signing')
+ signing_file.seek(0)
+ signature = bytearray(signing_file.read())
else:
- p = subprocess.Popen(
- ['openssl', 'rsautl', '-sign', '-inkey', key_path, '-raw'],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- (pout, perr) = p.communicate(str(raw_data_to_sign))
- retcode = p.wait()
- if retcode != 0:
- raise AvbError('Error signing: {}'.format(perr))
- signature = bytearray(pout)
+ if signing_helper is not None:
+ p = subprocess.Popen(
+ [signing_helper, algorithm_name, key_path],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ else:
+ p = subprocess.Popen(
+ ['openssl', 'rsautl', '-sign', '-inkey', key_path, '-raw'],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ (pout, perr) = p.communicate(str(raw_data_to_sign))
+ retcode = p.wait()
+ if retcode != 0:
+ raise AvbError('Error signing: {}'.format(perr))
+ signature = bytearray(pout)
if len(signature) != signature_num_bytes:
raise AvbError('Error signing: Invalid length of signature')
return signature
@@ -2334,10 +2348,13 @@
key_path, public_key_metadata_path, rollback_index,
flags, props, props_from_file, kernel_cmdlines,
setup_rootfs_from_kernel,
- include_descriptors_from_image, signing_helper,
+ include_descriptors_from_image,
+ signing_helper,
+ signing_helper_with_files,
release_string,
append_to_release_string,
- print_required_libavb_version):
+ print_required_libavb_version,
+ padding_size):
"""Implements the 'make_vbmeta_image' command.
Arguments:
@@ -2354,9 +2371,11 @@
setup_rootfs_from_kernel: None or file to generate from.
include_descriptors_from_image: List of file objects with descriptors.
signing_helper: Program which signs a hash and return signature.
+ signing_helper_with_files: Same as signing_helper but uses files instead.
release_string: None or avbtool release string to use instead of default.
append_to_release_string: None or string to append.
print_required_libavb_version: True to only print required libavb version.
+ padding_size: If not 0, pads output so size is a multiple of the number.
Raises:
AvbError: If a chained partition is malformed.
@@ -2378,13 +2397,19 @@
algorithm_name, key_path, public_key_metadata_path, descriptors,
chain_partitions, rollback_index, flags, props, props_from_file,
kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
- include_descriptors_from_image, signing_helper, release_string,
+ include_descriptors_from_image, signing_helper,
+ signing_helper_with_files, release_string,
append_to_release_string)
# Write entire vbmeta blob (header, authentication, auxiliary).
output.seek(0)
output.write(vbmeta_blob)
+ if padding_size > 0:
+ padded_size = round_to_multiple(len(vbmeta_blob), padding_size)
+ padding_needed = padded_size - len(vbmeta_blob)
+ output.write('\0' * padding_needed)
+
def _generate_vbmeta_blob(self, algorithm_name, key_path,
public_key_metadata_path, descriptors,
chain_partitions,
@@ -2393,6 +2418,7 @@
setup_rootfs_from_kernel,
ht_desc_to_setup,
include_descriptors_from_image, signing_helper,
+ signing_helper_with_files,
release_string, append_to_release_string):
"""Generates a VBMeta blob.
@@ -2422,6 +2448,7 @@
include_descriptors_from_image: List of file objects for which
to insert descriptors from.
signing_helper: Program which signs a hash and return signature.
+ signing_helper_with_files: Same as signing_helper but uses files instead.
release_string: None or avbtool release string.
append_to_release_string: None or string to append.
@@ -2598,7 +2625,9 @@
# Calculate the signature.
padding_and_hash = str(bytearray(alg.padding)) + binary_hash
- binary_signature.extend(raw_sign(signing_helper, algorithm_name,
+ binary_signature.extend(raw_sign(signing_helper,
+ signing_helper_with_files,
+ algorithm_name,
alg.signature_num_bytes, key_path,
padding_and_hash))
@@ -2705,7 +2734,8 @@
props_from_file, kernel_cmdlines,
setup_rootfs_from_kernel,
include_descriptors_from_image, calc_max_image_size,
- signing_helper, release_string, append_to_release_string,
+ signing_helper, signing_helper_with_files,
+ release_string, append_to_release_string,
output_vbmeta_image, do_not_append_vbmeta_image,
print_required_libavb_version):
"""Implementation of the add_hash_footer on unsparse images.
@@ -2733,6 +2763,7 @@
maximum image size leaving enough room for metadata with the
given |partition_size|.
signing_helper: Program which signs a hash and return signature.
+ signing_helper_with_files: Same as signing_helper but uses files instead.
release_string: None or avbtool release string.
append_to_release_string: None or string to append.
output_vbmeta_image: If not None, also write vbmeta struct to this file.
@@ -2823,7 +2854,8 @@
algorithm_name, key_path, public_key_metadata_path, [h_desc],
chain_partitions, rollback_index, flags, props, props_from_file,
kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
- include_descriptors_from_image, signing_helper, release_string,
+ include_descriptors_from_image, signing_helper,
+ signing_helper_with_files, release_string,
append_to_release_string)
# If the image isn't sparse, its size might not be a multiple of
@@ -2883,6 +2915,7 @@
setup_as_rootfs_from_kernel,
include_descriptors_from_image,
calc_max_image_size, signing_helper,
+ signing_helper_with_files,
release_string, append_to_release_string,
output_vbmeta_image, do_not_append_vbmeta_image,
print_required_libavb_version):
@@ -2919,6 +2952,7 @@
calculate the maximum image size leaving enough room for hashtree
and metadata with the given |partition_size|.
signing_helper: Program which signs a hash and return signature.
+ signing_helper_with_files: Same as signing_helper but uses files instead.
release_string: None or avbtool release string.
append_to_release_string: None or string to append.
output_vbmeta_image: If not None, also write vbmeta struct to this file.
@@ -3069,7 +3103,8 @@
algorithm_name, key_path, public_key_metadata_path, [ht_desc],
chain_partitions, rollback_index, flags, props, props_from_file,
kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
- include_descriptors_from_image, signing_helper, release_string,
+ include_descriptors_from_image, signing_helper,
+ signing_helper_with_files, release_string,
append_to_release_string)
padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -
len(vbmeta_blob))
@@ -3107,7 +3142,8 @@
def make_atx_certificate(self, output, authority_key_path, subject_key_path,
subject_key_version, subject,
- is_intermediate_authority, signing_helper):
+ is_intermediate_authority, signing_helper,
+ signing_helper_with_files):
"""Implements the 'make_atx_certificate' command.
Android Things certificates are required for Android Things public key
@@ -3129,6 +3165,7 @@
is_intermediate_authority: True if the certificate is for an intermediate
authority.
signing_helper: Program which signs a hash and returns the signature.
+ signing_helper_with_files: Same as signing_helper but uses files instead.
"""
signed_data = bytearray()
signed_data.extend(struct.pack('<I', 1)) # Format Version
@@ -3154,7 +3191,8 @@
padding_and_hash.extend(alg.padding)
hasher.update(signed_data)
padding_and_hash.extend(hasher.digest())
- signature.extend(raw_sign(signing_helper, algorithm_name,
+ signature.extend(raw_sign(signing_helper, signing_helper_with_files,
+ algorithm_name,
alg.signature_num_bytes, authority_key_path,
padding_and_hash))
output.write(signed_data)
@@ -3397,6 +3435,11 @@
metavar='APP',
default=None,
required=False)
+ sub_parser.add_argument('--signing_helper_with_files',
+ help='Path to helper used for signing using files',
+ metavar='APP',
+ default=None,
+ required=False)
sub_parser.add_argument('--public_key_metadata',
help='Path to public key metadata file',
metavar='KEY_METADATA',
@@ -3496,6 +3539,12 @@
sub_parser.add_argument('--output',
help='Output file name',
type=argparse.FileType('wb'))
+ sub_parser.add_argument('--padding_size',
+ metavar='NUMBER',
+ help='If non-zero, pads output with NUL bytes so '
+ 'its size is a multiple of NUMBER (default: 0)',
+ type=parse_number,
+ default=0)
self._add_common_args(sub_parser)
sub_parser.set_defaults(func=self.make_vbmeta_image)
@@ -3702,6 +3751,11 @@
metavar='APP',
default=None,
required=False)
+ sub_parser.add_argument('--signing_helper_with_files',
+ help='Path to helper used for signing using files',
+ metavar='APP',
+ default=None,
+ required=False)
sub_parser.set_defaults(func=self.make_atx_certificate)
sub_parser = subparsers.add_parser(
@@ -3764,9 +3818,11 @@
args.setup_rootfs_from_kernel,
args.include_descriptors_from_image,
args.signing_helper,
+ args.signing_helper_with_files,
args.internal_release_string,
args.append_to_release_string,
- args.print_required_libavb_version)
+ args.print_required_libavb_version,
+ args.padding_size)
def append_vbmeta_image(self, args):
"""Implements the 'append_vbmeta_image' sub-command."""
@@ -3786,7 +3842,9 @@
args.kernel_cmdline,
args.setup_rootfs_from_kernel,
args.include_descriptors_from_image,
- args.calc_max_image_size, args.signing_helper,
+ args.calc_max_image_size,
+ args.signing_helper,
+ args.signing_helper_with_files,
args.internal_release_string,
args.append_to_release_string,
args.output_vbmeta_image,
@@ -3815,7 +3873,9 @@
args.setup_rootfs_from_kernel,
args.setup_as_rootfs_from_kernel,
args.include_descriptors_from_image,
- args.calc_max_image_size, args.signing_helper,
+ args.calc_max_image_size,
+ args.signing_helper,
+ args.signing_helper_with_files,
args.internal_release_string,
args.append_to_release_string,
args.output_vbmeta_image,
@@ -3850,7 +3910,8 @@
args.subject_key_version,
args.subject.read(),
args.subject_is_intermediate_authority,
- args.signing_helper)
+ args.signing_helper,
+ args.signing_helper_with_files)
def make_atx_permanent_attributes(self, args):
"""Implements the 'make_atx_permanent_attributes' sub-command."""
diff --git a/test/avbtool_signing_helper_with_files_test.py b/test/avbtool_signing_helper_with_files_test.py
new file mode 100755
index 0000000..9811225
--- /dev/null
+++ b/test/avbtool_signing_helper_with_files_test.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+import subprocess
+import sys
+import errno
+import os
+
+def rsa_signer_with_files(argv):
+ if len(argv) != 4:
+ sys.stderr.write("Wrong number of arguments: {} <alg> <pub key> <file>\n".format(argv[0]))
+ return errno.EINVAL
+
+ signing_file = open(argv[3], mode='rw+')
+ data = signing_file.read()
+ if len(data) == 0:
+ sys.stderr.write("There is no input data\n")
+ return errno.EINVAL
+
+ if os.environ.get('SIGNING_HELPER_GENERATE_WRONG_SIGNATURE'):
+ # We're only called with this algorithm which signature size is 256.
+ assert argv[1] == 'SHA256_RSA2048'
+ signing_file.seek(0)
+ signing_file.write('X'*256)
+ return 0
+
+ if 'SIGNING_HELPER_TEST' not in os.environ or os.environ['SIGNING_HELPER_TEST'] == "":
+ sys.stderr.write("env SIGNING_HELPER_TEST is not set or empty\n")
+ return errno.EINVAL
+
+ test_file_name = os.environ['SIGNING_HELPER_TEST']
+ if os.path.isfile(test_file_name) and not os.access(test_file_name, os.W_OK):
+ sys.stderr.write("no permission to write into {} file\n".format(test_file_name))
+ return errno.EACCESS
+
+ p = subprocess.Popen(
+ ['openssl', 'rsautl', '-sign', '-inkey', argv[2], '-raw'],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+ (pout, _) = p.communicate(data)
+ retcode = p.wait()
+ if retcode != 0:
+ return retcode
+
+ signing_file.seek(0)
+ signing_file.write(pout)
+
+ with open(test_file_name, "w") as f:
+ f.write("DONE")
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(rsa_signer_with_files(sys.argv))
diff --git a/test/avbtool_unittest.cc b/test/avbtool_unittest.cc
index e8470d7..fbfa4dd 100644
--- a/test/avbtool_unittest.cc
+++ b/test/avbtool_unittest.cc
@@ -263,6 +263,35 @@
EXPECT_EQ('\n', s[20]);
}
+TEST_F(AvbToolTest, Padding) {
+ GenerateVBMetaImage("vbmeta.img",
+ "SHA256_RSA2048",
+ 0,
+ base::FilePath("test/data/testkey_rsa2048.pem"),
+ "--internal_release_string \"\"");
+
+ GenerateVBMetaImage("vbmeta_padded.img",
+ "SHA256_RSA2048",
+ 0,
+ base::FilePath("test/data/testkey_rsa2048.pem"),
+ "--internal_release_string \"\" --padding_size 4096");
+
+ base::FilePath vbmeta_path = testdir_.Append("vbmeta.img");
+ base::FilePath vbmeta_padded_path = testdir_.Append("vbmeta_padded.img");
+ int64_t vbmeta_size, vbmeta_padded_size;
+ ASSERT_TRUE(base::GetFileSize(vbmeta_path, &vbmeta_size));
+ ASSERT_TRUE(base::GetFileSize(vbmeta_padded_path, &vbmeta_padded_size));
+
+ EXPECT_NE(vbmeta_size, vbmeta_padded_size);
+
+ // The padded size should be a multiple of 4096.
+ EXPECT_EQ(vbmeta_padded_size % 4096, 0);
+
+ // When rounded up the unpadded size should equal the padded size.
+ int64_t vbmeta_size_rounded_up = ((vbmeta_size + 4095) / 4096) * 4096;
+ EXPECT_EQ(vbmeta_size_rounded_up, vbmeta_padded_size);
+}
+
TEST_F(AvbToolTest, CheckRollbackIndex) {
uint64_t rollback_index = 42;
GenerateVBMetaImage("vbmeta.img",
@@ -1575,6 +1604,27 @@
EXPECT_EQ("DONE", value);
}
+TEST_F(AvbToolTest, SigningHelperWithFilesBasic) {
+ base::FilePath vbmeta_path = testdir_.Append("vbmeta.bin");
+ base::FilePath signing_helper_test_path =
+ testdir_.Append("signing_helper_test");
+ EXPECT_COMMAND(
+ 0,
+ "SIGNING_HELPER_TEST=\"%s\" ./avbtool make_vbmeta_image "
+ "--output %s "
+ "--algorithm SHA256_RSA2048 --key test/data/testkey_rsa2048.pem "
+ "--signing_helper_with_files "
+ "test/avbtool_signing_helper_with_files_test.py "
+ "--internal_release_string \"\"",
+ signing_helper_test_path.value().c_str(),
+ vbmeta_path.value().c_str());
+
+ // Now check the value in test file.
+ std::string value;
+ ASSERT_TRUE(base::ReadFileToString(signing_helper_test_path, &value));
+ EXPECT_EQ("DONE", value);
+}
+
TEST_F(AvbToolTest, SigningHelperReturnError) {
base::FilePath vbmeta_path = testdir_.Append("vbmeta.bin");
EXPECT_COMMAND(
@@ -1587,6 +1637,19 @@
vbmeta_path.value().c_str());
}
+TEST_F(AvbToolTest, SigningHelperWithFilesReturnError) {
+ base::FilePath vbmeta_path = testdir_.Append("vbmeta.bin");
+ EXPECT_COMMAND(
+ 1,
+ "./avbtool make_vbmeta_image "
+ "--output %s "
+ "--algorithm SHA256_RSA2048 --key test/data/testkey_rsa2048.pem "
+ "--signing_helper_with_files "
+ "test/avbtool_signing_helper_with_files_test.py "
+ "--internal_release_string \"\"",
+ vbmeta_path.value().c_str());
+}
+
TEST_F(AvbToolTest, VerifyImageNoSignature) {
GenerateVBMetaImage("vbmeta.img",
"", // NONE