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