2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.jarutils;
19 import com.android.prefs.AndroidLocation;
20 import com.android.prefs.AndroidLocation.AndroidLocationException;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.security.KeyStore;
26 import java.security.KeyStoreException;
27 import java.security.NoSuchAlgorithmException;
28 import java.security.PrivateKey;
29 import java.security.UnrecoverableEntryException;
30 import java.security.UnrecoverableKeyException;
31 import java.security.cert.Certificate;
32 import java.security.cert.CertificateException;
35 * A provider of a dummy key to sign Android application for debugging purpose.
36 * <p/>This provider uses a custom keystore to create and store a key with a known password.
38 public class DebugKeyProvider {
40 public interface IKeyGenOutput {
41 public void out(String message);
42 public void err(String message);
45 private static final String PASSWORD_STRING = "android";
46 private static final char[] PASSWORD_CHAR = PASSWORD_STRING.toCharArray();
47 private static final String DEBUG_ALIAS = "AndroidDebugKey";
49 // Certificate CN value. This is a hard-coded value for the debug key.
50 // Android Market checks against this value in order to refuse applications signed with
52 private static final String CERTIFICATE_DESC = "CN=Android Debug,O=Android,C=US";
54 private KeyStore.PrivateKeyEntry mEntry;
56 public static class KeytoolException extends Exception {
57 /** default serial uid */
58 private static final long serialVersionUID = 1L;
59 private String mJavaHome = null;
60 private String mCommandLine = null;
62 KeytoolException(String message) {
66 KeytoolException(String message, String javaHome, String commandLine) {
70 mCommandLine = commandLine;
73 public String getJavaHome() {
77 public String getCommandLine() {
83 * Creates a provider using a keystore at the given location.
84 * <p/>The keystore, and a new random android debug key are created if they do not yet exist.
85 * <p/>Password for the store/key is <code>android</code>, and the key alias is
86 * <code>AndroidDebugKey</code>.
87 * @param osKeyStorePath the OS path to the keystore, or <code>null</code> if the default one
89 * @param storeType an optional keystore type, or <code>null</code> if the default is to
91 * @param output an optional {@link IKeyGenOutput} object to get the stdout and stderr
92 * of the keytool process call.
93 * @throws KeytoolException If the creation of the debug key failed.
94 * @throws AndroidLocationException
96 public DebugKeyProvider(String osKeyStorePath, String storeType, IKeyGenOutput output)
97 throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
98 UnrecoverableEntryException, IOException, KeytoolException, AndroidLocationException {
100 if (osKeyStorePath == null) {
101 osKeyStorePath = getDefaultKeyStoreOsPath();
104 if (loadKeyEntry(osKeyStorePath, storeType) == false) {
105 // create the store with the key
106 createNewStore(osKeyStorePath, storeType, output);
111 * Returns the OS path to the default debug keystore.
113 * @return The OS path to the default debug keystore.
114 * @throws KeytoolException
115 * @throws AndroidLocationException
117 public static String getDefaultKeyStoreOsPath()
118 throws KeytoolException, AndroidLocationException {
119 String folder = AndroidLocation.getFolder();
120 if (folder == null) {
121 throw new KeytoolException("Failed to get HOME directory!\n");
123 String osKeyStorePath = folder + "debug.keystore";
125 return osKeyStorePath;
129 * Returns the debug {@link PrivateKey} to use to sign applications for debug purpose.
130 * @return the private key or <code>null</code> if its creation failed.
132 public PrivateKey getDebugKey() throws KeyStoreException, NoSuchAlgorithmException,
133 UnrecoverableKeyException, UnrecoverableEntryException {
134 if (mEntry != null) {
135 return mEntry.getPrivateKey();
142 * Returns the debug {@link Certificate} to use to sign applications for debug purpose.
143 * @return the certificate or <code>null</code> if its creation failed.
145 public Certificate getCertificate() throws KeyStoreException, NoSuchAlgorithmException,
146 UnrecoverableKeyException, UnrecoverableEntryException {
147 if (mEntry != null) {
148 return mEntry.getCertificate();
155 * Loads the debug key from the keystore.
156 * @param osKeyStorePath the OS path to the keystore.
157 * @param storeType an optional keystore type, or <code>null</code> if the default is to
159 * @return <code>true</code> if success, <code>false</code> if the keystore does not exist.
161 private boolean loadKeyEntry(String osKeyStorePath, String storeType) throws KeyStoreException,
162 NoSuchAlgorithmException, CertificateException, IOException,
163 UnrecoverableEntryException {
165 KeyStore keyStore = KeyStore.getInstance(
166 storeType != null ? storeType : KeyStore.getDefaultType());
167 FileInputStream fis = new FileInputStream(osKeyStorePath);
168 keyStore.load(fis, PASSWORD_CHAR);
170 mEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(
171 DEBUG_ALIAS, new KeyStore.PasswordProtection(PASSWORD_CHAR));
172 } catch (FileNotFoundException e) {
180 * Creates a new store
181 * @param osKeyStorePath the location of the store
182 * @param storeType an optional keystore type, or <code>null</code> if the default is to
184 * @param output an optional {@link IKeyGenOutput} object to get the stdout and stderr
185 * of the keytool process call.
186 * @throws KeyStoreException
187 * @throws NoSuchAlgorithmException
188 * @throws CertificateException
189 * @throws UnrecoverableEntryException
190 * @throws IOException
191 * @throws KeytoolException
193 private void createNewStore(String osKeyStorePath, String storeType, IKeyGenOutput output)
194 throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
195 UnrecoverableEntryException, IOException, KeytoolException {
197 if (KeystoreHelper.createNewStore(osKeyStorePath, storeType, PASSWORD_STRING, DEBUG_ALIAS,
198 PASSWORD_STRING, CERTIFICATE_DESC, 1 /* validity*/, output)) {
199 loadKeyEntry(osKeyStorePath, storeType);