blob: 79418bd4899589ac689a17ef1eeaa7a4bbb044ca [file] [log] [blame]
Chung-yih Wangeec11822009-07-02 00:22:04 +08001/*
2 * Copyright (C) 2009 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
17package android.security;
18
Chung-yih Wangc9c119e2009-07-16 19:54:33 +080019import java.io.ByteArrayInputStream;
20import java.io.IOException;
21import java.security.cert.Certificate;
22import java.security.cert.CertificateException;
23import java.security.KeyStoreException;
24import java.security.NoSuchAlgorithmException;
25import java.security.UnrecoverableKeyException;
26
Chung-yih Wangeec11822009-07-02 00:22:04 +080027import android.content.Context;
28import android.content.Intent;
29import android.security.Keystore;
30import android.text.TextUtils;
Chung-yih Wangc9c119e2009-07-16 19:54:33 +080031import android.util.Log;
Chung-yih Wangeec11822009-07-02 00:22:04 +080032
33/**
34 * The CertTool class provides the functions to list the certs/keys,
35 * generate the certificate request(csr) and store the certificate into
36 * keystore.
37 *
38 * {@hide}
39 */
40public class CertTool {
Chung-yih Wang699ca3f2009-07-04 22:19:51 +080041 static {
42 System.loadLibrary("certtool_jni");
43 }
44
Chung-yih Wangeec11822009-07-02 00:22:04 +080045 public static final String ACTION_ADD_CREDENTIAL =
46 "android.security.ADD_CREDENTIAL";
47 public static final String KEY_TYPE_NAME = "typeName";
48 public static final String KEY_ITEM = "item";
49 public static final String KEY_NAMESPACE = "namespace";
50 public static final String KEY_DESCRIPTION = "description";
51
Chung-yih Wangc9c119e2009-07-16 19:54:33 +080052 public static final String TITLE_CA_CERT = "CA Certificate";
53 public static final String TITLE_USER_CERT = "User Certificate";
54 public static final String TITLE_PKCS12_KEYSTORE = "PKCS12 Keystore";
55 public static final String TITLE_PRIVATE_KEY = "Private Key";
Chung-yih Wang22726cf2009-07-22 05:31:48 +080056 public static final int INCORRECT_PKCS12_PASSPHRASE = -100;
Chung-yih Wangeec11822009-07-02 00:22:04 +080057
Chung-yih Wangc9c119e2009-07-16 19:54:33 +080058 private static final String TAG = "CertTool";
Chung-yih Wangeec11822009-07-02 00:22:04 +080059 private static final String UNKNOWN = "Unknown";
60 private static final String ISSUER_NAME = "Issuer Name:";
61 private static final String DISTINCT_NAME = "Distinct Name:";
62
63 private static final String CA_CERTIFICATE = "CACERT";
64 private static final String USER_CERTIFICATE = "USRCERT";
65 private static final String USER_KEY = "USRKEY";
66
Chung-yih Wangfa927c02009-07-02 19:11:11 +080067 private static final String KEYNAME_DELIMITER = "_";
Chung-yih Wang699ca3f2009-07-04 22:19:51 +080068 private static final Keystore sKeystore = Keystore.getInstance();
Chung-yih Wangeec11822009-07-02 00:22:04 +080069
Chung-yih Wangc9c119e2009-07-16 19:54:33 +080070 private native int getPkcs12Handle(byte[] data, String password);
71 private native String getPkcs12Certificate(int handle);
72 private native String getPkcs12PrivateKey(int handle);
73 private native String popPkcs12CertificateStack(int handle);
74 private native void freePkcs12Handle(int handle);
Chung-yih Wangeec11822009-07-02 00:22:04 +080075 private native String generateCertificateRequest(int bits, String subject);
76 private native boolean isPkcs12Keystore(byte[] data);
77 private native int generateX509Certificate(byte[] data);
78 private native boolean isCaCertificate(int handle);
79 private native String getIssuerDN(int handle);
80 private native String getCertificateDN(int handle);
81 private native String getPrivateKeyPEM(int handle);
82 private native void freeX509Certificate(int handle);
83
Chung-yih Wangbf20b992009-07-02 23:42:12 +080084 private static CertTool singleton = null;
85
Chung-yih Wang699ca3f2009-07-04 22:19:51 +080086 private CertTool() { }
87
Chung-yih Wangbf20b992009-07-02 23:42:12 +080088 public static final CertTool getInstance() {
89 if (singleton == null) {
90 singleton = new CertTool();
91 }
92 return singleton;
93 }
94
Chung-yih Wangeec11822009-07-02 00:22:04 +080095 public String getUserPrivateKey(String key) {
96 return USER_KEY + KEYNAME_DELIMITER + key;
97 }
98
99 public String getUserCertificate(String key) {
100 return USER_CERTIFICATE + KEYNAME_DELIMITER + key;
101 }
102
103 public String getCaCertificate(String key) {
104 return CA_CERTIFICATE + KEYNAME_DELIMITER + key;
105 }
106
107 public String[] getAllUserCertificateKeys() {
Chung-yih Wang699ca3f2009-07-04 22:19:51 +0800108 return sKeystore.listKeys(USER_KEY);
Chung-yih Wangeec11822009-07-02 00:22:04 +0800109 }
110
111 public String[] getAllCaCertificateKeys() {
Chung-yih Wang699ca3f2009-07-04 22:19:51 +0800112 return sKeystore.listKeys(CA_CERTIFICATE);
Chung-yih Wangeec11822009-07-02 00:22:04 +0800113 }
114
115 public String[] getSupportedKeyStrenghs() {
116 return new String[] {"High Grade", "Medium Grade"};
117 }
118
119 private int getKeyLength(int index) {
120 if (index == 0) return 2048;
121 return 1024;
122 }
123
124 public String generateKeyPair(int keyStrengthIndex, String challenge,
125 String dirName) {
126 return generateCertificateRequest(getKeyLength(keyStrengthIndex),
127 dirName);
128 }
129
130 private Intent prepareIntent(String title, byte[] data, String namespace,
131 String issuer, String distinctName) {
132 Intent intent = new Intent(ACTION_ADD_CREDENTIAL);
133 intent.putExtra(KEY_TYPE_NAME, title);
134 intent.putExtra(KEY_ITEM + "0", data);
135 intent.putExtra(KEY_NAMESPACE + "0", namespace);
136 intent.putExtra(KEY_DESCRIPTION + "0", ISSUER_NAME + issuer);
137 intent.putExtra(KEY_DESCRIPTION + "1", DISTINCT_NAME + distinctName);
138 return intent;
139 }
140
141 private void addExtraIntentInfo(Intent intent, String namespace,
142 String data) {
143 intent.putExtra(KEY_ITEM + "1", data);
144 intent.putExtra(KEY_NAMESPACE + "1", namespace);
145 }
146
Chung-yih Wang22726cf2009-07-22 05:31:48 +0800147 private int extractAndStoreKeysFromPkcs12(int handle, String keyname) {
148 int ret, i = 0;
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800149 String pemData;
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800150
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800151 if ((pemData = getPkcs12Certificate(handle)) != null) {
Chung-yih Wang22726cf2009-07-22 05:31:48 +0800152 if ((ret = sKeystore.put(USER_CERTIFICATE, keyname, pemData)) != 0) {
153 return ret;
154 }
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800155 }
156 if ((pemData = getPkcs12PrivateKey(handle)) != null) {
Chung-yih Wang22726cf2009-07-22 05:31:48 +0800157 if ((ret = sKeystore.put(USER_KEY, keyname, pemData)) != 0) {
158 return ret;
159 }
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800160 }
161 while ((pemData = this.popPkcs12CertificateStack(handle)) != null) {
162 if (i++ > 0) {
Chung-yih Wang22726cf2009-07-22 05:31:48 +0800163 if ((ret = sKeystore.put(CA_CERTIFICATE, keyname + i, pemData)) != 0) {
164 return ret;
165 }
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800166 } else {
Chung-yih Wang22726cf2009-07-22 05:31:48 +0800167 if ((ret = sKeystore.put(CA_CERTIFICATE, keyname, pemData)) != 0) {
168 return ret;
169 }
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800170 }
171 }
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800172 return 0;
173 }
174
Chung-yih Wang22726cf2009-07-22 05:31:48 +0800175 public int addPkcs12Keystore(byte[] p12Data, String password,
176 String keyname) {
177 int handle, ret;
178 Log.i("CertTool", "addPkcs12Keystore()");
179
180 if ((handle = getPkcs12Handle(p12Data, password)) == 0) {
181 return INCORRECT_PKCS12_PASSPHRASE;
182 }
183 ret = extractAndStoreKeysFromPkcs12(handle, keyname);
184 freePkcs12Handle(handle);
185 return ret;
186 }
187
Chung-yih Wangeec11822009-07-02 00:22:04 +0800188 public synchronized void addCertificate(byte[] data, Context context) {
189 int handle;
190 Intent intent = null;
191
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800192 Log.i("CertTool", "addCertificate()");
Chung-yih Wangeec11822009-07-02 00:22:04 +0800193 if (isPkcs12Keystore(data)) {
194 intent = prepareIntent(TITLE_PKCS12_KEYSTORE, data, USER_KEY,
195 UNKNOWN, UNKNOWN);
196 } else if ((handle = generateX509Certificate(data)) != 0) {
197 String issuer = getIssuerDN(handle);
198 String distinctName = getCertificateDN(handle);
199 String privateKeyPEM = getPrivateKeyPEM(handle);
200 if (isCaCertificate(handle)) {
201 intent = prepareIntent(TITLE_CA_CERT, data, CA_CERTIFICATE,
202 issuer, distinctName);
203 } else {
204 intent = prepareIntent(TITLE_USER_CERT, data, USER_CERTIFICATE,
205 issuer, distinctName);
206 if (!TextUtils.isEmpty(privateKeyPEM)) {
207 addExtraIntentInfo(intent, USER_KEY, privateKeyPEM);
208 }
209 }
210 freeX509Certificate(handle);
211 }
212 if (intent != null) context.startActivity(intent);
213 }
214}