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.

     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)
    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
    73   return SUCCESS;
    74 }
    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");
    89 }
    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("");
    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);
   109     }
   111     jenv->ReleaseStringUTFChars(jValue, value);
   112     jenv->ReleaseStringUTFChars(jPath, path);
   114     return ret;
   115 }
   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("");
   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);
   135     }
   137     jenv->ReleaseStringUTFChars(jValue, value);
   138     jenv->ReleaseStringUTFChars(jPath, path);
   140     return ret;
   141 }
   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     }
   160     slot = f_PK11_GetInternalKeySlot();
   161     if (!slot) {
   162       throwError(jenv, "PK11_GetInternalKeySlot");
   163       return SECFailure;
   164     }
   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     }
   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;
   195       }
   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       }
   211       rv = f_PK11SDR_Decrypt(&request, &reply, nullptr);
   212       if (rv != SECSuccess) {
   213         throwError(jenv, "PK11SDR_Decrypt");
   214         goto done;
   215       }
   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);
   224     }
   226 done:
   227     f_SECITEM_ZfreeItem(&reply, false);
   228     return rv;
   229 }
   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;
   244   if (rv == SECSuccess) {
   245     *_retval = (char *)malloc(strlen(encoded)+1);
   246     strcpy(*_retval, encoded);
   247   }
   249   if (encoded) {
   250     f_PR_Free(encoded);
   251   }
   253   return rv;
   254 }
   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;
   266   /* Compute length adjustment */
   267   if (len > 0 && data[len-1] == '=') {
   268     adjust++;
   269     if (data[len-2] == '=') adjust++;
   270   }
   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   }
   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);
   290   }
   291   f_PR_Free(decoded);
   292   return rv;
   293 }

mercurial