blob: 7cb8e375a969415f27a218e21714a5487115a996 [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());
100 out.writeByteArray(mSpec.getAttestationChallenge());
101 out.writeBoolean(mSpec.isUniqueIdIncluded());
102 out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
103 out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
104 }
105
106 private static Date readDateOrNull(Parcel in) {
107 boolean hasDate = in.readBoolean();
108 if (hasDate) {
109 return new Date(in.readLong());
110 } else {
111 return null;
112 }
113 }
114
115 private ParcelableKeyGenParameterSpec(Parcel in) {
116 String keystoreAlias = in.readString();
117 int purposes = in.readInt();
Eran Messeri47670542017-12-09 21:25:04 +0000118 KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
119 keystoreAlias, purposes);
Eran Messeri852c8f12017-11-15 05:55:52 +0000120 builder.setUid(in.readInt());
Eran Messeri47670542017-12-09 21:25:04 +0000121 // KeySize is -1 by default, if the KeyGenParameterSpec previously parcelled had the default
122 // value, do not set it as this will cause setKeySize to throw.
123 int keySize = in.readInt();
124 if (keySize >= 0) {
125 builder.setKeySize(keySize);
126 }
Eran Messeri852c8f12017-11-15 05:55:52 +0000127
128 int keySpecType = in.readInt();
129 AlgorithmParameterSpec algorithmSpec = null;
130 if (keySpecType == ALGORITHM_PARAMETER_SPEC_NONE) {
131 algorithmSpec = null;
132 } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_RSA) {
133 int rsaKeySize = in.readInt();
134 BigInteger publicExponent = new BigInteger(in.createByteArray());
135 algorithmSpec = new RSAKeyGenParameterSpec(rsaKeySize, publicExponent);
136 } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_EC) {
137 String stdName = in.readString();
138 algorithmSpec = new ECGenParameterSpec(stdName);
139 } else {
140 throw new IllegalArgumentException(
Eran Messeri47670542017-12-09 21:25:04 +0000141 String.format("Unknown algorithm parameter spec: %d", keySpecType));
Eran Messeri852c8f12017-11-15 05:55:52 +0000142 }
Eran Messeri47670542017-12-09 21:25:04 +0000143 if (algorithmSpec != null) {
144 builder.setAlgorithmParameterSpec(algorithmSpec);
145 }
Eran Messeri852c8f12017-11-15 05:55:52 +0000146 builder.setCertificateSubject(new X500Principal(in.createByteArray()));
147 builder.setCertificateSerialNumber(new BigInteger(in.createByteArray()));
Eran Messeri47670542017-12-09 21:25:04 +0000148 builder.setCertificateNotBefore(new Date(in.readLong()));
149 builder.setCertificateNotAfter(new Date(in.readLong()));
Eran Messeri852c8f12017-11-15 05:55:52 +0000150 builder.setKeyValidityStart(readDateOrNull(in));
151 builder.setKeyValidityForOriginationEnd(readDateOrNull(in));
152 builder.setKeyValidityForConsumptionEnd(readDateOrNull(in));
Eran Messeri47670542017-12-09 21:25:04 +0000153 String[] digests = in.createStringArray();
154 if (digests != null) {
155 builder.setDigests(digests);
156 }
Eran Messeri852c8f12017-11-15 05:55:52 +0000157 builder.setEncryptionPaddings(in.createStringArray());
158 builder.setSignaturePaddings(in.createStringArray());
159 builder.setBlockModes(in.createStringArray());
160 builder.setRandomizedEncryptionRequired(in.readBoolean());
161 builder.setUserAuthenticationRequired(in.readBoolean());
162 builder.setUserAuthenticationValidityDurationSeconds(in.readInt());
163 builder.setAttestationChallenge(in.createByteArray());
164 builder.setUniqueIdIncluded(in.readBoolean());
165 builder.setUserAuthenticationValidWhileOnBody(in.readBoolean());
166 builder.setInvalidatedByBiometricEnrollment(in.readBoolean());
167 mSpec = builder.build();
168 }
169
170 public static final Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
171 @Override
172 public ParcelableKeyGenParameterSpec createFromParcel(Parcel in) {
173 return new ParcelableKeyGenParameterSpec(in);
174 }
175
176 @Override
177 public ParcelableKeyGenParameterSpec[] newArray(int size) {
178 return new ParcelableKeyGenParameterSpec[size];
179 }
180 };
181
182 public KeyGenParameterSpec getSpec() {
183 return mSpec;
184 }
185}