Add script to sign Android image

sign_android_image.sh is the main script that signs the image. It makes
similar changes to an image like the Android official signing tool
(sign_target_files_apks.py) does, but more Chrome OS specific.

TEST=./sign_official_build.sh recovery recovery_image.bin \
         ../../tests/devkeys/ out_img
TEST=Same above but with a recovery image without Android image.
     Android signing was skipping.
TEST=Same above but with a M53 image.  Android signing was skipped.
TEST=Unpack the image and diff the before and after.  Looks correct.
BUG=b:29915721

Change-Id: I0ae5f0ad8d2b05e485d60262558517ea563bf527
Reviewed-on: https://chromium-review.googlesource.com/366794
Commit-Ready: Victor Hsieh <victorhsieh@chromium.org>
Tested-by: Victor Hsieh <victorhsieh@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
This commit is contained in:
Victor Hsieh
2016-08-02 16:47:01 -07:00
committed by chrome-bot
parent 8e917140b7
commit 7573ff7efb
11 changed files with 408 additions and 0 deletions

View File

@@ -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 <<EOF
Usage: $PROG /path/to/cros_root_fs/dir /path/to/keys/dir
Re-sign framework apks in an Android system image. The image itself does not
need to be signed since it is shipped with Chrome OS image, which is already
signed.
Android has many "framework apks" that are signed with 4 different framework
keys, depends on the purpose of the apk. During development, apks are signed
with the debug one. This script is to re-sign those apks with corresponding
release key. It also handles some of the consequences of the key changes, such
as sepolicy update.
EOF
if [[ $# -gt 0 ]]; then
error "$*"
exit 1
fi
exit 0
}
# Return name according to the current signing debug key. The name is used to
# select key files.
choose_key() {
local apk="$1"
local sha1=$(unzip -p "${apk}" META-INF/CERT.RSA | \
"${keytool_bin}" -printcert | awk '/^\s*SHA1:/ {print $2}')
# Fingerprints below are generated by:
# $ keytool -file vendor/google/certs/cheetskeys/$NAME.x509.pem -printcert \
# | grep SHA1:
case "${sha1}" in
"AA:04:E0:5F:82:9C:7E:D1:B9:F8:FC:99:6C:5A:54:43:83:D9:F5:BC")
echo "platform"
;;
"D4:C4:2D:E0:B9:1B:15:72:FA:7D:A7:21:E0:A6:09:94:B4:4C:B5:AE")
echo "media"
;;
"38:B6:2C:E1:75:98:E3:E1:1C:CC:F6:6B:83:BB:97:0E:2D:40:6C:AE")
echo "shared"
;;
"EC:63:36:20:23:B7:CB:66:18:70:D3:39:3C:A9:AE:7E:EF:A9:32:42")
# The above fingerprint is from devkey. Translate to releasekey.
echo "releasekey"
;;
*)
# Not a framework apk. Do not re-sign.
echo ""
;;
esac
}
# Re-sign framework apks with the corresponding release keys. Only apk with
# known key fingerprint are re-signed. We should not re-sign non-framework
# apks.
sign_framework_apks() {
local system_mnt="$1"
local key_dir="$2"
info "Start signing framework apks"
# Counters for sanity check.
local counter_platform=0
local counter_media=0
local counter_shared=0
local counter_releasekey=0
local counter_total=0
local apk
while read -d $'\0' -r apk; do
local keyname=$(choose_key "${apk}")
if [[ -z "${keyname}" ]]; then
continue
fi
info "Re-signing (${keyname}) ${apk}"
local temp_dir="$(make_temp_dir)"
local temp_apk="${temp_dir}/temp.apk"
local signed_apk="${temp_dir}/signed.apk"
local aligned_apk="${temp_dir}/aligned.apk"
# Follow the standard manual signing process. See
# https://developer.android.com/studio/publish/app-signing.html.
cp "${apk}" "${temp_apk}"
# Explicitly remove existing signature.
zip -q "${temp_apk}" -d "META-INF/*"
signapk "${key_dir}/$keyname.x509.pem" "${key_dir}/$keyname.pk8" \
"${temp_apk}" "${signed_apk}" > /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='(<signer signature=")\w+("><seinfo value="platform)'
sed -E "s/${pattern}/\1${new_cert}"'\2/g' "${xml}" > "${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 "$@"

View File

@@ -590,6 +590,35 @@ resign_firmware_payload() {
echo "Re-signed firmware AU payload in $image" 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 an image including rootfs hash using the specified keys.
verify_image() { verify_image() {
local rootfs_image=$(make_temp_file) local rootfs_image=$(make_temp_file)
@@ -772,6 +801,7 @@ sign_image_file() {
echo "Preparing ${image_type} image..." echo "Preparing ${image_type} image..."
cp --sparse=always "${input}" "${output}" cp --sparse=always "${input}" "${output}"
resign_firmware_payload "${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 # We do NOT strip /boot for factory installer, since some devices need it to
# boot EFI. crbug.com/260512 would obsolete this requirement. # boot EFI. crbug.com/260512 would obsolete this requirement.
# #

View File

@@ -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 <<EOF
Usage: $0 DIR
Generate Android's 4 framework key pairs at DIR. For detail, please refer to
"Certificates and private keys" and "Manually generating keys" in
https://source.android.com/devices/tech/ota/sign_builds.html.
EOF
if [[ $# -ne 0 ]]; then
echo "ERROR: $*" >&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 "$@"

Binary file not shown.

View File

@@ -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-----

Binary file not shown.

View File

@@ -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-----

Binary file not shown.

View File

@@ -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-----

Binary file not shown.

View File

@@ -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-----