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 21db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootimport org.apache.harmony.xnet.provider.jsse.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 Root@SuppressWarnings("deprecation") 53db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Rootpublic class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { 54db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root public static final String NAME = "AndroidKeyPairGenerator"; 55db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 56db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root private android.security.KeyStore mKeyStore; 57db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 58db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root private AndroidKeyPairGeneratorSpec mSpec; 59db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 60db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root /** 61db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * Generate a KeyPair which is backed by the Android keystore service. You 62db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * must call {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)} 63db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * with an {@link AndroidKeyPairGeneratorSpec} as the {@code params} 64db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * argument before calling this otherwise an {@code IllegalStateException} 65db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * will be thrown. 66db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * <p> 67db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * This will create an entry in the Android keystore service with a 68db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * self-signed certificate using the {@code params} specified in the 69db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * {@code initialize(params)} call. 70db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * 71db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * @throws IllegalStateException when called before calling 72db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)} 73db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root * @see java.security.KeyPairGeneratorSpi#generateKeyPair() 74db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root */ 75db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root @Override 76db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root public KeyPair generateKeyPair() { 77db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root if (mKeyStore == null || mSpec == null) { 78db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException( 79db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root "Must call initialize with an AndroidKeyPairGeneratorSpec first"); 80db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 81db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 82db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final String alias = mSpec.getKeystoreAlias(); 83db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 84db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root Credentials.deleteAllTypesForAlias(mKeyStore, alias); 85db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 86db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias; 87db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root mKeyStore.generate(privateKeyAlias); 88db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 89db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final PrivateKey privKey; 90db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore"); 91db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root try { 92db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root privKey = engine.getPrivateKeyById(privateKeyAlias); 93db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (InvalidKeyException e) { 94db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new RuntimeException("Can't get key", e); 95db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 96db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 97db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final byte[] pubKeyBytes = mKeyStore.getPubkey(privateKeyAlias); 98db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 99db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final PublicKey pubKey; 100db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root try { 101db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final KeyFactory keyFact = KeyFactory.getInstance("RSA"); 102db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes)); 103db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (NoSuchAlgorithmException e) { 104db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("Can't instantiate RSA key generator", e); 105db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (InvalidKeySpecException e) { 106db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("keystore returned invalid key encoding", e); 107db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 108db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 109db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); 110db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setPublicKey(pubKey); 111db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setSerialNumber(mSpec.getSerialNumber()); 112db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setSubjectDN(mSpec.getSubjectDN()); 113db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setIssuerDN(mSpec.getSubjectDN()); 114db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setNotBefore(mSpec.getStartDate()); 115db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setNotAfter(mSpec.getEndDate()); 116db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certGen.setSignatureAlgorithm("sha1WithRSA"); 117db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 118db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root final X509Certificate cert; 119db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root try { 120db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root cert = certGen.generate(privKey); 121db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (Exception e) { 122db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root Credentials.deleteAllTypesForAlias(mKeyStore, alias); 123db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("Can't generate certificate", e); 124db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 125db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 126db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root byte[] certBytes; 127db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root try { 128db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root certBytes = cert.getEncoded(); 129db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } catch (CertificateEncodingException e) { 130db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root Credentials.deleteAllTypesForAlias(mKeyStore, alias); 131db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("Can't get encoding of certificate", e); 132db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 133db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 134db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes)) { 135db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root Credentials.deleteAllTypesForAlias(mKeyStore, alias); 136db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalStateException("Can't store certificate in AndroidKeyStore"); 137db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 138db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 139db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root return new KeyPair(pubKey, privKey); 140db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 141db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 142db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root @Override 143db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root public void initialize(int keysize, SecureRandom random) { 144db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new IllegalArgumentException("cannot specify keysize with AndroidKeyPairGenerator"); 145db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 146db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 147db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root @Override 148db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root public void initialize(AlgorithmParameterSpec params, SecureRandom random) 149db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throws InvalidAlgorithmParameterException { 150db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root if (params == null) { 151db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new InvalidAlgorithmParameterException( 152db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root "must supply params of type AndroidKeyPairGenericSpec"); 153db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } else if (!(params instanceof AndroidKeyPairGeneratorSpec)) { 154db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root throw new InvalidAlgorithmParameterException( 155db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root "params must be of type AndroidKeyPairGeneratorSpec"); 156db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 157db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 158db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root AndroidKeyPairGeneratorSpec spec = (AndroidKeyPairGeneratorSpec) params; 159db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root 160db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root mSpec = spec; 161db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root mKeyStore = android.security.KeyStore.getInstance(); 162db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root } 163db026710ec0adcf7f72dfb24c65d38a882ee26d8Kenny Root} 164