Bumping gaia.json for 1 gaia revision(s) a=gaia-bump
[gecko.git] / mozglue / android / NSSBridge.cpp
blob5a19e6cf9dedbb5e6ef4c14668573256ecec3cb6
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/. */
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
14 #include "ElfLoader.h"
16 #ifdef DEBUG
17 #define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x)
18 #else
19 #define LOG(x...)
20 #endif
22 static bool initialized = false;
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)
40 int
41 setup_nss_functions(void *nss_handle,
42 void *nspr_handle,
43 void *plc_handle)
45 if (nss_handle == nullptr || nspr_handle == nullptr || plc_handle == nullptr) {
46 LOG("Missing handle\n");
47 return FAILURE;
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
73 return SUCCESS;
76 /* Throws the current NSS error. */
77 static void
78 throwError(JNIEnv* jenv, const char * funcString) {
79 char *msg;
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);
86 JNI_Throw(jenv, "java/lang/Exception", msg);
87 free(msg);
88 LOG("Error thrown\n");
91 extern "C" NS_EXPORT jstring JNICALL
92 Java_org_mozilla_gecko_NSSBridge_nativeEncrypt(JNIEnv* jenv, jclass,
93 jstring jPath,
94 jstring jValue)
96 jstring ret = jenv->NewStringUTF("");
98 const char* path;
99 path = jenv->GetStringUTFChars(jPath, nullptr);
101 const char* value;
102 value = jenv->GetStringUTFChars(jValue, nullptr);
104 char* result;
105 SECStatus rv = doCrypto(jenv, path, value, &result, true);
106 if (rv == SECSuccess) {
107 ret = jenv->NewStringUTF(result);
108 free(result);
111 jenv->ReleaseStringUTFChars(jValue, value);
112 jenv->ReleaseStringUTFChars(jPath, path);
114 return ret;
117 extern "C" NS_EXPORT jstring JNICALL
118 Java_org_mozilla_gecko_NSSBridge_nativeDecrypt(JNIEnv* jenv, jclass,
119 jstring jPath,
120 jstring jValue)
122 jstring ret = jenv->NewStringUTF("");
124 const char* path;
125 path = jenv->GetStringUTFChars(jPath, nullptr);
127 const char* value;
128 value = jenv->GetStringUTFChars(jValue, nullptr);
130 char* result;
131 SECStatus rv = doCrypto(jenv, path, value, &result, false);
132 if (rv == SECSuccess) {
133 ret = jenv->NewStringUTF(result);
134 free(result);
137 jenv->ReleaseStringUTFChars(jValue, value);
138 jenv->ReleaseStringUTFChars(jPath, path);
140 return ret;
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)
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;
157 initialized = true;
160 slot = f_PK11_GetInternalKeySlot();
161 if (!slot) {
162 throwError(jenv, "PK11_GetInternalKeySlot");
163 return SECFailure;
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;
175 SECItem request;
176 SECItem reply;
178 reply.data = 0;
179 reply.len = 0;
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);
187 SECItem keyid;
188 keyid.data = 0;
189 keyid.len = 0;
190 rv = f_PK11SDR_Encrypt(&keyid, &request, &reply, nullptr);
192 if (rv != SECSuccess) {
193 throwError(jenv, "PK11SDR_Encrypt");
194 goto done;
197 rv = encode(reply.data, reply.len, result);
198 if (rv != SECSuccess) {
199 throwError(jenv, "encode");
200 goto done;
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;
211 rv = f_PK11SDR_Decrypt(&request, &reply, nullptr);
212 if (rv != SECSuccess) {
213 throwError(jenv, "PK11SDR_Decrypt");
214 goto done;
217 *result = (char *)malloc(reply.len+1);
218 strncpy(*result, (char *)reply.data, reply.len);
219 (*result)[reply.len] = '\0';
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);
226 done:
227 f_SECITEM_ZfreeItem(&reply, false);
228 return rv;
232 * Base64 encodes the data passed in. The caller must deallocate _retval using free();
234 SECStatus
235 encode(const unsigned char *data, int32_t dataLen, char **_retval)
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;
244 if (rv == SECSuccess) {
245 *_retval = (char *)malloc(strlen(encoded)+1);
246 strcpy(*_retval, encoded);
249 if (encoded) {
250 f_PR_Free(encoded);
253 return rv;
257 * Base64 decodes the data passed in. The caller must deallocate result using free();
259 SECStatus
260 decode(const char *data, unsigned char **result, int32_t *length)
262 SECStatus rv = SECSuccess;
263 uint32_t len = strlen(data);
264 int adjust = 0;
266 /* Compute length adjustment */
267 if (len > 0 && data[len-1] == '=') {
268 adjust++;
269 if (data[len-2] == '=') adjust++;
272 char *decoded;
273 decoded = f_PL_Base64Decode(data, len, nullptr);
274 if (!decoded) {
275 return SECFailure;
277 if (!*decoded) {
278 return SECFailure;
281 *length = (len*3)/4 - adjust;
282 LOG("Decoded %i chars into %i chars\n", len, *length);
284 *result = (unsigned char*)malloc((size_t)len);
286 if (!*result) {
287 rv = SECFailure;
288 } else {
289 memcpy((char*)*result, decoded, len);
291 f_PR_Free(decoded);
292 return rv;