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