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