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