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