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.

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

mercurial