OSDN Git Service

android-2.1_r1 snapshot
[android-x86/sdk.git] / jarutils / src / com / android / jarutils / KeystoreHelper.java
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.jarutils.DebugKeyProvider.IKeyGenOutput;
20 import com.android.jarutils.DebugKeyProvider.KeytoolException;
21
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.InputStreamReader;
26 import java.security.KeyStoreException;
27 import java.security.NoSuchAlgorithmException;
28 import java.security.UnrecoverableEntryException;
29 import java.security.cert.CertificateException;
30 import java.util.ArrayList;
31
32 /**
33  * A Helper to create new keystore/key.
34  */
35 public final class KeystoreHelper {
36
37     /**
38      * Creates a new store
39      * @param osKeyStorePath the location of the store
40      * @param storeType an optional keystore type, or <code>null</code> if the default is to
41      * be used.
42      * @param output an optional {@link IKeyGenOutput} object to get the stdout and stderr
43      * of the keytool process call.
44      * @throws KeyStoreException
45      * @throws NoSuchAlgorithmException
46      * @throws CertificateException
47      * @throws UnrecoverableEntryException
48      * @throws IOException
49      * @throws KeytoolException
50      */
51     public static boolean createNewStore(
52             String osKeyStorePath,
53             String storeType,
54             String storePassword,
55             String alias,
56             String keyPassword,
57             String description,
58             int validityYears,
59             IKeyGenOutput output)
60             throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
61             UnrecoverableEntryException, IOException, KeytoolException {
62         
63         // get the executable name of keytool depending on the platform.
64         String os = System.getProperty("os.name");
65
66         String keytoolCommand;
67         if (os.startsWith("Windows")) {
68             keytoolCommand = "keytool.exe";
69         } else {
70             keytoolCommand = "keytool";
71         }
72
73         String javaHome = System.getProperty("java.home");
74
75         if (javaHome != null && javaHome.length() > 0) {
76             keytoolCommand = javaHome + File.separator + "bin" + File.separator + keytoolCommand; 
77         }
78         
79         // create the command line to call key tool to build the key with no user input.
80         ArrayList<String> commandList = new ArrayList<String>();
81         commandList.add(keytoolCommand);
82         commandList.add("-genkey");
83         commandList.add("-alias");
84         commandList.add(alias);
85         commandList.add("-keyalg");
86         commandList.add("RSA");
87         commandList.add("-dname");
88         commandList.add(description);
89         commandList.add("-validity");
90         commandList.add(Integer.toString(validityYears * 365));
91         commandList.add("-keypass");
92         commandList.add(keyPassword);
93         commandList.add("-keystore");
94         commandList.add(osKeyStorePath);
95         commandList.add("-storepass");
96         commandList.add(storePassword);
97         if (storeType != null) {
98             commandList.add("-storetype");
99             commandList.add(storeType);
100         }
101
102         String[] commandArray = commandList.toArray(new String[commandList.size()]);
103
104         // launch the command line process
105         int result = 0;
106         try {
107             result = grabProcessOutput(Runtime.getRuntime().exec(commandArray), output);
108         } catch (Exception e) {
109             // create the command line as one string
110             StringBuilder builder = new StringBuilder();
111             boolean firstArg = true;
112             for (String arg : commandArray) {
113                 boolean hasSpace = arg.indexOf(' ') != -1;
114                 
115                 if (firstArg == true) {
116                     firstArg = false;
117                 } else {
118                     builder.append(' ');
119                 }
120                 
121                 if (hasSpace) {
122                     builder.append('"');
123                 }
124                 
125                 builder.append(arg);
126
127                 if (hasSpace) {
128                     builder.append('"');
129                 }
130             }
131             
132             throw new KeytoolException("Failed to create key: " + e.getMessage(),
133                     javaHome, builder.toString());
134         }
135         
136         if (result != 0) {
137             return false;
138         }
139         
140         return true;
141     }
142     
143     /**
144      * Get the stderr/stdout outputs of a process and return when the process is done.
145      * Both <b>must</b> be read or the process will block on windows.
146      * @param process The process to get the ouput from
147      * @return the process return code.
148      * @throws InterruptedException
149      */
150     private static int grabProcessOutput(final Process process, final IKeyGenOutput output) {
151         // read the lines as they come. if null is returned, it's
152         // because the process finished
153         Thread t1 = new Thread("") {
154             @Override
155             public void run() {
156                 // create a buffer to read the stderr output
157                 InputStreamReader is = new InputStreamReader(process.getErrorStream());
158                 BufferedReader errReader = new BufferedReader(is);
159
160                 try {
161                     while (true) {
162                         String line = errReader.readLine();
163                         if (line != null) {
164                             if (output != null) {
165                                 output.err(line);
166                             } else {
167                                 System.err.println(line);
168                             }
169                         } else {
170                             break;
171                         }
172                     }
173                 } catch (IOException e) {
174                     // do nothing.
175                 }
176             }
177         };
178
179         Thread t2 = new Thread("") {
180             @Override
181             public void run() {
182                 InputStreamReader is = new InputStreamReader(process.getInputStream());
183                 BufferedReader outReader = new BufferedReader(is);
184
185                 try {
186                     while (true) {
187                         String line = outReader.readLine();
188                         if (line != null) {
189                             if (output != null) {
190                                 output.out(line);
191                             } else {
192                                 System.out.println(line);
193                             }
194                         } else {
195                             break;
196                         }
197                     }
198                 } catch (IOException e) {
199                     // do nothing.
200                 }
201             }
202         };
203
204         t1.start();
205         t2.start();
206
207         // it looks like on windows process#waitFor() can return
208         // before the thread have filled the arrays, so we wait for both threads and the
209         // process itself.
210         try {
211             t1.join();
212         } catch (InterruptedException e) {
213         }
214         try {
215             t2.join();
216         } catch (InterruptedException e) {
217         }
218
219         // get the return code from the process
220         try {
221             return process.waitFor();
222         } catch (InterruptedException e) {
223             // since we're waiting for the output thread above, we should never actually wait
224             // on the process to end, since it'll be done by the time we call waitFor()
225             return 0;
226         }
227     }
228 }