Chromium Code Reviews| 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 |