|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include <stdlib.h> |
|
6 #include "dlfcn.h" |
|
7 #include "NSSBridge.h" |
|
8 #include "APKOpen.h" |
|
9 #ifdef ANDROID |
|
10 #include <jni.h> |
|
11 #include <android/log.h> |
|
12 #endif |
|
13 |
|
14 #include "ElfLoader.h" |
|
15 |
|
16 #ifdef DEBUG |
|
17 #define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x) |
|
18 #else |
|
19 #define LOG(x...) |
|
20 #endif |
|
21 |
|
22 static bool initialized = false; |
|
23 |
|
24 #define NSS_WRAPPER_INT(name) name ## _t f_ ## name; |
|
25 NSS_WRAPPER_INT(NSS_Initialize) |
|
26 NSS_WRAPPER_INT(NSS_Shutdown) |
|
27 NSS_WRAPPER_INT(SECITEM_ZfreeItem) |
|
28 NSS_WRAPPER_INT(PK11SDR_Encrypt) |
|
29 NSS_WRAPPER_INT(PK11SDR_Decrypt) |
|
30 NSS_WRAPPER_INT(PK11_GetInternalKeySlot) |
|
31 NSS_WRAPPER_INT(PK11_NeedUserInit) |
|
32 NSS_WRAPPER_INT(PK11_InitPin) |
|
33 NSS_WRAPPER_INT(PR_ErrorToString) |
|
34 NSS_WRAPPER_INT(PR_GetError) |
|
35 NSS_WRAPPER_INT(PR_Free) |
|
36 NSS_WRAPPER_INT(PL_Base64Encode) |
|
37 NSS_WRAPPER_INT(PL_Base64Decode) |
|
38 NSS_WRAPPER_INT(PL_strfree) |
|
39 |
|
40 int |
|
41 setup_nss_functions(void *nss_handle, |
|
42 void *nspr_handle, |
|
43 void *plc_handle) |
|
44 { |
|
45 if (nss_handle == nullptr || nspr_handle == nullptr || plc_handle == nullptr) { |
|
46 LOG("Missing handle\n"); |
|
47 return FAILURE; |
|
48 } |
|
49 #define GETFUNC(name) f_ ## name = (name ## _t) (uintptr_t) __wrap_dlsym(nss_handle, #name); \ |
|
50 if (!f_ ##name) { __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "missing %s", #name); return FAILURE; } |
|
51 GETFUNC(NSS_Initialize); |
|
52 GETFUNC(NSS_Shutdown); |
|
53 GETFUNC(PK11SDR_Encrypt); |
|
54 GETFUNC(PK11SDR_Decrypt); |
|
55 GETFUNC(PK11_GetInternalKeySlot); |
|
56 GETFUNC(PK11_NeedUserInit); |
|
57 GETFUNC(PK11_InitPin); |
|
58 GETFUNC(SECITEM_ZfreeItem); |
|
59 #undef GETFUNC |
|
60 #define NSPRFUNC(name) f_ ## name = (name ## _t) (uintptr_t) __wrap_dlsym(nspr_handle, #name); \ |
|
61 if (!f_ ##name) { __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "missing %s", #name); return FAILURE; } |
|
62 NSPRFUNC(PR_ErrorToString); |
|
63 NSPRFUNC(PR_GetError); |
|
64 NSPRFUNC(PR_Free); |
|
65 #undef NSPRFUNC |
|
66 #define PLCFUNC(name) f_ ## name = (name ## _t) (uintptr_t) __wrap_dlsym(plc_handle, #name); \ |
|
67 if (!f_ ##name) { __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "missing %s", #name); return FAILURE; } |
|
68 PLCFUNC(PL_Base64Encode); |
|
69 PLCFUNC(PL_Base64Decode); |
|
70 PLCFUNC(PL_strfree); |
|
71 #undef PLCFUNC |
|
72 |
|
73 return SUCCESS; |
|
74 } |
|
75 |
|
76 /* Throws the current NSS error. */ |
|
77 static void |
|
78 throwError(JNIEnv* jenv, const char * funcString) { |
|
79 char *msg; |
|
80 |
|
81 PRErrorCode perr = f_PR_GetError(); |
|
82 char * errString = f_PR_ErrorToString(perr, 0); |
|
83 asprintf(&msg, "%s returned error %d: %s\n", funcString, perr, errString); |
|
84 LOG("Throwing error: %s\n", msg); |
|
85 |
|
86 JNI_Throw(jenv, "java/lang/Exception", msg); |
|
87 free(msg); |
|
88 LOG("Error thrown\n"); |
|
89 } |
|
90 |
|
91 extern "C" NS_EXPORT jstring JNICALL |
|
92 Java_org_mozilla_gecko_NSSBridge_nativeEncrypt(JNIEnv* jenv, jclass, |
|
93 jstring jPath, |
|
94 jstring jValue) |
|
95 { |
|
96 jstring ret = jenv->NewStringUTF(""); |
|
97 |
|
98 const char* path; |
|
99 path = jenv->GetStringUTFChars(jPath, nullptr); |
|
100 |
|
101 const char* value; |
|
102 value = jenv->GetStringUTFChars(jValue, nullptr); |
|
103 |
|
104 char* result; |
|
105 SECStatus rv = doCrypto(jenv, path, value, &result, true); |
|
106 if (rv == SECSuccess) { |
|
107 ret = jenv->NewStringUTF(result); |
|
108 free(result); |
|
109 } |
|
110 |
|
111 jenv->ReleaseStringUTFChars(jValue, value); |
|
112 jenv->ReleaseStringUTFChars(jPath, path); |
|
113 |
|
114 return ret; |
|
115 } |
|
116 |
|
117 extern "C" NS_EXPORT jstring JNICALL |
|
118 Java_org_mozilla_gecko_NSSBridge_nativeDecrypt(JNIEnv* jenv, jclass, |
|
119 jstring jPath, |
|
120 jstring jValue) |
|
121 { |
|
122 jstring ret = jenv->NewStringUTF(""); |
|
123 |
|
124 const char* path; |
|
125 path = jenv->GetStringUTFChars(jPath, nullptr); |
|
126 |
|
127 const char* value; |
|
128 value = jenv->GetStringUTFChars(jValue, nullptr); |
|
129 |
|
130 char* result; |
|
131 SECStatus rv = doCrypto(jenv, path, value, &result, false); |
|
132 if (rv == SECSuccess) { |
|
133 ret = jenv->NewStringUTF(result); |
|
134 free(result); |
|
135 } |
|
136 |
|
137 jenv->ReleaseStringUTFChars(jValue, value); |
|
138 jenv->ReleaseStringUTFChars(jPath, path); |
|
139 |
|
140 return ret; |
|
141 } |
|
142 |
|
143 |
|
144 /* Encrypts or decrypts a string. result should be freed with free() when done */ |
|
145 SECStatus |
|
146 doCrypto(JNIEnv* jenv, const char *path, const char *value, char** result, bool encrypt) |
|
147 { |
|
148 SECStatus rv; |
|
149 PK11SlotInfo *slot; |
|
150 if (!initialized) { |
|
151 LOG("Initialize crypto in %s\n", path); |
|
152 rv = f_NSS_Initialize(path, "", "", "secmod.db", NSS_INIT_NOROOTINIT); |
|
153 if (rv != SECSuccess) { |
|
154 throwError(jenv, "NSS_Initialize"); |
|
155 return rv; |
|
156 } |
|
157 initialized = true; |
|
158 } |
|
159 |
|
160 slot = f_PK11_GetInternalKeySlot(); |
|
161 if (!slot) { |
|
162 throwError(jenv, "PK11_GetInternalKeySlot"); |
|
163 return SECFailure; |
|
164 } |
|
165 |
|
166 if (f_PK11_NeedUserInit(slot)) { |
|
167 LOG("Initializing key3.db with default blank password.\n"); |
|
168 rv = f_PK11_InitPin(slot, nullptr, nullptr); |
|
169 if (rv != SECSuccess) { |
|
170 throwError(jenv, "PK11_InitPin"); |
|
171 return rv; |
|
172 } |
|
173 } |
|
174 |
|
175 SECItem request; |
|
176 SECItem reply; |
|
177 |
|
178 reply.data = 0; |
|
179 reply.len = 0; |
|
180 |
|
181 if (encrypt) { |
|
182 // This can print sensitive data. Uncomment if you need it. |
|
183 // LOG("Encrypting: %s\n", value); |
|
184 request.data = (unsigned char*)value; |
|
185 request.len = strlen(value); |
|
186 |
|
187 SECItem keyid; |
|
188 keyid.data = 0; |
|
189 keyid.len = 0; |
|
190 rv = f_PK11SDR_Encrypt(&keyid, &request, &reply, nullptr); |
|
191 |
|
192 if (rv != SECSuccess) { |
|
193 throwError(jenv, "PK11SDR_Encrypt"); |
|
194 goto done; |
|
195 } |
|
196 |
|
197 rv = encode(reply.data, reply.len, result); |
|
198 if (rv != SECSuccess) { |
|
199 throwError(jenv, "encode"); |
|
200 goto done; |
|
201 } |
|
202 LOG("Encrypted: %s\n", *result); |
|
203 } else { |
|
204 LOG("Decoding: %s\n", value); |
|
205 rv = decode(value, &request.data, (int32_t*)&request.len); |
|
206 if (rv != SECSuccess) { |
|
207 throwError(jenv, "decode"); |
|
208 return rv; |
|
209 } |
|
210 |
|
211 rv = f_PK11SDR_Decrypt(&request, &reply, nullptr); |
|
212 if (rv != SECSuccess) { |
|
213 throwError(jenv, "PK11SDR_Decrypt"); |
|
214 goto done; |
|
215 } |
|
216 |
|
217 *result = (char *)malloc(reply.len+1); |
|
218 strncpy(*result, (char *)reply.data, reply.len); |
|
219 (*result)[reply.len] = '\0'; |
|
220 |
|
221 // This can print sensitive data. Uncomment if you need it. |
|
222 // LOG("Decoded %i letters: %s\n", reply.len, *result); |
|
223 free(request.data); |
|
224 } |
|
225 |
|
226 done: |
|
227 f_SECITEM_ZfreeItem(&reply, false); |
|
228 return rv; |
|
229 } |
|
230 |
|
231 /* |
|
232 * Base64 encodes the data passed in. The caller must deallocate _retval using free(); |
|
233 */ |
|
234 SECStatus |
|
235 encode(const unsigned char *data, int32_t dataLen, char **_retval) |
|
236 { |
|
237 SECStatus rv = SECSuccess; |
|
238 char *encoded = f_PL_Base64Encode((const char *)data, dataLen, nullptr); |
|
239 if (!encoded) |
|
240 rv = SECFailure; |
|
241 if (!*encoded) |
|
242 rv = SECFailure; |
|
243 |
|
244 if (rv == SECSuccess) { |
|
245 *_retval = (char *)malloc(strlen(encoded)+1); |
|
246 strcpy(*_retval, encoded); |
|
247 } |
|
248 |
|
249 if (encoded) { |
|
250 f_PR_Free(encoded); |
|
251 } |
|
252 |
|
253 return rv; |
|
254 } |
|
255 |
|
256 /* |
|
257 * Base64 decodes the data passed in. The caller must deallocate result using free(); |
|
258 */ |
|
259 SECStatus |
|
260 decode(const char *data, unsigned char **result, int32_t *length) |
|
261 { |
|
262 SECStatus rv = SECSuccess; |
|
263 uint32_t len = strlen(data); |
|
264 int adjust = 0; |
|
265 |
|
266 /* Compute length adjustment */ |
|
267 if (len > 0 && data[len-1] == '=') { |
|
268 adjust++; |
|
269 if (data[len-2] == '=') adjust++; |
|
270 } |
|
271 |
|
272 char *decoded; |
|
273 decoded = f_PL_Base64Decode(data, len, nullptr); |
|
274 if (!decoded) { |
|
275 return SECFailure; |
|
276 } |
|
277 if (!*decoded) { |
|
278 return SECFailure; |
|
279 } |
|
280 |
|
281 *length = (len*3)/4 - adjust; |
|
282 LOG("Decoded %i chars into %i chars\n", len, *length); |
|
283 |
|
284 *result = (unsigned char*)malloc((size_t)len); |
|
285 |
|
286 if (!*result) { |
|
287 rv = SECFailure; |
|
288 } else { |
|
289 memcpy((char*)*result, decoded, len); |
|
290 } |
|
291 f_PR_Free(decoded); |
|
292 return rv; |
|
293 } |
|
294 |
|
295 |