diff options
Diffstat (limited to 'ipc/keystore')
-rw-r--r-- | ipc/keystore/KeyStore.cpp | 981 | ||||
-rw-r--r-- | ipc/keystore/KeyStore.h | 141 | ||||
-rw-r--r-- | ipc/keystore/KeyStoreConnector.cpp | 234 | ||||
-rw-r--r-- | ipc/keystore/KeyStoreConnector.h | 57 | ||||
-rw-r--r-- | ipc/keystore/moz.build | 18 |
5 files changed, 0 insertions, 1431 deletions
diff --git a/ipc/keystore/KeyStore.cpp b/ipc/keystore/KeyStore.cpp deleted file mode 100644 index 5544b698d..000000000 --- a/ipc/keystore/KeyStore.cpp +++ /dev/null @@ -1,981 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=2 et ft=cpp: tw=80: */ -/* 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 <limits.h> -#include <pwd.h> -#include <sys/stat.h> -#include <sys/types.h> - -#define KEYSTORE_LOG(args...) printf(args); - -#include "KeyStore.h" -#include "jsfriendapi.h" -#include "KeyStoreConnector.h" -#include "MainThreadUtils.h" // For NS_IsMainThread. -#include "nsICryptoHash.h" - -#include "plbase64.h" -#include "certdb.h" -#include "ScopedNSSTypes.h" - -using namespace mozilla::ipc; -#if ANDROID_VERSION >= 18 -// After Android 4.3, it uses binder to access keystore instead of unix socket. -#include <android/log.h> -#include <binder/BinderService.h> -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <security/keystore/include/keystore/IKeystoreService.h> -#include <security/keystore/include/keystore/keystore.h> - -using namespace android; - -namespace android { -// This class is used to make compiler happy. -class BpKeystoreService : public BpInterface<IKeystoreService> -{ -public: - BpKeystoreService(const sp<IBinder>& impl) - : BpInterface<IKeystoreService>(impl) - { - } - - virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {return 0;} - virtual int32_t test() {return 0;} - virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid, int32_t flags) {return 0;} - virtual int32_t del(const String16& name, int uid) {return 0;} - virtual int32_t exist(const String16& name, int uid) {return 0;} - virtual int32_t saw(const String16& name, int uid, Vector<String16>* matches) {return 0;} - virtual int32_t reset() {return 0;} - virtual int32_t password(const String16& password) {return 0;} - virtual int32_t lock() {return 0;} - virtual int32_t unlock(const String16& password) {return 0;} - virtual int32_t zero() {return 0;} - virtual int32_t import(const String16& name, const uint8_t* data, size_t length, int uid, int32_t flags) {return 0;} - virtual int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out, size_t* outLength) {return 0;} - virtual int32_t verify(const String16& name, const uint8_t* data, size_t dataLength, const uint8_t* signature, size_t signatureLength) {return 0;} - virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {return 0;} - virtual int32_t del_key(const String16& name, int uid) {return 0;} - virtual int32_t grant(const String16& name, int32_t granteeUid) {return 0;} - virtual int32_t ungrant(const String16& name, int32_t granteeUid) {return 0;} - virtual int64_t getmtime(const String16& name) {return 0;} - virtual int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey, int32_t destUid) {return 0;} - virtual int32_t clear_uid(int64_t uid) {return 0;} -#if ANDROID_VERSION >= 21 - virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return 0;} - virtual int32_t is_hardware_backed(const String16& keyType) {return 0;} - virtual int32_t reset_uid(int32_t uid) {return 0;} - virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {return 0;} - virtual int32_t password_uid(const String16& password, int32_t uid) {return 0;} -#elif ANDROID_VERSION == 18 - virtual int32_t generate(const String16& name, int uid, int32_t flags) {return 0;} - virtual int32_t is_hardware_backed() {return 0;} -#else - virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return 0;} - virtual int32_t is_hardware_backed(const String16& keyType) {return 0;} -#endif -}; - -IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.keystore"); - -// Here comes binder requests. -status_t BnKeystoreService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case TEST: { - CHECK_INTERFACE(IKeystoreService, data, reply); - reply->writeNoException(); - reply->writeInt32(test()); - return NO_ERROR; - } break; - case GET: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - String8 tmp(name); - uint8_t* data = NULL; - size_t dataLength = 0; - int32_t ret = get(name, &data, &dataLength); - - reply->writeNoException(); - if (ret == 1) { - reply->writeInt32(dataLength); - void* buf = reply->writeInplace(dataLength); - memcpy(buf, data, dataLength); - free(data); - } else { - reply->writeInt32(-1); - } - return NO_ERROR; - } break; - case GET_PUBKEY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - uint8_t* data = nullptr; - size_t dataLength = 0; - int32_t ret = get_pubkey(name, &data, &dataLength); - - reply->writeNoException(); - if (dataLength > 0 && data != nullptr) { - reply->writeInt32(dataLength); - void* buf = reply->writeInplace(dataLength); - memcpy(buf, data, dataLength); - free(data); - } else { - reply->writeInt32(-1); - } - reply->writeInt32(ret); - return NO_ERROR; - } break; - case SIGN: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - ssize_t signDataSize = data.readInt32(); - const uint8_t *signData = nullptr; - if (signDataSize >= 0 && (size_t)signDataSize <= data.dataAvail()) { - signData = (const uint8_t *)data.readInplace(signDataSize); - } - - uint8_t *signResult = nullptr; - size_t signResultSize; - int32_t ret = sign(name, signData, (size_t)signDataSize, &signResult, - &signResultSize); - - reply->writeNoException(); - if (signResultSize > 0 && signResult != nullptr) { - reply->writeInt32(signResultSize); - void* buf = reply->writeInplace(signResultSize); - memcpy(buf, signResult, signResultSize); - free(signResult); - } else { - reply->writeInt32(-1); - } - reply->writeInt32(ret); - return NO_ERROR; - } break; - default: - return NO_ERROR; - } -} - -// Provide service for binder. -class KeyStoreService : public BnKeystoreService - , public nsNSSShutDownObject -{ -public: - int32_t test() { - uid_t callingUid = IPCThreadState::self()->getCallingUid(); - if (!mozilla::ipc::checkPermission(callingUid)) { - return ::PERMISSION_DENIED; - } - - return ::NO_ERROR; - } - - int32_t get(const String16& name, uint8_t** item, size_t* itemLength) { - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return ::SYSTEM_ERROR; - } - - uid_t callingUid = IPCThreadState::self()->getCallingUid(); - if (!mozilla::ipc::checkPermission(callingUid)) { - return ::PERMISSION_DENIED; - } - - String8 certName(name); - if (!strncmp(certName.string(), "WIFI_USERKEY_", 13)) { - return getPrivateKey(certName.string(), (const uint8_t**)item, itemLength); - } - - return getCertificate(certName.string(), (const uint8_t**)item, itemLength); - } - - int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid, int32_t flags) {return ::UNDEFINED_ACTION;} - int32_t del(const String16& name, int uid) {return ::UNDEFINED_ACTION;} - int32_t exist(const String16& name, int uid) {return ::UNDEFINED_ACTION;} - int32_t saw(const String16& name, int uid, Vector<String16>* matches) {return ::UNDEFINED_ACTION;} - int32_t reset() {return ::UNDEFINED_ACTION;} - int32_t password(const String16& password) {return ::UNDEFINED_ACTION;} - int32_t lock() {return ::UNDEFINED_ACTION;} - int32_t unlock(const String16& password) {return ::UNDEFINED_ACTION;} - int32_t zero() {return ::UNDEFINED_ACTION;} - int32_t import(const String16& name, const uint8_t* data, size_t length, int uid, int32_t flags) {return ::UNDEFINED_ACTION;} - int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out, size_t* outLength) - { - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return ::SYSTEM_ERROR; - } - - uid_t callingUid = IPCThreadState::self()->getCallingUid(); - if (!mozilla::ipc::checkPermission(callingUid)) { - return ::PERMISSION_DENIED; - } - - if (data == nullptr) { - return ::SYSTEM_ERROR; - } - - String8 keyName(name); - if (!strncmp(keyName.string(), "WIFI_USERKEY_", 13)) { - return signData(keyName.string(), data, length, out, outLength); - } - - return ::UNDEFINED_ACTION; - } - - int32_t verify(const String16& name, const uint8_t* data, size_t dataLength, const uint8_t* signature, size_t signatureLength) {return ::UNDEFINED_ACTION;} - int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) { - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return ::SYSTEM_ERROR; - } - - uid_t callingUid = IPCThreadState::self()->getCallingUid(); - if (!mozilla::ipc::checkPermission(callingUid)) { - return ::PERMISSION_DENIED; - } - - String8 keyName(name); - if (!strncmp(keyName.string(), "WIFI_USERKEY_", 13)) { - return getPublicKey(keyName.string(), (const uint8_t**)pubkey, pubkeyLength); - } - - return ::UNDEFINED_ACTION; - } - - int32_t del_key(const String16& name, int uid) {return ::UNDEFINED_ACTION;} - int32_t grant(const String16& name, int32_t granteeUid) {return ::UNDEFINED_ACTION;} - int32_t ungrant(const String16& name, int32_t granteeUid) {return ::UNDEFINED_ACTION;} - int64_t getmtime(const String16& name) {return ::UNDEFINED_ACTION;} - int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey, int32_t destUid) {return ::UNDEFINED_ACTION;} - int32_t clear_uid(int64_t uid) {return ::UNDEFINED_ACTION;} -#if ANDROID_VERSION >= 21 - virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return ::UNDEFINED_ACTION;} - virtual int32_t is_hardware_backed(const String16& keyType) {return ::UNDEFINED_ACTION;} - virtual int32_t reset_uid(int32_t uid) {return ::UNDEFINED_ACTION;;} - virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {return ::UNDEFINED_ACTION;} - virtual int32_t password_uid(const String16& password, int32_t uid) {return ::UNDEFINED_ACTION;} -#elif ANDROID_VERSION == 18 - virtual int32_t generate(const String16& name, int uid, int32_t flags) {return ::UNDEFINED_ACTION;} - virtual int32_t is_hardware_backed() {return ::UNDEFINED_ACTION;} -#else - virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize, int32_t flags, Vector<sp<KeystoreArg> >* args) {return ::UNDEFINED_ACTION;} - virtual int32_t is_hardware_backed(const String16& keyType) {return ::UNDEFINED_ACTION;} -#endif - -protected: - virtual void virtualDestroyNSSReference() {} - -private: - ~KeyStoreService() { - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - return; - } - shutdown(ShutdownCalledFrom::Object); - } -}; - -} // namespace android - -void startKeyStoreService() -{ - android::sp<android::IServiceManager> sm = android::defaultServiceManager(); - android::sp<android::KeyStoreService> keyStoreService = new android::KeyStoreService(); - sm->addService(String16("android.security.keystore"), keyStoreService); -} -#else -void startKeyStoreService() { return; } -#endif - -static const char *CA_BEGIN = "-----BEGIN ", - *CA_END = "-----END ", - *CA_TAILER = "-----\n"; - -namespace mozilla { -namespace ipc { - -static const char* KEYSTORE_ALLOWED_USERS[] = { - "root", - "wifi", - NULL -}; -static const char* KEYSTORE_ALLOWED_PREFIXES[] = { - "WIFI_SERVERCERT_", - "WIFI_USERCERT_", - "WIFI_USERKEY_", - NULL -}; - -// Transform base64 certification data into DER format -void -FormatCaData(const char *aCaData, int aCaDataLength, - const char *aName, const uint8_t **aFormatData, - size_t *aFormatDataLength) -{ - size_t 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); - if (!buf) { - *aFormatData = nullptr; - return; - } - - *aFormatDataLength = bufSize; - *aFormatData = (const uint8_t *)buf; - - char *ptr = buf; - size_t 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); -} - -ResponseCode -getCertificate(const char *aCertName, const uint8_t **aCertData, - size_t *aCertDataLength) -{ - // certificate name prefix check. - if (!aCertName) { - return KEY_NOT_FOUND; - } - - const char **prefix = KEYSTORE_ALLOWED_PREFIXES; - for (; *prefix; prefix++ ) { - if (!strncmp(*prefix, aCertName, strlen(*prefix))) { - break; - } - } - if (!(*prefix)) { - return KEY_NOT_FOUND; - } - - // Get cert from NSS by name - ScopedCERTCertificate cert(CERT_FindCertByNickname(CERT_GetDefaultCertDB(), - aCertName)); - - if (!cert) { - return KEY_NOT_FOUND; - } - - char *certDER = PL_Base64Encode((const char *)cert->derCert.data, - cert->derCert.len, nullptr); - if (!certDER) { - return SYSTEM_ERROR; - } - - FormatCaData(certDER, strlen(certDER), "CERTIFICATE", aCertData, - aCertDataLength); - PL_strfree(certDER); - - if (!(*aCertData)) { - return SYSTEM_ERROR; - } - - return SUCCESS; -} - -ResponseCode getPrivateKey(const char *aKeyName, const uint8_t **aKeyData, - size_t *aKeyDataLength) -{ - *aKeyData = nullptr; - // Get corresponding user certificate nickname - char userCertName[128] = {0}; - snprintf(userCertName, sizeof(userCertName) - 1, "WIFI_USERCERT_%s", aKeyName + 13); - - // Get private key from user certificate. - ScopedCERTCertificate userCert( - CERT_FindCertByNickname(CERT_GetDefaultCertDB(), userCertName)); - if (!userCert) { - return KEY_NOT_FOUND; - } - - ScopedSECKEYPrivateKey privateKey( - PK11_FindKeyByAnyCert(userCert.get(), nullptr)); - if (!privateKey) { - return KEY_NOT_FOUND; - } - - // Export private key in PKCS#12 encrypted format, no password. - unsigned char pwstr[] = {0, 0}; - SECItem password = {siBuffer, pwstr, sizeof(pwstr)}; - ScopedSECKEYEncryptedPrivateKeyInfo encryptedPrivateKey( - PK11_ExportEncryptedPrivKeyInfo(privateKey->pkcs11Slot, - SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4, &password, privateKey, 1, - privateKey->wincx)); - - if (!encryptedPrivateKey) { - return KEY_NOT_FOUND; - } - - // Decrypt into RSA private key. - // - // Generate key for PKCS#12 encryption, we use SHA1 with 1 iteration, as the - // parameters used in PK11_ExportEncryptedPrivKeyInfo() above. - // see: PKCS#12 v1.0, B.2. - // - uint8_t DSP[192] = {0}; - memset(DSP, 0x01, 64); // Diversifier part, ID = 1 for decryption. - memset(DSP + 128, 0x00, 64); // Password part, no password. - - uint8_t *S = &DSP[64]; // Salt part. - uint8_t *salt = encryptedPrivateKey->algorithm.parameters.data + 4; - int saltLength = (int)encryptedPrivateKey->algorithm.parameters.data[3]; - if (saltLength <= 0) { - return SYSTEM_ERROR; - } - for (int i = 0; i < 64; i++) { - S[i] = salt[i % saltLength]; - } - - // Generate key by SHA-1 - nsresult rv; - nsCOMPtr<nsICryptoHash> hash = - do_CreateInstance("@mozilla.org/security/hash;1", &rv); - if (NS_FAILED(rv)) { - return SYSTEM_ERROR; - } - - rv = hash->Init(nsICryptoHash::SHA1); - if (NS_FAILED(rv)) { - return SYSTEM_ERROR; - } - - rv = hash->Update(DSP, sizeof(DSP)); - if (NS_FAILED(rv)) { - return SYSTEM_ERROR; - } - - nsCString hashResult; - rv = hash->Finish(false, hashResult); - if (NS_FAILED(rv)) { - return SYSTEM_ERROR; - } - - // First 40-bit as key for RC4. - uint8_t key[5]; - memcpy(key, hashResult.get(), sizeof(key)); - - ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); - if (!slot) { - return SYSTEM_ERROR; - } - - SECItem keyItem = {siBuffer, key, sizeof(key)}; - ScopedPK11SymKey symKey(PK11_ImportSymKey(slot, CKM_RC4, PK11_OriginUnwrap, - CKA_DECRYPT, &keyItem, nullptr)); - if (!symKey) { - return SYSTEM_ERROR; - } - - // Get expected decrypted data size then allocate memory. - uint8_t *encryptedData = (uint8_t *)encryptedPrivateKey->encryptedData.data; - unsigned int encryptedDataLen = encryptedPrivateKey->encryptedData.len; - unsigned int decryptedDataLen = encryptedDataLen; - SECStatus srv = PK11_Decrypt(symKey, CKM_RC4, &keyItem, nullptr, - &decryptedDataLen, encryptedDataLen, - encryptedData, encryptedDataLen); - if (srv != SECSuccess) { - return SYSTEM_ERROR; - } - - ScopedSECItem decryptedData(::SECITEM_AllocItem(nullptr, nullptr, - decryptedDataLen)); - if (!decryptedData) { - return SYSTEM_ERROR; - } - - // Decrypt by RC4. - srv = PK11_Decrypt(symKey, CKM_RC4, &keyItem, decryptedData->data, - &decryptedDataLen, decryptedData->len, encryptedData, - encryptedDataLen); - if (srv != SECSuccess) { - return SYSTEM_ERROR; - } - - // Export key in PEM format. - char *keyPEM = PL_Base64Encode((const char *)decryptedData->data, - decryptedDataLen, nullptr); - - if (!keyPEM) { - return SYSTEM_ERROR; - } - - FormatCaData(keyPEM, strlen(keyPEM), "PRIVATE KEY", aKeyData, aKeyDataLength); - PL_strfree(keyPEM); - - if (!(*aKeyData)) { - return SYSTEM_ERROR; - } - - return SUCCESS; -} - -ResponseCode getPublicKey(const char *aKeyName, const uint8_t **aKeyData, - size_t *aKeyDataLength) -{ - *aKeyData = nullptr; - - // Get corresponding user certificate nickname - char userCertName[128] = {0}; - snprintf(userCertName, sizeof(userCertName) - 1, "WIFI_USERCERT_%s", aKeyName + 13); - - // Get public key from user certificate. - ScopedCERTCertificate userCert( - CERT_FindCertByNickname(CERT_GetDefaultCertDB(), userCertName)); - if (!userCert) { - return KEY_NOT_FOUND; - } - - // Get public key. - ScopedSECKEYPublicKey publicKey(CERT_ExtractPublicKey(userCert)); - if (!publicKey) { - return KEY_NOT_FOUND; - } - - ScopedSECItem keyItem(PK11_DEREncodePublicKey(publicKey)); - if (!keyItem) { - return KEY_NOT_FOUND; - } - - size_t bufSize = keyItem->len; - char *buf = (char *)malloc(bufSize); - if (!buf) { - return SYSTEM_ERROR; - } - - memcpy(buf, keyItem->data, bufSize); - *aKeyData = (const uint8_t *)buf; - *aKeyDataLength = bufSize; - - return SUCCESS; -} - -ResponseCode signData(const char *aKeyName, const uint8_t *data, size_t length, - uint8_t **out, size_t *outLength) -{ - *out = nullptr; - // Get corresponding user certificate nickname - char userCertName[128] = {0}; - snprintf(userCertName, sizeof(userCertName) - 1, "WIFI_USERCERT_%s", aKeyName + 13); - - // Get private key from user certificate. - ScopedCERTCertificate userCert( - CERT_FindCertByNickname(CERT_GetDefaultCertDB(), userCertName)); - if (!userCert) { - return KEY_NOT_FOUND; - } - - ScopedSECKEYPrivateKey privateKey( - PK11_FindKeyByAnyCert(userCert.get(), nullptr)); - if (!privateKey) { - return KEY_NOT_FOUND; - } - - // - // Find hash data from incoming data. - // - // Incoming data might be padded by PKCS-1 format: - // 00 01 FF FF ... FF 00 || Hash of length 36 - // If the padding part exists, we have to ignore them. - // - uint8_t *hash = (uint8_t *)data; - const size_t HASH_LENGTH = 36; - if (length < HASH_LENGTH) { - return VALUE_CORRUPTED; - } - if (hash[0] == 0x00 && hash[1] == 0x01 && hash[2] == 0xFF && hash[3] == 0xFF) { - hash += 4; - while (*hash == 0xFF) { - if (hash + HASH_LENGTH > data + length) { - return VALUE_CORRUPTED; - } - hash++; - } - if (*hash != 0x00) { - return VALUE_CORRUPTED; - } - hash++; - } - if (hash + HASH_LENGTH != data + length) { - return VALUE_CORRUPTED; - } - SECItem hashItem = {siBuffer, hash, HASH_LENGTH}; - - // Sign hash. - ScopedSECItem signItem(::SECITEM_AllocItem(nullptr, nullptr, - PK11_SignatureLen(privateKey))); - if (!signItem) { - return SYSTEM_ERROR; - } - - SECStatus srv; - srv = PK11_Sign(privateKey, signItem.get(), &hashItem); - if (srv != SECSuccess) { - return SYSTEM_ERROR; - } - - uint8_t *buf = (uint8_t *)malloc(signItem->len); - if (!buf) { - return SYSTEM_ERROR; - } - - memcpy(buf, signItem->data, signItem->len); - *out = buf; - *outLength = signItem->len; - - return SUCCESS; -} - -bool -checkPermission(uid_t uid) -{ - struct passwd *userInfo = getpwuid(uid); - for (const char **user = KEYSTORE_ALLOWED_USERS; *user; user++ ) { - if (!strcmp(*user, userInfo->pw_name)) { - return true; - } - } - - return false; -} - -// -// KeyStore -// - -KeyStore::KeyStore() -: mShutdown(false) -{ - MOZ_COUNT_CTOR(KeyStore); - ::startKeyStoreService(); - Listen(); -} - -KeyStore::~KeyStore() -{ - nsNSSShutDownPreventionLock locker; - MOZ_COUNT_DTOR(KeyStore); - - if (isAlreadyShutDown()) { - return; - } - - shutdown(ShutdownCalledFrom::Object); - - MOZ_ASSERT(!mListenSocket); - MOZ_ASSERT(!mStreamSocket); -} - -void -KeyStore::Shutdown() -{ - // We set mShutdown first, so that |OnDisconnect| won't try to reconnect. - mShutdown = true; - - if (mStreamSocket) { - mStreamSocket->Close(); - mStreamSocket = nullptr; - } - if (mListenSocket) { - mListenSocket->Close(); - mListenSocket = nullptr; - } -} - -void -KeyStore::Listen() -{ - // We only allocate one |StreamSocket|, but re-use it for every connection. - if (mStreamSocket) { - mStreamSocket->Close(); - } else { - mStreamSocket = new StreamSocket(this, STREAM_SOCKET); - } - - if (!mListenSocket) { - // We only ever allocate one |ListenSocket|... - mListenSocket = new ListenSocket(this, LISTEN_SOCKET); - mListenSocket->Listen(new KeyStoreConnector(KEYSTORE_ALLOWED_USERS), - mStreamSocket); - } else { - // ... but keep it open. - mListenSocket->Listen(mStreamSocket); - } - - ResetHandlerInfo(); -} - -void -KeyStore::ResetHandlerInfo() -{ - mHandlerInfo.state = STATE_IDLE; - mHandlerInfo.command = 0; - mHandlerInfo.paramCount = 0; - mHandlerInfo.commandPattern = nullptr; - for (int i = 0; i < MAX_PARAM; i++) { - mHandlerInfo.param[i].length = 0; - memset(mHandlerInfo.param[i].data, 0, VALUE_SIZE); - } -} - -bool -KeyStore::CheckSize(UnixSocketBuffer *aMessage, size_t aExpectSize) -{ - return (aMessage->GetSize() >= aExpectSize); -} - -ResponseCode -KeyStore::ReadCommand(UnixSocketBuffer *aMessage) -{ - if (mHandlerInfo.state != STATE_IDLE) { - NS_WARNING("Wrong state in ReadCommand()!"); - return SYSTEM_ERROR; - } - - if (!CheckSize(aMessage, 1)) { - NS_WARNING("Data size error in ReadCommand()!"); - return PROTOCOL_ERROR; - } - - mHandlerInfo.command = *aMessage->GetData(); - aMessage->Consume(1); - - // 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 PROTOCOL_ERROR; - } - - // 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 SUCCESS; -} - -ResponseCode -KeyStore::ReadLength(UnixSocketBuffer *aMessage) -{ - if (mHandlerInfo.state != STATE_READ_PARAM_LEN) { - NS_WARNING("Wrong state in ReadLength()!"); - return SYSTEM_ERROR; - } - - if (!CheckSize(aMessage, 2)) { - NS_WARNING("Data size error in ReadLength()!"); - return PROTOCOL_ERROR; - } - - // Read length of command parameter. - // FIXME: Depends on endianess and (sizeof(unsigned short) == 2) - unsigned short dataLength; - memcpy(&dataLength, aMessage->GetData(), 2); - aMessage->Consume(2); - mHandlerInfo.param[mHandlerInfo.paramCount].length = ntohs(dataLength); - - mHandlerInfo.state = STATE_READ_PARAM_DATA; - - return SUCCESS; -} - -ResponseCode -KeyStore::ReadData(UnixSocketBuffer *aMessage) -{ - if (mHandlerInfo.state != STATE_READ_PARAM_DATA) { - NS_WARNING("Wrong state in ReadData()!"); - return SYSTEM_ERROR; - } - - if (!CheckSize(aMessage, mHandlerInfo.param[mHandlerInfo.paramCount].length)) { - NS_WARNING("Data size error in ReadData()!"); - return PROTOCOL_ERROR; - } - - // Read command parameter. - memcpy(mHandlerInfo.param[mHandlerInfo.paramCount].data, - aMessage->GetData(), - mHandlerInfo.param[mHandlerInfo.paramCount].length); - aMessage->Consume(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 SUCCESS; -} - -// Status response -void -KeyStore::SendResponse(ResponseCode aResponse) -{ - MOZ_ASSERT(mStreamSocket); - - if (aResponse == NO_RESPONSE) - return; - - uint8_t response = (uint8_t)aResponse; - UnixSocketRawData* data = new UnixSocketRawData((const void *)&response, 1); - mStreamSocket->SendSocketData(data); -} - -// Data response -void -KeyStore::SendData(const uint8_t *aData, int aLength) -{ - MOZ_ASSERT(mStreamSocket); - - unsigned short dataLength = htons(aLength); - - UnixSocketRawData* length = new UnixSocketRawData((const void *)&dataLength, 2); - mStreamSocket->SendSocketData(length); - - UnixSocketRawData* data = new UnixSocketRawData((const void *)aData, aLength); - mStreamSocket->SendSocketData(data); -} - -// |StreamSocketConsumer|, |ListenSocketConsumer| - -void -KeyStore::ReceiveSocketData(int aIndex, UniquePtr<UnixSocketBuffer>& aMessage) -{ - MOZ_ASSERT(NS_IsMainThread()); - - // Handle request. - ResponseCode result = SUCCESS; - while (aMessage->GetSize() || - mHandlerInfo.state == STATE_PROCESSING) { - switch (mHandlerInfo.state) { - case STATE_IDLE: - result = ReadCommand(aMessage.get()); - break; - case STATE_READ_PARAM_LEN: - result = ReadLength(aMessage.get()); - break; - case STATE_READ_PARAM_DATA: - result = ReadData(aMessage.get()); - break; - case STATE_PROCESSING: - if (mHandlerInfo.command == 'g') { - result = SYSTEM_ERROR; - - nsNSSShutDownPreventionLock locker; - if (isAlreadyShutDown()) { - break; - } - - // Get CA - const uint8_t *data; - size_t dataLength; - const char *name = (const char *)mHandlerInfo.param[0].data; - - if (!strncmp(name, "WIFI_USERKEY_", 13)) { - result = getPrivateKey(name, &data, &dataLength); - } else { - result = getCertificate(name, &data, &dataLength); - } - if (result != SUCCESS) { - break; - } - - SendResponse(SUCCESS); - SendData(data, (int)dataLength); - - free((void *)data); - } - - ResetHandlerInfo(); - break; - } - - if (result != SUCCESS) { - SendResponse(result); - ResetHandlerInfo(); - return; - } - } -} - -void -KeyStore::OnConnectSuccess(int aIndex) -{ - if (aIndex == STREAM_SOCKET) { - mShutdown = false; - } -} - -void -KeyStore::OnConnectError(int aIndex) -{ - if (mShutdown) { - return; - } - - if (aIndex == STREAM_SOCKET) { - // Stream socket error; start listening again - Listen(); - } -} - -void -KeyStore::OnDisconnect(int aIndex) -{ - if (mShutdown) { - return; - } - - switch (aIndex) { - case LISTEN_SOCKET: - // Listen socket disconnected; start anew. - mListenSocket = nullptr; - Listen(); - break; - case STREAM_SOCKET: - // Stream socket disconnected; start listening again. - Listen(); - break; - } -} - -} // namespace ipc -} // namespace mozilla diff --git a/ipc/keystore/KeyStore.h b/ipc/keystore/KeyStore.h deleted file mode 100644 index c6bb09023..000000000 --- a/ipc/keystore/KeyStore.h +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=2 et ft=cpp: tw=80: */ -/* 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 <sys/socket.h> -#include <sys/un.h> -#include "cert.h" -#include "mozilla/ipc/ListenSocket.h" -#include "mozilla/ipc/ListenSocketConsumer.h" -#include "mozilla/ipc/StreamSocket.h" -#include "mozilla/ipc/StreamSocketConsumer.h" -#include "nsNSSShutDown.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 -}; - -void FormatCaData(const uint8_t *aCaData, int aCaDataLength, - const char *aName, const uint8_t **aFormatData, - size_t *aFormatDataLength); - -ResponseCode getCertificate(const char *aCertName, const uint8_t **aCertData, - size_t *aCertDataLength); -ResponseCode getPrivateKey(const char *aKeyName, const uint8_t **aKeyData, - size_t *aKeyDataLength); -ResponseCode getPublicKey(const char *aKeyName, const uint8_t **aKeyData, - size_t *aKeyDataLength); -ResponseCode signData(const char *aKeyName, const uint8_t *data, size_t length, - uint8_t **out, size_t *outLength); - -bool checkPermission(uid_t uid); - -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 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 KeyStore final - : public StreamSocketConsumer - , public ListenSocketConsumer - , public nsNSSShutDownObject -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(KeyStore) - - KeyStore(); - - void Shutdown(); - -protected: - virtual void virtualDestroyNSSReference() {} - -private: - enum SocketType { - LISTEN_SOCKET, - STREAM_SOCKET - }; - - ~KeyStore(); - - struct { - ProtocolHandlerState state; - uint8_t command; - struct ProtocolParam param[MAX_PARAM]; - int paramCount; - const struct ProtocolCommand *commandPattern; - } mHandlerInfo; - void ResetHandlerInfo(); - void Listen(); - - bool CheckSize(UnixSocketBuffer *aMessage, size_t aExpectSize); - ResponseCode ReadCommand(UnixSocketBuffer *aMessage); - ResponseCode ReadLength(UnixSocketBuffer *aMessage); - ResponseCode ReadData(UnixSocketBuffer *aMessage); - void SendResponse(ResponseCode response); - void SendData(const uint8_t *data, int length); - - // Methods for |StreamSocketConsumer| - // - - void ReceiveSocketData(int aIndex, - UniquePtr<UnixSocketBuffer>& aMessage) override; - void OnConnectSuccess(int aIndex) override; - void OnConnectError(int aIndex) override; - void OnDisconnect(int aIndex) override; - - bool mShutdown; - - RefPtr<ListenSocket> mListenSocket; - RefPtr<StreamSocket> mStreamSocket; -}; - -} // namespace ipc -} // namespace mozilla - -#endif // mozilla_ipc_KeyStore_h diff --git a/ipc/keystore/KeyStoreConnector.cpp b/ipc/keystore/KeyStoreConnector.cpp deleted file mode 100644 index 4baf14175..000000000 --- a/ipc/keystore/KeyStoreConnector.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=2 et ft=cpp: tw=80: */ - -/* 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 "KeyStoreConnector.h" -#include <fcntl.h> -#include <pwd.h> -#include <sys/stat.h> -#include <sys/un.h> -#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR -#include "nsThreadUtils.h" // For NS_IsMainThread. - -#define KEYSTORE_LOG(args...) printf(args); - -namespace mozilla { -namespace ipc { - -static const char KEYSTORE_SOCKET_PATH[] = "/dev/socket/keystore"; - -KeyStoreConnector::KeyStoreConnector(const char** const aAllowedUsers) - : mAllowedUsers(aAllowedUsers) -{ - MOZ_COUNT_CTOR_INHERITED(KeyStoreConnector, UnixSocketConnector); -} - -KeyStoreConnector::~KeyStoreConnector() -{ - MOZ_COUNT_DTOR_INHERITED(KeyStoreConnector, UnixSocketConnector); -} - -nsresult -KeyStoreConnector::CreateSocket(int& aFd) const -{ - unlink(KEYSTORE_SOCKET_PATH); - - aFd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (aFd < 0) { - KEYSTORE_LOG("Could not open KeyStore socket!"); - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - -nsresult -KeyStoreConnector::SetSocketFlags(int aFd) const -{ - static const int sReuseAddress = 1; - - // Set close-on-exec bit. - int flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFD)); - if (flags < 0) { - return NS_ERROR_FAILURE; - } - flags |= FD_CLOEXEC; - int res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFD, flags)); - if (res < 0) { - return NS_ERROR_FAILURE; - } - - // Set non-blocking status flag. - flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFL)); - if (flags < 0) { - return NS_ERROR_FAILURE; - } - flags |= O_NONBLOCK; - res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, flags)); - if (res < 0) { - return NS_ERROR_FAILURE; - } - - // Set socket addr to be reused even if kernel is still waiting to close. - res = setsockopt(aFd, SOL_SOCKET, SO_REUSEADDR, &sReuseAddress, - sizeof(sReuseAddress)); - if (res < 0) { - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - -nsresult -KeyStoreConnector::CheckPermission(int aFd) const -{ - struct ucred userCred; - socklen_t len = sizeof(userCred); - - if (getsockopt(aFd, SOL_SOCKET, SO_PEERCRED, &userCred, &len)) { - return NS_ERROR_FAILURE; - } - - const struct passwd* userInfo = getpwuid(userCred.uid); - if (!userInfo) { - return NS_ERROR_FAILURE; - } - - if (!mAllowedUsers) { - return NS_ERROR_FAILURE; - } - - for (const char** user = mAllowedUsers; *user; ++user) { - if (!strcmp(*user, userInfo->pw_name)) { - return NS_OK; - } - } - - return NS_ERROR_FAILURE; -} - -nsresult -KeyStoreConnector::CreateAddress(struct sockaddr& aAddress, - socklen_t& aAddressLength) const -{ - struct sockaddr_un* address = - reinterpret_cast<struct sockaddr_un*>(&aAddress); - - size_t namesiz = strlen(KEYSTORE_SOCKET_PATH) + 1; // include trailing '\0' - - if (namesiz > sizeof(address->sun_path)) { - KEYSTORE_LOG("Address too long for socket struct!"); - return NS_ERROR_FAILURE; - } - - address->sun_family = AF_UNIX; - memcpy(address->sun_path, KEYSTORE_SOCKET_PATH, namesiz); - - aAddressLength = offsetof(struct sockaddr_un, sun_path) + namesiz; - - return NS_OK; -} - -// |UnixSocketConnector| - -nsresult -KeyStoreConnector::ConvertAddressToString(const struct sockaddr& aAddress, - socklen_t aAddressLength, - nsACString& aAddressString) -{ - MOZ_ASSERT(aAddress.sa_family == AF_UNIX); - - const struct sockaddr_un* un = - reinterpret_cast<const struct sockaddr_un*>(&aAddress); - - size_t len = aAddressLength - offsetof(struct sockaddr_un, sun_path); - - aAddressString.Assign(un->sun_path, len); - - return NS_OK; -} - -nsresult -KeyStoreConnector::CreateListenSocket(struct sockaddr* aAddress, - socklen_t* aAddressLength, - int& aListenFd) -{ - ScopedClose fd; - - nsresult rv = CreateSocket(fd.rwget()); - if (NS_FAILED(rv)) { - return rv; - } - rv = SetSocketFlags(fd); - if (NS_FAILED(rv)) { - return rv; - } - if (aAddress && aAddressLength) { - rv = CreateAddress(*aAddress, *aAddressLength); - if (NS_FAILED(rv)) { - return rv; - } - } - - // Allow access for wpa_supplicant (different user, different group) - // - // TODO: Improve this by setting specific user/group for - // wpa_supplicant by calling |fchmod| and |fchown|. - // - chmod(KEYSTORE_SOCKET_PATH, S_IRUSR|S_IWUSR| - S_IRGRP|S_IWGRP| - S_IROTH|S_IWOTH); - - aListenFd = fd.forget(); - - return NS_OK; -} - -nsresult -KeyStoreConnector::AcceptStreamSocket(int aListenFd, - struct sockaddr* aAddress, - socklen_t* aAddressLength, - int& aStreamFd) -{ - ScopedClose fd( - TEMP_FAILURE_RETRY(accept(aListenFd, aAddress, aAddressLength))); - if (fd < 0) { - NS_WARNING("Cannot accept file descriptor!"); - return NS_ERROR_FAILURE; - } - nsresult rv = SetSocketFlags(fd); - if (NS_FAILED(rv)) { - return rv; - } - rv = CheckPermission(fd); - if (NS_FAILED(rv)) { - return rv; - } - - aStreamFd = fd.forget(); - - return NS_OK; -} - -nsresult -KeyStoreConnector::CreateStreamSocket(struct sockaddr* aAddress, - socklen_t* aAddressLength, - int& aStreamFd) -{ - MOZ_CRASH("|KeyStoreConnector| does not support creating stream sockets."); - return NS_ERROR_FAILURE; -} - -nsresult -KeyStoreConnector::Duplicate(UnixSocketConnector*& aConnector) -{ - aConnector = new KeyStoreConnector(*this); - - return NS_OK; -} - -} -} diff --git a/ipc/keystore/KeyStoreConnector.h b/ipc/keystore/KeyStoreConnector.h deleted file mode 100644 index 349b030de..000000000 --- a/ipc/keystore/KeyStoreConnector.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=2 et ft=cpp: tw=80: */ - -/* 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_KeyStoreConnector_h -#define mozilla_ipc_KeyStoreConnector_h - -#include "mozilla/ipc/UnixSocketConnector.h" - -namespace mozilla { -namespace ipc { - -class KeyStoreConnector final : public UnixSocketConnector -{ -public: - KeyStoreConnector(const char** const aAllowedUsers); - ~KeyStoreConnector(); - - // Methods for |UnixSocketConnector| - // - - nsresult ConvertAddressToString(const struct sockaddr& aAddress, - socklen_t aAddressLength, - nsACString& aAddressString) override; - - nsresult CreateListenSocket(struct sockaddr* aAddress, - socklen_t* aAddressLength, - int& aListenFd) override; - - nsresult AcceptStreamSocket(int aListenFd, - struct sockaddr* aAddress, - socklen_t* aAddressLength, - int& aStreamFd) override; - - nsresult CreateStreamSocket(struct sockaddr* aAddress, - socklen_t* aAddressLength, - int& aStreamFd) override; - - nsresult Duplicate(UnixSocketConnector*& aConnector) override; - -private: - nsresult CreateSocket(int& aFd) const; - nsresult SetSocketFlags(int aFd) const; - nsresult CheckPermission(int aFd) const; - nsresult CreateAddress(struct sockaddr& aAddress, - socklen_t& aAddressLength) const; - - const char** const mAllowedUsers; -}; - -} -} - -#endif diff --git a/ipc/keystore/moz.build b/ipc/keystore/moz.build deleted file mode 100644 index e5df10a30..000000000 --- a/ipc/keystore/moz.build +++ /dev/null @@ -1,18 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -EXPORTS.mozilla.ipc += [ - 'KeyStore.h' -] - -SOURCES += [ - 'KeyStore.cpp', - 'KeyStoreConnector.cpp' -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' |