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; 18 19 import static org.hamcrest.Matchers.is; 20 import static org.junit.Assert.assertArrayEquals; 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertThat; 23 24 import android.os.Parcel; 25 import android.security.keystore.KeyGenParameterSpec; 26 import android.security.keystore.KeyProperties; 27 import android.security.keystore.ParcelableKeyGenParameterSpec; 28 29 import androidx.test.runner.AndroidJUnit4; 30 31 import org.junit.Test; 32 import org.junit.runner.RunWith; 33 34 import java.math.BigInteger; 35 import java.security.spec.ECGenParameterSpec; 36 import java.security.spec.RSAKeyGenParameterSpec; 37 import java.util.Date; 38 39 import javax.security.auth.x500.X500Principal; 40 41 /** Unit tests for {@link ParcelableKeyGenParameterSpec}. */ 42 @RunWith(AndroidJUnit4.class) 43 public final class ParcelableKeyGenParameterSpecTest { 44 static final String ALIAS = "keystore-alias"; 45 static final String ANOTHER_ALIAS = "another-keystore-alias"; 46 static final int KEY_PURPOSES = KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY; 47 static final int KEYSIZE = 2048; 48 static final X500Principal SUBJECT = new X500Principal("CN=subject"); 49 static final BigInteger SERIAL = new BigInteger("1234567890"); 50 static final Date NOT_BEFORE = new Date(1511799590); 51 static final Date NOT_AFTER = new Date(1511899590); 52 static final Date KEY_VALIDITY_START = new Date(1511799591); 53 static final Date KEY_VALIDITY_FOR_ORIG_END = new Date(1511799593); 54 static final Date KEY_VALIDITY_FOR_CONSUMPTION_END = new Date(1511799594); 55 static final String DIGEST = KeyProperties.DIGEST_SHA256; 56 static final String ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1; 57 static final String SIGNATURE_PADDING = KeyProperties.SIGNATURE_PADDING_RSA_PSS; 58 static final String BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC; 59 static final int USER_AUTHENTICATION_DURATION = 300; 60 static final byte[] ATTESTATION_CHALLENGE = new byte[] {'c', 'h'}; 61 configureDefaultSpec()62 public static KeyGenParameterSpec configureDefaultSpec() { 63 return new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES) 64 .setNamespace(KeyProperties.NAMESPACE_WIFI) 65 .setKeySize(KEYSIZE) 66 .setCertificateSubject(SUBJECT) 67 .setCertificateSerialNumber(SERIAL) 68 .setCertificateNotBefore(NOT_BEFORE) 69 .setCertificateNotAfter(NOT_AFTER) 70 .setKeyValidityStart(KEY_VALIDITY_START) 71 .setKeyValidityForOriginationEnd(KEY_VALIDITY_FOR_ORIG_END) 72 .setKeyValidityForConsumptionEnd(KEY_VALIDITY_FOR_CONSUMPTION_END) 73 .setDigests(DIGEST) 74 .setEncryptionPaddings(ENCRYPTION_PADDING) 75 .setSignaturePaddings(SIGNATURE_PADDING) 76 .setBlockModes(BLOCK_MODE) 77 .setRandomizedEncryptionRequired(true) 78 .setUserAuthenticationRequired(true) 79 .setUserAuthenticationValidityDurationSeconds(USER_AUTHENTICATION_DURATION) 80 .setAttestationChallenge(ATTESTATION_CHALLENGE) 81 .setUniqueIdIncluded(true) 82 .setUserAuthenticationValidWhileOnBody(true) 83 .setInvalidatedByBiometricEnrollment(true) 84 .setIsStrongBoxBacked(true) 85 .setUserConfirmationRequired(true) 86 .setUnlockedDeviceRequired(true) 87 .setCriticalToDeviceEncryption(true) 88 .build(); 89 } 90 validateSpecValues(KeyGenParameterSpec spec, @KeyProperties.Namespace int namespace, String alias)91 public static void validateSpecValues(KeyGenParameterSpec spec, 92 @KeyProperties.Namespace int namespace, String alias) { 93 assertThat(spec.getKeystoreAlias(), is(alias)); 94 assertThat(spec.getPurposes(), is(KEY_PURPOSES)); 95 assertThat(spec.getNamespace(), is(namespace)); 96 assertThat(spec.getKeySize(), is(KEYSIZE)); 97 assertThat(spec.getCertificateSubject(), is(SUBJECT)); 98 assertThat(spec.getCertificateSerialNumber(), is(SERIAL)); 99 assertThat(spec.getCertificateNotBefore(), is(NOT_BEFORE)); 100 assertThat(spec.getCertificateNotAfter(), is(NOT_AFTER)); 101 assertThat(spec.getKeyValidityStart(), is(KEY_VALIDITY_START)); 102 assertThat(spec.getKeyValidityForOriginationEnd(), is(KEY_VALIDITY_FOR_ORIG_END)); 103 assertThat(spec.getKeyValidityForConsumptionEnd(), is(KEY_VALIDITY_FOR_CONSUMPTION_END)); 104 assertThat(spec.getDigests(), is(new String[] {DIGEST})); 105 assertThat(spec.isMgf1DigestsSpecified(), is(false)); 106 assertThat(spec.getEncryptionPaddings(), is(new String[] {ENCRYPTION_PADDING})); 107 assertThat(spec.getSignaturePaddings(), is(new String[] {SIGNATURE_PADDING})); 108 assertThat(spec.getBlockModes(), is(new String[] {BLOCK_MODE})); 109 assertThat(spec.isRandomizedEncryptionRequired(), is(true)); 110 assertThat(spec.isUserAuthenticationRequired(), is(true)); 111 assertThat( 112 spec.getUserAuthenticationValidityDurationSeconds(), 113 is(USER_AUTHENTICATION_DURATION)); 114 assertThat(spec.getAttestationChallenge(), is(ATTESTATION_CHALLENGE)); 115 assertThat(spec.isUniqueIdIncluded(), is(true)); 116 assertThat(spec.isUserAuthenticationValidWhileOnBody(), is(true)); 117 assertThat(spec.isInvalidatedByBiometricEnrollment(), is(true)); 118 assertThat(spec.isStrongBoxBacked(), is(true)); 119 assertThat(spec.isUserConfirmationRequired(), is(true)); 120 assertThat(spec.isUnlockedDeviceRequired(), is(true)); 121 assertThat(spec.isCriticalToDeviceEncryption(), is(true)); 122 } 123 parcelForReading(ParcelableKeyGenParameterSpec spec)124 private Parcel parcelForReading(ParcelableKeyGenParameterSpec spec) { 125 Parcel parcel = Parcel.obtain(); 126 spec.writeToParcel(parcel, spec.describeContents()); 127 128 parcel.setDataPosition(0); 129 return parcel; 130 } 131 132 @Test testParcelingWithAllValues()133 public void testParcelingWithAllValues() { 134 ParcelableKeyGenParameterSpec spec = 135 new ParcelableKeyGenParameterSpec(configureDefaultSpec()); 136 Parcel parcel = parcelForReading(spec); 137 ParcelableKeyGenParameterSpec fromParcel = 138 ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel); 139 validateSpecValues(fromParcel.getSpec(), KeyProperties.NAMESPACE_WIFI, ALIAS); 140 assertThat(parcel.dataAvail(), is(0)); 141 } 142 143 @Test testParcelingWithNullValues()144 public void testParcelingWithNullValues() { 145 ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec( 146 new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES).build()); 147 148 Parcel parcel = parcelForReading(spec); 149 KeyGenParameterSpec fromParcel = ParcelableKeyGenParameterSpec.CREATOR 150 .createFromParcel(parcel) 151 .getSpec(); 152 assertThat(fromParcel.getKeystoreAlias(), is(ALIAS)); 153 assertThat(fromParcel.getPurposes(), is(KEY_PURPOSES)); 154 assertThat(fromParcel.getCertificateNotBefore(), is(new Date(0L))); 155 assertThat(fromParcel.getCertificateNotAfter(), is(new Date(2461449600000L))); 156 assertThat(parcel.dataAvail(), is(0)); 157 } 158 159 @Test testParcelingRSAAlgoParameter()160 public void testParcelingRSAAlgoParameter() { 161 RSAKeyGenParameterSpec rsaSpec = 162 new RSAKeyGenParameterSpec(2048, new BigInteger("5231123")); 163 ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec( 164 new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES) 165 .setAlgorithmParameterSpec(rsaSpec) 166 .build()); 167 168 Parcel parcel = parcelForReading(spec); 169 KeyGenParameterSpec fromParcel = 170 ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel).getSpec(); 171 RSAKeyGenParameterSpec parcelSpec = 172 (RSAKeyGenParameterSpec) fromParcel.getAlgorithmParameterSpec(); 173 // Compare individual fields as RSAKeyGenParameterSpec, on android, does not 174 // implement equals() 175 assertEquals(parcelSpec.getKeysize(), rsaSpec.getKeysize()); 176 assertEquals(parcelSpec.getPublicExponent(), rsaSpec.getPublicExponent()); 177 } 178 179 @Test testParcelingECAlgoParameter()180 public void testParcelingECAlgoParameter() { 181 ECGenParameterSpec ecSpec = new ECGenParameterSpec("P-256"); 182 ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec( 183 new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES) 184 .setAlgorithmParameterSpec(ecSpec) 185 .build()); 186 Parcel parcel = parcelForReading(spec); 187 KeyGenParameterSpec fromParcel = 188 ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel).getSpec(); 189 // Compare individual fields as ECGenParameterSpec, on android, does not 190 // implement equals() 191 ECGenParameterSpec parcelSpec = (ECGenParameterSpec) fromParcel.getAlgorithmParameterSpec(); 192 assertEquals(parcelSpec.getName(), ecSpec.getName()); 193 } 194 195 @Test testParcelingMgf1Digests()196 public void testParcelingMgf1Digests() { 197 String[] mgf1Digests = 198 new String[] {KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA256}; 199 200 ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec( 201 new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES) 202 .setMgf1Digests(mgf1Digests) 203 .build()); 204 Parcel parcel = parcelForReading(spec); 205 KeyGenParameterSpec fromParcel = 206 ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel).getSpec(); 207 assertArrayEquals(fromParcel.getMgf1Digests().toArray(), mgf1Digests); 208 } 209 } 210