Home | History | Annotate | Download | only in security
      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
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    237     public static boolean deleteLegacyKeyForAlias(KeyStore keystore, String alias, int uid) {
    238         return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
    239     }
    240 }
    241