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 SECStatus doCrypto(JNIEnv* jenv, const char* path, const char* value,
41 char** result, bool doEncrypt);
42 SECStatus encode(const uint8_t* data, uint32_t srclen, char** result);
43 SECStatus decode(const char* data, uint8_t** result, uint32_t* length);
44
setup_nss_functions(void * nss_handle,void * nspr_handle,void * plc_handle)45 int setup_nss_functions(void* nss_handle, void* nspr_handle, void* plc_handle) {
46 if (nss_handle == nullptr || nspr_handle == nullptr ||
47 plc_handle == nullptr) {
48 LOG("Missing handle\n");
49 return FAILURE;
50 }
51 #define GETFUNC(name) \
52 f_##name = (name##_t)(uintptr_t)__wrap_dlsym(nss_handle, #name); \
53 if (!f_##name) { \
54 __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "missing %s", #name); \
55 return FAILURE; \
56 }
57 GETFUNC(NSS_Initialize);
58 GETFUNC(NSS_Shutdown);
59 GETFUNC(PK11SDR_Encrypt);
60 GETFUNC(PK11SDR_Decrypt);
61 GETFUNC(PK11_GetInternalKeySlot);
62 GETFUNC(PK11_NeedUserInit);
63 GETFUNC(PK11_InitPin);
64 GETFUNC(SECITEM_ZfreeItem);
65 #undef GETFUNC
66 #define NSPRFUNC(name) \
67 f_##name = (name##_t)(uintptr_t)__wrap_dlsym(nspr_handle, #name); \
68 if (!f_##name) { \
69 __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "missing %s", #name); \
70 return FAILURE; \
71 }
72 NSPRFUNC(PR_ErrorToString);
73 NSPRFUNC(PR_GetError);
74 NSPRFUNC(PR_Free);
75 #undef NSPRFUNC
76 #define PLCFUNC(name) \
77 f_##name = (name##_t)(uintptr_t)__wrap_dlsym(plc_handle, #name); \
78 if (!f_##name) { \
79 __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "missing %s", #name); \
80 return FAILURE; \
81 }
82 PLCFUNC(PL_Base64Encode);
83 PLCFUNC(PL_Base64Decode);
84 PLCFUNC(PL_strfree);
85 #undef PLCFUNC
86
87 return SUCCESS;
88 }
89
90 /* Throws the current NSS error. */
throwError(JNIEnv * jenv,const char * funcString)91 static void throwError(JNIEnv* jenv, const char* funcString) {
92 char* msg;
93
94 PRErrorCode perr = f_PR_GetError();
95 char* errString = f_PR_ErrorToString(perr, 0);
96 asprintf(&msg, "%s returned error %d: %s\n", funcString, perr, errString);
97 LOG("Throwing error: %s\n", msg);
98
99 JNI_Throw(jenv, "java/lang/Exception", msg);
100 free(msg);
101 LOG("Error thrown\n");
102 }
103
104 extern "C" APKOPEN_EXPORT jstring MOZ_JNICALL
Java_org_mozilla_gecko_NSSBridge_nativeEncrypt(JNIEnv * jenv,jclass,jstring jPath,jstring jValue)105 Java_org_mozilla_gecko_NSSBridge_nativeEncrypt(JNIEnv* jenv, jclass,
106 jstring jPath, jstring jValue) {
107 jstring ret = jenv->NewStringUTF("");
108
109 const char* path;
110 path = jenv->GetStringUTFChars(jPath, nullptr);
111
112 const char* value;
113 value = jenv->GetStringUTFChars(jValue, nullptr);
114
115 char* result;
116 SECStatus rv = doCrypto(jenv, path, value, &result, true);
117 if (rv == SECSuccess) {
118 ret = jenv->NewStringUTF(result);
119 free(result);
120 }
121
122 jenv->ReleaseStringUTFChars(jValue, value);
123 jenv->ReleaseStringUTFChars(jPath, path);
124
125 return ret;
126 }
127
128 extern "C" APKOPEN_EXPORT jstring MOZ_JNICALL
Java_org_mozilla_gecko_NSSBridge_nativeDecrypt(JNIEnv * jenv,jclass,jstring jPath,jstring jValue)129 Java_org_mozilla_gecko_NSSBridge_nativeDecrypt(JNIEnv* jenv, jclass,
130 jstring jPath, jstring jValue) {
131 jstring ret = jenv->NewStringUTF("");
132
133 const char* path;
134 path = jenv->GetStringUTFChars(jPath, nullptr);
135
136 const char* value;
137 value = jenv->GetStringUTFChars(jValue, nullptr);
138
139 char* result;
140 SECStatus rv = doCrypto(jenv, path, value, &result, false);
141 if (rv == SECSuccess) {
142 ret = jenv->NewStringUTF(result);
143 free(result);
144 }
145
146 jenv->ReleaseStringUTFChars(jValue, value);
147 jenv->ReleaseStringUTFChars(jPath, path);
148
149 return ret;
150 }
151
152 /* Encrypts or decrypts a string. result should be freed with free() when done
153 */
doCrypto(JNIEnv * jenv,const char * path,const char * value,char ** result,bool encrypt)154 SECStatus doCrypto(JNIEnv* jenv, const char* path, const char* value,
155 char** result, bool encrypt) {
156 SECStatus rv;
157 PK11SlotInfo* slot;
158 if (!initialized) {
159 LOG("Initialize crypto in %s\n", path);
160 rv = f_NSS_Initialize(path, "", "", "secmod.db", NSS_INIT_NOROOTINIT);
161 if (rv != SECSuccess) {
162 throwError(jenv, "NSS_Initialize");
163 return rv;
164 }
165 initialized = true;
166 }
167
168 slot = f_PK11_GetInternalKeySlot();
169 if (!slot) {
170 throwError(jenv, "PK11_GetInternalKeySlot");
171 return SECFailure;
172 }
173
174 if (f_PK11_NeedUserInit(slot)) {
175 LOG("Initializing key3.db with default blank password.\n");
176 rv = f_PK11_InitPin(slot, nullptr, nullptr);
177 if (rv != SECSuccess) {
178 throwError(jenv, "PK11_InitPin");
179 return rv;
180 }
181 }
182
183 SECItem request;
184 SECItem reply;
185
186 reply.data = 0;
187 reply.len = 0;
188
189 if (encrypt) {
190 // This can print sensitive data. Uncomment if you need it.
191 // LOG("Encrypting: %s\n", value);
192 request.data = (unsigned char*)value;
193 request.len = strlen(value);
194
195 SECItem keyid;
196 keyid.data = 0;
197 keyid.len = 0;
198 rv = f_PK11SDR_Encrypt(&keyid, &request, &reply, nullptr);
199
200 if (rv == SECSuccess) {
201 rv = encode(reply.data, reply.len, result);
202 if (rv == SECSuccess) {
203 LOG("Encrypted: %s\n", *result);
204 } else {
205 throwError(jenv, "encode");
206 }
207 } else {
208 throwError(jenv, "PK11SDR_Encrypt");
209 }
210
211 } else {
212 LOG("Decoding: %s\n", value);
213 rv = decode(value, &request.data, &request.len);
214 if (rv != SECSuccess) {
215 throwError(jenv, "decode");
216 return rv;
217 }
218
219 rv = f_PK11SDR_Decrypt(&request, &reply, nullptr);
220
221 if (rv == SECSuccess) {
222 *result = static_cast<char*>(malloc(reply.len + 1));
223 strncpy(*result, reinterpret_cast<char*>(reply.data), reply.len);
224 (*result)[reply.len] = '\0';
225
226 // This can print sensitive data. Uncomment if you need it.
227 // LOG("Decoded %i letters: %s\n", reply.len, *result);
228 } else {
229 throwError(jenv, "PK11SDR_Decrypt");
230 }
231 free(request.data);
232 }
233
234 f_SECITEM_ZfreeItem(&reply, false);
235 return rv;
236 }
237
238 /*
239 * Base64 encodes the data passed in. The caller must deallocate _retval using
240 * free();
241 */
encode(const uint8_t * data,uint32_t srclen,char ** result)242 SECStatus encode(const uint8_t* data, uint32_t srclen, char** result) {
243 if (srclen > (PR_UINT32_MAX / 4) * 3) {
244 return SECFailure;
245 }
246
247 const uint32_t dstlen = ((srclen + 2) / 3) * 4;
248 char* const buffer = static_cast<char*>(malloc(dstlen + 1));
249
250 if (!buffer ||
251 !f_PL_Base64Encode(reinterpret_cast<const char*>(data), srclen, buffer)) {
252 free(buffer);
253 *result = nullptr;
254 return SECFailure;
255 }
256
257 buffer[dstlen] = '\0';
258 *result = buffer;
259 return SECSuccess;
260 }
261
262 /*
263 * Base64 decodes the data passed in. The caller must deallocate result using
264 * free();
265 */
decode(const char * data,uint8_t ** result,uint32_t * length)266 SECStatus decode(const char* data, uint8_t** result, uint32_t* length) {
267 uint32_t srclen = strlen(data);
268 while (srclen && data[srclen - 1] == '=') {
269 srclen--;
270 }
271
272 // Avoid overflow when calculating result length.
273 const uint32_t dstlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4;
274 // At most 2 extra bytes due to padding in input.
275 uint8_t* const buffer = static_cast<uint8_t*>(malloc(dstlen + 2));
276
277 if (!buffer ||
278 !f_PL_Base64Decode(data, srclen, reinterpret_cast<char*>(buffer))) {
279 free(buffer);
280 *result = nullptr;
281 *length = 0;
282 return SECFailure;
283 }
284
285 buffer[dstlen] = '\0';
286 *result = buffer;
287 *length = dstlen;
288 return SECSuccess;
289 }
290