244 lines
10 KiB
Java
244 lines
10 KiB
Java
![]() |
/*
|
||
|
* 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.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
|
||
|
import java.math.BigInteger;
|
||
|
import java.security.spec.AlgorithmParameterSpec;
|
||
|
import java.security.spec.ECGenParameterSpec;
|
||
|
import java.security.spec.RSAKeyGenParameterSpec;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.Collections;
|
||
|
import java.util.Date;
|
||
|
import java.util.List;
|
||
|
import java.util.Set;
|
||
|
|
||
|
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.getNamespace());
|
||
|
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);
|
||
|
}
|
||
|
if (mSpec.isMgf1DigestsSpecified()) {
|
||
|
out.writeStringList(List.copyOf(mSpec.getMgf1Digests()));
|
||
|
} else {
|
||
|
out.writeStringList(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.writeInt(mSpec.getUserAuthenticationType());
|
||
|
out.writeBoolean(mSpec.isUserPresenceRequired());
|
||
|
out.writeByteArray(mSpec.getAttestationChallenge());
|
||
|
out.writeBoolean(mSpec.isDevicePropertiesAttestationIncluded());
|
||
|
out.writeIntArray(mSpec.getAttestationIds());
|
||
|
out.writeBoolean(mSpec.isUniqueIdIncluded());
|
||
|
out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
|
||
|
out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
|
||
|
out.writeBoolean(mSpec.isStrongBoxBacked());
|
||
|
out.writeBoolean(mSpec.isUserConfirmationRequired());
|
||
|
out.writeBoolean(mSpec.isUnlockedDeviceRequired());
|
||
|
out.writeBoolean(mSpec.isCriticalToDeviceEncryption());
|
||
|
out.writeInt(mSpec.getMaxUsageCount());
|
||
|
out.writeString(mSpec.getAttestKeyAlias());
|
||
|
out.writeLong(mSpec.getBoundToSpecificSecureUserId());
|
||
|
}
|
||
|
|
||
|
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 namespace = 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 ArrayList<String> mgf1Digests = in.createStringArrayList();
|
||
|
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 int userAuthenticationTypes = in.readInt();
|
||
|
final boolean userPresenceRequired = in.readBoolean();
|
||
|
final byte[] attestationChallenge = in.createByteArray();
|
||
|
final boolean devicePropertiesAttestationIncluded = in.readBoolean();
|
||
|
final int[] attestationIds = in.createIntArray();
|
||
|
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();
|
||
|
final boolean criticalToDeviceEncryption = in.readBoolean();
|
||
|
final int maxUsageCount = in.readInt();
|
||
|
final String attestKeyAlias = in.readString();
|
||
|
final long boundToSecureUserId = in.readLong();
|
||
|
// 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,
|
||
|
namespace,
|
||
|
keySize,
|
||
|
algorithmSpec,
|
||
|
certificateSubject,
|
||
|
certificateSerialNumber,
|
||
|
certificateNotBefore,
|
||
|
certificateNotAfter,
|
||
|
keyValidityStartDate,
|
||
|
keyValidityForOriginationEnd,
|
||
|
keyValidityForConsumptionEnd,
|
||
|
purposes,
|
||
|
digests,
|
||
|
mgf1Digests != null ? Set.copyOf(mgf1Digests) : Collections.emptySet(),
|
||
|
encryptionPaddings,
|
||
|
signaturePaddings,
|
||
|
blockModes,
|
||
|
randomizedEncryptionRequired,
|
||
|
userAuthenticationRequired,
|
||
|
userAuthenticationValidityDurationSeconds,
|
||
|
userAuthenticationTypes,
|
||
|
userPresenceRequired,
|
||
|
attestationChallenge,
|
||
|
devicePropertiesAttestationIncluded,
|
||
|
attestationIds,
|
||
|
uniqueIdIncluded,
|
||
|
userAuthenticationValidWhileOnBody,
|
||
|
invalidatedByBiometricEnrollment,
|
||
|
isStrongBoxBacked,
|
||
|
userConfirmationRequired,
|
||
|
unlockedDeviceRequired,
|
||
|
criticalToDeviceEncryption,
|
||
|
maxUsageCount,
|
||
|
attestKeyAlias,
|
||
|
boundToSecureUserId);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|