OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.net; | 5 package org.chromium.net; |
6 | 6 |
7 import android.util.Log; | 7 import android.util.Log; |
8 | 8 |
9 import org.chromium.base.CalledByNative; | |
10 import org.chromium.base.JNINamespace; | |
11 | |
12 import java.lang.reflect.Method; | 9 import java.lang.reflect.Method; |
13 import java.security.NoSuchAlgorithmException; | 10 import java.security.NoSuchAlgorithmException; |
14 import java.security.PrivateKey; | 11 import java.security.PrivateKey; |
15 import java.security.Signature; | 12 import java.security.Signature; |
16 import java.security.interfaces.DSAKey; | 13 import java.security.interfaces.DSAKey; |
17 import java.security.interfaces.DSAParams; | 14 import java.security.interfaces.DSAParams; |
18 import java.security.interfaces.DSAPrivateKey; | 15 import java.security.interfaces.DSAPrivateKey; |
19 import java.security.interfaces.ECKey; | 16 import java.security.interfaces.ECKey; |
20 import java.security.interfaces.ECPrivateKey; | 17 import java.security.interfaces.ECPrivateKey; |
21 import java.security.interfaces.RSAKey; | 18 import java.security.interfaces.RSAKey; |
22 import java.security.interfaces.RSAPrivateKey; | 19 import java.security.interfaces.RSAPrivateKey; |
23 import java.security.spec.ECParameterSpec; | 20 import java.security.spec.ECParameterSpec; |
24 | 21 |
25 @JNINamespace("net::android") | 22 /** |
26 public class AndroidKeyStore { | 23 * Simple implementation of the AndroidKeyStoreInterface for use with an in-proc
ess Java KeyStore. |
| 24 */ |
| 25 public class AndroidKeyStoreLocalImpl implements AndroidKeyStore { |
27 | 26 |
28 private static final String TAG = "AndroidKeyStore"; | 27 private static final String TAG = "AndroidKeyStoreLocalImpl"; |
| 28 |
| 29 private static class LocalPrivateKey implements AndroidPrivateKey { |
| 30 // The actual Java key being wrapped. |
| 31 final PrivateKey mKey; |
| 32 // Key store handling this key. |
| 33 final AndroidKeyStoreLocalImpl mStore; |
| 34 |
| 35 LocalPrivateKey(PrivateKey key, AndroidKeyStoreLocalImpl store) { |
| 36 mKey = key; |
| 37 mStore = store; |
| 38 } |
| 39 |
| 40 PrivateKey getJavaKey() { |
| 41 return mKey; |
| 42 } |
| 43 |
| 44 @Override |
| 45 public AndroidKeyStore getKeyStore() { |
| 46 return mStore; |
| 47 } |
| 48 } |
| 49 |
| 50 public AndroidPrivateKey createKey(PrivateKey javaKey) { |
| 51 return new LocalPrivateKey(javaKey, this); |
| 52 } |
29 | 53 |
30 //////////////////////////////////////////////////////////////////// | 54 //////////////////////////////////////////////////////////////////// |
31 // | 55 // |
32 // Message signing support. | 56 // Message signing support. |
33 | 57 |
34 /** | 58 /** |
35 * Returns the public modulus of a given RSA private key as a byte | 59 * Returns the public modulus of a given RSA private key as a byte |
36 * buffer. | 60 * buffer. |
37 * This can be used by native code to convert the modulus into | 61 * This can be used by native code to convert the modulus into |
38 * an OpenSSL BIGNUM object. Required to craft a custom native RSA | 62 * an OpenSSL BIGNUM object. Required to craft a custom native RSA |
39 * object where RSA_size() works as expected. | 63 * object where RSA_size() works as expected. |
40 * | 64 * |
41 * @param key A PrivateKey instance, must implement RSAKey. | 65 * @param key A PrivateKey instance, must implement RSAKey. |
42 * @return A byte buffer corresponding to the modulus. This is | 66 * @return A byte buffer corresponding to the modulus. This is |
43 * big-endian representation of a BigInteger. | 67 * big-endian representation of a BigInteger. |
44 */ | 68 */ |
45 @CalledByNative | 69 |
46 public static byte[] getRSAKeyModulus(PrivateKey key) { | 70 @Override |
47 if (key instanceof RSAKey) { | 71 public byte[] getRSAKeyModulus(AndroidPrivateKey key) { |
48 return ((RSAKey) key).getModulus().toByteArray(); | 72 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); |
| 73 if (javaKey instanceof RSAKey) { |
| 74 return ((RSAKey) javaKey).getModulus().toByteArray(); |
49 } else { | 75 } else { |
50 Log.w(TAG, "Not a RSAKey instance!"); | 76 Log.w(TAG, "Not a RSAKey instance!"); |
51 return null; | 77 return null; |
52 } | 78 } |
53 } | 79 } |
54 | 80 |
55 /** | 81 /** |
56 * Returns the 'Q' parameter of a given DSA private key as a byte | 82 * Returns the 'Q' parameter of a given DSA private key as a byte |
57 * buffer. | 83 * buffer. |
58 * This can be used by native code to convert it into an OpenSSL BIGNUM | 84 * This can be used by native code to convert it into an OpenSSL BIGNUM |
59 * object where DSA_size() works as expected. | 85 * object where DSA_size() works as expected. |
60 * | 86 * |
61 * @param key A PrivateKey instance. Must implement DSAKey. | 87 * @param key A PrivateKey instance. Must implement DSAKey. |
62 * @return A byte buffer corresponding to the Q parameter. This is | 88 * @return A byte buffer corresponding to the Q parameter. This is |
63 * a big-endian representation of a BigInteger. | 89 * a big-endian representation of a BigInteger. |
64 */ | 90 */ |
65 @CalledByNative | 91 |
66 public static byte[] getDSAKeyParamQ(PrivateKey key) { | 92 @Override |
67 if (key instanceof DSAKey) { | 93 public byte[] getDSAKeyParamQ(AndroidPrivateKey key) { |
68 DSAParams params = ((DSAKey) key).getParams(); | 94 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); |
| 95 if (javaKey instanceof DSAKey) { |
| 96 DSAParams params = ((DSAKey) javaKey).getParams(); |
69 return params.getQ().toByteArray(); | 97 return params.getQ().toByteArray(); |
70 } else { | 98 } else { |
71 Log.w(TAG, "Not a DSAKey instance!"); | 99 Log.w(TAG, "Not a DSAKey instance!"); |
72 return null; | 100 return null; |
73 } | 101 } |
74 } | 102 } |
75 | 103 |
76 /** | 104 /** |
77 * Returns the 'order' parameter of a given ECDSA private key as a | 105 * Returns the 'order' parameter of a given ECDSA private key as a |
78 * a byte buffer. | 106 * a byte buffer. |
79 * @param key A PrivateKey instance. Must implement ECKey. | 107 * @param key A PrivateKey instance. Must implement ECKey. |
80 * @return A byte buffer corresponding to the 'order' parameter. | 108 * @return A byte buffer corresponding to the 'order' parameter. |
81 * This is a big-endian representation of a BigInteger. | 109 * This is a big-endian representation of a BigInteger. |
82 */ | 110 */ |
83 @CalledByNative | 111 |
84 public static byte[] getECKeyOrder(PrivateKey key) { | 112 @Override |
85 if (key instanceof ECKey) { | 113 public byte[] getECKeyOrder(AndroidPrivateKey key) { |
86 ECParameterSpec params = ((ECKey) key).getParams(); | 114 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); |
| 115 if (javaKey instanceof ECKey) { |
| 116 ECParameterSpec params = ((ECKey) javaKey).getParams(); |
87 return params.getOrder().toByteArray(); | 117 return params.getOrder().toByteArray(); |
88 } else { | 118 } else { |
89 Log.w(TAG, "Not an ECKey instance!"); | 119 Log.w(TAG, "Not an ECKey instance!"); |
90 return null; | 120 return null; |
91 } | 121 } |
92 } | 122 } |
93 | 123 |
94 /** | 124 /** |
95 * Returns the encoded data corresponding to a given PrivateKey. | 125 * Returns the encoded data corresponding to a given PrivateKey. |
96 * Note that this will fail for platform keys on Android 4.0.4 | 126 * Note that this will fail for platform keys on Android 4.0.4 |
97 * and higher. It can be used on 4.0.3 and older platforms to | 127 * and higher. It can be used on 4.0.3 and older platforms to |
98 * route around the platform bug described below. | 128 * route around the platform bug described below. |
99 * @param key A PrivateKey instance | 129 * @param key A PrivateKey instance |
100 * @return encoded key as PKCS#8 byte array, can be null. | 130 * @return encoded key as PKCS#8 byte array, can be null. |
101 */ | 131 */ |
102 @CalledByNative | 132 |
103 public static byte[] getPrivateKeyEncodedBytes(PrivateKey key) { | 133 @Override |
104 return key.getEncoded(); | 134 public byte[] getPrivateKeyEncodedBytes(AndroidPrivateKey key) { |
| 135 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); |
| 136 return javaKey.getEncoded(); |
105 } | 137 } |
106 | 138 |
107 /** | 139 /** |
108 * Sign a given message with a given PrivateKey object. This method | 140 * Sign a given message with a given PrivateKey object. This method |
109 * shall only be used to implement signing in the context of SSL | 141 * shall only be used to implement signing in the context of SSL |
110 * client certificate support. | 142 * client certificate support. |
111 * | 143 * |
112 * The message will actually be a hash, computed by OpenSSL itself, | 144 * The message will actually be a hash, computed by OpenSSL itself, |
113 * depending on the type of the key. The result should match exactly | 145 * depending on the type of the key. The result should match exactly |
114 * what the vanilla implementations of the following OpenSSL function | 146 * what the vanilla implementations of the following OpenSSL function |
115 * calls do: | 147 * calls do: |
116 * | 148 * |
117 * - For a RSA private key, this should be equivalent to calling | 149 * - For a RSA private key, this should be equivalent to calling |
118 * RSA_private_encrypt(..., RSA_PKCS1_PADDING), i.e. it must | 150 * RSA_private_encrypt(..., RSA_PKCS1_PADDING), i.e. it must |
119 * generate a raw RSA signature. The message must be either a | 151 * generate a raw RSA signature. The message must be either a |
120 * combined, 36-byte MD5+SHA1 message digest or a DigestInfo | 152 * combined, 36-byte MD5+SHA1 message digest or a DigestInfo |
121 * value wrapping a message digest. | 153 * value wrapping a message digest. |
122 * | 154 * |
123 * - For a DSA and ECDSA private keys, this should be equivalent to | 155 * - For a DSA and ECDSA private keys, this should be equivalent to |
124 * calling DSA_sign(0,...) and ECDSA_sign(0,...) respectively. The | 156 * calling DSA_sign(0,...) and ECDSA_sign(0,...) respectively. The |
125 * message must be a hash and the function shall compute a direct | 157 * message must be a hash and the function shall compute a direct |
126 * DSA/ECDSA signature for it. | 158 * DSA/ECDSA signature for it. |
127 * | 159 * |
128 * @param privateKey The PrivateKey handle. | 160 * @param key The PrivateKey handle. |
129 * @param message The message to sign. | 161 * @param message The message to sign. |
130 * @return signature as a byte buffer. | 162 * @return signature as a byte buffer. |
131 * | 163 * |
132 * Important: Due to a platform bug, this function will always fail on | 164 * Important: Due to a platform bug, this function will always fail on |
133 * Android < 4.2 for RSA PrivateKey objects. See the | 165 * Android < 4.2 for RSA PrivateKey objects. See the |
134 * getOpenSSLHandleForPrivateKey() below for work-around. | 166 * getOpenSSLHandleForPrivateKey() below for work-around. |
135 */ | 167 */ |
136 @CalledByNative | 168 |
137 public static byte[] rawSignDigestWithPrivateKey(PrivateKey privateKey, | 169 @Override |
| 170 public byte[] rawSignDigestWithPrivateKey(AndroidPrivateKey key, |
138 byte[] message) { | 171 byte[] message) { |
| 172 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); |
139 // Get the Signature for this key. | 173 // Get the Signature for this key. |
140 Signature signature = null; | 174 Signature signature = null; |
141 // Hint: Algorithm names come from: | 175 // Hint: Algorithm names come from: |
142 // http://docs.oracle.com/javase/6/docs/technotes/guides/security/Standa
rdNames.html | 176 // http://docs.oracle.com/javase/6/docs/technotes/guides/security/Standa
rdNames.html |
143 try { | 177 try { |
144 if (privateKey instanceof RSAPrivateKey) { | 178 if (javaKey instanceof RSAPrivateKey) { |
145 // IMPORTANT: Due to a platform bug, this will throw NoSuchAlgor
ithmException | 179 // IMPORTANT: Due to a platform bug, this will throw NoSuchAlgor
ithmException |
146 // on Android 4.0.x and 4.1.x. Fixed in 4.2 and higher. | 180 // on Android 4.0.x and 4.1.x. Fixed in 4.2 and higher. |
147 // See https://android-review.googlesource.com/#/c/40352/ | 181 // See https://android-review.googlesource.com/#/c/40352/ |
148 signature = Signature.getInstance("NONEwithRSA"); | 182 signature = Signature.getInstance("NONEwithRSA"); |
149 } else if (privateKey instanceof DSAPrivateKey) { | 183 } else if (javaKey instanceof DSAPrivateKey) { |
150 signature = Signature.getInstance("NONEwithDSA"); | 184 signature = Signature.getInstance("NONEwithDSA"); |
151 } else if (privateKey instanceof ECPrivateKey) { | 185 } else if (javaKey instanceof ECPrivateKey) { |
152 signature = Signature.getInstance("NONEwithECDSA"); | 186 signature = Signature.getInstance("NONEwithECDSA"); |
153 } | 187 } |
154 } catch (NoSuchAlgorithmException e) { | 188 } catch (NoSuchAlgorithmException e) { |
155 ; | 189 ; |
156 } | 190 } |
157 | 191 |
158 if (signature == null) { | 192 if (signature == null) { |
159 Log.e(TAG, "Unsupported private key algorithm: " + privateKey.getAlg
orithm()); | 193 Log.e(TAG, "Unsupported private key algorithm: " + javaKey.getAlgori
thm()); |
160 return null; | 194 return null; |
161 } | 195 } |
162 | 196 |
163 // Sign the message. | 197 // Sign the message. |
164 try { | 198 try { |
165 signature.initSign(privateKey); | 199 signature.initSign(javaKey); |
166 signature.update(message); | 200 signature.update(message); |
167 return signature.sign(); | 201 return signature.sign(); |
168 } catch (Exception e) { | 202 } catch (Exception e) { |
169 Log.e(TAG, "Exception while signing message with " + privateKey.getA
lgorithm() + | 203 Log.e(TAG, "Exception while signing message with " + javaKey.getAlgo
rithm() + |
170 " private key: " + e); | 204 " private key: " + e); |
171 return null; | 205 return null; |
172 } | 206 } |
173 } | 207 } |
174 | 208 |
175 /** | 209 /** |
176 * Return the type of a given PrivateKey object. This is an integer | 210 * Return the type of a given PrivateKey object. This is an integer |
177 * that maps to one of the values defined by org.chromium.net.PrivateKeyType
, | 211 * that maps to one of the values defined by org.chromium.net.PrivateKeyType
, |
178 * which is itself auto-generated from net/android/private_key_type_list.h | 212 * which is itself auto-generated from net/android/private_key_type_list.h |
179 * @param privateKey The PrivateKey handle | 213 * @param key The PrivateKey handle |
180 * @return key type, or PrivateKeyType.INVALID if unknown. | 214 * @return key type, or PrivateKeyType.INVALID if unknown. |
181 */ | 215 */ |
182 @CalledByNative | 216 |
183 public static int getPrivateKeyType(PrivateKey privateKey) { | 217 @Override |
184 if (privateKey instanceof RSAPrivateKey) | 218 public int getPrivateKeyType(AndroidPrivateKey key) { |
| 219 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); |
| 220 if (javaKey instanceof RSAPrivateKey) |
185 return PrivateKeyType.RSA; | 221 return PrivateKeyType.RSA; |
186 if (privateKey instanceof DSAPrivateKey) | 222 if (javaKey instanceof DSAPrivateKey) |
187 return PrivateKeyType.DSA; | 223 return PrivateKeyType.DSA; |
188 if (privateKey instanceof ECPrivateKey) | 224 if (javaKey instanceof ECPrivateKey) |
189 return PrivateKeyType.ECDSA; | 225 return PrivateKeyType.ECDSA; |
190 else | 226 else |
191 return PrivateKeyType.INVALID; | 227 return PrivateKeyType.INVALID; |
192 } | 228 } |
193 | 229 |
194 /** | 230 /** |
195 * Return the system EVP_PKEY handle corresponding to a given PrivateKey | 231 * Return the system EVP_PKEY handle corresponding to a given PrivateKey |
196 * object, obtained through reflection. | 232 * object, obtained through reflection. |
197 * | 233 * |
198 * This shall only be used when the "NONEwithRSA" signature is not | 234 * This shall only be used when the "NONEwithRSA" signature is not |
(...skipping 13 matching lines...) Expand all Loading... |
212 * Note that the object returned was created with the platform version | 248 * Note that the object returned was created with the platform version |
213 * of OpenSSL, and _not_ the one that comes with Chromium. Whether the | 249 * of OpenSSL, and _not_ the one that comes with Chromium. Whether the |
214 * object can be used safely with the Chromium OpenSSL library depends | 250 * object can be used safely with the Chromium OpenSSL library depends |
215 * on differences between their actual ABI / implementation details. | 251 * on differences between their actual ABI / implementation details. |
216 * | 252 * |
217 * To better understand what's going on below, please refer to the | 253 * To better understand what's going on below, please refer to the |
218 * following source files in the Android 4.0.4 and 4.1 source trees: | 254 * following source files in the Android 4.0.4 and 4.1 source trees: |
219 * libcore/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLR
SAPrivateKey.java | 255 * libcore/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLR
SAPrivateKey.java |
220 * libcore/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_Native
Crypto.cpp | 256 * libcore/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_Native
Crypto.cpp |
221 * | 257 * |
222 * @param privateKey The PrivateKey handle. | 258 * @param key The PrivateKey handle. |
223 * @return The EVP_PKEY handle, as a 32-bit integer (0 if not available) | 259 * @return The EVP_PKEY handle, as a 32-bit integer (0 if not available) |
224 */ | 260 */ |
225 @CalledByNative | 261 |
226 public static int getOpenSSLHandleForPrivateKey(PrivateKey privateKey) { | 262 @Override |
| 263 public int getOpenSSLHandleForPrivateKey(AndroidPrivateKey key) { |
| 264 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); |
227 // Sanity checks | 265 // Sanity checks |
228 if (privateKey == null) { | 266 if (javaKey == null) { |
229 Log.e(TAG, "privateKey == null"); | 267 Log.e(TAG, "key == null"); |
230 return 0; | 268 return 0; |
231 } | 269 } |
232 if (!(privateKey instanceof RSAPrivateKey)) { | 270 if (!(javaKey instanceof RSAPrivateKey)) { |
233 Log.e(TAG, "does not implement RSAPrivateKey"); | 271 Log.e(TAG, "does not implement RSAPrivateKey"); |
234 return 0; | 272 return 0; |
235 } | 273 } |
236 // First, check that this is a proper instance of OpenSSLRSAPrivateKey | 274 // First, check that this is a proper instance of OpenSSLRSAPrivateKey |
237 // or one of its sub-classes. | 275 // or one of its sub-classes. |
238 Class<?> superClass; | 276 Class<?> superClass; |
239 try { | 277 try { |
240 superClass = Class.forName( | 278 superClass = Class.forName( |
241 "org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey"
); | 279 "org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey"
); |
242 } catch (Exception e) { | 280 } catch (Exception e) { |
243 // This may happen if the target device has a completely different | 281 // This may happen if the target device has a completely different |
244 // implementation of the java.security APIs, compared to vanilla | 282 // implementation of the java.security APIs, compared to vanilla |
245 // Android. Highly unlikely, but still possible. | 283 // Android. Highly unlikely, but still possible. |
246 Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e); | 284 Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e); |
247 return 0; | 285 return 0; |
248 } | 286 } |
249 if (!superClass.isInstance(privateKey)) { | 287 if (!superClass.isInstance(key)) { |
250 // This may happen if the PrivateKey was not created by the "Android
OpenSSL" | 288 // This may happen if the PrivateKey was not created by the "Android
OpenSSL" |
251 // provider, which should be the default. That could happen if an OE
M decided | 289 // provider, which should be the default. That could happen if an OE
M decided |
252 // to implement a different default provider. Also highly unlikely. | 290 // to implement a different default provider. Also highly unlikely. |
253 Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its
class name is:" + | 291 Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its
class name is:" + |
254 privateKey.getClass().getCanonicalName()); | 292 javaKey.getClass().getCanonicalName()); |
255 return 0; | 293 return 0; |
256 } | 294 } |
257 | 295 |
258 try { | 296 try { |
259 // Use reflection to invoke the 'getOpenSSLKey()' method on | 297 // Use reflection to invoke the 'getOpenSSLKey()' method on |
260 // the private key. This returns another Java object that wraps | 298 // the private key. This returns another Java object that wraps |
261 // a native EVP_PKEY. Note that the method is final, so calling | 299 // a native EVP_PKEY. Note that the method is final, so calling |
262 // the superclass implementation is ok. | 300 // the superclass implementation is ok. |
263 Method getKey = superClass.getDeclaredMethod("getOpenSSLKey"); | 301 Method getKey = superClass.getDeclaredMethod("getOpenSSLKey"); |
264 getKey.setAccessible(true); | 302 getKey.setAccessible(true); |
265 Object opensslKey = null; | 303 Object opensslKey = null; |
266 try { | 304 try { |
267 opensslKey = getKey.invoke(privateKey); | 305 opensslKey = getKey.invoke(javaKey); |
268 } finally { | 306 } finally { |
269 getKey.setAccessible(false); | 307 getKey.setAccessible(false); |
270 } | 308 } |
271 if (opensslKey == null) { | 309 if (opensslKey == null) { |
272 // Bail when detecting OEM "enhancement". | 310 // Bail when detecting OEM "enhancement". |
273 Log.e(TAG, "getOpenSSLKey() returned null"); | 311 Log.e(TAG, "getOpenSSLKey() returned null"); |
274 return 0; | 312 return 0; |
275 } | 313 } |
276 | 314 |
277 // Use reflection to invoke the 'getPkeyContext' method on the | 315 // Use reflection to invoke the 'getPkeyContext' method on the |
(...skipping 19 matching lines...) Expand all Loading... |
297 Log.e(TAG, "getPkeyContext() returned null"); | 335 Log.e(TAG, "getPkeyContext() returned null"); |
298 } | 336 } |
299 return evp_pkey; | 337 return evp_pkey; |
300 | 338 |
301 } catch (Exception e) { | 339 } catch (Exception e) { |
302 Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handl
e: " + e); | 340 Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handl
e: " + e); |
303 return 0; | 341 return 0; |
304 } | 342 } |
305 } | 343 } |
306 } | 344 } |
OLD | NEW |