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