OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.net; | |
6 | |
7 import android.util.Log; | |
8 | |
9 import java.lang.reflect.Method; | |
10 import java.security.NoSuchAlgorithmException; | |
11 import java.security.PrivateKey; | |
12 import java.security.Signature; | |
13 import java.security.interfaces.DSAKey; | |
14 import java.security.interfaces.DSAParams; | |
15 import java.security.interfaces.DSAPrivateKey; | |
16 import java.security.interfaces.ECKey; | |
17 import java.security.interfaces.ECPrivateKey; | |
18 import java.security.interfaces.RSAKey; | |
19 import java.security.interfaces.RSAPrivateKey; | |
20 import java.security.spec.ECParameterSpec; | |
21 | |
22 /** | |
23 * Simple implementation of the AndroidKeyStoreInterface for use with an in-proc ess Java KeyStore. | |
24 */ | |
25 public class AndroidKeyStoreLocalImpl implements AndroidKeyStore { | |
bulach
2014/02/14 10:45:29
nit: perhaps "InProcess" instead of "Local"?
Yaron
2014/02/14 19:36:56
Done.
| |
26 | |
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 } | |
53 | |
54 @Override | |
55 public byte[] getRSAKeyModulus(AndroidPrivateKey key) { | |
56 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); | |
57 if (javaKey instanceof RSAKey) { | |
58 return ((RSAKey) javaKey).getModulus().toByteArray(); | |
59 } else { | |
bulach
2014/02/14 10:45:29
remove the "else" here and in the following method
Yaron
2014/02/14 19:36:56
Done.
| |
60 Log.w(TAG, "Not a RSAKey instance!"); | |
61 return null; | |
62 } | |
63 } | |
64 | |
65 @Override | |
66 public byte[] getDSAKeyParamQ(AndroidPrivateKey key) { | |
67 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); | |
68 if (javaKey instanceof DSAKey) { | |
69 DSAParams params = ((DSAKey) javaKey).getParams(); | |
70 return params.getQ().toByteArray(); | |
71 } else { | |
72 Log.w(TAG, "Not a DSAKey instance!"); | |
73 return null; | |
74 } | |
75 } | |
76 | |
77 @Override | |
78 public byte[] getECKeyOrder(AndroidPrivateKey key) { | |
79 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); | |
80 if (javaKey instanceof ECKey) { | |
81 ECParameterSpec params = ((ECKey) javaKey).getParams(); | |
82 return params.getOrder().toByteArray(); | |
83 } else { | |
84 Log.w(TAG, "Not an ECKey instance!"); | |
85 return null; | |
86 } | |
87 } | |
88 | |
89 @Override | |
90 public byte[] getPrivateKeyEncodedBytes(AndroidPrivateKey key) { | |
91 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); | |
92 return javaKey.getEncoded(); | |
93 } | |
94 | |
95 @Override | |
96 public byte[] rawSignDigestWithPrivateKey(AndroidPrivateKey key, | |
97 byte[] message) { | |
98 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); | |
99 // Get the Signature for this key. | |
100 Signature signature = null; | |
101 // Hint: Algorithm names come from: | |
102 // http://docs.oracle.com/javase/6/docs/technotes/guides/security/Standa rdNames.html | |
103 try { | |
104 if (javaKey instanceof RSAPrivateKey) { | |
105 // IMPORTANT: Due to a platform bug, this will throw NoSuchAlgor ithmException | |
106 // on Android 4.0.x and 4.1.x. Fixed in 4.2 and higher. | |
107 // See https://android-review.googlesource.com/#/c/40352/ | |
108 signature = Signature.getInstance("NONEwithRSA"); | |
109 } else if (javaKey instanceof DSAPrivateKey) { | |
110 signature = Signature.getInstance("NONEwithDSA"); | |
111 } else if (javaKey instanceof ECPrivateKey) { | |
112 signature = Signature.getInstance("NONEwithECDSA"); | |
113 } | |
114 } catch (NoSuchAlgorithmException e) { | |
115 ; | |
116 } | |
117 | |
118 if (signature == null) { | |
119 Log.e(TAG, "Unsupported private key algorithm: " + javaKey.getAlgori thm()); | |
120 return null; | |
121 } | |
122 | |
123 // Sign the message. | |
124 try { | |
125 signature.initSign(javaKey); | |
126 signature.update(message); | |
127 return signature.sign(); | |
128 } catch (Exception e) { | |
129 Log.e(TAG, "Exception while signing message with " + javaKey.getAlgo rithm() + | |
130 " private key: " + e); | |
131 return null; | |
132 } | |
133 } | |
134 | |
135 @Override | |
136 public int getPrivateKeyType(AndroidPrivateKey key) { | |
137 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); | |
138 if (javaKey instanceof RSAPrivateKey) | |
139 return PrivateKeyType.RSA; | |
140 if (javaKey instanceof DSAPrivateKey) | |
141 return PrivateKeyType.DSA; | |
142 if (javaKey instanceof ECPrivateKey) | |
143 return PrivateKeyType.ECDSA; | |
144 else | |
145 return PrivateKeyType.INVALID; | |
146 } | |
147 | |
148 @Override | |
149 public int getOpenSSLHandleForPrivateKey(AndroidPrivateKey key) { | |
150 PrivateKey javaKey = ((LocalPrivateKey) key).getJavaKey(); | |
151 // Sanity checks | |
152 if (javaKey == null) { | |
153 Log.e(TAG, "key == null"); | |
154 return 0; | |
155 } | |
156 if (!(javaKey instanceof RSAPrivateKey)) { | |
157 Log.e(TAG, "does not implement RSAPrivateKey"); | |
158 return 0; | |
159 } | |
160 // First, check that this is a proper instance of OpenSSLRSAPrivateKey | |
161 // or one of its sub-classes. | |
162 Class<?> superClass; | |
163 try { | |
164 superClass = Class.forName( | |
165 "org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey" ); | |
166 } catch (Exception e) { | |
167 // This may happen if the target device has a completely different | |
168 // implementation of the java.security APIs, compared to vanilla | |
169 // Android. Highly unlikely, but still possible. | |
170 Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e); | |
171 return 0; | |
172 } | |
173 if (!superClass.isInstance(key)) { | |
174 // This may happen if the PrivateKey was not created by the "Android OpenSSL" | |
175 // provider, which should be the default. That could happen if an OE M decided | |
176 // to implement a different default provider. Also highly unlikely. | |
177 Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:" + | |
178 javaKey.getClass().getCanonicalName()); | |
179 return 0; | |
180 } | |
181 | |
182 try { | |
183 // Use reflection to invoke the 'getOpenSSLKey()' method on | |
184 // the private key. This returns another Java object that wraps | |
185 // a native EVP_PKEY. Note that the method is final, so calling | |
186 // the superclass implementation is ok. | |
187 Method getKey = superClass.getDeclaredMethod("getOpenSSLKey"); | |
188 getKey.setAccessible(true); | |
189 Object opensslKey = null; | |
190 try { | |
191 opensslKey = getKey.invoke(javaKey); | |
192 } finally { | |
193 getKey.setAccessible(false); | |
194 } | |
195 if (opensslKey == null) { | |
196 // Bail when detecting OEM "enhancement". | |
197 Log.e(TAG, "getOpenSSLKey() returned null"); | |
198 return 0; | |
199 } | |
200 | |
201 // Use reflection to invoke the 'getPkeyContext' method on the | |
202 // result of the getOpenSSLKey(). This is an 32-bit integer | |
203 // which is the address of an EVP_PKEY object. | |
204 Method getPkeyContext; | |
205 try { | |
206 getPkeyContext = opensslKey.getClass().getDeclaredMethod("getPke yContext"); | |
207 } catch (Exception e) { | |
208 // Bail here too, something really not working as expected. | |
209 Log.e(TAG, "No getPkeyContext() method on OpenSSLKey member:" + e); | |
210 return 0; | |
211 } | |
212 getPkeyContext.setAccessible(true); | |
213 int evp_pkey = 0; | |
214 try { | |
215 evp_pkey = (Integer) getPkeyContext.invoke(opensslKey); | |
216 } finally { | |
217 getPkeyContext.setAccessible(false); | |
218 } | |
219 if (evp_pkey == 0) { | |
220 // The PrivateKey is probably rotten for some reason. | |
221 Log.e(TAG, "getPkeyContext() returned null"); | |
222 } | |
223 return evp_pkey; | |
224 | |
225 } catch (Exception e) { | |
226 Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handl e: " + e); | |
227 return 0; | |
228 } | |
229 } | |
230 | |
231 @Override | |
232 public void releaseKey(AndroidPrivateKey key) { | |
233 // no-op for local. GC will handle key collection | |
234 } | |
235 } | |
OLD | NEW |