Test for DevicePolicyManager.installKeyPair() variant

Add a new test to cover installKeyPair() variant which installs a
client certificate chain.

Bug: 28289854
Change-Id: Iec8f1745631f08bb260a03b0d6b675e812e5a186
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/ca.conf b/hostsidetests/devicepolicy/app/DeviceOwner/assets/ca.conf
new file mode 100644
index 0000000..c27a473
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/ca.conf
@@ -0,0 +1,156 @@
+# OpenSSL root CA configuration file.
+# Copy to `/root/ca/openssl.cnf`.
+
+[ ca ]
+# `man ca`
+
+[ RootCA ]
+# Directory and file locations.
+dir               = ./rootca
+certs             = $dir/certs
+crl_dir           = $dir/crl
+new_certs_dir     = $dir/newcerts
+database          = $dir/index.txt
+serial            = $dir/serial
+RANDFILE          = $dir/private/.rand
+
+# The root key and root certificate.
+private_key       = $dir/private/ca.key.pem
+certificate       = $dir/certs/ca.cert.pem
+
+# For certificate revocation lists.
+crlnumber         = $dir/crlnumber
+crl               = $dir/crl/ca.crl.pem
+crl_extensions    = crl_ext
+default_crl_days  = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md        = sha256
+
+name_opt          = ca_default
+cert_opt          = ca_default
+default_days      = 375
+preserve          = no
+policy            = policy_strict
+
+[ IntermediateCA ]
+# Directory and file locations.
+dir               = ./intermediate
+certs             = $dir/certs
+crl_dir           = $dir/crl
+new_certs_dir     = $dir/newcerts
+database          = $dir/index.txt
+serial            = $dir/serial
+RANDFILE          = $dir/private/.rand
+
+# The root key and root certificate.
+private_key       = $dir/private/intermediate.key.pem
+certificate       = $dir/certs/intermediate.cert.pem
+
+# For certificate revocation lists.
+crlnumber         = $dir/crlnumber
+crl               = $dir/crl/ca.crl.pem
+crl_extensions    = crl_ext
+default_crl_days  = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md        = sha256
+
+name_opt          = ca_default
+cert_opt          = ca_default
+default_days      = 375
+preserve          = no
+policy            = policy_strict
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName             = match
+stateOrProvinceName     = match
+organizationName        = match
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits        = 4096
+distinguished_name  = req_distinguished_name
+string_mask         = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md          = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions     = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName                     = Country Name (2 letter code)
+stateOrProvinceName             = State or Province Name
+0.organizationName              = Organization Name
+organizationalUnitName          = Organizational Unit Name
+commonName                      = Common Name
+
+# Optionally, specify some defaults.
+countryName_default             = GB
+stateOrProvinceName_default     = England
+0.organizationName_default      = Google UK
+organizationalUnitName_default  = AfW
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/generate-client-cert-chain.sh b/hostsidetests/devicepolicy/app/DeviceOwner/assets/generate-client-cert-chain.sh
new file mode 100755
index 0000000..8b0639f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/generate-client-cert-chain.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+#
+# Generates:
+#  - user-cert-chain.crt
+#  - user-cert-chain.key
+#
+
+set -e
+
+WORKDIR='temp'
+
+mkdir "$WORKDIR"
+cp ca.conf "$WORKDIR/"
+pushd "$WORKDIR"
+
+## Generate root CA
+mkdir -p rootca/{certs,crl,newcerts,private}
+pushd rootca
+touch index.txt
+echo '1000' > serial
+openssl req \
+    -config ../ca.conf \
+    -new \
+    -x509 \
+    -days 7300 \
+    -sha256 \
+    -extensions v3_ca \
+    -keyout private/ca.key.pem \
+    -out certs/ca.cert.pem
+popd
+
+## Generate Intermediate CA
+mkdir intermediate intermediate/{certs,crl,csr,newcerts,private}
+touch intermediate/index.txt
+
+echo '1000' > intermediate/serial
+echo '1000' > intermediate/crlnumber
+
+openssl req \
+    -config ca.conf \
+    -new \
+    -sha256 \
+    -keyout intermediate/private/intermediate.key.pem \
+    -out intermediate/csr/intermediate.csr.pem
+
+openssl ca \
+    -config ca.conf \
+    -name RootCA \
+    -extensions v3_intermediate_ca \
+    -days 3650 \
+    -notext \
+    -md sha256 \
+    -in intermediate/csr/intermediate.csr.pem \
+    -out intermediate/certs/intermediate.cert.pem
+
+## Generate client cert
+openssl req \
+    -config ca.conf \
+    -newkey rsa:1024 \
+    -keyout user.key.pem \
+    -nodes \
+    -days 3650 \
+    -out user.csr.pem
+
+openssl ca \
+    -config ca.conf \
+    -name IntermediateCA \
+    -extensions usr_cert \
+    -days 365 \
+    -notext \
+    -md sha256 \
+    -in user.csr.pem \
+    -out user.cert.pem
+
+popd # WORKDIR
+
+## Convert client cert to acceptable form
+cat \
+    "$WORKDIR"/user.cert.pem \
+    "$WORKDIR"/intermediate/certs/intermediate.cert.pem \
+    "$WORKDIR"/rootca/certs/ca.cert.pem \
+    > user-cert-chain.crt
+
+openssl pkcs8 \
+    -topk8 \
+    -nocrypt \
+    -inform PEM \
+    -outform DER \
+    -in "$WORKDIR"/user.key.pem \
+    -out user-cert-chain.key
+
+rm -r "$WORKDIR"
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.crt b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.crt
new file mode 100644
index 0000000..72a86e3
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.crt
@@ -0,0 +1,96 @@
+-----BEGIN CERTIFICATE-----
+MIIFLzCCAxegAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwZDELMAkGA1UEBhMCR0Ix
+EDAOBgNVBAgMB0VuZ2xhbmQxEjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwD
+QWZ3MSEwHwYDVQQDDBhBZlcgVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTYwMzE4
+MTcxMzA4WhcNMTcwMzI4MTcxMzA4WjCBiDELMAkGA1UEBhMCR0IxEDAOBgNVBAgM
+B0VuZ2xhbmQxEjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwDQWZ3MSUwIwYD
+VQQDDBxVc2VyMDAgdW5kZXIgaW50ZXJtZWRpYXRlIENBMR4wHAYJKoZIhvcNAQkB
+Fg90ZXN0QGdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQC8W+PUeNVDIy6GSeTVjN9JSkYxcsupFq9AOUma0R+7z9EGuZBURZprgbrN7c2q
+RQnlSBZTC9fRMkXZ6LImWoY5GqS3NcbkJbUlA+UeK2uJXQQfjTO7bYDslvudX+8y
+WfYrR71DLpIFgDkxQAWGywMzNTR6TEmPy1qBGIFYohGqZkQoTS//s/iEEKDSsbPr
+mkTrf4lDAc8cgnmUPFPkN1Lr4ITkvhmEHQjJTcS+Qjeotlt+ss5vrmlqopFkCbI9
+7uC6RQDI0PvP9achzBsTUi0vNsGg45luCJhNrDu6s4NpnusKIVAoJPSJdion2yoD
+3Dp8LX/ueGNbP64LY6qmDWDlAgMBAAGjgcUwgcIwCQYDVR0TBAIwADARBglghkgB
+hvhCAQEEBAMCBaAwMwYJYIZIAYb4QgENBCYWJE9wZW5TU0wgR2VuZXJhdGVkIENs
+aWVudCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUSp7kS1On3b7MdMstDVPCNkHm/EUw
+HwYDVR0jBBgwFoAUdejD6Fb3X8ZHOCKMWe5XwukxBDswDgYDVR0PAQH/BAQDAgXg
+MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQsFAAOC
+AgEAXIOVhMjxbpO1uxe1MnyIsTrl0ajPlkn+4qWLwjXzUQ6TcE2Ow91AMcYs5siq
+UBplZyNYNBOhX8TZLNy7jJ/REwj65Qa/y0TcDucpGhtT9l1JIJCdEpPoymyiM18C
+NktXDyaw+DFkWC0a5oUhjk4UuzTfHkSVMKjZUnRPPiwL2gl9zEgS8qVI3ew4JjdP
+KCYGy/1B+61EE5vCP8GAByeKgtgnh4sVZnsKYQZzjwwUGL1uXQtazPs04qTUw3IK
+YvoOyNsXB4gcp2u4DXv2roVI36DQM5ZGenS9MViTeblg5vkZgy8xsktHyDGDlNe6
+cPw5OgyxDo4nr6TY4SX9eankantPMx7498n390B4lYAgBj4Cz4QaXM1IGN3JVF5J
+EEKqGkLpOYMRNZ4qPFhMknDZgHljjgFlcXGwtXtugCzQ5ldwkFb9qZeB5lQn1Aw0
+PthcDdGp/KCtHC5jF+BjlQITt0tVqJ4+SAdHyF53H+ScoINFul89m32pgvJjI/0k
+c0tidvXNPNodbJCqHmc917DryVJGXbxp+BqxTQ0a7e9K/WA4MnRKPfBTTeDq/j+w
+6B/rLd0bhMrPDi6a/1w97PqfAbS9TlkpnK8Gj4pN+ZOEEF0j0DtDRbb+CfJX14fR
+2R96mEfCeSbCuxLcbwdG1OUQM8GKlIcYfWIp0KjICxRKaDU=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFojCCA4qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwXDELMAkGA1UEBhMCR0Ix
+EDAOBgNVBAgMB0VuZ2xhbmQxEjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwD
+QWZXMRkwFwYDVQQDDBBBZncgVGVzdCBSb290IENBMB4XDTE2MDMxODE3MDQ1N1oX
+DTI2MDMxNjE3MDQ1N1owZDELMAkGA1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQx
+EjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwDQWZ3MSEwHwYDVQQDDBhBZlcg
+VGVzdCBJbnRlcm1lZGlhdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQCZbYchy2Fry9nJuu2YEp2P13lIbyWu0FXF8qTus8Vp/25LyXDjBiDXZUlY
+PL32PY0PRbBQjm7tm/WNqXw8S7gw+5XXpY+XNCd/ygyIZhMdxPm7nqYsEtZDFViL
+ct/QJNAKILFejZQOfRSeyxeINprL+EjFHecA6KtruZULzJE0u0UGTgs5h9HbqhH7
+LbZ8iiE/TfG6kflUI2kAPxGiRpIyerYoVjp3Ta5026T+aoc6VyNnSYiZULgYLoL8
+P8x19G3Pplqf4U5bUyKtRtnPWOvM9iYphxsVuTc8rRpZGcMKhdL4gGLQpdruIZ43
+gvGMq4Kt2xVJExBOKMg3j3x52j1XtOcad/nz7ncak/6ElTd0gfhFgt9PwAfQZ32b
+BL3Zlcb+7Pvtv14xAWNHy5cMyn7UDzIsy/yqWLvJSfkZViU0vPuokXMKZIyzv73V
+4N9qXQAWXNz4HwgWy35rB1sirgMxLdWCpHrVeh/DzSrWZ/MtJIC9Ac1jTAuI6F1u
+b7dRRujWpcr57ReKDXXJzM83JQnENJQ3gAHrY8qTkGz7NLa7DsyzPdKOC7vZ0+Ed
+VMvn+c2AMWrwkRpn9JlU5bd2BN7D6UWGLTdzSN9QH7n7sXmQNAo/M7Lr9baxKZNY
+aU5DORVjnGvITZDHYiw9OuakWZUZATF+TTInKEasF131r9q9ZwIDAQABo2YwZDAd
+BgNVHQ4EFgQUdejD6Fb3X8ZHOCKMWe5XwukxBDswHwYDVR0jBBgwFoAUV4EHHOi0
+AqQIj4IMjPEFW3fVS8QwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC
+AYYwDQYJKoZIhvcNAQELBQADggIBACs0qS3EXymo1VgBInR9GrzvUq1gC/d3ohSG
+iB3x2zfqfQ4D0eiYADcCdXTPIwPtm8P8woK5QsRV/MCklqyvgVpRHFQe1uOAZJ7X
+Ud6hx9CCye0QkEoy+JDeVdPeFFf1b8S/daxLXUVbCKSTA+z8YLPRSEFi2d3cOwpx
+WPlkfLSwP6DfODicmPNd1V/qB/fevlmfRB6UKquT+v9xWyQqu4aa6F6xGWYWmc+1
+E/MB/oEOizJVv8VVETqMk8/xFPrMk28foI8ohrLkstSx8gH+oII1Ud1k1XoMMqqU
+Ge656Tr85Di5WfacMdKUommOEKQYRiic6ikcNEAVVNOHlOtw08ua7g1k1G/dwcj0
+DCF2WmWzdAMwST0AH/RPa+i9cX8f/yS15OUP7ncSaI7/ChGT3EBzP+bqxeXFOCNH
+0yNLk4tNLIzNwnKXGTfSbKMTYOZ3ngAiR4w3ro/LJhe2z03MOawxoiIosTc9UwKA
+YJ3nYHYw8/EJCKPth6yrUU3gU1V0vyaBy34y4xuha3oWnbc53vm1cv4BINwmuAms
+ASQpqCiGp2ZaalNu87xCnWE3HA4S3+0U3dsFJXdPdQt/cDzX+kDzojWeHmECp6mn
+GodmmPbEBqzDckMaM9CvSAp8NyZuO8hrOSoGTdxQtP1w3waOeM4zLYd7aBYUfefL
+36OoziEN
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFnjCCA4agAwIBAgIJANLdX1zcxUSUMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV
+BAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMRIwEAYDVQQKDAlHb29nbGUgVUsxDDAK
+BgNVBAsMA0FmVzEZMBcGA1UEAwwQQWZ3IFRlc3QgUm9vdCBDQTAeFw0xNjAzMTgx
+NzAxMDBaFw0zNjAzMTMxNzAxMDBaMFwxCzAJBgNVBAYTAkdCMRAwDgYDVQQIDAdF
+bmdsYW5kMRIwEAYDVQQKDAlHb29nbGUgVUsxDDAKBgNVBAsMA0FmVzEZMBcGA1UE
+AwwQQWZ3IFRlc3QgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBANFyOD/BIGV4iHSGDrp1ajvp+00098dn+p1cqlMHMrWUjnqzcMdOVmeqSaQ/
+EkOlAIsdcl1yb+oo3DhomIzX/B2lTQSOSLDmthIgmu0hfk/gAiqLdA8/L2F9m64N
+9x4+72xscN3MxzvjKGUBgPDmRfR9Tp347j42HUCjmF5sTa7DzGMrU7I3gCmi7B3D
+zbkgdTwpucH2JDqHQPv+7PLaNyuZNEmiXM76DPyMypxMrtGrq/FDVJ7JwF+cSwbY
+WVfzbmOfHG7g6hRw7Bap/NNjcdtP09hRPG/g2WDy4z0Ay8MTZVe95EHTsyeR+kpv
+0f60eUI0cV7EovbLmp10I3RdsxbWTjbeFmNjM7WmmmsFRzA1jMlFGil/po4mJvMF
+Bcqbi4kUhQ49F4tRUlHRG1b/up71tDuzToF0YmN9GHkf/kt7/noVTYdEsm4RwaeF
+mhoaTMFaNaHGTHSyqroqbBCqlkfTqB1Cqw1weGqV6bGfaYpCJGx5vXmr06mh5dwo
+zvpyHQKCQu96a0G81T526RtVeA4QR89ELa0JSBpWR9MqVZKBte9AgS5vlF0386uM
+vcKC3zJ4srv1YrTOmMkLktNJHsyfLQgb70RdHR38hDEwKaq6VDWiewKDhsWAI5SJ
+wRgjAYspsNUVahDWvpXq/bRGM3JTW+QxiR22vgEitvKeIysLAgMBAAGjYzBhMB0G
+A1UdDgQWBBRXgQcc6LQCpAiPggyM8QVbd9VLxDAfBgNVHSMEGDAWgBRXgQcc6LQC
+pAiPggyM8QVbd9VLxDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAN
+BgkqhkiG9w0BAQsFAAOCAgEAjo/Fj7iTOr1/nTvZpeaon0/xY4D+Hf83FW/4yASZ
+Et0ITa510zIi8rIVvlaR1xdbXLYxHgdtm4vQtKZStwOBdwj+4VZrb9WgwQyBCYU5
+RqK387oMUeZdfsh9m2nqM8buYls3mldv34XUg8y1oytx6GDdC7NKz6PLNpIVkj5F
+aBnyfh43FsXHkzAy0nfkdE2mqfhQ4CD9Zkm9fJcX0inEmcspM5G8ba16uESZDqUS
+oJc1bgNtW64fL7pOtVfHDIJqKf/G/iIq1lk33gv5/4z6Z8e7fYVm1JabUUd9rZ6t
+cjXXFqkA7SkcXTs829/gaXQQv2FARt7g70UxJmNN0MCKfYnKM4dKddi934mTWrOI
+eLe0u3OAa1wZaHggJJXgRxMx/acWnGfersTpsAB1XG74XTSXHV7zHHnNWXjQ+gu0
+N4RAkQFMYWqp6KoHgQrdQfLPcaw0wc+ZMJj35z50b4ab+Bygthx3W+v/MiMFK9Wv
+/AsQCGslDcGWbFCYP7IvHDfownIFGefMnOm41NKWus9z6HoEUmfJiiSSVxECDT/2
+fE7M+sQovdrlHx7ru/fO6PP+6ocUE1afY6cHUzE0Dhv6xMcdvwL7COGd5ZU1bqAQ
+TqbePM5Kpk1ytkigdixzMDz/HFum0fdGfc/59Ll+f6+uHAX5NpOJZkBHBCWAoCeX
+bsg=
+-----END CERTIFICATE-----
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.key b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.key
new file mode 100644
index 0000000..8bb399e
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.key
Binary files differ
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
index 5d6d7fb..219dfc2 100755
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
@@ -27,21 +27,29 @@
 import android.test.ActivityInstrumentationTestCase2;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 import java.security.cert.Certificate;
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.AssetManager;
 
 public class KeyManagementTest extends ActivityInstrumentationTestCase2<KeyManagementActivity> {
 
@@ -126,6 +134,38 @@
         assertGranted(withhold, false);
     }
 
+    public void testCanInstallCertChain() throws Exception {
+        // Use assets/generate-client-cert-chain.sh to regenerate the client cert chain.
+        final PrivateKey privKey = loadPrivateKeyFromAsset("user-cert-chain.key");
+        final Collection<Certificate> certs = loadCertificatesFromAsset("user-cert-chain.crt");
+        final Certificate[] certChain = certs.toArray(new Certificate[certs.size()]);
+        final String alias = "com.android.test.clientkeychain";
+        // Some sanity check on the cert chain
+        assertTrue(certs.size() > 1);
+        for (int i = 1; i < certs.size(); i++) {
+            certChain[i - 1].verify(certChain[i].getPublicKey());
+        }
+
+        // Install keypairs.
+        assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, certChain, alias, true));
+        try {
+            // Verify only the requested key was actually granted.
+            assertGranted(alias, true);
+
+            // Verify the granted key is actually obtainable in PrivateKey form.
+            assertEquals(KeyChain.getPrivateKey(getActivity(), alias).getAlgorithm(), "RSA");
+
+            // Verify the certificate chain is correct
+            X509Certificate[] returnedCerts = KeyChain.getCertificateChain(getActivity(), alias);
+            assertTrue(Arrays.equals(certChain, returnedCerts));
+        } finally {
+            // Delete both keypairs.
+            assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias));
+        }
+        // Verify they're actually gone.
+        assertGranted(alias, false);
+    }
+
     public void testGrantsDoNotPersistBetweenInstallations() throws Exception {
         final String alias = "com.android.test.persistent-key-1";
         final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey , "RSA");
