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