--- /dev/null
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.internal.build;
+
+import com.android.prefs.AndroidLocation;
+import com.android.prefs.AndroidLocation.AndroidLocationException;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableEntryException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+
+/**
+ * A provider of a dummy key to sign Android application for debugging purpose.
+ * <p/>This provider uses a custom keystore to create and store a key with a known password.
+ */
+public class DebugKeyProvider {
+
+ public interface IKeyGenOutput {
+ public void out(String message);
+ public void err(String message);
+ }
+
+ private static final String PASSWORD_STRING = "android";
+ private static final char[] PASSWORD_CHAR = PASSWORD_STRING.toCharArray();
+ private static final String DEBUG_ALIAS = "AndroidDebugKey";
+
+ // Certificate CN value. This is a hard-coded value for the debug key.
+ // Android Market checks against this value in order to refuse applications signed with
+ // debug keys.
+ private static final String CERTIFICATE_DESC = "CN=Android Debug,O=Android,C=US";
+
+ private KeyStore.PrivateKeyEntry mEntry;
+
+ public static class KeytoolException extends Exception {
+ /** default serial uid */
+ private static final long serialVersionUID = 1L;
+ private String mJavaHome = null;
+ private String mCommandLine = null;
+
+ KeytoolException(String message) {
+ super(message);
+ }
+
+ KeytoolException(String message, String javaHome, String commandLine) {
+ super(message);
+
+ mJavaHome = javaHome;
+ mCommandLine = commandLine;
+ }
+
+ public String getJavaHome() {
+ return mJavaHome;
+ }
+
+ public String getCommandLine() {
+ return mCommandLine;
+ }
+ }
+
+ /**
+ * Creates a provider using a keystore at the given location.
+ * <p/>The keystore, and a new random android debug key are created if they do not yet exist.
+ * <p/>Password for the store/key is <code>android</code>, and the key alias is
+ * <code>AndroidDebugKey</code>.
+ * @param osKeyStorePath the OS path to the keystore, or <code>null</code> if the default one
+ * is to be used.
+ * @param storeType an optional keystore type, or <code>null</code> if the default is to
+ * be used.
+ * @param output an optional {@link IKeyGenOutput} object to get the stdout and stderr
+ * of the keytool process call.
+ * @throws KeytoolException If the creation of the debug key failed.
+ * @throws AndroidLocationException
+ */
+ public DebugKeyProvider(String osKeyStorePath, String storeType, IKeyGenOutput output)
+ throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
+ UnrecoverableEntryException, IOException, KeytoolException, AndroidLocationException {
+
+ if (osKeyStorePath == null) {
+ osKeyStorePath = getDefaultKeyStoreOsPath();
+ }
+
+ if (loadKeyEntry(osKeyStorePath, storeType) == false) {
+ // create the store with the key
+ createNewStore(osKeyStorePath, storeType, output);
+ }
+ }
+
+ /**
+ * Returns the OS path to the default debug keystore.
+ *
+ * @return The OS path to the default debug keystore.
+ * @throws KeytoolException
+ * @throws AndroidLocationException
+ */
+ public static String getDefaultKeyStoreOsPath()
+ throws KeytoolException, AndroidLocationException {
+ String folder = AndroidLocation.getFolder();
+ if (folder == null) {
+ throw new KeytoolException("Failed to get HOME directory!\n");
+ }
+ String osKeyStorePath = folder + "debug.keystore";
+
+ return osKeyStorePath;
+ }
+
+ /**
+ * Returns the debug {@link PrivateKey} to use to sign applications for debug purpose.
+ * @return the private key or <code>null</code> if its creation failed.
+ */
+ public PrivateKey getDebugKey() throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException, UnrecoverableEntryException {
+ if (mEntry != null) {
+ return mEntry.getPrivateKey();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the debug {@link Certificate} to use to sign applications for debug purpose.
+ * @return the certificate or <code>null</code> if its creation failed.
+ */
+ public Certificate getCertificate() throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException, UnrecoverableEntryException {
+ if (mEntry != null) {
+ return mEntry.getCertificate();
+ }
+
+ return null;
+ }
+
+ /**
+ * Loads the debug key from the keystore.
+ * @param osKeyStorePath the OS path to the keystore.
+ * @param storeType an optional keystore type, or <code>null</code> if the default is to
+ * be used.
+ * @return <code>true</code> if success, <code>false</code> if the keystore does not exist.
+ */
+ private boolean loadKeyEntry(String osKeyStorePath, String storeType) throws KeyStoreException,
+ NoSuchAlgorithmException, CertificateException, IOException,
+ UnrecoverableEntryException {
+ try {
+ KeyStore keyStore = KeyStore.getInstance(
+ storeType != null ? storeType : KeyStore.getDefaultType());
+ FileInputStream fis = new FileInputStream(osKeyStorePath);
+ keyStore.load(fis, PASSWORD_CHAR);
+ fis.close();
+ mEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(
+ DEBUG_ALIAS, new KeyStore.PasswordProtection(PASSWORD_CHAR));
+ } catch (FileNotFoundException e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Creates a new store
+ * @param osKeyStorePath the location of the store
+ * @param storeType an optional keystore type, or <code>null</code> if the default is to
+ * be used.
+ * @param output an optional {@link IKeyGenOutput} object to get the stdout and stderr
+ * of the keytool process call.
+ * @throws KeyStoreException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ * @throws UnrecoverableEntryException
+ * @throws IOException
+ * @throws KeytoolException
+ */
+ private void createNewStore(String osKeyStorePath, String storeType, IKeyGenOutput output)
+ throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
+ UnrecoverableEntryException, IOException, KeytoolException {
+
+ if (KeystoreHelper.createNewStore(osKeyStorePath, storeType, PASSWORD_STRING, DEBUG_ALIAS,
+ PASSWORD_STRING, CERTIFICATE_DESC, 1 /* validity*/, output)) {
+ loadKeyEntry(osKeyStorePath, storeType);
+ }
+ }
+}