diff --git a/scripts/image_signing/sign_android_image.sh b/scripts/image_signing/sign_android_image.sh new file mode 100755 index 0000000000..6f9997937c --- /dev/null +++ b/scripts/image_signing/sign_android_image.sh @@ -0,0 +1,219 @@ +#!/bin/bash + +# Copyright 2016 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +. "$(dirname "$0")/common.sh" + +set -e + +keytool_bin="/usr/local/buildtools/java/jdk/bin/keytool" + +# Print usage string +usage() { + cat < /dev/null + zipalign 4 "${signed_apk}" "${aligned_apk}" + + sudo mv -f "${aligned_apk}" "${apk}" + + : $(( counter_${keyname} += 1 )) + : $(( counter_total += 1 )) + done < <(find "${system_mnt}/system" -type f -name '*.apk' -print0) + + # Sanity check. + if [[ ${counter_platform} -lt 2 || ${counter_media} -lt 2 || + ${counter_shared} -lt 2 || ${counter_releasekey} -lt 2 || + ${counter_total} -lt 25 ]]; then + die "Number of re-signed package seems to be wrong" + fi +} + +# Platform key is part of the SELinux policy. Since we are re-signing framework +# apks, we need to replace the key in the policy as well. +update_sepolicy() { + local system_mnt=$1 + local key_dir=$2 + + # Only platform is used at this time. + local public_platform_key="${key_dir}/platform.x509.pem" + + info "Start updating sepolicy" + + local new_cert=$(sed -E '/(BEGIN|END) CERTIFICATE/d' \ + "${public_platform_key}" | tr -d '\n' \ + | base64 --decode | hexdump -v -e '/1 "%02x"') + + if [[ -z "${new_cert}" ]]; then + die "Unable to get the public platform key" + fi + + local output=$(make_temp_file) + local xml="${system_mnt}/system/etc/security/mac_permissions.xml" + local pattern='( "${output}" + + # Sanity check. + if cmp "${xml}" "${output}"; then + die "Failed to replace SELinux policy cert" + fi + + sudo mv -f "${output}" "${xml}" +} + +# Replace the debug key in OTA cert with release key. +replace_ota_cert() { + local system_mnt=$1 + local release_cert=$2 + local ota_zip="${system_mnt}/system/etc/security/otacerts.zip" + + info "Replacing OTA cert" + + local temp_dir=$(make_temp_dir) + pushd "${temp_dir}" > /dev/null + cp "${release_cert}" . + sudo rm "${ota_zip}" + sudo zip -q -r "${ota_zip}" . + popd > /dev/null +} + +# Restore SELinux context. This has to run after all file changes, before +# creating the new squashfs image. +reapply_file_security_context() { + local system_mnt=$1 + local root_fs_dir=$2 + + info "Reapplying file security context" + + sudo /sbin/setfiles -v -r "${system_mnt}" \ + "${root_fs_dir}/etc/selinux/arc/contexts/files/android_file_contexts" \ + "${system_mnt}" +} + +main() { + local root_fs_dir=$1 + local key_dir=$2 + local android_dir="${root_fs_dir}/opt/google/containers/android" + local system_img="${android_dir}/system.raw.img" + + if [[ $# -ne 2 ]]; then + usage "command takes exactly 2 args" + fi + + if [[ ! -f "${system_img}" ]]; then + die "System image does not exist: ${system_img}" + fi + + local working_dir=$(make_temp_dir) + local system_mnt="${working_dir}/mnt" + + info "Unpacking sqaushfs image to ${system_img}" + sudo unsquashfs -f -d "${system_mnt}" "${system_img}" + + sign_framework_apks "${system_mnt}" "${key_dir}" + update_sepolicy "${system_mnt}" "${key_dir}" + replace_ota_cert "${system_mnt}" "${key_dir}/releasekey.x509.pem" + reapply_file_security_context "${system_mnt}" "${root_fs_dir}" + + info "Repacking sqaushfs image" + + local new_system_img="${working_dir}/system.raw.img" + sudo mksquashfs "${system_mnt}" "${new_system_img}" -comp lzo + + local old_size=$(stat -c '%s' "${system_img}") + local new_size=$(stat -c '%s' "${new_system_img}") + info "Android system image size change: ${old_size} -> ${new_size}" + + sudo mv -f "${new_system_img}" "${system_img}" +} + +main "$@" diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh index 4f3407ef0d..badfaa92fb 100755 --- a/scripts/image_signing/sign_official_build.sh +++ b/scripts/image_signing/sign_official_build.sh @@ -590,6 +590,35 @@ resign_firmware_payload() { echo "Re-signed firmware AU payload in $image" } +# Re-sign Android image if exists. +resign_android_image_if_exists() { + local image=$1 + + local rootfs_dir=$(make_temp_dir) + mount_image_partition "${image}" 3 "${rootfs_dir}" + + local system_img="${rootfs_dir}/opt/google/containers/android/system.raw.img" + + if [[ ! -e "${system_img}" ]]; then + info "Android image not found. Not signing Android APKs." + sudo umount "${rootfs_dir}" + return + fi + + # Sign only 54+ images to make sure it works on dev channel first. + local milestone=$(grep CHROMEOS_RELEASE_CHROME_MILESTONE= \ + "${rootfs_dir}/etc/lsb-release" | cut -d= -f2) + if [[ "${milestone}" -le 53 ]]; then + info "Not signing Android apks before 53 (incl.). Current: ${milestone}." + return + fi + + "${SCRIPT_DIR}/sign_android_image.sh" "${rootfs_dir}" "${KEY_DIR}/android" + + sudo umount "${rootfs_dir}" + echo "Re-signed Android image" +} + # Verify an image including rootfs hash using the specified keys. verify_image() { local rootfs_image=$(make_temp_file) @@ -772,6 +801,7 @@ sign_image_file() { echo "Preparing ${image_type} image..." cp --sparse=always "${input}" "${output}" resign_firmware_payload "${output}" + resign_android_image_if_exists "${output}" # We do NOT strip /boot for factory installer, since some devices need it to # boot EFI. crbug.com/260512 would obsolete this requirement. # diff --git a/scripts/keygeneration/create_new_android_keys.sh b/scripts/keygeneration/create_new_android_keys.sh new file mode 100755 index 0000000000..a233a97a92 --- /dev/null +++ b/scripts/keygeneration/create_new_android_keys.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Copyright 2016 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +set -e + +usage() { + cat <&2 + exit 1 + else + exit 0 + fi +} + +# Use the same SUBJECT used in Nexus. +SUBJECT='/C=US/ST=California/L=Mountain View/O=Google Inc./OU=Android/CN=Android' + +# Generate .pk8 and .x509.pem at the given directory. +make_pair() { + local dir=$1 + local name=$2 + + # Generate RSA key. + openssl genrsa -3 -out "${dir}/temp.pem" 2048 + + # Create a certificate with the public part of the key. + openssl req -new -x509 -key "${dir}/temp.pem" -out "${dir}/${name}.x509.pem" \ + -days 10000 -subj "${SUBJECT}" + + # Create a PKCS#8-formatted version of the private key. + openssl pkcs8 -in "${dir}/temp.pem" -topk8 -outform DER \ + -out "${dir}/${name}.pk8" -nocrypt + + # Best attempt to securely delete the temp.pem file. + shred --remove "${dir}/temp.pem" +} + +main() { + if [[ $# -ne 1 ]]; then + usage "Invalid argument." + fi + + local dir=$1 + + make_pair "${dir}" platform + make_pair "${dir}" shared + make_pair "${dir}" media + make_pair "${dir}" releasekey +} + +main "$@" diff --git a/tests/devkeys/android/media.pk8 b/tests/devkeys/android/media.pk8 new file mode 100644 index 0000000000..53fb253154 Binary files /dev/null and b/tests/devkeys/android/media.pk8 differ diff --git a/tests/devkeys/android/media.x509.pem b/tests/devkeys/android/media.x509.pem new file mode 100644 index 0000000000..d3ec5bedf7 --- /dev/null +++ b/tests/devkeys/android/media.x509.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID/TCCAuWgAwIBAgIJAMi4UJBVFupsMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g +VmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UE +AwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0xNjA2MjkyMTUxNDVaFw00MzExMTUyMTUxNDVaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G +A1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UEAwwHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANRmZX0ek4H/HTuYfuS4WPvMBBtRRXSmysX1 +I/EIAXPVkMswIWmvw/3nBXnjmZDLrg/XG0pOQbUGSJ7RI4d27jHblX/3RQNwpmEx +r8RPLcnBosM/KYaE+9lmSGl/XfbR0b8nreWOeJVBkGMDrrC5O4f7FSrORJBs2JI8 +ZZjiRFcnstdcPHwKBnHjNCRkhC72MvHMUXmndxMBnT18RWk8KrF/de9PotqPmZOZ +fMJrebuCw0G/j0nwciqd3tpO0oANAGtWbzJ9xk53DlYRj4qu74rnQjAtyD0a73dO +U1QRnan28Duk+lKIaIUzqqrcx9uEKYp4N2figpDWKaL9QUnVSW8CAwEAAaNQME4w +HQYDVR0OBBYEFN99GqWFkNea+rCFvb4x45xBmMhIMB8GA1UdIwQYMBaAFN99GqWF +kNea+rCFvb4x45xBmMhIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AFluihpLMwTAcv6l3jJZomf/a8fjEn3Ghx54B3g5n8xeDD0h2OxDOdrDc63Bg14Q +s+ANOXsqNRkZse3ze97lX6qGzXmTfuUwXdlCzgnNA970/WG8EqOgI4yQJ+7a5bu5 +jE7WHaGRuZg5r3XiX+/A8Amo8w1vPsSTCHIiMeCShC9I6L/yF+o4bg7X/mnrVvzt +QLkpYhbxZ68sLlnessfj9zigHpyUtY6HzAvYbRKN4y/2RvkMwRHBHaxZyu1g8LeY +A5c/EfktgF7ORsBrxZeKejOu+8nFzlf8TQAr0zVCHaaP1FLtA2qeLDQsGeYaKBTE +1Ol/AEBSc6LFhA3Inj6xHoI= +-----END CERTIFICATE----- diff --git a/tests/devkeys/android/platform.pk8 b/tests/devkeys/android/platform.pk8 new file mode 100644 index 0000000000..7b615ecba5 Binary files /dev/null and b/tests/devkeys/android/platform.pk8 differ diff --git a/tests/devkeys/android/platform.x509.pem b/tests/devkeys/android/platform.x509.pem new file mode 100644 index 0000000000..8b422ac760 --- /dev/null +++ b/tests/devkeys/android/platform.x509.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID/TCCAuWgAwIBAgIJAKsh6Cqx4cjwMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g +VmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UE +AwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0xNjA2MjkyMTUxNDBaFw00MzExMTUyMTUxNDBaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G +A1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UEAwwHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBALK5wH9wQ7BxBeE7lKNn3xnerYzZcBwyAscQ +nr+SWz4wmIUaNLZ7d2BwpzNaa84P2hiC7F3dbJDumjvgBlsNI5ALIUZcBqYkngG8 +UJhzpPw1CmvruGCsVUwaMWSx0Fh2f9o2SKuQPbGcBcdTha0tkmypONVuuZ1PeDlE +tiSHT3b/PDMqbCGhuunLUaPCOYyBoB/qC6oR1+aInrz860U5IVfubSj4hzAOrysm +EymSwsXkbMOG1gmZZiVjDn1pyIRC7Dy2u70JWaL92nRtRfeVaFwk0KRDXi+PYm+k +eQ0gOTcmbGwTh/FO4Wqc0sG78qoALB8Or+WuRTvZKsp6NRF1Kw8CAwEAAaNQME4w +HQYDVR0OBBYEFKYVE2bBhv9LZ136ipflr1O3RlVWMB8GA1UdIwQYMBaAFKYVE2bB +hv9LZ136ipflr1O3RlVWMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AAK7tIOyglsBLWHhl/Kc1ZjHUTvhrI3n+pz4aCtViynaHJs5O5qW3hYCLwetxBJf +92SoRNIUc1va7vLkc5fk7k5FpW+kjz1XtLasGE9KsqN6Y2I5Y88w6f6ZS5Yj/DZp +jvVAJkyCu4Un/6Qygw8DzbRGoKqlUR4x7lrqM8ZU4LkeTkxZnwX95ygth3YyXtG/ +ozbJSCx0iiJQX/uH/bXtngp5LbhFcmQj/rUxvLchRQxGPONvvpiB+6mqkN2hDLMN +KFBc2z9vu5s477bz9sz1+uPZVOnwc8u3q6VF0dowFReXtzKViciYst/zktcGzz04 +z3jF4S6UhxYQ93pmqvI0pKI= +-----END CERTIFICATE----- diff --git a/tests/devkeys/android/releasekey.pk8 b/tests/devkeys/android/releasekey.pk8 new file mode 100644 index 0000000000..502b5d98b0 Binary files /dev/null and b/tests/devkeys/android/releasekey.pk8 differ diff --git a/tests/devkeys/android/releasekey.x509.pem b/tests/devkeys/android/releasekey.x509.pem new file mode 100644 index 0000000000..e375026592 --- /dev/null +++ b/tests/devkeys/android/releasekey.x509.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID/TCCAuWgAwIBAgIJAOP6XMUWw6ovMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g +VmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UE +AwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0xNjA2MjkyMTUyMTBaFw00MzExMTUyMTUyMTBaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G +A1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UEAwwHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBALZPiJrLQcYJItjj8KpR879BDpoSEXy5Ptik +TVVVXN8KoEpXWtRPwYSIG110lIY+U/VugOGz085m3VtC5mlobALvZDYz8L61XvIi ++ZYsWjoJBstBhQCr//P2uYWIJRElV1wKppJwqsS/gBc1Qmk6UZAPCABs4lF/8W1E +p31vQpsRsi9d7kS3PFqoriI3ECYqlQ/7y2zXpulY+IlYLdan+FusunGuVEX4RO8X +T6t/ICtV4kfvIok+WcAVrJS4ry0CWgVxEBzgkHnpuNxYsrP+VELQgvyiDrz2ZN6N +Sdqteso6vF+LBgfnZbE28SVnXLEIq9qokAO/+vsMLS3cC0MMAQsCAwEAAaNQME4w +HQYDVR0OBBYEFDygTzrIA3e5rGFzdiO2wvSc19psMB8GA1UdIwQYMBaAFDygTzrI +A3e5rGFzdiO2wvSc19psMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKa7SCivs+mdPcCPlB9IcBjAU6VrZx2L1hup/g1ciE0TiKW0T43rlA/F/14OBIuD +W9767ynezlc84edcStDrczFK6fXFivnUL5I9OWt2SqgrWJvA8340mdPpu01Ot+AH +95LshV+ObC7ZBgIzdkcvpeFn9Z0MhUHGBWubdj+9FLrKNJZylZjX6YaRlHpjzALf +xyDs2gkwOpEXkoEOhSsXgCX5A1nrFaM3WAjAiJa/Mbq+FfrvY/9IlVKaHrGaohQz +NkucJC+Y147gmvVEENbUsJzV1LKJMWurEpdETMvAKlqlaLuQEbpM2d78u0uNnTEC +6JbScH21uNVRu8UMNFh3HFs= +-----END CERTIFICATE----- diff --git a/tests/devkeys/android/shared.pk8 b/tests/devkeys/android/shared.pk8 new file mode 100644 index 0000000000..9403f0f8b7 Binary files /dev/null and b/tests/devkeys/android/shared.pk8 differ diff --git a/tests/devkeys/android/shared.x509.pem b/tests/devkeys/android/shared.x509.pem new file mode 100644 index 0000000000..63bc602d27 --- /dev/null +++ b/tests/devkeys/android/shared.x509.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID/TCCAuWgAwIBAgIJAMAHZkxZ4orXMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g +VmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UE +AwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0xNjA2MjkyMTUxNTBaFw00MzExMTUyMTUxNTBaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G +A1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UEAwwHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBALr6JlzAZ7FZi/tOUMJTkh9Q7JuKXqqMqrNR +d2Y3/O4WFVVH/cLhLcbaRXzLTDnc1+X6U/hGxqEsxMw/ibzMez5Wcjpw1iUtjlAv +xFS21Fl/plasmpZicCeGr7zrN0rWBAQFDqAGWLter/NTFwPJ//gxQWLumCs5RAx9 +KUH0c7SKKwyxj5iHeu9M/af26w0ZBNDaWMjASaOKL9Zf4mPxL6BT5n57WcYgRr/w +DGzfQXJRFS1gkhmBLlBpK1Iqn+Em6QgtKvcLRIpxgIEHvYfQ9Wp+qJfzObbF571J +UJvgebql21zESNURDM0MuME+8o5jFwCko9xp0bGBU47SHF9uKbUCAwEAAaNQME4w +HQYDVR0OBBYEFGbO0kw1I8ALeMIbYEGg70I+iW/kMB8GA1UdIwQYMBaAFGbO0kw1 +I8ALeMIbYEGg70I+iW/kMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AI4Q7dUgKjAPHEyUXsrWaQRalN86O01QorUNnGfXeNN+9YJbGUTB7Of0PUTFoU0o +Fgw+yHcq1WbZeAH87TnQ6iICcDzcI2vUTxOT7Ag+TM1ZaxU56zhW+YFW8m4swq6C +NQIRxqmPMObdnaWZcRbp3jl4o3xADGVCmylfnpwRWbCE1fvEIWI3oLtDHT1S+UDt +Z0KVj93r3iauOt9CEkTJGKIy9bmaDXq8fEiS41gk0fYHZv2KA0YuxfldROqa18Mb +E0WZMBvIuhmC5cdiNrfZ6bGJmc2ydkehZfYO5XKk/3gIxw7OCBK72t7N7jAQ5LGc +fvx96vPRpY9nEAvElBEvv8o= +-----END CERTIFICATE-----