blob: c96cd4f4d9079a595d4c0001e5e1ce8222ffbd30 [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 Wangeec11822009-07-02 00:22:04 +080056
Chung-yih Wangc9c119e2009-07-16 19:54:33 +080057 private static final String TAG = "CertTool";
Chung-yih Wangeec11822009-07-02 00:22:04 +080058 private static final String UNKNOWN = "Unknown";
59 private static final String ISSUER_NAME = "Issuer Name:";
60 private static final String DISTINCT_NAME = "Distinct Name:";
61
62 private static final String CA_CERTIFICATE = "CACERT";
63 private static final String USER_CERTIFICATE = "USRCERT";
64 private static final String USER_KEY = "USRKEY";
65
Chung-yih Wangfa927c02009-07-02 19:11:11 +080066 private static final String KEYNAME_DELIMITER = "_";
Chung-yih Wang699ca3f2009-07-04 22:19:51 +080067 private static final Keystore sKeystore = Keystore.getInstance();
Chung-yih Wangeec11822009-07-02 00:22:04 +080068
Chung-yih Wangc9c119e2009-07-16 19:54:33 +080069 private native int getPkcs12Handle(byte[] data, String password);
70 private native String getPkcs12Certificate(int handle);
71 private native String getPkcs12PrivateKey(int handle);
72 private native String popPkcs12CertificateStack(int handle);
73 private native void freePkcs12Handle(int handle);
Chung-yih Wangeec11822009-07-02 00:22:04 +080074 private native String generateCertificateRequest(int bits, String subject);
75 private native boolean isPkcs12Keystore(byte[] data);
76 private native int generateX509Certificate(byte[] data);
77 private native boolean isCaCertificate(int handle);
78 private native String getIssuerDN(int handle);
79 private native String getCertificateDN(int handle);
80 private native String getPrivateKeyPEM(int handle);
81 private native void freeX509Certificate(int handle);
82
Chung-yih Wangbf20b992009-07-02 23:42:12 +080083 private static CertTool singleton = null;
84
Chung-yih Wang699ca3f2009-07-04 22:19:51 +080085 private CertTool() { }
86
Chung-yih Wangbf20b992009-07-02 23:42:12 +080087 public static final CertTool getInstance() {
88 if (singleton == null) {
89 singleton = new CertTool();
90 }
91 return singleton;
92 }
93
Chung-yih Wangeec11822009-07-02 00:22:04 +080094 public String getUserPrivateKey(String key) {
95 return USER_KEY + KEYNAME_DELIMITER + key;
96 }
97
98 public String getUserCertificate(String key) {
99 return USER_CERTIFICATE + KEYNAME_DELIMITER + key;
100 }
101
102 public String getCaCertificate(String key) {
103 return CA_CERTIFICATE + KEYNAME_DELIMITER + key;
104 }
105
106 public String[] getAllUserCertificateKeys() {
Chung-yih Wang699ca3f2009-07-04 22:19:51 +0800107 return sKeystore.listKeys(USER_KEY);
Chung-yih Wangeec11822009-07-02 00:22:04 +0800108 }
109
110 public String[] getAllCaCertificateKeys() {
Chung-yih Wang699ca3f2009-07-04 22:19:51 +0800111 return sKeystore.listKeys(CA_CERTIFICATE);
Chung-yih Wangeec11822009-07-02 00:22:04 +0800112 }
113
114 public String[] getSupportedKeyStrenghs() {
115 return new String[] {"High Grade", "Medium Grade"};
116 }
117
118 private int getKeyLength(int index) {
119 if (index == 0) return 2048;
120 return 1024;
121 }
122
123 public String generateKeyPair(int keyStrengthIndex, String challenge,
124 String dirName) {
125 return generateCertificateRequest(getKeyLength(keyStrengthIndex),
126 dirName);
127 }
128
129 private Intent prepareIntent(String title, byte[] data, String namespace,
130 String issuer, String distinctName) {
131 Intent intent = new Intent(ACTION_ADD_CREDENTIAL);
132 intent.putExtra(KEY_TYPE_NAME, title);
133 intent.putExtra(KEY_ITEM + "0", data);
134 intent.putExtra(KEY_NAMESPACE + "0", namespace);
135 intent.putExtra(KEY_DESCRIPTION + "0", ISSUER_NAME + issuer);
136 intent.putExtra(KEY_DESCRIPTION + "1", DISTINCT_NAME + distinctName);
137 return intent;
138 }
139
140 private void addExtraIntentInfo(Intent intent, String namespace,
141 String data) {
142 intent.putExtra(KEY_ITEM + "1", data);
143 intent.putExtra(KEY_NAMESPACE + "1", namespace);
144 }
145
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800146 public int addPkcs12Keystore(byte[] p12Data, String password,
147 String keyname) {
148 int handle, i = 0;
149 String pemData;
150 Log.i("CertTool", "addPkcs12Keystore()");
151
152 if ((handle = getPkcs12Handle(p12Data, password)) == 0) return -1;
153 if ((pemData = getPkcs12Certificate(handle)) != null) {
154 sKeystore.put(USER_CERTIFICATE, keyname, pemData);
155 }
156 if ((pemData = getPkcs12PrivateKey(handle)) != null) {
157 sKeystore.put(USER_KEY, keyname, pemData);
158 }
159 while ((pemData = this.popPkcs12CertificateStack(handle)) != null) {
160 if (i++ > 0) {
161 sKeystore.put(CA_CERTIFICATE, keyname + i, pemData);
162 } else {
163 sKeystore.put(CA_CERTIFICATE, keyname, pemData);
164 }
165 }
166 freePkcs12Handle(handle);
167 return 0;
168 }
169
Chung-yih Wangeec11822009-07-02 00:22:04 +0800170 public synchronized void addCertificate(byte[] data, Context context) {
171 int handle;
172 Intent intent = null;
173
Chung-yih Wangc9c119e2009-07-16 19:54:33 +0800174 Log.i("CertTool", "addCertificate()");
Chung-yih Wangeec11822009-07-02 00:22:04 +0800175 if (isPkcs12Keystore(data)) {
176 intent = prepareIntent(TITLE_PKCS12_KEYSTORE, data, USER_KEY,
177 UNKNOWN, UNKNOWN);
178 } else if ((handle = generateX509Certificate(data)) != 0) {
179 String issuer = getIssuerDN(handle);
180 String distinctName = getCertificateDN(handle);
181 String privateKeyPEM = getPrivateKeyPEM(handle);
182 if (isCaCertificate(handle)) {
183 intent = prepareIntent(TITLE_CA_CERT, data, CA_CERTIFICATE,
184 issuer, distinctName);
185 } else {
186 intent = prepareIntent(TITLE_USER_CERT, data, USER_CERTIFICATE,
187 issuer, distinctName);
188 if (!TextUtils.isEmpty(privateKeyPEM)) {
189 addExtraIntentInfo(intent, USER_KEY, privateKeyPEM);
190 }
191 }
192 freeX509Certificate(handle);
193 }
194 if (intent != null) context.startActivity(intent);
195 }
196}