• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getFeatureVersionKeystore(boolean isStrongBox)97     public static int getFeatureVersionKeystore(boolean isStrongBox) {
98         if (isStrongBox) {
99             return TestUtils.getFeatureVersionKeystoreStrongBox(
100             ApplicationProvider.getApplicationContext());
101         }
102         return TestUtils.getFeatureVersionKeystore(ApplicationProvider.getApplicationContext());
103     }
104 
hasStrongBox()105     public static boolean hasStrongBox() {
106         Context context = ApplicationProvider.getApplicationContext();
107         return TestUtils.hasStrongBox(context);
108     }
109 
assumeStrongBox()110     public static void assumeStrongBox() {
111         TestUtils.assumeStrongBox();
112     }
113 
isSupportedDigest(String digest, boolean isStrongBox)114     public static boolean isSupportedDigest(String digest, boolean isStrongBox) {
115         if (isStrongBox) {
116             return digest.equalsIgnoreCase("sha-256");
117         }
118         return kmSupportedDigests.contains(digest.toLowerCase());
119     }
120 
isSupportedMgfDigest(String digest, boolean isStrongBox)121     public static boolean isSupportedMgfDigest(String digest, boolean isStrongBox) {
122         if (isStrongBox) {
123             return digest.equalsIgnoreCase("sha-1")
124                     || digest.equalsIgnoreCase("sha-256");
125         }
126         return kmSupportedDigests.contains(digest.toLowerCase());
127     }
128 
isSupportedRsaKeySize(int keySize, boolean isStrongBox)129     public static boolean isSupportedRsaKeySize(int keySize, boolean isStrongBox) {
130         if (isStrongBox) {
131             return keySize == 2048;
132         }
133         return keySize == 2048 || keySize == 3072 || keySize == 4096;
134     }
135 
createCertificate( KeyPair keyPair, X500Principal subject, X500Principal issuer)136     public static X509Certificate createCertificate(
137             KeyPair keyPair, X500Principal subject, X500Principal issuer)
138             throws OperatorCreationException, CertificateException, IOException {
139         // Make the certificate valid for two days.
140         long millisPerDay = 24 * 60 * 60 * 1000;
141         long now = System.currentTimeMillis();
142         Date start = new Date(now - millisPerDay);
143         Date end = new Date(now + millisPerDay);
144 
145         // Assign a random serial number.
146         byte[] serialBytes = new byte[16];
147         new SecureRandom().nextBytes(serialBytes);
148         BigInteger serialNumber = new BigInteger(1, serialBytes);
149 
150         // Create the certificate builder
151         X509v3CertificateBuilder x509cg =
152                 new X509v3CertificateBuilder(
153                         X500Name.getInstance(issuer.getEncoded()),
154                         serialNumber,
155                         start,
156                         end,
157                         X500Name.getInstance(subject.getEncoded()),
158                         SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()));
159 
160         // Choose a signature algorithm matching the key format.
161         String keyAlgorithm = keyPair.getPrivate().getAlgorithm();
162         String signatureAlgorithm;
163         if (keyAlgorithm.equals("RSA")) {
164             signatureAlgorithm = "SHA256withRSA";
165         } else if (keyAlgorithm.equals("EC")) {
166             signatureAlgorithm = "SHA256withECDSA";
167         } else {
168             throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm);
169         }
170 
171         // Sign the certificate and generate it.
172         X509CertificateHolder x509holder =
173                 x509cg.build(
174                         new JcaContentSignerBuilder(signatureAlgorithm)
175                                 .build(keyPair.getPrivate()));
176         CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
177         X509Certificate x509c =
178                 (X509Certificate)
179                         certFactory.generateCertificate(
180                                 new ByteArrayInputStream(x509holder.getEncoded()));
181         return x509c;
182     }
183 
assumeKeyMintV1OrNewer(boolean isStrongBox)184     public static void assumeKeyMintV1OrNewer(boolean isStrongBox) {
185         assumeTrue("Test can only run on KeyMint v1 and above",
186             KeyStoreUtil.getFeatureVersionKeystore(isStrongBox) >= KM_VERSION_KEYMINT_1);
187     }
188 }
189