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

Side by Side Diff: net/android/keystore_openssl.cc

Issue 11571059: Add net/android/keystore.h (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Add DSA + ECDSA test keys and signing tests Created 7 years, 11 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 #include "net/android/keystore_openssl.h"
6
7 #include <jni.h>
8 #include <openssl/engine.h>
9 #include <openssl/evp.h>
10 #include <openssl/rsa.h>
11
12 #include "base/android/jni_android.h"
13 #include "base/android/scoped_java_ref.h"
14 #include "base/basictypes.h"
15 #include "base/logging.h"
16 #include "crypto/openssl_util.h"
17 #include "net/android/keystore.h"
18 #include "net/base/ssl_client_cert_type.h"
19
20 // IMPORTANT NOTE: The following code will currently only work when used
21 // to implement client certificate support with OpenSSL. That's because
22 // only signing is implemented here.
23 //
24
25 // The OpenSSL EVP_PKEY type is a generic wrapper around key pairs.
26 // Internally, it can hold a pointer to a RSA, DSA or ECDA structure,
27 // which model keypair implementations of each respective crypto
28 // algorithm.
29 //
30 // The RSA type has a 'method' field pointer to a vtable-like structure
31 // called a RSA_METHOD. This contains several function pointers that
32 // correspond to operations on RSA keys (e.g. decode/encode with public
33 // key, decode/encode with private key, signing, validation), as well as
34 // a few flags.
35 //
36 // For example, the RSA_sign() function will call "method->rsa_sign()" if
37 // method->rsa_sign is not NULL, otherwise, it will perform a regular
38 // signing operation using the other fields in the RSA structure (which
39 // are used to hold the typical modulus / exponent / parameters for the
40 // key pair).
41 //
42 // This source file thus defines a custom RSA_METHOD structure, which
43 // fields points to static methods used to implement the corresponding
44 // RSA operation using platform Android APIs.
45 //
46 // However, the platform APIs require a jobject JNI reference to work.
47 // It must be stored in the RSA instance, or made accessible when the
48 // custom RSA methods are called. This is done by using RSA_set_app_data()
49 // and RSA_get_app_data().
50 //
51 // One can thus _directly_ create a new EVP_PKEY that uses a custom RSA
52 // object with the following:
53 //
54 // RSA* rsa = RSA_new()
55 // RSA_set_method(&custom_rsa_method);
56 // RSA_set_app_data(rsa, jni_private_key);
57 //
58 // EVP_PKEY* pkey = EVP_PKEY_new();
59 // EVP_PKEY_assign_RSA(pkey, rsa);
60 //
61 // Note that because EVP_PKEY_assign_RSA() is used, instead of
62 // EVP_PKEY_set1_RSA(), the new EVP_PKEY now owns the RSA object, and
63 // will destroy it when it is itself destroyed.
64 //
65 // Similarly, custom DSA_METHOD and ECDSA_METHOD are defined by this source
66 // file.
67 //
68 // Note that there is no need to define an OpenSSL ENGINE here. These
69 // are objects that can be used to expose custom methods (i.e. either
70 // RSA_METHOD, DSA_METHOD, ECDSA_METHOD, and a large number of other ones
71 // for types not related to this source file), and make them used by
72 // default for a lot of operations. Very fortunately, this is not needed
73 // here, which saves a lot of complexity.
74 //
75
76 namespace {
77
78 ///////////////////////////////////////////////////////////////////////////
79 //
80 // Custom RSA_METHOD to be used to use the platform APIs.
81 // Note that for now, only signing through RSA_sign() is really supported.
82 // all other method pointers are either stubs returning errors, or no-ops.
83 //
84 // See <openssl/rsa.h> for exact declaration of RSA_METHOD.
85 //
86
87 int RsaMethodPubEnc(int flen,
88 const unsigned char* from,
89 unsigned char* to,
90 RSA* rsa,
91 int padding) {
92 NOTIMPLEMENTED();
93 RSAerr(RSA_F_RSA_PUBLIC_ENCRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
94 return -1;
95 }
96
97 int RsaMethodPubDec(int flen,
98 const unsigned char* from,
99 unsigned char* to,
100 RSA* rsa,
101 int padding) {
102 NOTIMPLEMENTED();
103 RSAerr(RSA_F_RSA_PUBLIC_DECRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
104 return -1;
105 }
106
107 int RsaMethodPrivEnc(int flen,
108 const unsigned char *from,
109 unsigned char *to,
110 RSA *rsa,
111 int padding) {
112 NOTIMPLEMENTED();
113 RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
114 return -1;
115 }
116
117 int RsaMethodPrivDec(int flen,
118 const unsigned char* from,
119 unsigned char* to,
120 RSA* rsa,
121 int padding) {
122 NOTIMPLEMENTED();
123 RSAerr(RSA_F_RSA_PRIVATE_DECRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
124 return -1;
125 }
126
127 int RsaMethodInit(RSA* rsa) {
128 // Required to ensure that RsaMethodSign will be called.
129 rsa->flags |= RSA_FLAG_SIGN_VER;
130 return 0;
131 }
132
133 int RsaMethodFinish(RSA* rsa) {
134 // Ensure the global JNI reference is destroyed with this key.
135 jobject key = reinterpret_cast<jobject>(RSA_get_app_data(rsa));
136 if (key != NULL) {
137 RSA_set_app_data(rsa, NULL);
138 JNIEnv* env = base::android::AttachCurrentThread();
139 env->DeleteGlobalRef(key);
140 }
141 // Actual return value is ignored by OpenSSL. There are no docs
142 // explaining what this is supposed to be.
143 return 0;
144 }
145
146 int RsaMethodSign(int type,
147 const unsigned char* message,
148 unsigned int message_len,
149 unsigned char* signature,
150 unsigned int* signature_len,
151 const RSA* rsa) {
152 // This is only used for client certificate support.
153 DCHECK_EQ(NID_md5_sha1, type);
154 if (type != NID_md5_sha1) {
155 RSAerr(RSA_F_RSA_SIGN, RSA_R_UNKNOWN_ALGORITHM_TYPE);
156 return 0;
157 }
158 // Retrieve private key JNI reference.
159 jobject private_key = reinterpret_cast<jobject>(RSA_get_app_data(rsa));
160 if (!private_key) {
161 LOG(WARNING) << "Null JNI reference passed to RsaMethodSign!";
162 return 0;
163 }
164 // Sign message with it through JNI.
165 base::StringPiece message_piece(reinterpret_cast<const char*>(message),
166 static_cast<size_t>(message_len));
167 std::vector<uint8> result;
168
169 if (!net::android::SignWithPrivateKey(
170 private_key, message_piece, &result)) {
171 LOG(WARNING) << "Could not sign message in RsaMethodSign!";
172 return 0;
173 }
174 // Copy result to OpenSSL-provided buffer
175 memcpy(signature, &result[0], result.size());
176 *signature_len = static_cast<unsigned int>(result.size());
177 return 1;
178 }
179
180 const RSA_METHOD android_rsa_method = {
181 /* .name = */ "Android signing-only RSA method",
182 /* .rsa_pub_enc = */ RsaMethodPubEnc,
183 /* .rsa_pub_dec = */ RsaMethodPubDec,
184 /* .rsa_priv_enc = */ RsaMethodPrivEnc,
185 /* .rsa_priv_dec = */ RsaMethodPrivDec,
186 /* .rsa_mod_exp = */ NULL,
187 /* .bn_mod_exp = */ NULL,
188 /* .init = */ RsaMethodInit,
189 /* .finish = */ RsaMethodFinish,
190 /* .flags = */ RSA_FLAG_SIGN_VER, // indicates that rsa_sign is usable.
191 /* .app_data = */ NULL,
192 /* .rsa_sign = */ RsaMethodSign,
193 /* .rsa_verify = */ NULL,
194 /* .rsa_keygen = */ NULL,
195 };
196
197 } // namespace
198
199
200 namespace net {
201 namespace android {
202
203 EVP_PKEY* GetOpenSSLPrivateKeyWrapper(jobject private_key) {
204 // Create scoped JNI global reference from the private key.
205 // This ensure that it will be usable from any thread, not only
206 // from the caller's.
207 //
208 // Note: "ScopedJavaGlobalRef<jobject> ref(a_jobject)" doesn't
209 // compile. Route around this by creating an empty object first,
210 // then resetting it.
211 base::android::ScopedJavaGlobalRef<jobject> global_key;
212 global_key.Reset(NULL, private_key);
213 if (global_key.is_null())
214 return NULL;
215
216 // Create new empty EVP_PKEY instance.
217 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> pkey(EVP_PKEY_new());
218 if (!pkey.get())
219 return NULL;
220
221 // Create sub key type, depending on private key's algorithm type.
222 SSLClientCertType key_type = GetPrivateKeySigningType(global_key.obj());
223 switch (key_type) {
224 case CLIENT_CERT_RSA_SIGN:
225 {
226 RSA* rsa = RSA_new();
227 RSA_set_method(rsa, &android_rsa_method);
228 RSA_set_app_data(rsa, global_key.Release());
229 EVP_PKEY_assign_RSA(pkey.get(), rsa);
230 }
231 break;
232 case CLIENT_CERT_DSS_SIGN:
233 // TODO(digit): Implement this.
234 NOTIMPLEMENTED();
235 return NULL;
236 case CLIENT_CERT_ECDSA_SIGN:
237 // TODO(digit): Implement this.
238 NOTIMPLEMENTED();
239 return NULL;
240 default:
241 LOG(WARNING)
242 << "GetOpenSSLPrivateKeyWrapper() called with invalid key type";
243 return NULL;
244 }
245
246 return pkey.release();
247 }
248
249 } // namespace android
250 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698