Home | History | Annotate | Download | only in keystore
      1 /*
      2  * Copyright (C) 2017 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;
     18 
     19 import android.os.Parcelable;
     20 import android.os.Parcel;
     21 
     22 import java.math.BigInteger;
     23 import java.security.spec.AlgorithmParameterSpec;
     24 import java.security.spec.ECGenParameterSpec;
     25 import java.security.spec.RSAKeyGenParameterSpec;
     26 import java.util.Date;
     27 
     28 import javax.security.auth.x500.X500Principal;
     29 
     30 /**
     31  * A parcelable version of KeyGenParameterSpec
     32  * @hide only used for communicating with the DPMS.
     33  */
     34 public final class ParcelableKeyGenParameterSpec implements Parcelable {
     35     private static final int ALGORITHM_PARAMETER_SPEC_NONE = 1;
     36     private static final int ALGORITHM_PARAMETER_SPEC_RSA = 2;
     37     private static final int ALGORITHM_PARAMETER_SPEC_EC = 3;
     38 
     39     private final KeyGenParameterSpec mSpec;
     40 
     41     public ParcelableKeyGenParameterSpec(
     42             KeyGenParameterSpec spec) {
     43         mSpec = spec;
     44     }
     45 
     46     public int describeContents() {
     47         return 0;
     48     }
     49 
     50     private static void writeOptionalDate(Parcel out, Date date) {
     51         if (date != null) {
     52             out.writeBoolean(true);
     53             out.writeLong(date.getTime());
     54         } else {
     55             out.writeBoolean(false);
     56         }
     57     }
     58 
     59     public void writeToParcel(Parcel out, int flags) {
     60         out.writeString(mSpec.getKeystoreAlias());
     61         out.writeInt(mSpec.getPurposes());
     62         out.writeInt(mSpec.getUid());
     63         out.writeInt(mSpec.getKeySize());
     64 
     65         // Only needs to support RSAKeyGenParameterSpec and ECGenParameterSpec.
     66         AlgorithmParameterSpec algoSpec = mSpec.getAlgorithmParameterSpec();
     67         if (algoSpec == null) {
     68             out.writeInt(ALGORITHM_PARAMETER_SPEC_NONE);
     69         } else if (algoSpec instanceof RSAKeyGenParameterSpec) {
     70             RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algoSpec;
     71             out.writeInt(ALGORITHM_PARAMETER_SPEC_RSA);
     72             out.writeInt(rsaSpec.getKeysize());
     73             out.writeByteArray(rsaSpec.getPublicExponent().toByteArray());
     74         } else if (algoSpec instanceof ECGenParameterSpec) {
     75             ECGenParameterSpec ecSpec = (ECGenParameterSpec) algoSpec;
     76             out.writeInt(ALGORITHM_PARAMETER_SPEC_EC);
     77             out.writeString(ecSpec.getName());
     78         } else {
     79             throw new IllegalArgumentException(
     80                     String.format("Unknown algorithm parameter spec: %s", algoSpec.getClass()));
     81         }
     82         out.writeByteArray(mSpec.getCertificateSubject().getEncoded());
     83         out.writeByteArray(mSpec.getCertificateSerialNumber().toByteArray());
     84         out.writeLong(mSpec.getCertificateNotBefore().getTime());
     85         out.writeLong(mSpec.getCertificateNotAfter().getTime());
     86         writeOptionalDate(out, mSpec.getKeyValidityStart());
     87         writeOptionalDate(out, mSpec.getKeyValidityForOriginationEnd());
     88         writeOptionalDate(out, mSpec.getKeyValidityForConsumptionEnd());
     89         if (mSpec.isDigestsSpecified()) {
     90             out.writeStringArray(mSpec.getDigests());
     91         } else {
     92             out.writeStringArray(null);
     93         }
     94         out.writeStringArray(mSpec.getEncryptionPaddings());
     95         out.writeStringArray(mSpec.getSignaturePaddings());
     96         out.writeStringArray(mSpec.getBlockModes());
     97         out.writeBoolean(mSpec.isRandomizedEncryptionRequired());
     98         out.writeBoolean(mSpec.isUserAuthenticationRequired());
     99         out.writeInt(mSpec.getUserAuthenticationValidityDurationSeconds());
    100         out.writeByteArray(mSpec.getAttestationChallenge());
    101         out.writeBoolean(mSpec.isUniqueIdIncluded());
    102         out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
    103         out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
    104         out.writeBoolean(mSpec.isUserPresenceRequired());
    105     }
    106 
    107     private static Date readDateOrNull(Parcel in) {
    108         boolean hasDate = in.readBoolean();
    109         if (hasDate) {
    110             return new Date(in.readLong());
    111         } else {
    112             return null;
    113         }
    114     }
    115 
    116     private ParcelableKeyGenParameterSpec(Parcel in) {
    117         String keystoreAlias = in.readString();
    118         int purposes = in.readInt();
    119         KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
    120                 keystoreAlias, purposes);
    121         builder.setUid(in.readInt());
    122         // KeySize is -1 by default, if the KeyGenParameterSpec previously parcelled had the default
    123         // value, do not set it as this will cause setKeySize to throw.
    124         int keySize = in.readInt();
    125         if (keySize >= 0) {
    126             builder.setKeySize(keySize);
    127         }
    128 
    129         int keySpecType = in.readInt();
    130         AlgorithmParameterSpec algorithmSpec = null;
    131         if (keySpecType == ALGORITHM_PARAMETER_SPEC_NONE) {
    132             algorithmSpec = null;
    133         } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_RSA) {
    134             int rsaKeySize = in.readInt();
    135             BigInteger publicExponent = new BigInteger(in.createByteArray());
    136             algorithmSpec = new RSAKeyGenParameterSpec(rsaKeySize, publicExponent);
    137         } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_EC) {
    138             String stdName = in.readString();
    139             algorithmSpec = new ECGenParameterSpec(stdName);
    140         } else {
    141             throw new IllegalArgumentException(
    142                     String.format("Unknown algorithm parameter spec: %d", keySpecType));
    143         }
    144         if (algorithmSpec != null) {
    145             builder.setAlgorithmParameterSpec(algorithmSpec);
    146         }
    147         builder.setCertificateSubject(new X500Principal(in.createByteArray()));
    148         builder.setCertificateSerialNumber(new BigInteger(in.createByteArray()));
    149         builder.setCertificateNotBefore(new Date(in.readLong()));
    150         builder.setCertificateNotAfter(new Date(in.readLong()));
    151         builder.setKeyValidityStart(readDateOrNull(in));
    152         builder.setKeyValidityForOriginationEnd(readDateOrNull(in));
    153         builder.setKeyValidityForConsumptionEnd(readDateOrNull(in));
    154         String[] digests = in.createStringArray();
    155         if (digests != null) {
    156             builder.setDigests(digests);
    157         }
    158         builder.setEncryptionPaddings(in.createStringArray());
    159         builder.setSignaturePaddings(in.createStringArray());
    160         builder.setBlockModes(in.createStringArray());
    161         builder.setRandomizedEncryptionRequired(in.readBoolean());
    162         builder.setUserAuthenticationRequired(in.readBoolean());
    163         builder.setUserAuthenticationValidityDurationSeconds(in.readInt());
    164         builder.setAttestationChallenge(in.createByteArray());
    165         builder.setUniqueIdIncluded(in.readBoolean());
    166         builder.setUserAuthenticationValidWhileOnBody(in.readBoolean());
    167         builder.setInvalidatedByBiometricEnrollment(in.readBoolean());
    168         builder.setUserPresenceRequired(in.readBoolean());
    169         mSpec = builder.build();
    170     }
    171 
    172     public static final Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
    173         @Override
    174         public ParcelableKeyGenParameterSpec createFromParcel(Parcel in) {
    175             return new ParcelableKeyGenParameterSpec(in);
    176         }
    177 
    178         @Override
    179         public ParcelableKeyGenParameterSpec[] newArray(int size) {
    180             return new ParcelableKeyGenParameterSpec[size];
    181         }
    182     };
    183 
    184     public KeyGenParameterSpec getSpec() {
    185         return mSpec;
    186     }
    187 }
    188