1 /*
2  * Copyright (C) 2009 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;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 
21 import com.android.org.bouncycastle.util.io.pem.PemObject;
22 import com.android.org.bouncycastle.util.io.pem.PemReader;
23 import com.android.org.bouncycastle.util.io.pem.PemWriter;
24 
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.OutputStreamWriter;
30 import java.io.Reader;
31 import java.io.Writer;
32 import java.nio.charset.StandardCharsets;
33 import java.security.cert.Certificate;
34 import java.security.cert.CertificateEncodingException;
35 import java.security.cert.CertificateException;
36 import java.security.cert.CertificateFactory;
37 import java.security.cert.X509Certificate;
38 import java.util.ArrayList;
39 import java.util.List;
40 
41 /**
42  * {@hide}
43  */
44 public class Credentials {
45     private static final String LOGTAG = "Credentials";
46 
47     public static final String INSTALL_ACTION = "android.credentials.INSTALL";
48 
49     public static final String INSTALL_AS_USER_ACTION = "android.credentials.INSTALL_AS_USER";
50 
51     /** Key prefix for CA certificates. */
52     public static final String CA_CERTIFICATE = "CACERT_";
53 
54     /** Key prefix for user certificates. */
55     public static final String USER_CERTIFICATE = "USRCERT_";
56 
57     /** Key prefix for user private and secret keys. */
58     public static final String USER_PRIVATE_KEY = "USRPKEY_";
59 
60     /** Key prefix for user secret keys.
61      *  @deprecated use {@code USER_PRIVATE_KEY} for this category instead.
62      */
63     public static final String USER_SECRET_KEY = "USRSKEY_";
64 
65     /** Key prefix for VPN. */
66     public static final String VPN = "VPN_";
67 
68     /** Key prefix for platform VPNs. */
69     public static final String PLATFORM_VPN = "PLATFORM_VPN_";
70 
71     /** Key prefix for WIFI. */
72     public static final String WIFI = "WIFI_";
73 
74     /** Key prefix for App Source certificates. */
75     public static final String APP_SOURCE_CERTIFICATE = "FSV_";
76 
77     /** Key containing suffix of lockdown VPN profile. */
78     public static final String LOCKDOWN_VPN = "LOCKDOWN_VPN";
79 
80     /** Name of CA certificate usage. */
81     public static final String CERTIFICATE_USAGE_CA = "ca";
82 
83     /** Name of User certificate usage. */
84     public static final String CERTIFICATE_USAGE_USER = "user";
85 
86     /** Name of WIFI certificate usage. */
87     public static final String CERTIFICATE_USAGE_WIFI = "wifi";
88 
89     /** Name of App Source certificate usage. */
90     public static final String CERTIFICATE_USAGE_APP_SOURCE = "appsrc";
91 
92     /** Data type for public keys. */
93     public static final String EXTRA_PUBLIC_KEY = "KEY";
94 
95     /** Data type for private keys. */
96     public static final String EXTRA_PRIVATE_KEY = "PKEY";
97 
98     // historically used by Android
99     public static final String EXTENSION_CRT = ".crt";
100     public static final String EXTENSION_P12 = ".p12";
101     // commonly used on Windows
102     public static final String EXTENSION_CER = ".cer";
103     public static final String EXTENSION_PFX = ".pfx";
104 
105     /**
106      * Intent extra: install the certificate bundle as this UID instead of
107      * system.
108      */
109     public static final String EXTRA_INSTALL_AS_UID = "install_as_uid";
110 
111     /**
112      * Intent extra: type of the certificate to install
113      */
114     public static final String EXTRA_CERTIFICATE_USAGE = "certificate_install_usage";
115 
116     /**
117      * Intent extra: name for the user's key pair.
118      */
119     public static final String EXTRA_USER_KEY_ALIAS = "user_key_pair_name";
120 
121     /**
122      * Intent extra: data for the user's private key in PEM-encoded PKCS#8.
123      */
124     public static final String EXTRA_USER_PRIVATE_KEY_DATA = "user_private_key_data";
125 
126     /**
127      * Intent extra: data for the user's certificate in PEM-encoded X.509.
128      */
129     public static final String EXTRA_USER_CERTIFICATE_DATA = "user_certificate_data";
130 
131     /**
132      * Intent extra: data for CA certificate chain in PEM-encoded X.509.
133      */
134     public static final String EXTRA_CA_CERTIFICATES_DATA = "ca_certificates_data";
135 
136     /**
137      * Convert objects to a PEM format which is used for
138      * CA_CERTIFICATE and USER_CERTIFICATE entries.
139      */
140     @UnsupportedAppUsage
convertToPem(Certificate... objects)141     public static byte[] convertToPem(Certificate... objects)
142             throws IOException, CertificateEncodingException {
143         ByteArrayOutputStream bao = new ByteArrayOutputStream();
144         Writer writer = new OutputStreamWriter(bao, StandardCharsets.US_ASCII);
145         PemWriter pw = new PemWriter(writer);
146         for (Certificate o : objects) {
147             pw.writeObject(new PemObject("CERTIFICATE", o.getEncoded()));
148         }
149         pw.close();
150         return bao.toByteArray();
151     }
152     /**
153      * Convert objects from PEM format, which is used for
154      * CA_CERTIFICATE and USER_CERTIFICATE entries.
155      */
convertFromPem(byte[] bytes)156     public static List<X509Certificate> convertFromPem(byte[] bytes)
157             throws IOException, CertificateException {
158         ByteArrayInputStream bai = new ByteArrayInputStream(bytes);
159         Reader reader = new InputStreamReader(bai, StandardCharsets.US_ASCII);
160         PemReader pr = new PemReader(reader);
161 
162         try {
163             CertificateFactory cf = CertificateFactory.getInstance("X509");
164 
165             List<X509Certificate> result = new ArrayList<X509Certificate>();
166             PemObject o;
167             while ((o = pr.readPemObject()) != null) {
168                 if (o.getType().equals("CERTIFICATE")) {
169                     Certificate c = cf.generateCertificate(new ByteArrayInputStream(o.getContent()));
170                     result.add((X509Certificate) c);
171                 } else {
172                     throw new IllegalArgumentException("Unknown type " + o.getType());
173                 }
174             }
175             return result;
176         } finally {
177             pr.close();
178         }
179     }
180 
181     /**
182      * Delete all types (private key, user certificate, CA certificate) for a
183      * particular {@code alias}. All three can exist for any given alias.
184      * Returns {@code true} if the alias no longer contains any types.
185      */
deleteAllTypesForAlias(KeyStore keystore, String alias)186     public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
187         return deleteAllTypesForAlias(keystore, alias, KeyStore.UID_SELF);
188     }
189 
190     /**
191      * Delete all types (private key, user certificate, CA certificate) for a
192      * particular {@code alias}. All three can exist for any given alias.
193      * Returns {@code true} if the alias no longer contains any types.
194      */
deleteAllTypesForAlias(KeyStore keystore, String alias, int uid)195     public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias, int uid) {
196         /*
197          * Make sure every type is deleted. There can be all three types, so
198          * don't use a conditional here.
199          */
200         return deleteUserKeyTypeForAlias(keystore, alias, uid)
201                 & deleteCertificateTypesForAlias(keystore, alias, uid);
202     }
203 
204     /**
205      * Delete certificate types (user certificate, CA certificate) for a
206      * particular {@code alias}. Both can exist for any given alias.
207      * Returns {@code true} if the alias no longer contains either type.
208      */
deleteCertificateTypesForAlias(KeyStore keystore, String alias)209     public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
210         return deleteCertificateTypesForAlias(keystore, alias, KeyStore.UID_SELF);
211     }
212 
213     /**
214      * Delete certificate types (user certificate, CA certificate) for a
215      * particular {@code alias}. Both can exist for any given alias.
216      * Returns {@code true} if the alias no longer contains either type.
217      */
deleteCertificateTypesForAlias(KeyStore keystore, String alias, int uid)218     public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias, int uid) {
219         /*
220          * Make sure every certificate type is deleted. There can be two types,
221          * so don't use a conditional here.
222          */
223         return keystore.delete(Credentials.USER_CERTIFICATE + alias, uid)
224                 & keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
225     }
226 
227     /**
228      * Delete user key for a particular {@code alias}.
229      * Returns {@code true} if the entry no longer exists.
230      */
deleteUserKeyTypeForAlias(KeyStore keystore, String alias)231     public static boolean deleteUserKeyTypeForAlias(KeyStore keystore, String alias) {
232         return deleteUserKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
233     }
234 
235     /**
236      * Delete user key for a particular {@code alias}.
237      * Returns {@code true} if the entry no longer exists.
238      */
deleteUserKeyTypeForAlias(KeyStore keystore, String alias, int uid)239     public static boolean deleteUserKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
240         int ret = keystore.delete2(Credentials.USER_PRIVATE_KEY + alias, uid);
241         if (ret == KeyStore.KEY_NOT_FOUND) {
242             return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
243         }
244         return ret == KeyStore.NO_ERROR;
245     }
246 
247     /**
248      * Delete legacy prefixed entry for a particular {@code alias}
249      * Returns {@code true} if the entry no longer exists.
250      */
deleteLegacyKeyForAlias(KeyStore keystore, String alias, int uid)251     public static boolean deleteLegacyKeyForAlias(KeyStore keystore, String alias, int uid) {
252         return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
253     }
254 }
255