mozglue/android/NSSBridge.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial