1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.security.keystore.recovery;
18 
19 import static android.security.keystore.recovery.X509CertificateParsingUtils.decodeBase64Cert;
20 
21 import android.annotation.NonNull;
22 import android.util.ArrayMap;
23 
24 import java.security.cert.CertificateException;
25 import java.security.cert.X509Certificate;
26 import java.util.Map;
27 
28 /**
29  * Trusted root certificates for use by the
30  * {@link android.security.keystore.recovery.RecoveryController}. These certificates are used to
31  * verify the public keys of remote secure hardware modules. This is to prevent AOSP backing up keys
32  * to untrusted devices.
33  *
34  * @hide
35  */
36 public final class TrustedRootCertificates {
37 
38     public static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS =
39             "GoogleCloudKeyVaultServiceV1";
40     /**
41      * Certificate used for client-side end-to-end encryption tests.
42      * When recovery controller is initialized with the certificate, recovery snapshots will only
43      * contain application keys started with {@link #INSECURE_KEY_ALIAS_PREFIX}.
44      * Recovery snapshot will only be created if device is unlocked with password started with
45      * {@link #INSECURE_PASSWORD_PREFIX}.
46      *
47      * @hide
48      */
49     public static final String TEST_ONLY_INSECURE_CERTIFICATE_ALIAS =
50             "TEST_ONLY_INSECURE_CERTIFICATE_ALIAS";
51 
52     /**
53      * TODO: Add insecure certificate to TestApi.
54      * @hide
55      */
getTestOnlyInsecureCertificate()56     public static @NonNull X509Certificate getTestOnlyInsecureCertificate() {
57         return parseBase64Certificate(TEST_ONLY_INSECURE_CERTIFICATE_BASE64);
58     }
59     /**
60      * Keys, which alias starts with the prefix are not protected if
61      * recovery agent uses {@link #TEST_ONLY_INSECURE_CERTIFICATE_ALIAS} root certificate.
62      * @hide
63      */
64     public static final String INSECURE_KEY_ALIAS_PREFIX =
65             "INSECURE_KEY_ALIAS_KEY_MATERIAL_IS_NOT_PROTECTED_";
66     /**
67      * Prefix for insecure passwords with length 14.
68      * Passwords started with the prefix are not protected if recovery agent uses
69      * {@link #TEST_ONLY_INSECURE_CERTIFICATE_ALIAS} root certificate.
70      * @hide
71      */
72     public static final String INSECURE_PASSWORD_PREFIX =
73             "INSECURE_PSWD_";
74 
75     private static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64 = ""
76             + "MIIFDzCCAvegAwIBAgIQbNdueU2o0vM9gGq4N6bhjzANBgkqhkiG9w0BAQsFADAx"
77             + "MS8wLQYDVQQDEyZHb29nbGUgQ2xvdWQgS2V5IFZhdWx0IFNlcnZpY2UgUm9vdCBD"
78             + "QTAeFw0xODA1MDcxODI0MDJaFw0zODA1MDgxOTI0MDJaMDExLzAtBgNVBAMTJkdv"
79             + "b2dsZSBDbG91ZCBLZXkgVmF1bHQgU2VydmljZSBSb290IENBMIICIjANBgkqhkiG"
80             + "9w0BAQEFAAOCAg8AMIICCgKCAgEArUgzu+4o9yl22eql1BiGBq3gWXooh2ql3J+v"
81             + "Vuzf/ThjzdIg0xkkkw/NAFxYFi49Eo1fa/hf8wCIoAqCEs1lD6tE3cCD3T3+EQPq"
82             + "uh6CB2KmZDJ6mPnXvVUlUuFr0O2MwZkwylqBETzK0x5NCHgL/p47vkjhHx6LqVao"
83             + "bigKlHxszvVi4fkt/qq7KW3YTVxhwdLGEab+OqSfwMxdBLhMfE0K0dvFt8bs8yJA"
84             + "F04DJsMbRChFFBpT17Z0u53iIAAu5qVQhKrQXiIAwgboZqd+JkHLXU1fJeVT5WJO"
85             + "JgoJFWHkdWkHta4mSYlS72J1Q927JD1JdET1kFtH+EDtYAtx7x7F9xAAbb2tMITw"
86             + "s/wwd2rAzZTX/kxRbDlXVLToU05LFYPr+dFV1wvXmi0jlkIxnhdaVBqWC93p528U"
87             + "iUcLpib+HVzMWGdYI3G1NOa/lTp0c8LcbJjapiiVneRQJ3cIqDPOSEnEq40hyZd1"
88             + "jx3JnOxJMwHs8v4s9GIlb3BcOmDvA/Mu09xEMKwpHBm4TFDKXeGHOWha7ccWEECb"
89             + "yO5ncu6XuN2iyz9S+TuMyjZBE552p6Pu5gEC2xk+qab0NGDTHdLKLbyWn3IxdmBH"
90             + "yTr7iPCqmpyHngkC/pbGfvGusc5BpBugsBtlz67m4RWLJ72yAeVPO/ly/8w4orNs"
91             + "GWjn3s0CAwEAAaMjMCEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w"
92             + "DQYJKoZIhvcNAQELBQADggIBAGiWlu+4qyxgPb6RsA0mwR7V21UJ9rEpYhSN+ARp"
93             + "TWGiI22RCJSGK0ZrPGeFQzE2BpnVRdmLTV5jf9JUStjHoPvNYFnwLTJ0E2e9Olj8"
94             + "MrHrAucAUFLhl4woWz0kU/X0EB1j6Y2SXrAaZPiMMpq8BKj3mH1MbV4stZ0kiHUp"
95             + "Zu6PEmrojYG7FKKN30na2xXfiOfl2JusVsyHDqmUn/HjTh6zASKqE6hxE+FJRl2V"
96             + "Q4dcr4SviHtdbimMy2LghLnZ4FE4XhJgRnw9TeRV5C9Sn7pmnAA5X0C8ZXhXvfvr"
97             + "dx4fL3UKlk1Lqlb5skxoK1R9wwr+aNIO+cuR8JA5DmEDWFw5Budh/uWWZlBTyVW2"
98             + "ybbTB6tkmOc8c08XOgxBaKrsXALmJcluabjmN1jp81ae1epeN31jJ4N5IE5aq7Xb"
99             + "TFmKkwpgTTvJmqCR2XzWujlvdbdjfiABliWsnLzLQCP8eZwcM4LA5UK3f1ktHolr"
100             + "1OI9etSOkebE2py8LPYBJWlX36tRAagZhU/NoyOtvhRzq9rb3rbf96APEHKUFsXG"
101             + "9nBEd2BUKZghLKPf+JNCU/2pOGx0jdMcf+K+a1DeG0YzGYMRkFvpN3hvHYrJdByL"
102             + "3kSP3UtD0H2g8Ps7gRLELG2HODxbSn8PV3XtuSvxVanA6uyaaS3AZ6SxeVLvmw50"
103             + "7aYI";
104 
105     private static final String TEST_ONLY_INSECURE_CERTIFICATE_BASE64 = ""
106             + "MIIFMDCCAxigAwIBAgIJAIZ9/G8KQie9MA0GCSqGSIb3DQEBDQUAMCUxIzAhBgNV"
107             + "BAMMGlRlc3QgT25seSBVbnNlY3VyZSBSb290IENBMB4XDTE4MDMyODAwMzIyM1oX"
108             + "DTM4MDMyMzAwMzIyM1owJTEjMCEGA1UEAwwaVGVzdCBPbmx5IFVuc2VjdXJlIFJv"
109             + "b3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGxFNzAEyzSPmw"
110             + "E5gfuBXdXq++bl9Ep62V7Xn1UiejvmS+pRHT39pf/M7sl4Zr9ezanJTrFvf9+B85"
111             + "VGehdsD32TgfEjThcqaoQCI6pKkHYsUo7FZ5n+G3eE8oabWRZJMVo3QDjnnFYp7z"
112             + "20vnpjDofI2oQyxHcb/1yep+ca1+4lIvbUp/ybhNFqhRXAMcDXo7pyH38eUQ1JdK"
113             + "Q/QlBbShpFEqx1Y6KilKfTDf7Wenqr67LkaEim//yLZjlHzn/BpuRTrpo+XmJZx1"
114             + "P9CX9LGOXTtmsaCcYgD4yijOvV8aEsIJaf1kCIO558oH0oQc+0JG5aXeLN7BDlyZ"
115             + "vH0RdSx5nQLS9kj2I6nthOw/q00/L+S6A0m5jyNZOAl1SY78p+wO0d9eHbqQzJwf"
116             + "EsSq3qGAqlgQyyjp6oxHBqT9hZtN4rxw+iq0K1S4kmTLNF1FvmIB1BE+lNvvoGdY"
117             + "5G0b6Pe4R5JFn9LV3C3PEmSYnae7iG0IQlKmRADIuvfJ7apWAVanJPJAAWh2Akfp"
118             + "8Uxr02cHoY6o7vsEhJJOeMkipaBHThESm/XeFVubQzNfZ9gjQnB9ZX2v+lyj+WYZ"
119             + "SAz3RuXx6TlLrmWccMpQDR1ibcgyyjLUtX3kwZl2OxmJXitjuD7xlxvAXYob15N+"
120             + "K4xKHgxUDrbt2zU/tY0vgepAUg/xbwIDAQABo2MwYTAdBgNVHQ4EFgQUwyeNpYgs"
121             + "XXYvh9z0/lFrja7sV+swHwYDVR0jBBgwFoAUwyeNpYgsXXYvh9z0/lFrja7sV+sw"
122             + "DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQENBQAD"
123             + "ggIBAGuOsvMN5SD3RIQnMJtBpcHNrxun+QFjPZFlYCLfIPrUkHpn5O1iIIq8tVLd"
124             + "2V+12VKnToUEANsYBD3MP8XjP+6GZ7ZQ2rwLGvUABKSX4YXvmjEEXZUZp0y3tIV4"
125             + "kUDlbACzguPneZDp5Qo7YWH4orgqzHkn0sD/ikO5XrAqmzc245ewJlrf+V11mjcu"
126             + "ELfDrEejpPhi7Hk/ZNR0ftP737Hs/dNoCLCIaVNgYzBZhgo4kd220TeJu2ttW0XZ"
127             + "ldyShtpcOmyWKBgVseixR6L/3sspPHyAPXkSuRo0Eh1xvzDKCg9ttb0qoacTlXMF"
128             + "GkBpNzmVq67NWFGGa9UElift1mv6RfktPCAGZ+Ai8xUiKAUB0Eookpt/8gX9Senq"
129             + "yP/jMxkxXmHWxUu8+KnLvj6WLrfftuuD7u3cfc7j5kkrheDz3O4h4477GnqL5wdo"
130             + "9DuEsNc4FxJVz8Iy8RS6cJuW4pihYpM1Tyn7uopLnImpYzEY+R5aQqqr+q/A1diq"
131             + "ogbEKPH6oUiqJUwq3nD70gPBUKJmIzS4vLwLouqUHEm1k/MgHV/BkEU0uVHszPFa"
132             + "XUMMCHb0iT9P8LuZ7Ajer3SR/0TRVApCrk/6OV68e+6k/OFpM5kcZnNMD5ANyBri"
133             + "Tsz3NrDwSw4i4+Dsfh6A9dB/cEghw4skLaBxnQLQIgVeqCzK";
134 
135     /**
136      * The X509 certificate of the trusted root CA cert for the recoverable key store service.
137      */
138     private static final X509Certificate GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_CERTIFICATE =
139             parseBase64Certificate(GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64);
140 
141     private static final int NUMBER_OF_ROOT_CERTIFICATES = 1;
142 
143     private static final ArrayMap<String, X509Certificate> ALL_ROOT_CERTIFICATES =
144             constructRootCertificateMap();
145 
146     /**
147      * Returns all available root certificates, keyed by alias.
148      */
getRootCertificates()149     public static @NonNull Map<String, X509Certificate> getRootCertificates() {
150         return new ArrayMap(ALL_ROOT_CERTIFICATES);
151     }
152 
153     /**
154      * Gets a root certificate referenced by the given {@code alias}.
155      *
156      * @param alias the alias of the certificate
157      * @return the certificate referenced by the alias, or null if such a certificate doesn't exist.
158      */
getRootCertificate(String alias)159     public static @NonNull X509Certificate getRootCertificate(String alias) {
160         return ALL_ROOT_CERTIFICATES.get(alias);
161     }
162 
constructRootCertificateMap()163     private static ArrayMap<String, X509Certificate> constructRootCertificateMap() {
164         ArrayMap<String, X509Certificate> certificates =
165                 new ArrayMap<>(NUMBER_OF_ROOT_CERTIFICATES);
166         certificates.put(
167                 GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS,
168                 GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_CERTIFICATE);
169         return certificates;
170     }
171 
parseBase64Certificate(String base64Certificate)172     private static X509Certificate parseBase64Certificate(String base64Certificate) {
173         try {
174             return decodeBase64Cert(base64Certificate);
175         } catch (CertificateException e) {
176             // Should not happen
177             throw new RuntimeException(e);
178         }
179     }
180 
181     // Statics only
TrustedRootCertificates()182     private TrustedRootCertificates() {}
183 }
184