blob: d8030fb8ab7980db7432ef4f340342e3842814e6 [file] [log] [blame]
Eran Messeri852c8f12017-11-15 05:55:52 +00001/*
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
17package android.security.keystore;
18
19import android.os.Parcelable;
20import android.os.Parcel;
21
22import java.math.BigInteger;
23import java.security.spec.AlgorithmParameterSpec;
24import java.security.spec.ECGenParameterSpec;
25import java.security.spec.RSAKeyGenParameterSpec;
26import java.util.Date;
27
28import javax.security.auth.x500.X500Principal;
29
30/**
31 * A parcelable version of KeyGenParameterSpec
32 * @hide only used for communicating with the DPMS.
33 */
34public 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());
Eran Messeri47670542017-12-09 21:25:04 +000084 out.writeLong(mSpec.getCertificateNotBefore().getTime());
85 out.writeLong(mSpec.getCertificateNotAfter().getTime());
Eran Messeri852c8f12017-11-15 05:55:52 +000086 writeOptionalDate(out, mSpec.getKeyValidityStart());
87 writeOptionalDate(out, mSpec.getKeyValidityForOriginationEnd());
88 writeOptionalDate(out, mSpec.getKeyValidityForConsumptionEnd());
Eran Messeri47670542017-12-09 21:25:04 +000089 if (mSpec.isDigestsSpecified()) {
90 out.writeStringArray(mSpec.getDigests());
91 } else {
92 out.writeStringArray(null);
93 }
Eran Messeri852c8f12017-11-15 05:55:52 +000094 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());
Eran Messeri5a5c6e02018-06-28 11:20:44 +0100100 out.writeBoolean(mSpec.isUserPresenceRequired());
Eran Messeri852c8f12017-11-15 05:55:52 +0000101 out.writeByteArray(mSpec.getAttestationChallenge());
102 out.writeBoolean(mSpec.isUniqueIdIncluded());
103 out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
104 out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
Eran Messeri5a5c6e02018-06-28 11:20:44 +0100105 out.writeBoolean(mSpec.isStrongBoxBacked());
106 out.writeBoolean(mSpec.isUserConfirmationRequired());
107 out.writeBoolean(mSpec.isUnlockedDeviceRequired());
Eran Messeri852c8f12017-11-15 05:55:52 +0000108 }
109
110 private static Date readDateOrNull(Parcel in) {
111 boolean hasDate = in.readBoolean();
112 if (hasDate) {
113 return new Date(in.readLong());
114 } else {
115 return null;
116 }
117 }
118
119 private ParcelableKeyGenParameterSpec(Parcel in) {
Eran Messeri5a5c6e02018-06-28 11:20:44 +0100120 final String keystoreAlias = in.readString();
121 final int purposes = in.readInt();
122 final int uid = in.readInt();
123 final int keySize = in.readInt();
Eran Messeri852c8f12017-11-15 05:55:52 +0000124
Eran Messeri5a5c6e02018-06-28 11:20:44 +0100125 final int keySpecType = in.readInt();
Eran Messeri852c8f12017-11-15 05:55:52 +0000126 AlgorithmParameterSpec algorithmSpec = null;
127 if (keySpecType == ALGORITHM_PARAMETER_SPEC_NONE) {
128 algorithmSpec = null;
129 } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_RSA) {
130 int rsaKeySize = in.readInt();
131 BigInteger publicExponent = new BigInteger(in.createByteArray());
132 algorithmSpec = new RSAKeyGenParameterSpec(rsaKeySize, publicExponent);
133 } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_EC) {
134 String stdName = in.readString();
135 algorithmSpec = new ECGenParameterSpec(stdName);
136 } else {
137 throw new IllegalArgumentException(
Eran Messeri47670542017-12-09 21:25:04 +0000138 String.format("Unknown algorithm parameter spec: %d", keySpecType));
Eran Messeri852c8f12017-11-15 05:55:52 +0000139 }
Eran Messeri5a5c6e02018-06-28 11:20:44 +0100140
141 final X500Principal certificateSubject = new X500Principal(in.createByteArray());
142 final BigInteger certificateSerialNumber = new BigInteger(in.createByteArray());
143 final Date certificateNotBefore = new Date(in.readLong());
144 final Date certificateNotAfter = new Date(in.readLong());
145 final Date keyValidityStartDate = readDateOrNull(in);
146 final Date keyValidityForOriginationEnd = readDateOrNull(in);
147 final Date keyValidityForConsumptionEnd = readDateOrNull(in);
148 final String[] digests = in.createStringArray();
149 final String[] encryptionPaddings = in.createStringArray();
150 final String[] signaturePaddings = in.createStringArray();
151 final String[] blockModes = in.createStringArray();
152 final boolean randomizedEncryptionRequired = in.readBoolean();
153 final boolean userAuthenticationRequired = in.readBoolean();
154 final int userAuthenticationValidityDurationSeconds = in.readInt();
155 final boolean userPresenceRequired = in.readBoolean();
156 final byte[] attestationChallenge = in.createByteArray();
157 final boolean uniqueIdIncluded = in.readBoolean();
158 final boolean userAuthenticationValidWhileOnBody = in.readBoolean();
159 final boolean invalidatedByBiometricEnrollment = in.readBoolean();
160 final boolean isStrongBoxBacked = in.readBoolean();
161 final boolean userConfirmationRequired = in.readBoolean();
162 final boolean unlockedDeviceRequired = in.readBoolean();
163 // The KeyGenParameterSpec is intentionally not constructed using a Builder here:
164 // The intention is for this class to break if new parameters are added to the
165 // KeyGenParameterSpec constructor (whereas using a builder would silently drop them).
166 mSpec = new KeyGenParameterSpec(
167 keystoreAlias,
168 uid,
169 keySize,
170 algorithmSpec,
171 certificateSubject,
172 certificateSerialNumber,
173 certificateNotBefore,
174 certificateNotAfter,
175 keyValidityStartDate,
176 keyValidityForOriginationEnd,
177 keyValidityForConsumptionEnd,
178 purposes,
179 digests,
180 encryptionPaddings,
181 signaturePaddings,
182 blockModes,
183 randomizedEncryptionRequired,
184 userAuthenticationRequired,
185 userAuthenticationValidityDurationSeconds,
186 userPresenceRequired,
187 attestationChallenge,
188 uniqueIdIncluded,
189 userAuthenticationValidWhileOnBody,
190 invalidatedByBiometricEnrollment,
191 isStrongBoxBacked,
192 userConfirmationRequired,
193 unlockedDeviceRequired);
Eran Messeri852c8f12017-11-15 05:55:52 +0000194 }
195
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700196 public static final @android.annotation.NonNull Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
Eran Messeri852c8f12017-11-15 05:55:52 +0000197 @Override
198 public ParcelableKeyGenParameterSpec createFromParcel(Parcel in) {
199 return new ParcelableKeyGenParameterSpec(in);
200 }
201
202 @Override
203 public ParcelableKeyGenParameterSpec[] newArray(int size) {
204 return new ParcelableKeyGenParameterSpec[size];
205 }
206 };
207
208 public KeyGenParameterSpec getSpec() {
209 return mSpec;
210 }
211}