ipc/keystore/KeyStore.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim: set sw=4 ts=8 et ft=cpp: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include <fcntl.h>
     8 #include <sys/stat.h>
    10 #undef CHROMIUM_LOG
    11 #if defined(MOZ_WIDGET_GONK)
    12 #include <android/log.h>
    13 #define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
    14 #else
    15 #define CHROMIUM_LOG(args...)  printf(args);
    16 #endif
    18 #include "KeyStore.h"
    19 #include "jsfriendapi.h"
    20 #include "MainThreadUtils.h" // For NS_IsMainThread.
    22 #include "plbase64.h"
    23 #include "certdb.h"
    24 #include "ScopedNSSTypes.h"
    26 using namespace mozilla::ipc;
    28 namespace mozilla {
    29 namespace ipc {
    31 static const char* KEYSTORE_SOCKET_NAME = "keystore";
    32 static const char* KEYSTORE_SOCKET_PATH = "/dev/socket/keystore";
    34 int
    35 KeyStoreConnector::Create()
    36 {
    37   MOZ_ASSERT(!NS_IsMainThread());
    39   int fd;
    41   unlink(KEYSTORE_SOCKET_PATH);
    43   fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    45   if (fd < 0) {
    46     NS_WARNING("Could not open keystore socket!");
    47     return -1;
    48   }
    50   return fd;
    51 }
    53 bool
    54 KeyStoreConnector::CreateAddr(bool aIsServer,
    55                               socklen_t& aAddrSize,
    56                               sockaddr_any& aAddr,
    57                               const char* aAddress)
    58 {
    59   // Keystore socket must be server
    60   MOZ_ASSERT(aIsServer);
    62   aAddr.un.sun_family = AF_LOCAL;
    63   if(strlen(KEYSTORE_SOCKET_PATH) > sizeof(aAddr.un.sun_path)) {
    64       NS_WARNING("Address too long for socket struct!");
    65       return false;
    66   }
    67   strcpy((char*)&aAddr.un.sun_path, KEYSTORE_SOCKET_PATH);
    68   aAddrSize = strlen(KEYSTORE_SOCKET_PATH) + offsetof(struct sockaddr_un, sun_path) + 1;
    70   return true;
    71 }
    73 bool
    74 KeyStoreConnector::SetUp(int aFd)
    75 {
    76   return true;
    77 }
    79 bool
    80 KeyStoreConnector::SetUpListenSocket(int aFd)
    81 {
    82   // Allow access of wpa_supplicant(different user, differnt group)
    83   chmod(KEYSTORE_SOCKET_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
    85   return true;
    86 }
    88 void
    89 KeyStoreConnector::GetSocketAddr(const sockaddr_any& aAddr,
    90                                  nsAString& aAddrStr)
    91 {
    92   // Unused.
    93   MOZ_CRASH("This should never be called!");
    94 }
    96 static char *
    97 get_cert_db_filename(void *arg, int vers)
    98 {
    99   static char keystoreDbPath[] = "/data/misc/wifi/keystore";
   100   return keystoreDbPath;
   101 }
   103 KeyStore::KeyStore()
   104 {
   105   // Initial NSS
   106   certdb = CERT_GetDefaultCertDB();
   108   Listen();
   109 }
   111 void
   112 KeyStore::Shutdown()
   113 {
   114   mShutdown = true;
   115   CloseSocket();
   116 }
   118 void
   119 KeyStore::Listen()
   120 {
   121   ListenSocket(new KeyStoreConnector());
   123   ResetHandlerInfo();
   124 }
   126 void
   127 KeyStore::ResetHandlerInfo()
   128 {
   129   mHandlerInfo.state = STATE_IDLE;
   130   mHandlerInfo.command = 0;
   131   mHandlerInfo.paramCount = 0;
   132   mHandlerInfo.commandPattern = nullptr;
   133   for (int i = 0; i < MAX_PARAM; i++) {
   134     mHandlerInfo.param[i].length = 0;
   135     memset(mHandlerInfo.param[i].data, 0, VALUE_SIZE);
   136   }
   137 }
   139 bool
   140 KeyStore::CheckSize(UnixSocketRawData *aMessage, size_t aExpectSize)
   141 {
   142   return (aMessage->mSize - aMessage->mCurrentWriteOffset >= aExpectSize) ?
   143          true : false;
   144 }
   146 bool
   147 KeyStore::ReadCommand(UnixSocketRawData *aMessage)
   148 {
   149   if (mHandlerInfo.state != STATE_IDLE) {
   150     NS_WARNING("Wrong state in ReadCommand()!");
   151     return false;
   152   }
   154   if (!CheckSize(aMessage, 1)) {
   155     NS_WARNING("Data size error in ReadCommand()!");
   156     return false;
   157   }
   159   mHandlerInfo.command = aMessage->mData[aMessage->mCurrentWriteOffset];
   160   aMessage->mCurrentWriteOffset++;
   162   // Find corrsponding command pattern
   163   const struct ProtocolCommand *command = commands;
   164   while (command->command && command->command != mHandlerInfo.command) {
   165     command++;
   166   }
   168   if (!command->command) {
   169     NS_WARNING("Unsupported command!");
   170     return false;
   171   }
   173   // Get command pattern.
   174   mHandlerInfo.commandPattern = command;
   175   if (command->paramNum) {
   176     // Read command parameter if needed.
   177     mHandlerInfo.state = STATE_READ_PARAM_LEN;
   178   } else {
   179     mHandlerInfo.state = STATE_PROCESSING;
   180   }
   182   return true;
   183 }
   185 bool
   186 KeyStore::ReadLength(UnixSocketRawData *aMessage)
   187 {
   188   if (mHandlerInfo.state != STATE_READ_PARAM_LEN) {
   189     NS_WARNING("Wrong state in ReadLength()!");
   190     return false;
   191   }
   193   if (!CheckSize(aMessage, 2)) {
   194     NS_WARNING("Data size error in ReadLength()!");
   195     return false;
   196   }
   198   // Read length of command parameter.
   199   unsigned short dataLength;
   200   memcpy(&dataLength, &aMessage->mData[aMessage->mCurrentWriteOffset], 2);
   201   aMessage->mCurrentWriteOffset += 2;
   202   mHandlerInfo.param[mHandlerInfo.paramCount].length = ntohs(dataLength);
   204   mHandlerInfo.state = STATE_READ_PARAM_DATA;
   206   return true;
   207 }
   209 bool
   210 KeyStore::ReadData(UnixSocketRawData *aMessage)
   211 {
   212   if (mHandlerInfo.state != STATE_READ_PARAM_DATA) {
   213     NS_WARNING("Wrong state in ReadData()!");
   214     return false;
   215   }
   217   if (!CheckSize(aMessage, mHandlerInfo.param[mHandlerInfo.paramCount].length)) {
   218     NS_WARNING("Data size error in ReadData()!");
   219     return false;
   220   }
   222   // Read command parameter.
   223   memcpy(mHandlerInfo.param[mHandlerInfo.paramCount].data,
   224          &aMessage->mData[aMessage->mCurrentWriteOffset],
   225          mHandlerInfo.param[mHandlerInfo.paramCount].length);
   226   aMessage->mCurrentWriteOffset += mHandlerInfo.param[mHandlerInfo.paramCount].length;
   227   mHandlerInfo.paramCount++;
   229   if (mHandlerInfo.paramCount == mHandlerInfo.commandPattern->paramNum) {
   230     mHandlerInfo.state = STATE_PROCESSING;
   231   } else {
   232     mHandlerInfo.state = STATE_READ_PARAM_LEN;
   233   }
   235   return true;
   236 }
   238 // Transform base64 certification data into DER format
   239 void
   240 KeyStore::FormatCaData(const uint8_t *aCaData, int aCaDataLength,
   241                        const char *aName, const uint8_t **aFormatData,
   242                        int &aFormatDataLength)
   243 {
   244   int bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 +
   245                 strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE + 2;
   246   char *buf = (char *)malloc(bufSize);
   248   aFormatDataLength = bufSize;
   249   *aFormatData = (const uint8_t *)buf;
   251   char *ptr = buf;
   252   int len;
   254   // Create DER header.
   255   len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER);
   256   ptr += len;
   257   bufSize -= len;
   259   // Split base64 data in lines.
   260   int copySize;
   261   while (aCaDataLength > 0) {
   262     copySize = (aCaDataLength > CA_LINE_SIZE) ? CA_LINE_SIZE : aCaDataLength;
   264     memcpy(ptr, aCaData, copySize);
   265     ptr += copySize;
   266     aCaData += copySize;
   267     aCaDataLength -= copySize;
   268     bufSize -= copySize;
   270     *ptr = '\n';
   271     ptr++;
   272     bufSize--;
   273   }
   275   // Create DEA tailer.
   276   snprintf(ptr, bufSize, "%s%s%s", CA_END, aName, CA_TAILER);
   277 }
   279 // Status response
   280 void
   281 KeyStore::SendResponse(ResponseCode aResponse)
   282 {
   283   if (aResponse == NO_RESPONSE)
   284     return;
   286   uint8_t response = (uint8_t)aResponse;
   287   UnixSocketRawData* data = new UnixSocketRawData((const void *)&response, 1);
   288   SendSocketData(data);
   289 }
   291 // Data response
   292 void
   293 KeyStore::SendData(const uint8_t *aData, int aLength)
   294 {
   295   unsigned short dataLength = htons(aLength);
   297   UnixSocketRawData* length = new UnixSocketRawData((const void *)&dataLength, 2);
   298   SendSocketData(length);
   300   UnixSocketRawData* data = new UnixSocketRawData((const void *)aData, aLength);
   301   SendSocketData(data);
   302 }
   304 void
   305 KeyStore::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
   306 {
   307   MOZ_ASSERT(NS_IsMainThread());
   309   bool success = true;
   310   while (aMessage->mCurrentWriteOffset < aMessage->mSize ||
   311          mHandlerInfo.state == STATE_PROCESSING) {
   312     switch (mHandlerInfo.state) {
   313       case STATE_IDLE:
   314         success = ReadCommand(aMessage);
   315         break;
   316       case STATE_READ_PARAM_LEN:
   317         success = ReadLength(aMessage);
   318         break;
   319       case STATE_READ_PARAM_DATA:
   320         success = ReadData(aMessage);
   321         break;
   322       case STATE_PROCESSING:
   323         success = false;
   324         if (mHandlerInfo.command == 'g') {
   325           // Get CA
   326           const uint8_t *certData;
   327           int certDataLength;
   328           const char *certName = (const char *)mHandlerInfo.param[0].data;
   330           // Get cert from NSS by name
   331           ScopedCERTCertificate cert(CERT_FindCertByNickname(certdb, certName));
   332           if (!cert) {
   333             break;
   334           }
   336           char *certDER = PL_Base64Encode((const char *)cert->derCert.data,
   337                                           cert->derCert.len, nullptr);
   338           if (!certDER) {
   339             break;
   340           }
   342           FormatCaData((const uint8_t *)certDER, strlen(certDER), "CERTIFICATE",
   343                        &certData, certDataLength);
   344           PL_strfree(certDER);
   346           SendResponse(SUCCESS);
   347           SendData(certData, certDataLength);
   348           success = true;
   350           free((void *)certData);
   351         }
   353         ResetHandlerInfo();
   354         break;
   355     }
   357     if (!success) {
   358       SendResponse(PROTOCOL_ERROR);
   359       ResetHandlerInfo();
   360       return;
   361     }
   362   }
   363 }
   365 void
   366 KeyStore::OnConnectSuccess()
   367 {
   368   mShutdown = false;
   369 }
   371 void
   372 KeyStore::OnConnectError()
   373 {
   374   if (!mShutdown) {
   375     Listen();
   376   }
   377 }
   379 void
   380 KeyStore::OnDisconnect()
   381 {
   382   if (!mShutdown) {
   383     Listen();
   384   }
   385 }
   387 } // namespace ipc
   388 } // namespace mozilla

mercurial