AndroidKeyPairGenerator.java revision 12e752225aa96888358294be0d725d499a1c9f03
1db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root/* 2db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * Copyright (C) 2012 The Android Open Source Project 3db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * 4db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 5db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * you may not use this file except in compliance with the License. 6db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * You may obtain a copy of the License at 7db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * 8db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * http://www.apache.org/licenses/LICENSE-2.0 9db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * 10db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * Unless required by applicable law or agreed to in writing, software 11db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * distributed under the License is distributed on an "AS IS" BASIS, 12db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * See the License for the specific language governing permissions and 14db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * limitations under the License. 15db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root */ 16db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 17db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootpackage android.security; 18db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 19db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport com.android.org.bouncycastle.x509.X509V3CertificateGenerator; 20db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 2112e752225aa96888358294be0d725d499a1c9f03Kenny Rootimport com.android.org.conscrypt.OpenSSLEngine; 22db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 23db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.InvalidAlgorithmParameterException; 24db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.InvalidKeyException; 25db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.KeyFactory; 26db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.KeyPair; 27db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.KeyPairGenerator; 28db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.KeyPairGeneratorSpi; 29db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.NoSuchAlgorithmException; 30db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.PrivateKey; 31db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.PublicKey; 32db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.SecureRandom; 33db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.cert.CertificateEncodingException; 34db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.cert.X509Certificate; 35db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.spec.AlgorithmParameterSpec; 36db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.spec.InvalidKeySpecException; 37db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport java.security.spec.X509EncodedKeySpec; 38db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 39db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root/** 40db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * Provides a way to create instances of a KeyPair which will be placed in the 41db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * Android keystore service usable only by the application that called it. This 42db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * can be used in conjunction with 43db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * {@link java.security.KeyStore#getInstance(String)} using the 44db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * {@code "AndroidKeyStore"} type. 45db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * <p> 46db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * This class can not be directly instantiated and must instead be used via the 47db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * {@link KeyPairGenerator#getInstance(String) 48db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * KeyPairGenerator.getInstance("AndroidKeyPairGenerator")} API. 49db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * 50db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * {@hide} 51db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root */ 52db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootpublic class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { 53db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root private android.security.KeyStore mKeyStore; 54db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 55db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root private AndroidKeyPairGeneratorSpec mSpec; 56db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 57db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root /** 58db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * Generate a KeyPair which is backed by the Android keystore service. You 59db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * must call {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)} 60db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * with an {@link AndroidKeyPairGeneratorSpec} as the {@code params} 61db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * argument before calling this otherwise an {@code IllegalStateException} 62db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * will be thrown. 63db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * <p> 64db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * This will create an entry in the Android keystore service with a 65db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * self-signed certificate using the {@code params} specified in the 66db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * {@code initialize(params)} call. 67db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * 68db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * @throws IllegalStateException when called before calling 69db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)} 70db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * @see java.security.KeyPairGeneratorSpi#generateKeyPair() 71db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root */ 72db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root @Override 73db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root public KeyPair generateKeyPair() { 74db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root if (mKeyStore == null || mSpec == null) { 75db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException( 76db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root "Must call initialize with an AndroidKeyPairGeneratorSpec first"); 77db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 78db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 79bf2147669e295384df17b50afc53a4d450b05bddKenny Root if (((mSpec.getFlags() & KeyStore.FLAG_ENCRYPTED) != 0) 80bf2147669e295384df17b50afc53a4d450b05bddKenny Root && (mKeyStore.state() != KeyStore.State.UNLOCKED)) { 81bf2147669e295384df17b50afc53a4d450b05bddKenny Root throw new IllegalStateException( 82bf2147669e295384df17b50afc53a4d450b05bddKenny Root "Android keystore must be in initialized and unlocked state " 83bf2147669e295384df17b50afc53a4d450b05bddKenny Root + "if encryption is required"); 84bf2147669e295384df17b50afc53a4d450b05bddKenny Root } 85bf2147669e295384df17b50afc53a4d450b05bddKenny Root 86db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final String alias = mSpec.getKeystoreAlias(); 87db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 88db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root Credentials.deleteAllTypesForAlias(mKeyStore, alias); 89db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 90db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias; 91bf2147669e295384df17b50afc53a4d450b05bddKenny Root if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, mSpec.getFlags())) { 92bf2147669e295384df17b50afc53a4d450b05bddKenny Root throw new IllegalStateException("could not generate key in keystore"); 93bf2147669e295384df17b50afc53a4d450b05bddKenny Root } 94db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 95db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final PrivateKey privKey; 96db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore"); 97db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root try { 98db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root privKey = engine.getPrivateKeyById(privateKeyAlias); 99db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (InvalidKeyException e) { 100db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new RuntimeException("Can't get key", e); 101db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 102db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 103db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final byte[] pubKeyBytes = mKeyStore.getPubkey(privateKeyAlias); 104db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 105db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final PublicKey pubKey; 106db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root try { 107db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final KeyFactory keyFact = KeyFactory.getInstance("RSA"); 108db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes)); 109db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (NoSuchAlgorithmException e) { 110db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("Can't instantiate RSA key generator", e); 111db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (InvalidKeySpecException e) { 112db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("keystore returned invalid key encoding", e); 113db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 114db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 115db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); 116db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setPublicKey(pubKey); 117db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setSerialNumber(mSpec.getSerialNumber()); 118db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setSubjectDN(mSpec.getSubjectDN()); 119db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setIssuerDN(mSpec.getSubjectDN()); 120db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setNotBefore(mSpec.getStartDate()); 121db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setNotAfter(mSpec.getEndDate()); 122db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setSignatureAlgorithm("sha1WithRSA"); 123db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 124db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final X509Certificate cert; 125db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root try { 126db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root cert = certGen.generate(privKey); 127db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (Exception e) { 128db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root Credentials.deleteAllTypesForAlias(mKeyStore, alias); 129db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("Can't generate certificate", e); 130db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 131db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 132db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root byte[] certBytes; 133db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root try { 134db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certBytes = cert.getEncoded(); 135db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (CertificateEncodingException e) { 136db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root Credentials.deleteAllTypesForAlias(mKeyStore, alias); 137db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("Can't get encoding of certificate", e); 138db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 139db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 140bf2147669e295384df17b50afc53a4d450b05bddKenny Root if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes, KeyStore.UID_SELF, 141bf2147669e295384df17b50afc53a4d450b05bddKenny Root mSpec.getFlags())) { 142db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root Credentials.deleteAllTypesForAlias(mKeyStore, alias); 143db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("Can't store certificate in AndroidKeyStore"); 144db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 145db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 146db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root return new KeyPair(pubKey, privKey); 147db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 148db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 149db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root @Override 150db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root public void initialize(int keysize, SecureRandom random) { 151db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalArgumentException("cannot specify keysize with AndroidKeyPairGenerator"); 152db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 153db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 154db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root @Override 155db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root public void initialize(AlgorithmParameterSpec params, SecureRandom random) 156db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throws InvalidAlgorithmParameterException { 157db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root if (params == null) { 158db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new InvalidAlgorithmParameterException( 159db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root "must supply params of type AndroidKeyPairGenericSpec"); 160db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } else if (!(params instanceof AndroidKeyPairGeneratorSpec)) { 161db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new InvalidAlgorithmParameterException( 162db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root "params must be of type AndroidKeyPairGeneratorSpec"); 163db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 164db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 165db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root AndroidKeyPairGeneratorSpec spec = (AndroidKeyPairGeneratorSpec) params; 166db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 167db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root mSpec = spec; 168db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root mKeyStore = android.security.KeyStore.getInstance(); 169db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 170db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root} 171