• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 package com.android.jarutils;
18 
19 import com.android.prefs.AndroidLocation;
20 import com.android.prefs.AndroidLocation.AndroidLocationException;
21 
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;
33 
34 /**
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.
37  */
38 public class DebugKeyProvider {
39 
40     public interface IKeyGenOutput {
out(String message)41         public void out(String message);
err(String message)42         public void err(String message);
43     }
44 
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";
48 
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
51     // debug keys.
52     private static final String CERTIFICATE_DESC = "CN=Android Debug,O=Android,C=US";
53 
54     private KeyStore.PrivateKeyEntry mEntry;
55 
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;
61 
KeytoolException(String message)62         KeytoolException(String message) {
63             super(message);
64         }
65 
KeytoolException(String message, String javaHome, String commandLine)66         KeytoolException(String message, String javaHome, String commandLine) {
67             super(message);
68 
69             mJavaHome = javaHome;
70             mCommandLine = commandLine;
71         }
72 
getJavaHome()73         public String getJavaHome() {
74             return mJavaHome;
75         }
76 
getCommandLine()77         public String getCommandLine() {
78             return mCommandLine;
79         }
80     }
81 
82     /**
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
88      * is to be used.
89      * @param storeType an optional keystore type, or <code>null</code> if the default is to
90      * be used.
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
95      */
DebugKeyProvider(String osKeyStorePath, String storeType, IKeyGenOutput output)96     public DebugKeyProvider(String osKeyStorePath, String storeType, IKeyGenOutput output)
97             throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
98             UnrecoverableEntryException, IOException, KeytoolException, AndroidLocationException {
99 
100         if (osKeyStorePath == null) {
101             osKeyStorePath = getDefaultKeyStoreOsPath();
102         }
103 
104         if (loadKeyEntry(osKeyStorePath, storeType) == false) {
105             // create the store with the key
106             createNewStore(osKeyStorePath, storeType, output);
107         }
108     }
109 
110     /**
111      * Returns the OS path to the default debug keystore.
112      *
113      * @return The OS path to the default debug keystore.
114      * @throws KeytoolException
115      * @throws AndroidLocationException
116      */
getDefaultKeyStoreOsPath()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");
122         }
123         String osKeyStorePath = folder + "debug.keystore";
124 
125         return osKeyStorePath;
126     }
127 
128     /**
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.
131      */
getDebugKey()132     public PrivateKey getDebugKey() throws KeyStoreException, NoSuchAlgorithmException,
133             UnrecoverableKeyException, UnrecoverableEntryException {
134         if (mEntry != null) {
135             return mEntry.getPrivateKey();
136         }
137 
138         return null;
139     }
140 
141     /**
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.
144      */
getCertificate()145     public Certificate getCertificate() throws KeyStoreException, NoSuchAlgorithmException,
146             UnrecoverableKeyException, UnrecoverableEntryException {
147         if (mEntry != null) {
148             return mEntry.getCertificate();
149         }
150 
151         return null;
152     }
153 
154     /**
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
158      * be used.
159      * @return <code>true</code> if success, <code>false</code> if the keystore does not exist.
160      */
loadKeyEntry(String osKeyStorePath, String storeType)161     private boolean loadKeyEntry(String osKeyStorePath, String storeType) throws KeyStoreException,
162             NoSuchAlgorithmException, CertificateException, IOException,
163             UnrecoverableEntryException {
164         try {
165             KeyStore keyStore = KeyStore.getInstance(
166                     storeType != null ? storeType : KeyStore.getDefaultType());
167             FileInputStream fis = new FileInputStream(osKeyStorePath);
168             keyStore.load(fis, PASSWORD_CHAR);
169             fis.close();
170             mEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(
171                     DEBUG_ALIAS, new KeyStore.PasswordProtection(PASSWORD_CHAR));
172         } catch (FileNotFoundException e) {
173             return false;
174         }
175 
176         return true;
177     }
178 
179     /**
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
183      * be used.
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
192      */
createNewStore(String osKeyStorePath, String storeType, IKeyGenOutput output)193     private void createNewStore(String osKeyStorePath, String storeType, IKeyGenOutput output)
194             throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
195             UnrecoverableEntryException, IOException, KeytoolException {
196 
197         if (KeystoreHelper.createNewStore(osKeyStorePath, storeType, PASSWORD_STRING, DEBUG_ALIAS,
198                 PASSWORD_STRING, CERTIFICATE_DESC, 1 /* validity*/, output)) {
199             loadKeyEntry(osKeyStorePath, storeType);
200         }
201     }
202 }
203