ipc/keystore/KeyStore.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/keystore/KeyStore.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,388 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim: set sw=4 ts=8 et ft=cpp: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include <fcntl.h>
    1.11 +#include <sys/stat.h>
    1.12 +
    1.13 +#undef CHROMIUM_LOG
    1.14 +#if defined(MOZ_WIDGET_GONK)
    1.15 +#include <android/log.h>
    1.16 +#define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
    1.17 +#else
    1.18 +#define CHROMIUM_LOG(args...)  printf(args);
    1.19 +#endif
    1.20 +
    1.21 +#include "KeyStore.h"
    1.22 +#include "jsfriendapi.h"
    1.23 +#include "MainThreadUtils.h" // For NS_IsMainThread.
    1.24 +
    1.25 +#include "plbase64.h"
    1.26 +#include "certdb.h"
    1.27 +#include "ScopedNSSTypes.h"
    1.28 +
    1.29 +using namespace mozilla::ipc;
    1.30 +
    1.31 +namespace mozilla {
    1.32 +namespace ipc {
    1.33 +
    1.34 +static const char* KEYSTORE_SOCKET_NAME = "keystore";
    1.35 +static const char* KEYSTORE_SOCKET_PATH = "/dev/socket/keystore";
    1.36 +
    1.37 +int
    1.38 +KeyStoreConnector::Create()
    1.39 +{
    1.40 +  MOZ_ASSERT(!NS_IsMainThread());
    1.41 +
    1.42 +  int fd;
    1.43 +
    1.44 +  unlink(KEYSTORE_SOCKET_PATH);
    1.45 +
    1.46 +  fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    1.47 +
    1.48 +  if (fd < 0) {
    1.49 +    NS_WARNING("Could not open keystore socket!");
    1.50 +    return -1;
    1.51 +  }
    1.52 +
    1.53 +  return fd;
    1.54 +}
    1.55 +
    1.56 +bool
    1.57 +KeyStoreConnector::CreateAddr(bool aIsServer,
    1.58 +                              socklen_t& aAddrSize,
    1.59 +                              sockaddr_any& aAddr,
    1.60 +                              const char* aAddress)
    1.61 +{
    1.62 +  // Keystore socket must be server
    1.63 +  MOZ_ASSERT(aIsServer);
    1.64 +
    1.65 +  aAddr.un.sun_family = AF_LOCAL;
    1.66 +  if(strlen(KEYSTORE_SOCKET_PATH) > sizeof(aAddr.un.sun_path)) {
    1.67 +      NS_WARNING("Address too long for socket struct!");
    1.68 +      return false;
    1.69 +  }
    1.70 +  strcpy((char*)&aAddr.un.sun_path, KEYSTORE_SOCKET_PATH);
    1.71 +  aAddrSize = strlen(KEYSTORE_SOCKET_PATH) + offsetof(struct sockaddr_un, sun_path) + 1;
    1.72 +
    1.73 +  return true;
    1.74 +}
    1.75 +
    1.76 +bool
    1.77 +KeyStoreConnector::SetUp(int aFd)
    1.78 +{
    1.79 +  return true;
    1.80 +}
    1.81 +
    1.82 +bool
    1.83 +KeyStoreConnector::SetUpListenSocket(int aFd)
    1.84 +{
    1.85 +  // Allow access of wpa_supplicant(different user, differnt group)
    1.86 +  chmod(KEYSTORE_SOCKET_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
    1.87 +
    1.88 +  return true;
    1.89 +}
    1.90 +
    1.91 +void
    1.92 +KeyStoreConnector::GetSocketAddr(const sockaddr_any& aAddr,
    1.93 +                                 nsAString& aAddrStr)
    1.94 +{
    1.95 +  // Unused.
    1.96 +  MOZ_CRASH("This should never be called!");
    1.97 +}
    1.98 +
    1.99 +static char *
   1.100 +get_cert_db_filename(void *arg, int vers)
   1.101 +{
   1.102 +  static char keystoreDbPath[] = "/data/misc/wifi/keystore";
   1.103 +  return keystoreDbPath;
   1.104 +}
   1.105 +
   1.106 +KeyStore::KeyStore()
   1.107 +{
   1.108 +  // Initial NSS
   1.109 +  certdb = CERT_GetDefaultCertDB();
   1.110 +
   1.111 +  Listen();
   1.112 +}
   1.113 +
   1.114 +void
   1.115 +KeyStore::Shutdown()
   1.116 +{
   1.117 +  mShutdown = true;
   1.118 +  CloseSocket();
   1.119 +}
   1.120 +
   1.121 +void
   1.122 +KeyStore::Listen()
   1.123 +{
   1.124 +  ListenSocket(new KeyStoreConnector());
   1.125 +
   1.126 +  ResetHandlerInfo();
   1.127 +}
   1.128 +
   1.129 +void
   1.130 +KeyStore::ResetHandlerInfo()
   1.131 +{
   1.132 +  mHandlerInfo.state = STATE_IDLE;
   1.133 +  mHandlerInfo.command = 0;
   1.134 +  mHandlerInfo.paramCount = 0;
   1.135 +  mHandlerInfo.commandPattern = nullptr;
   1.136 +  for (int i = 0; i < MAX_PARAM; i++) {
   1.137 +    mHandlerInfo.param[i].length = 0;
   1.138 +    memset(mHandlerInfo.param[i].data, 0, VALUE_SIZE);
   1.139 +  }
   1.140 +}
   1.141 +
   1.142 +bool
   1.143 +KeyStore::CheckSize(UnixSocketRawData *aMessage, size_t aExpectSize)
   1.144 +{
   1.145 +  return (aMessage->mSize - aMessage->mCurrentWriteOffset >= aExpectSize) ?
   1.146 +         true : false;
   1.147 +}
   1.148 +
   1.149 +bool
   1.150 +KeyStore::ReadCommand(UnixSocketRawData *aMessage)
   1.151 +{
   1.152 +  if (mHandlerInfo.state != STATE_IDLE) {
   1.153 +    NS_WARNING("Wrong state in ReadCommand()!");
   1.154 +    return false;
   1.155 +  }
   1.156 +
   1.157 +  if (!CheckSize(aMessage, 1)) {
   1.158 +    NS_WARNING("Data size error in ReadCommand()!");
   1.159 +    return false;
   1.160 +  }
   1.161 +
   1.162 +  mHandlerInfo.command = aMessage->mData[aMessage->mCurrentWriteOffset];
   1.163 +  aMessage->mCurrentWriteOffset++;
   1.164 +
   1.165 +  // Find corrsponding command pattern
   1.166 +  const struct ProtocolCommand *command = commands;
   1.167 +  while (command->command && command->command != mHandlerInfo.command) {
   1.168 +    command++;
   1.169 +  }
   1.170 +
   1.171 +  if (!command->command) {
   1.172 +    NS_WARNING("Unsupported command!");
   1.173 +    return false;
   1.174 +  }
   1.175 +
   1.176 +  // Get command pattern.
   1.177 +  mHandlerInfo.commandPattern = command;
   1.178 +  if (command->paramNum) {
   1.179 +    // Read command parameter if needed.
   1.180 +    mHandlerInfo.state = STATE_READ_PARAM_LEN;
   1.181 +  } else {
   1.182 +    mHandlerInfo.state = STATE_PROCESSING;
   1.183 +  }
   1.184 +
   1.185 +  return true;
   1.186 +}
   1.187 +
   1.188 +bool
   1.189 +KeyStore::ReadLength(UnixSocketRawData *aMessage)
   1.190 +{
   1.191 +  if (mHandlerInfo.state != STATE_READ_PARAM_LEN) {
   1.192 +    NS_WARNING("Wrong state in ReadLength()!");
   1.193 +    return false;
   1.194 +  }
   1.195 +
   1.196 +  if (!CheckSize(aMessage, 2)) {
   1.197 +    NS_WARNING("Data size error in ReadLength()!");
   1.198 +    return false;
   1.199 +  }
   1.200 +
   1.201 +  // Read length of command parameter.
   1.202 +  unsigned short dataLength;
   1.203 +  memcpy(&dataLength, &aMessage->mData[aMessage->mCurrentWriteOffset], 2);
   1.204 +  aMessage->mCurrentWriteOffset += 2;
   1.205 +  mHandlerInfo.param[mHandlerInfo.paramCount].length = ntohs(dataLength);
   1.206 +
   1.207 +  mHandlerInfo.state = STATE_READ_PARAM_DATA;
   1.208 +
   1.209 +  return true;
   1.210 +}
   1.211 +
   1.212 +bool
   1.213 +KeyStore::ReadData(UnixSocketRawData *aMessage)
   1.214 +{
   1.215 +  if (mHandlerInfo.state != STATE_READ_PARAM_DATA) {
   1.216 +    NS_WARNING("Wrong state in ReadData()!");
   1.217 +    return false;
   1.218 +  }
   1.219 +
   1.220 +  if (!CheckSize(aMessage, mHandlerInfo.param[mHandlerInfo.paramCount].length)) {
   1.221 +    NS_WARNING("Data size error in ReadData()!");
   1.222 +    return false;
   1.223 +  }
   1.224 +
   1.225 +  // Read command parameter.
   1.226 +  memcpy(mHandlerInfo.param[mHandlerInfo.paramCount].data,
   1.227 +         &aMessage->mData[aMessage->mCurrentWriteOffset],
   1.228 +         mHandlerInfo.param[mHandlerInfo.paramCount].length);
   1.229 +  aMessage->mCurrentWriteOffset += mHandlerInfo.param[mHandlerInfo.paramCount].length;
   1.230 +  mHandlerInfo.paramCount++;
   1.231 +
   1.232 +  if (mHandlerInfo.paramCount == mHandlerInfo.commandPattern->paramNum) {
   1.233 +    mHandlerInfo.state = STATE_PROCESSING;
   1.234 +  } else {
   1.235 +    mHandlerInfo.state = STATE_READ_PARAM_LEN;
   1.236 +  }
   1.237 +
   1.238 +  return true;
   1.239 +}
   1.240 +
   1.241 +// Transform base64 certification data into DER format
   1.242 +void
   1.243 +KeyStore::FormatCaData(const uint8_t *aCaData, int aCaDataLength,
   1.244 +                       const char *aName, const uint8_t **aFormatData,
   1.245 +                       int &aFormatDataLength)
   1.246 +{
   1.247 +  int bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 +
   1.248 +                strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE + 2;
   1.249 +  char *buf = (char *)malloc(bufSize);
   1.250 +
   1.251 +  aFormatDataLength = bufSize;
   1.252 +  *aFormatData = (const uint8_t *)buf;
   1.253 +
   1.254 +  char *ptr = buf;
   1.255 +  int len;
   1.256 +
   1.257 +  // Create DER header.
   1.258 +  len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER);
   1.259 +  ptr += len;
   1.260 +  bufSize -= len;
   1.261 +
   1.262 +  // Split base64 data in lines.
   1.263 +  int copySize;
   1.264 +  while (aCaDataLength > 0) {
   1.265 +    copySize = (aCaDataLength > CA_LINE_SIZE) ? CA_LINE_SIZE : aCaDataLength;
   1.266 +
   1.267 +    memcpy(ptr, aCaData, copySize);
   1.268 +    ptr += copySize;
   1.269 +    aCaData += copySize;
   1.270 +    aCaDataLength -= copySize;
   1.271 +    bufSize -= copySize;
   1.272 +
   1.273 +    *ptr = '\n';
   1.274 +    ptr++;
   1.275 +    bufSize--;
   1.276 +  }
   1.277 +
   1.278 +  // Create DEA tailer.
   1.279 +  snprintf(ptr, bufSize, "%s%s%s", CA_END, aName, CA_TAILER);
   1.280 +}
   1.281 +
   1.282 +// Status response
   1.283 +void
   1.284 +KeyStore::SendResponse(ResponseCode aResponse)
   1.285 +{
   1.286 +  if (aResponse == NO_RESPONSE)
   1.287 +    return;
   1.288 +
   1.289 +  uint8_t response = (uint8_t)aResponse;
   1.290 +  UnixSocketRawData* data = new UnixSocketRawData((const void *)&response, 1);
   1.291 +  SendSocketData(data);
   1.292 +}
   1.293 +
   1.294 +// Data response
   1.295 +void
   1.296 +KeyStore::SendData(const uint8_t *aData, int aLength)
   1.297 +{
   1.298 +  unsigned short dataLength = htons(aLength);
   1.299 +
   1.300 +  UnixSocketRawData* length = new UnixSocketRawData((const void *)&dataLength, 2);
   1.301 +  SendSocketData(length);
   1.302 +
   1.303 +  UnixSocketRawData* data = new UnixSocketRawData((const void *)aData, aLength);
   1.304 +  SendSocketData(data);
   1.305 +}
   1.306 +
   1.307 +void
   1.308 +KeyStore::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
   1.309 +{
   1.310 +  MOZ_ASSERT(NS_IsMainThread());
   1.311 +
   1.312 +  bool success = true;
   1.313 +  while (aMessage->mCurrentWriteOffset < aMessage->mSize ||
   1.314 +         mHandlerInfo.state == STATE_PROCESSING) {
   1.315 +    switch (mHandlerInfo.state) {
   1.316 +      case STATE_IDLE:
   1.317 +        success = ReadCommand(aMessage);
   1.318 +        break;
   1.319 +      case STATE_READ_PARAM_LEN:
   1.320 +        success = ReadLength(aMessage);
   1.321 +        break;
   1.322 +      case STATE_READ_PARAM_DATA:
   1.323 +        success = ReadData(aMessage);
   1.324 +        break;
   1.325 +      case STATE_PROCESSING:
   1.326 +        success = false;
   1.327 +        if (mHandlerInfo.command == 'g') {
   1.328 +          // Get CA
   1.329 +          const uint8_t *certData;
   1.330 +          int certDataLength;
   1.331 +          const char *certName = (const char *)mHandlerInfo.param[0].data;
   1.332 +
   1.333 +          // Get cert from NSS by name
   1.334 +          ScopedCERTCertificate cert(CERT_FindCertByNickname(certdb, certName));
   1.335 +          if (!cert) {
   1.336 +            break;
   1.337 +          }
   1.338 +
   1.339 +          char *certDER = PL_Base64Encode((const char *)cert->derCert.data,
   1.340 +                                          cert->derCert.len, nullptr);
   1.341 +          if (!certDER) {
   1.342 +            break;
   1.343 +          }
   1.344 +
   1.345 +          FormatCaData((const uint8_t *)certDER, strlen(certDER), "CERTIFICATE",
   1.346 +                       &certData, certDataLength);
   1.347 +          PL_strfree(certDER);
   1.348 +
   1.349 +          SendResponse(SUCCESS);
   1.350 +          SendData(certData, certDataLength);
   1.351 +          success = true;
   1.352 +
   1.353 +          free((void *)certData);
   1.354 +        }
   1.355 +
   1.356 +        ResetHandlerInfo();
   1.357 +        break;
   1.358 +    }
   1.359 +
   1.360 +    if (!success) {
   1.361 +      SendResponse(PROTOCOL_ERROR);
   1.362 +      ResetHandlerInfo();
   1.363 +      return;
   1.364 +    }
   1.365 +  }
   1.366 +}
   1.367 +
   1.368 +void
   1.369 +KeyStore::OnConnectSuccess()
   1.370 +{
   1.371 +  mShutdown = false;
   1.372 +}
   1.373 +
   1.374 +void
   1.375 +KeyStore::OnConnectError()
   1.376 +{
   1.377 +  if (!mShutdown) {
   1.378 +    Listen();
   1.379 +  }
   1.380 +}
   1.381 +
   1.382 +void
   1.383 +KeyStore::OnDisconnect()
   1.384 +{
   1.385 +  if (!mShutdown) {
   1.386 +    Listen();
   1.387 +  }
   1.388 +}
   1.389 +
   1.390 +} // namespace ipc
   1.391 +} // namespace mozilla

mercurial