@@ -200,6 +240,35 @@
                 new ByteArrayInputStream(cert));
     }
 
+    private Collection<Certificate> loadCertificatesFromAsset(String assetName) {
+        try {
+            final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            AssetManager am = getActivity().getAssets();
+            InputStream is = am.open(assetName);
+            return (Collection<Certificate>) certFactory.generateCertificates(is);
+        } catch (IOException | CertificateException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private PrivateKey loadPrivateKeyFromAsset(String assetName) {
+        try {
+            AssetManager am = getActivity().getAssets();
+            InputStream is = am.open(assetName);
+            ByteArrayOutputStream output = new ByteArrayOutputStream();
+            int length;
+            byte[] buffer = new byte[4096];
+            while ((length = is.read(buffer, 0, buffer.length)) != -1) {
+              output.write(buffer, 0, length);
+            }
+            return getPrivateKey(output.toByteArray(), "RSA");
+        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
     private class KeyChainAliasFuture implements KeyChainAliasCallback {
         private final CountDownLatch mLatch = new CountDownLatch(1);
         private String mChosenAlias = null;
@@ -224,5 +293,5 @@
             assertTrue("Chooser timeout", mLatch.await(KEYCHAIN_TIMEOUT_MINS, TimeUnit.MINUTES));
             return mChosenAlias;
         }
-    };
+    }
 }