1 /** 2 * Licensed under the Apache License, Version 2.0 (the "License"); 3 * you may not use this file except in compliance with the License. 4 * You may obtain a copy of the License at 5 * 6 * http://www.apache.org/licenses/LICENSE-2.0 7 * 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 * See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 package android.keystore.cts.util; 15 16 import static org.junit.Assume.assumeTrue; 17 import android.content.Context; 18 import android.security.keystore.KeyProtection; 19 import android.keystore.cts.util.TestUtils; 20 import androidx.test.core.app.ApplicationProvider; 21 import org.bouncycastle.asn1.x500.X500Name; 22 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 23 import org.bouncycastle.cert.X509CertificateHolder; 24 import org.bouncycastle.cert.X509v3CertificateBuilder; 25 import org.bouncycastle.operator.OperatorCreationException; 26 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; 27 import java.io.ByteArrayInputStream; 28 import java.io.IOException; 29 import java.math.BigInteger; 30 import java.security.GeneralSecurityException; 31 import java.security.KeyPair; 32 import java.security.KeyStore; 33 import java.security.PrivateKey; 34 import java.security.PublicKey; 35 import java.security.SecureRandom; 36 import java.security.cert.Certificate; 37 import java.security.cert.CertificateException; 38 import java.security.cert.CertificateFactory; 39 import java.security.cert.X509Certificate; 40 import java.util.Date; 41 import java.util.Enumeration; 42 import java.util.List; 43 import javax.crypto.spec.SecretKeySpec; 44 import javax.security.auth.x500.X500Principal; 45 46 /** Keystore utilities */ 47 public class KeyStoreUtil { 48 // Known KeyMaster/KeyMint versions. This is the version number 49 // which appear in the keymasterVersion field. 50 public static final int KM_VERSION_KEYMASTER_1 = 10; 51 public static final int KM_VERSION_KEYMASTER_1_1 = 11; 52 public static final int KM_VERSION_KEYMASTER_2 = 20; 53 public static final int KM_VERSION_KEYMASTER_3 = 30; 54 public static final int KM_VERSION_KEYMASTER_4 = 40; 55 public static final int KM_VERSION_KEYMASTER_4_1 = 41; 56 public static final int KM_VERSION_KEYMINT_1 = 100; 57 public static final int KM_VERSION_KEYMINT_2 = 200; 58 public static final int KM_VERSION_KEYMINT_3 = 300; 59 60 private static final List kmSupportedDigests = List.of("md5","sha-1","sha-224","sha-384", 61 "sha-256","sha-512"); 62 saveKeysToKeystore(String alias, PublicKey pubKey, PrivateKey privKey, KeyProtection keyProtection)63 public static KeyStore saveKeysToKeystore(String alias, PublicKey pubKey, PrivateKey privKey, 64 KeyProtection keyProtection) throws Exception { 65 KeyPair keyPair = new KeyPair(pubKey, privKey); 66 X509Certificate certificate = createCertificate(keyPair, 67 new X500Principal("CN=Test1"), 68 new X500Principal("CN=Test1")); 69 Certificate[] certChain = new Certificate[]{certificate}; 70 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 71 keyStore.load(null); 72 keyStore.setEntry(alias, 73 new KeyStore.PrivateKeyEntry(privKey, certChain), 74 keyProtection); 75 return keyStore; 76 } 77 saveSecretKeyToKeystore(String alias, SecretKeySpec keySpec, KeyProtection keyProtection)78 public static KeyStore saveSecretKeyToKeystore(String alias, SecretKeySpec keySpec, 79 KeyProtection keyProtection) throws Exception { 80 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 81 keyStore.load(null); 82 keyStore.setEntry(alias, 83 new KeyStore.SecretKeyEntry(keySpec), 84 keyProtection); 85 return keyStore; 86 } 87 cleanUpKeyStore()88 public static void cleanUpKeyStore() throws Exception { 89 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 90 keyStore.load(null); 91 for (Enumeration<String> aliases = keyStore.aliases(); aliases.hasMoreElements();) { 92 String alias = aliases.nextElement(); 93 keyStore.deleteEntry(alias); 94 } 95 } 96 hasStrongBox()97 public static boolean hasStrongBox() { 98 Context context = ApplicationProvider.getApplicationContext(); 99 return TestUtils.hasStrongBox(context); 100 } 101 assumeStrongBox()102 public static void assumeStrongBox() { 103 TestUtils.assumeStrongBox(); 104 } 105 isSupportedDigest(String digest, boolean isStrongBox)106 public static boolean isSupportedDigest(String digest, boolean isStrongBox) { 107 if (isStrongBox) { 108 return digest.equalsIgnoreCase("sha-256"); 109 } 110 return kmSupportedDigests.contains(digest.toLowerCase()); 111 } 112 isSupportedMgfDigest(String digest, boolean isStrongBox)113 public static boolean isSupportedMgfDigest(String digest, boolean isStrongBox) { 114 if (isStrongBox) { 115 return digest.equalsIgnoreCase("sha-1") 116 || digest.equalsIgnoreCase("sha-256"); 117 } 118 return kmSupportedDigests.contains(digest.toLowerCase()); 119 } 120 isSupportedRsaKeySize(int keySize, boolean isStrongBox)121 public static boolean isSupportedRsaKeySize(int keySize, boolean isStrongBox) { 122 if (isStrongBox) { 123 return keySize == 2048; 124 } 125 return keySize == 2048 || keySize == 3072 || keySize == 4096; 126 } 127 createCertificate( KeyPair keyPair, X500Principal subject, X500Principal issuer)128 public static X509Certificate createCertificate( 129 KeyPair keyPair, X500Principal subject, X500Principal issuer) 130 throws OperatorCreationException, CertificateException, IOException { 131 // Make the certificate valid for two days. 132 long millisPerDay = 24 * 60 * 60 * 1000; 133 long now = System.currentTimeMillis(); 134 Date start = new Date(now - millisPerDay); 135 Date end = new Date(now + millisPerDay); 136 137 // Assign a random serial number. 138 byte[] serialBytes = new byte[16]; 139 new SecureRandom().nextBytes(serialBytes); 140 BigInteger serialNumber = new BigInteger(1, serialBytes); 141 142 // Create the certificate builder 143 X509v3CertificateBuilder x509cg = 144 new X509v3CertificateBuilder( 145 X500Name.getInstance(issuer.getEncoded()), 146 serialNumber, 147 start, 148 end, 149 X500Name.getInstance(subject.getEncoded()), 150 SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded())); 151 152 // Choose a signature algorithm matching the key format. 153 String keyAlgorithm = keyPair.getPrivate().getAlgorithm(); 154 String signatureAlgorithm; 155 if (keyAlgorithm.equals("RSA")) { 156 signatureAlgorithm = "SHA256withRSA"; 157 } else if (keyAlgorithm.equals("EC")) { 158 signatureAlgorithm = "SHA256withECDSA"; 159 } else { 160 throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm); 161 } 162 163 // Sign the certificate and generate it. 164 X509CertificateHolder x509holder = 165 x509cg.build( 166 new JcaContentSignerBuilder(signatureAlgorithm) 167 .build(keyPair.getPrivate())); 168 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 169 X509Certificate x509c = 170 (X509Certificate) 171 certFactory.generateCertificate( 172 new ByteArrayInputStream(x509holder.getEncoded())); 173 return x509c; 174 } 175 assumeKeyMintV1OrNewer(boolean isStrongBox)176 public static void assumeKeyMintV1OrNewer(boolean isStrongBox) { 177 assumeTrue("Test can only run on KeyMint v1 and above", 178 TestUtils.hasKeystoreVersion(isStrongBox, KM_VERSION_KEYMINT_1)); 179 } 180 } 181