mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 789217 - 0002. Implement keystore. r=qdot
This commit is contained in:
parent
dcf61fcabb
commit
3b1493a373
381
ipc/keystore/KeyStore.cpp
Normal file
381
ipc/keystore/KeyStore.cpp
Normal file
@ -0,0 +1,381 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et ft=cpp: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#undef LOG
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <android/log.h>
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
|
||||
#else
|
||||
#define LOG(args...) printf(args);
|
||||
#endif
|
||||
|
||||
#include "KeyStore.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "MainThreadUtils.h" // For NS_IsMainThread.
|
||||
|
||||
#include "plbase64.h"
|
||||
#include "certdb.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
static const char* KEYSTORE_SOCKET_NAME = "keystore";
|
||||
static const char* KEYSTORE_SOCKET_PATH = "/dev/socket/keystore";
|
||||
|
||||
int
|
||||
KeyStoreConnector::Create()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
int fd;
|
||||
|
||||
unlink(KEYSTORE_SOCKET_PATH);
|
||||
|
||||
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
|
||||
if (fd < 0) {
|
||||
NS_WARNING("Could not open keystore socket!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Allow access of wpa_supplicant(different user, differnt group)
|
||||
chmod(KEYSTORE_SOCKET_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStoreConnector::CreateAddr(bool aIsServer,
|
||||
socklen_t& aAddrSize,
|
||||
sockaddr_any& aAddr,
|
||||
const char* aAddress)
|
||||
{
|
||||
// Keystore socket must be server
|
||||
MOZ_ASSERT(aIsServer);
|
||||
|
||||
aAddr.un.sun_family = AF_LOCAL;
|
||||
if(strlen(KEYSTORE_SOCKET_PATH) > sizeof(aAddr.un.sun_path)) {
|
||||
NS_WARNING("Address too long for socket struct!");
|
||||
return false;
|
||||
}
|
||||
strcpy((char*)&aAddr.un.sun_path, KEYSTORE_SOCKET_PATH);
|
||||
aAddrSize = strlen(KEYSTORE_SOCKET_PATH) + offsetof(struct sockaddr_un, sun_path) + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStoreConnector::SetUp(int aFd)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
KeyStoreConnector::GetSocketAddr(const sockaddr_any& aAddr,
|
||||
nsAString& aAddrStr)
|
||||
{
|
||||
// Unused.
|
||||
MOZ_CRASH("This should never be called!");
|
||||
}
|
||||
|
||||
static char *
|
||||
get_cert_db_filename(void *arg, int vers)
|
||||
{
|
||||
static char keystoreDbPath[] = "/data/misc/wifi/keystore";
|
||||
return keystoreDbPath;
|
||||
}
|
||||
|
||||
KeyStore::KeyStore()
|
||||
{
|
||||
// Initial NSS
|
||||
certdb = CERT_GetDefaultCertDB();
|
||||
|
||||
Listen();
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::Shutdown()
|
||||
{
|
||||
mShutdown = true;
|
||||
CloseSocket();
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::Listen()
|
||||
{
|
||||
ListenSocket(new KeyStoreConnector());
|
||||
|
||||
ResetHandlerInfo();
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::ResetHandlerInfo()
|
||||
{
|
||||
mHandlerInfo.state = STATE_IDLE;
|
||||
mHandlerInfo.command = 0;
|
||||
mHandlerInfo.paramCount = 0;
|
||||
mHandlerInfo.commandPattern = NULL;
|
||||
for (int i = 0; i < MAX_PARAM; i++) {
|
||||
mHandlerInfo.param[i].length = 0;
|
||||
memset(mHandlerInfo.param[i].data, 0, VALUE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStore::CheckSize(UnixSocketRawData *aMessage, size_t aExpectSize)
|
||||
{
|
||||
return (aMessage->mSize - aMessage->mCurrentWriteOffset >= aExpectSize) ?
|
||||
true : false;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStore::ReadCommand(UnixSocketRawData *aMessage)
|
||||
{
|
||||
if (mHandlerInfo.state != STATE_IDLE) {
|
||||
NS_WARNING("Wrong state in ReadCommand()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckSize(aMessage, 1)) {
|
||||
NS_WARNING("Data size error in ReadCommand()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mHandlerInfo.command = aMessage->mData[aMessage->mCurrentWriteOffset];
|
||||
aMessage->mCurrentWriteOffset++;
|
||||
|
||||
// Find corrsponding command pattern
|
||||
const struct ProtocolCommand *command = commands;
|
||||
while (command->command && command->command != mHandlerInfo.command) {
|
||||
command++;
|
||||
}
|
||||
|
||||
if (!command->command) {
|
||||
NS_WARNING("Unsupported command!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get command pattern.
|
||||
mHandlerInfo.commandPattern = command;
|
||||
if (command->paramNum) {
|
||||
// Read command parameter if needed.
|
||||
mHandlerInfo.state = STATE_READ_PARAM_LEN;
|
||||
} else {
|
||||
mHandlerInfo.state = STATE_PROCESSING;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStore::ReadLength(UnixSocketRawData *aMessage)
|
||||
{
|
||||
if (mHandlerInfo.state != STATE_READ_PARAM_LEN) {
|
||||
NS_WARNING("Wrong state in ReadLength()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckSize(aMessage, 2)) {
|
||||
NS_WARNING("Data size error in ReadLength()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read length of command parameter.
|
||||
unsigned short dataLength;
|
||||
memcpy(&dataLength, &aMessage->mData[aMessage->mCurrentWriteOffset], 2);
|
||||
aMessage->mCurrentWriteOffset += 2;
|
||||
mHandlerInfo.param[mHandlerInfo.paramCount].length = ntohs(dataLength);
|
||||
|
||||
mHandlerInfo.state = STATE_READ_PARAM_DATA;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyStore::ReadData(UnixSocketRawData *aMessage)
|
||||
{
|
||||
if (mHandlerInfo.state != STATE_READ_PARAM_DATA) {
|
||||
NS_WARNING("Wrong state in ReadData()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckSize(aMessage, mHandlerInfo.param[mHandlerInfo.paramCount].length)) {
|
||||
NS_WARNING("Data size error in ReadData()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read command parameter.
|
||||
memcpy(mHandlerInfo.param[mHandlerInfo.paramCount].data,
|
||||
&aMessage->mData[aMessage->mCurrentWriteOffset],
|
||||
mHandlerInfo.param[mHandlerInfo.paramCount].length);
|
||||
aMessage->mCurrentWriteOffset += mHandlerInfo.param[mHandlerInfo.paramCount].length;
|
||||
mHandlerInfo.paramCount++;
|
||||
|
||||
if (mHandlerInfo.paramCount == mHandlerInfo.commandPattern->paramNum) {
|
||||
mHandlerInfo.state = STATE_PROCESSING;
|
||||
} else {
|
||||
mHandlerInfo.state = STATE_READ_PARAM_LEN;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Transform base64 certification data into DER format
|
||||
void
|
||||
KeyStore::FormatCaData(const uint8_t *aCaData, int aCaDataLength,
|
||||
const char *aName, const uint8_t **aFormatData,
|
||||
int &aFormatDataLength)
|
||||
{
|
||||
int bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 +
|
||||
strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE + 2;
|
||||
char *buf = (char *)malloc(bufSize);
|
||||
|
||||
aFormatDataLength = bufSize;
|
||||
*aFormatData = (const uint8_t *)buf;
|
||||
|
||||
char *ptr = buf;
|
||||
int len;
|
||||
|
||||
// Create DER header.
|
||||
len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER);
|
||||
ptr += len;
|
||||
bufSize -= len;
|
||||
|
||||
// Split base64 data in lines.
|
||||
int copySize;
|
||||
while (aCaDataLength > 0) {
|
||||
copySize = (aCaDataLength > CA_LINE_SIZE) ? CA_LINE_SIZE : aCaDataLength;
|
||||
|
||||
memcpy(ptr, aCaData, copySize);
|
||||
ptr += copySize;
|
||||
aCaData += copySize;
|
||||
aCaDataLength -= copySize;
|
||||
bufSize -= copySize;
|
||||
|
||||
*ptr = '\n';
|
||||
ptr++;
|
||||
bufSize--;
|
||||
}
|
||||
|
||||
// Create DEA tailer.
|
||||
snprintf(ptr, bufSize, "%s%s%s", CA_END, aName, CA_TAILER);
|
||||
}
|
||||
|
||||
// Status response
|
||||
void
|
||||
KeyStore::SendResponse(ResponseCode aResponse)
|
||||
{
|
||||
if (aResponse == NO_RESPONSE)
|
||||
return;
|
||||
|
||||
uint8_t response = (uint8_t)aResponse;
|
||||
UnixSocketRawData* data = new UnixSocketRawData((const void *)&response, 1);
|
||||
SendSocketData(data);
|
||||
}
|
||||
|
||||
// Data response
|
||||
void
|
||||
KeyStore::SendData(const uint8_t *aData, int aLength)
|
||||
{
|
||||
unsigned short dataLength = htons(aLength);
|
||||
|
||||
UnixSocketRawData* length = new UnixSocketRawData((const void *)&dataLength, 2);
|
||||
SendSocketData(length);
|
||||
|
||||
UnixSocketRawData* data = new UnixSocketRawData((const void *)aData, aLength);
|
||||
SendSocketData(data);
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
bool success = true;
|
||||
while (aMessage->mCurrentWriteOffset < aMessage->mSize ||
|
||||
mHandlerInfo.state == STATE_PROCESSING) {
|
||||
switch (mHandlerInfo.state) {
|
||||
case STATE_IDLE:
|
||||
success = ReadCommand(aMessage);
|
||||
break;
|
||||
case STATE_READ_PARAM_LEN:
|
||||
success = ReadLength(aMessage);
|
||||
break;
|
||||
case STATE_READ_PARAM_DATA:
|
||||
success = ReadData(aMessage);
|
||||
break;
|
||||
case STATE_PROCESSING:
|
||||
success = false;
|
||||
if (mHandlerInfo.command == 'g') {
|
||||
// Get CA
|
||||
const uint8_t *certData;
|
||||
int certDataLength;
|
||||
const char *certName = (const char *)mHandlerInfo.param[0].data;
|
||||
|
||||
// Get cert from NSS by name
|
||||
CERTCertificate *cert = CERT_FindCertByNickname(certdb, certName);
|
||||
if (!cert) {
|
||||
break;
|
||||
}
|
||||
|
||||
char *certDER = PL_Base64Encode((const char *)cert->derCert.data,
|
||||
cert->derCert.len, nullptr);
|
||||
if (!certDER) {
|
||||
break;
|
||||
}
|
||||
|
||||
FormatCaData((const uint8_t *)certDER, strlen(certDER), "CERTIFICATE",
|
||||
&certData, certDataLength);
|
||||
PL_strfree(certDER);
|
||||
|
||||
SendResponse(SUCCESS);
|
||||
SendData(certData, certDataLength);
|
||||
success = true;
|
||||
|
||||
free((void *)certData);
|
||||
}
|
||||
|
||||
ResetHandlerInfo();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
SendResponse(PROTOCOL_ERROR);
|
||||
ResetHandlerInfo();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::OnConnectSuccess()
|
||||
{
|
||||
mShutdown = false;
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::OnConnectError()
|
||||
{
|
||||
if (!mShutdown) {
|
||||
Listen();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
KeyStore::OnDisconnect()
|
||||
{
|
||||
if (!mShutdown) {
|
||||
Listen();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
131
ipc/keystore/KeyStore.h
Normal file
131
ipc/keystore/KeyStore.h
Normal file
@ -0,0 +1,131 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ipc_KeyStore_h
|
||||
#define mozilla_ipc_KeyStore_h 1
|
||||
|
||||
#include "mozilla/ipc/UnixSocket.h"
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "cert.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
enum ResponseCode {
|
||||
SUCCESS = 1,
|
||||
LOCKED = 2,
|
||||
UNINITIALIZED = 3,
|
||||
SYSTEM_ERROR = 4,
|
||||
PROTOCOL_ERROR = 5,
|
||||
PERMISSION_DENIED = 6,
|
||||
KEY_NOT_FOUND = 7,
|
||||
VALUE_CORRUPTED = 8,
|
||||
UNDEFINED_ACTION = 9,
|
||||
WRONG_PASSWORD_0 = 10,
|
||||
WRONG_PASSWORD_1 = 11,
|
||||
WRONG_PASSWORD_2 = 12,
|
||||
WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4
|
||||
NO_RESPONSE
|
||||
};
|
||||
|
||||
static const int MAX_PARAM = 2;
|
||||
static const int KEY_SIZE = ((NAME_MAX - 15) / 2);
|
||||
static const int VALUE_SIZE = 32768;
|
||||
static const int PASSWORD_SIZE = VALUE_SIZE;
|
||||
|
||||
static const char *CA_BEGIN = "-----BEGIN ",
|
||||
*CA_END = "-----END ",
|
||||
*CA_TAILER = "-----\n";
|
||||
static const int CA_LINE_SIZE = 64;
|
||||
|
||||
struct ProtocolCommand {
|
||||
int8_t command;
|
||||
int paramNum;
|
||||
};
|
||||
|
||||
static const struct ProtocolCommand commands[] = {
|
||||
{'g', 1}, // Get CA, command "g CERT_NAME"
|
||||
{ 0, 0}
|
||||
};
|
||||
|
||||
struct ProtocolParam{
|
||||
uint length;
|
||||
int8_t data[VALUE_SIZE];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
STATE_IDLE,
|
||||
STATE_READ_PARAM_LEN,
|
||||
STATE_READ_PARAM_DATA,
|
||||
STATE_PROCESSING
|
||||
} ProtocolHandlerState;
|
||||
|
||||
class KeyStoreConnector : public mozilla::ipc::UnixSocketConnector
|
||||
{
|
||||
public:
|
||||
KeyStoreConnector()
|
||||
{}
|
||||
|
||||
virtual ~KeyStoreConnector()
|
||||
{}
|
||||
|
||||
virtual int Create();
|
||||
virtual bool CreateAddr(bool aIsServer,
|
||||
socklen_t& aAddrSize,
|
||||
sockaddr_any& aAddr,
|
||||
const char* aAddress);
|
||||
virtual bool SetUp(int aFd);
|
||||
virtual void GetSocketAddr(const sockaddr_any& aAddr,
|
||||
nsAString& aAddrStr);
|
||||
};
|
||||
|
||||
class KeyStore : public mozilla::ipc::UnixSocketConsumer
|
||||
{
|
||||
public:
|
||||
KeyStore();
|
||||
virtual ~KeyStore() {}
|
||||
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage);
|
||||
|
||||
virtual void OnConnectSuccess();
|
||||
virtual void OnConnectError();
|
||||
virtual void OnDisconnect();
|
||||
|
||||
private:
|
||||
struct {
|
||||
ProtocolHandlerState state;
|
||||
uint8_t command;
|
||||
struct ProtocolParam param[MAX_PARAM];
|
||||
int paramCount;
|
||||
const struct ProtocolCommand *commandPattern;
|
||||
} mHandlerInfo;
|
||||
void ResetHandlerInfo();
|
||||
void Listen();
|
||||
|
||||
void FormatCaData(const uint8_t *caData, int caDataLength, const char *name,
|
||||
const uint8_t **formatData, int &formatDataLength);
|
||||
|
||||
bool CheckSize(UnixSocketRawData *aMessage, size_t aExpectSize);
|
||||
bool ReadCommand(UnixSocketRawData *aMessage);
|
||||
bool ReadLength(UnixSocketRawData *aMessage);
|
||||
bool ReadData(UnixSocketRawData *aMessage);
|
||||
void SendResponse(ResponseCode response);
|
||||
void SendData(const uint8_t *data, int length);
|
||||
|
||||
bool mShutdown;
|
||||
|
||||
CERTCertDBHandle *certdb;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_KeyStore_h
|
@ -7,9 +7,11 @@
|
||||
MODULE = 'ipc'
|
||||
|
||||
EXPORTS.mozilla.ipc += [
|
||||
'KeyStore.h'
|
||||
]
|
||||
|
||||
CPP_SOURCES += [
|
||||
'KeyStore.cpp'
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
Loading…
Reference in New Issue
Block a user