blob: d8030fb8ab7980db7432ef4f340342e3842814e6 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.security.keystore;
import android.os.Parcelable;
import android.os.Parcel;
import java.math.BigInteger;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
/**
* A parcelable version of KeyGenParameterSpec
* @hide only used for communicating with the DPMS.
*/
public final class ParcelableKeyGenParameterSpec implements Parcelable {
private static final int ALGORITHM_PARAMETER_SPEC_NONE = 1;
private static final int ALGORITHM_PARAMETER_SPEC_RSA = 2;
private static final int ALGORITHM_PARAMETER_SPEC_EC = 3;
private final KeyGenParameterSpec mSpec;
public ParcelableKeyGenParameterSpec(
KeyGenParameterSpec spec) {
mSpec = spec;
}
public int describeContents() {
return 0;
}
private static void writeOptionalDate(Parcel out, Date date) {
if (date != null) {
out.writeBoolean(true);
out.writeLong(date.getTime());
} else {
out.writeBoolean(false);
}
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(mSpec.getKeystoreAlias());
out.writeInt(mSpec.getPurposes());
out.writeInt(mSpec.getUid());
out.writeInt(mSpec.getKeySize());
// Only needs to support RSAKeyGenParameterSpec and ECGenParameterSpec.
AlgorithmParameterSpec algoSpec = mSpec.getAlgorithmParameterSpec();
if (algoSpec == null) {
out.writeInt(ALGORITHM_PARAMETER_SPEC_NONE);
} else if (algoSpec instanceof RSAKeyGenParameterSpec) {
RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algoSpec;
out.writeInt(ALGORITHM_PARAMETER_SPEC_RSA);
out.writeInt(rsaSpec.getKeysize());
out.writeByteArray(rsaSpec.getPublicExponent().toByteArray());
} else if (algoSpec instanceof ECGenParameterSpec) {
ECGenParameterSpec ecSpec = (ECGenParameterSpec) algoSpec;
out.writeInt(ALGORITHM_PARAMETER_SPEC_EC);
out.writeString(ecSpec.getName());
} else {
throw new IllegalArgumentException(
String.format("Unknown algorithm parameter spec: %s", algoSpec.getClass()));
}
out.writeByteArray(mSpec.getCertificateSubject().getEncoded());
out.writeByteArray(mSpec.getCertificateSerialNumber().toByteArray());
out.writeLong(mSpec.getCertificateNotBefore().getTime());
out.writeLong(mSpec.getCertificateNotAfter().getTime());
writeOptionalDate(out, mSpec.getKeyValidityStart());
writeOptionalDate(out, mSpec.getKeyValidityForOriginationEnd());
writeOptionalDate(out, mSpec.getKeyValidityForConsumptionEnd());
if (mSpec.isDigestsSpecified()) {
out.writeStringArray(mSpec.getDigests());
} else {
out.writeStringArray(null);
}
out.writeStringArray(mSpec.getEncryptionPaddings());
out.writeStringArray(mSpec.getSignaturePaddings());
out.writeStringArray(mSpec.getBlockModes());
out.writeBoolean(mSpec.isRandomizedEncryptionRequired());
out.writeBoolean(mSpec.isUserAuthenticationRequired());
out.writeInt(mSpec.getUserAuthenticationValidityDurationSeconds());
out.writeBoolean(mSpec.isUserPresenceRequired());
out.writeByteArray(mSpec.getAttestationChallenge());
out.writeBoolean(mSpec.isUniqueIdIncluded());
out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
out.writeBoolean(mSpec.isStrongBoxBacked());
out.writeBoolean(mSpec.isUserConfirmationRequired());
out.writeBoolean(mSpec.isUnlockedDeviceRequired());
}
private static Date readDateOrNull(Parcel in) {
boolean hasDate = in.readBoolean();
if (hasDate) {
return new Date(in.readLong());
} else {
return null;
}
}
private ParcelableKeyGenParameterSpec(Parcel in) {
final String keystoreAlias = in.readString();
final int purposes = in.readInt();
final int uid = in.readInt();
final int keySize = in.readInt();
final int keySpecType = in.readInt();
AlgorithmParameterSpec algorithmSpec = null;
if (keySpecType == ALGORITHM_PARAMETER_SPEC_NONE) {
algorithmSpec = null;
} else if (keySpecType == ALGORITHM_PARAMETER_SPEC_RSA) {
int rsaKeySize = in.readInt();
BigInteger publicExponent = new BigInteger(in.createByteArray());
algorithmSpec = new RSAKeyGenParameterSpec(rsaKeySize, publicExponent);
} else if (keySpecType == ALGORITHM_PARAMETER_SPEC_EC) {
String stdName = in.readString();
algorithmSpec = new ECGenParameterSpec(stdName);
} else {
throw new IllegalArgumentException(
String.format("Unknown algorithm parameter spec: %d", keySpecType));
}
final X500Principal certificateSubject = new X500Principal(in.createByteArray());
final BigInteger certificateSerialNumber = new BigInteger(in.createByteArray());
final Date certificateNotBefore = new Date(in.readLong());
final Date certificateNotAfter = new Date(in.readLong());
final Date keyValidityStartDate = readDateOrNull(in);
final Date keyValidityForOriginationEnd = readDateOrNull(in);
final Date keyValidityForConsumptionEnd = readDateOrNull(in);
final String[] digests = in.createStringArray();
final String[] encryptionPaddings = in.createStringArray();
final String[] signaturePaddings = in.createStringArray();
final String[] blockModes = in.createStringArray();
final boolean randomizedEncryptionRequired = in.readBoolean();
final boolean userAuthenticationRequired = in.readBoolean();
final int userAuthenticationValidityDurationSeconds = in.readInt();
final boolean userPresenceRequired = in.readBoolean();
final byte[] attestationChallenge = in.createByteArray();
final boolean uniqueIdIncluded = in.readBoolean();
final boolean userAuthenticationValidWhileOnBody = in.readBoolean();
final boolean invalidatedByBiometricEnrollment = in.readBoolean();
final boolean isStrongBoxBacked = in.readBoolean();
final boolean userConfirmationRequired = in.readBoolean();
final boolean unlockedDeviceRequired = in.readBoolean();
// The KeyGenParameterSpec is intentionally not constructed using a Builder here:
// The intention is for this class to break if new parameters are added to the
// KeyGenParameterSpec constructor (whereas using a builder would silently drop them).
mSpec = new KeyGenParameterSpec(
keystoreAlias,
uid,
keySize,
algorithmSpec,
certificateSubject,
certificateSerialNumber,
certificateNotBefore,
certificateNotAfter,
keyValidityStartDate,
keyValidityForOriginationEnd,
keyValidityForConsumptionEnd,
purposes,
digests,
encryptionPaddings,
signaturePaddings,
blockModes,
randomizedEncryptionRequired,
userAuthenticationRequired,
userAuthenticationValidityDurationSeconds,
userPresenceRequired,
attestationChallenge,
uniqueIdIncluded,
userAuthenticationValidWhileOnBody,
invalidatedByBiometricEnrollment,
isStrongBoxBacked,
userConfirmationRequired,
unlockedDeviceRequired);
}
public static final @android.annotation.NonNull Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
@Override
public ParcelableKeyGenParameterSpec createFromParcel(Parcel in) {
return new ParcelableKeyGenParameterSpec(in);
}
@Override
public ParcelableKeyGenParameterSpec[] newArray(int size) {
return new ParcelableKeyGenParameterSpec[size];
}
};
public KeyGenParameterSpec getSpec() {
return mSpec;
}
}