Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(315)

Side by Side Diff: net/android/java/src/org/chromium/net/AndroidKeyStore.java

Issue 11571059: Add net/android/keystore.h (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Appease the angry 'findbugs' gods. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 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.InvocationTargetException;
10 import java.lang.reflect.Method;
11 import java.security.interfaces.DSAPrivateKey;
12 import java.security.interfaces.ECPrivateKey;
13 import java.security.interfaces.RSAPrivateKey;
14 import java.security.NoSuchAlgorithmException;
15 import java.security.PrivateKey;
16 import java.security.Signature;
17
18 import org.chromium.base.CalledByNative;
19 import org.chromium.base.JNINamespace;
20 import org.chromium.net.PrivateKeyType;;
21
22 @JNINamespace("net::android")
23 public class AndroidKeyStore {
24
25 private static final String TAG = AndroidKeyStore.class.getName();
26
27 ////////////////////////////////////////////////////////////////////
28 //
29 // Message signing support.
30 //
31
32 /**
33 * Called from native code to sign a given message with a given
34 * PrivateKey object. This is used to implement SSL client certificate
35 * support through OpenSSL. Thus, it must match the behaviour of the
36 * OpenSSL RSA_sign() / DSA_sign() / ECDSA_sign() functions.
37 * @param privateKey The PrivateKey handle.
38 * @param message The message to sign.
agl 2013/01/30 14:28:53 I'm assuming here that |message| has already been
digit1 2013/01/30 16:55:01 Yes, what the function receives is the actual hash
39 * @return signature as a byte buffer.
40 *
41 * Important: Due to a platform bug, this function will always fail on
42 * Android < 4.2 for RSA PrivateKey objects. See the
43 * getOpenSSLHandleForPrivateKey() below for work-around.
44 */
45 @CalledByNative
46 public static byte[] signWithPrivateKey(PrivateKey privateKey,
Ryan Sleevi 2013/01/31 03:09:53 perhaps name this "rawSignWithPrivateKey", since i
digit1 2013/01/31 17:44:30 Done.
47 byte[] message) {
48 // Get the Signature for this key.
49 Signature signature = null;
50 // Hint: Algorithm names come from:
51 // http://docs.oracle.com/javase/6/docs/technotes/guides/security/Standa rdNames.html
52 try {
53 if (privateKey instanceof RSAPrivateKey) {
54 // IMPORTANT: Due to what looks like a platform bug, this will
55 // throw NoSuchAlgorithmException on Android 4.0.x and 4.1.x. Fi xed in 4.2
56 // and higher. See https://android-review.googlesource.com/#/c/4 0352/
57 signature = Signature.getInstance("NONEwithRSA");
58 } else if (privateKey instanceof DSAPrivateKey) {
59 signature = Signature.getInstance("NONEwithDSA");
60 } else if (privateKey instanceof ECPrivateKey) {
61 signature = Signature.getInstance("NONEwithECDSA");
62 }
63 } catch (NoSuchAlgorithmException e) {
64 ;
65 }
66
67 if (signature == null) {
68 Log.e(TAG, "Unsupported private key algorithm: " + privateKey.getAlg orithm());
69 return null;
70 }
71
72 // Sign the message.
73 try {
74 signature.initSign(privateKey);
75 signature.update(message);
76 return signature.sign();
77 } catch (Exception e) {
78 Log.e(TAG, "Exception while signing message with " + privateKey.getA lgorithm() +
79 " private key: " + e);
80 return null;
81 }
82 }
83
84 /**
85 * Called from native code to return the type of a given PrivateKey
86 * object. This is an integer that maps to one of the values defined
87 * by org.chromium.net.PrivateKeyType, which is itself
88 * auto-generated from net/android/private_key_type_list.h
89 * @param privateKey The PrivateKey handle
90 * @return key type, or PrivateKeyType.INVALID if unknown.
91 */
92 @CalledByNative
93 public static int getPrivateKeyType(PrivateKey privateKey) {
94 if (privateKey instanceof RSAPrivateKey)
95 return PrivateKeyType.RSA;
96 if (privateKey instanceof DSAPrivateKey)
97 return PrivateKeyType.DSA;
98 if (privateKey instanceof ECPrivateKey)
99 return PrivateKeyType.ECDSA;
100 else
101 return PrivateKeyType.INVALID;
102 }
103
104 /**
105 * Called from native code to return the system EVP_PKEY handle
106 * corresponding to a given PrivateKey object, obtained through
107 * reflection (a.k.a. "Evil Hack").
108 *
109 * This shall only be used for RSA private keys on Android 4.0 and
110 * 4.1 in order to work around the platform bug described in the
111 * signWithPrivateKey() comment above (namely that the NONEwithRSA
112 * signature is not available before Android 4.2).
113 *
114 * This assumes that the target device uses a vanilla AOSP
115 * implementation of its java.security classes, which is also
116 * based on OpenSSL (fortunately, no OEM has apperently changed to
117 * a different implementation, according to the Android team).
118 *
119 * Note that the object returned was created with the platform version
120 * of OpenSSL, and _not_ the one that comes with Chromium. Whether the
121 * object can be used safely with the Chromium OpenSSL library depends
122 * on differences between their actual ABI / implementation details.
123 *
124 * To better understand what's going on below, please refer to the
125 * following source files in the Android 4.0 and 4.1 source trees:
126 * libcore/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLR SAPrivateKey.java
127 * libcore/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_Native Crypto.cpp
128 *
129 * @param privateKey The PrivateKey handle.
130 * @return The EVP_PKEY handle, as a 32-bit integer (0 if not available)
131 */
132 @CalledByNative
133 public static int getOpenSSLHandleForPrivateKey(PrivateKey privateKey) {
134 // Sanity checks
135 if (privateKey == null) {
136 Log.e(TAG, "privateKey == null");
137 return 0;
138 }
139 if (!(privateKey instanceof RSAPrivateKey)) {
140 Log.e(TAG, "does not implement RSAPrivateKey");
141 return 0;
142 }
143 // First, check that this is a proper instance of OpenSSLRSAPrivateKey
144 // or one of its sub-classes.
145 Class<?> superClass;
146 try {
147 superClass = Class.forName(
148 "org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey" );
149 } catch (Exception e) {
150 // This may happen if the target device has a completely different
151 // implementation of the java.security APIs, compared to vanilla
152 // Android. Highly unlikely, but still possible.
153 Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e);
154 return 0;
155 }
156 if (!superClass.isInstance(privateKey)) {
157 // This may happen if the PrivateKey was not created by the "Android OpenSSL"
158 // provider, which should be the default. That could happen if an OE M decided
159 // to implement a different default provider. Also highly unlikely.
160 Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:" +
161 privateKey.getClass().getCanonicalName());
162 return 0;
163 }
164
165 try {
166 // Use reflection to invoke the 'getOpenSSLKey()' method on
167 // the private key. This returns another Java object that wraps
168 // a native EVP_PKEY. Note that the method is final, so calling
169 // the superclass implementation is ok.
170 Method getKey = superClass.getDeclaredMethod("getOpenSSLKey");
171 getKey.setAccessible(true);
172 Object opensslKey = null;
173 try {
174 opensslKey = getKey.invoke(privateKey);
175 } finally {
176 getKey.setAccessible(false);
177 }
178 if (opensslKey == null) {
179 // Bail when detecting OEM "enhancement".
180 Log.e(TAG, "getOpenSSLKey() returned null");
181 return 0;
182 }
183
184 // Use reflection to invoke the 'getPkeyContext' method on the
185 // result of the getOpenSSLKey(). This is an integer which
agl 2013/01/30 14:28:53 "which value"? Maybe "This is an integer who's val
digit1 2013/01/30 16:55:01 thanks, I'll fix this to "whose value".
186 // value is the address of the wrapper EVP_PKEY object.
187 Method getPkeyContext;
188 try {
189 getPkeyContext = opensslKey.getClass().getDeclaredMethod("getPke yContext");
190 } catch (Exception e) {
191 // Bail here too, something really not working as expected.
192 Log.e(TAG, "No getPkeyContext() method on OpenSSLKey member:" + e);
193 return 0;
194 }
195 getPkeyContext.setAccessible(true);
196 int evp_pkey = 0;
197 try {
198 evp_pkey = (Integer) getPkeyContext.invoke(opensslKey);
199 } finally {
200 getPkeyContext.setAccessible(false);
201 }
202 if (evp_pkey == 0) {
203 // The PrivateKey is probably rotten for some reason.
204 Log.e(TAG, "getPkeyContext() returned null");
205 }
206 return evp_pkey;
Ryan Sleevi 2013/01/31 03:09:53 I am nervous about the potential for ABI issues he
digit1 2013/01/31 17:44:30 I'm concerned about it too. I think longer term, i
207
208 } catch (Exception e) {
209 Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handl e: " + e);
210 return 0;
211 }
212 }
213 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698