mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1012549 - 0004. Support read private key in keystore. r=dkeeler r=qdot
This commit is contained in:
parent
d99d66578e
commit
ac72d5e34a
2
config/external/nss/nss.def
vendored
2
config/external/nss/nss.def
vendored
@ -317,6 +317,7 @@ PK11_DigestOp
|
|||||||
PK11_DoesMechanism
|
PK11_DoesMechanism
|
||||||
PK11_Encrypt
|
PK11_Encrypt
|
||||||
PK11_ExportDERPrivateKeyInfo
|
PK11_ExportDERPrivateKeyInfo
|
||||||
|
PK11_ExportEncryptedPrivKeyInfo
|
||||||
PK11_ExtractKeyValue
|
PK11_ExtractKeyValue
|
||||||
PK11_FindCertFromNickname
|
PK11_FindCertFromNickname
|
||||||
PK11_FindCertsFromEmailAddress
|
PK11_FindCertsFromEmailAddress
|
||||||
@ -512,6 +513,7 @@ SECKEY_CopyPublicKey
|
|||||||
SECKEY_CopySubjectPublicKeyInfo
|
SECKEY_CopySubjectPublicKeyInfo
|
||||||
SECKEY_CreateSubjectPublicKeyInfo
|
SECKEY_CreateSubjectPublicKeyInfo
|
||||||
SECKEY_DecodeDERSubjectPublicKeyInfo
|
SECKEY_DecodeDERSubjectPublicKeyInfo
|
||||||
|
SECKEY_DestroyEncryptedPrivateKeyInfo
|
||||||
SECKEY_DestroyPrivateKey
|
SECKEY_DestroyPrivateKey
|
||||||
SECKEY_DestroyPrivateKeyList
|
SECKEY_DestroyPrivateKeyList
|
||||||
SECKEY_DestroyPublicKey
|
SECKEY_DestroyPublicKey
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "KeyStore.h"
|
#include "KeyStore.h"
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
#include "MainThreadUtils.h" // For NS_IsMainThread.
|
#include "MainThreadUtils.h" // For NS_IsMainThread.
|
||||||
|
#include "nsICryptoHash.h"
|
||||||
|
|
||||||
#include "plbase64.h"
|
#include "plbase64.h"
|
||||||
#include "certdb.h"
|
#include "certdb.h"
|
||||||
@ -108,19 +109,65 @@ status_t BnKeystoreService::onTransact(uint32_t code, const Parcel& data, Parcel
|
|||||||
reply->writeInt32(dataLength);
|
reply->writeInt32(dataLength);
|
||||||
void* buf = reply->writeInplace(dataLength);
|
void* buf = reply->writeInplace(dataLength);
|
||||||
memcpy(buf, data, dataLength);
|
memcpy(buf, data, dataLength);
|
||||||
free(data);
|
moz_free(data);
|
||||||
} else {
|
} else {
|
||||||
reply->writeInt32(-1);
|
reply->writeInt32(-1);
|
||||||
}
|
}
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
} break;
|
} 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);
|
||||||
|
moz_free(data);
|
||||||
|
} else {
|
||||||
|
reply->writeInt32(-1);
|
||||||
|
}
|
||||||
|
reply->writeInt32(ret);
|
||||||
|
return NO_ERROR;
|
||||||
|
} break;
|
||||||
|
case SIGN: {
|
||||||
|
CHECK_INTERFACE(IKeystoreService, data, reply);
|
||||||
|
String16 name = data.readString16();
|
||||||
|
size_t signDataSize = data.readInt32();
|
||||||
|
const uint8_t *signData = nullptr;
|
||||||
|
if (signDataSize >= 0 && signDataSize <= data.dataAvail()) {
|
||||||
|
signData = (const uint8_t *)data.readInplace(signDataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *signResult = nullptr;
|
||||||
|
size_t signResultSize;
|
||||||
|
int32_t ret = sign(name, signData, signDataSize, &signResult,
|
||||||
|
&signResultSize);
|
||||||
|
|
||||||
|
reply->writeNoException();
|
||||||
|
if (signResultSize > 0 && signResult != nullptr) {
|
||||||
|
reply->writeInt32(signResultSize);
|
||||||
|
void* buf = reply->writeInplace(signResultSize);
|
||||||
|
memcpy(buf, signResult, signResultSize);
|
||||||
|
moz_free(signResult);
|
||||||
|
} else {
|
||||||
|
reply->writeInt32(-1);
|
||||||
|
}
|
||||||
|
reply->writeInt32(ret);
|
||||||
|
return NO_ERROR;
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide service for binder.
|
// Provide service for binder.
|
||||||
class KeyStoreService: public BnKeystoreService
|
class KeyStoreService : public BnKeystoreService
|
||||||
|
, public nsNSSShutDownObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int32_t test() {
|
int32_t test() {
|
||||||
@ -133,13 +180,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {
|
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();
|
uid_t callingUid = IPCThreadState::self()->getCallingUid();
|
||||||
if (!mozilla::ipc::checkPermission(callingUid)) {
|
if (!mozilla::ipc::checkPermission(callingUid)) {
|
||||||
return ::PERMISSION_DENIED;
|
return ::PERMISSION_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
String8 certName(name);
|
String8 certName(name);
|
||||||
return mozilla::ipc::getCertificate(certName.string(), (const uint8_t **)item, (int *)itemLength);
|
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 insert(const String16& name, const uint8_t* item, size_t itemLength, int uid, int32_t flags) {return ::UNDEFINED_ACTION;}
|
||||||
@ -152,9 +208,50 @@ public:
|
|||||||
int32_t unlock(const String16& password) {return ::UNDEFINED_ACTION;}
|
int32_t unlock(const String16& password) {return ::UNDEFINED_ACTION;}
|
||||||
int32_t zero() {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 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) {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 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) {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 del_key(const String16& name, int uid) {return ::UNDEFINED_ACTION;}
|
||||||
int32_t grant(const String16& name, int32_t granteeUid) {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;}
|
int32_t ungrant(const String16& name, int32_t granteeUid) {return ::UNDEFINED_ACTION;}
|
||||||
@ -174,6 +271,18 @@ public:
|
|||||||
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 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 is_hardware_backed(const String16& keyType) {return ::UNDEFINED_ACTION;}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void virtualDestroyNSSReference() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~KeyStoreService() {
|
||||||
|
nsNSSShutDownPreventionLock locker;
|
||||||
|
if (isAlreadyShutDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
shutdown(calledFromObject);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
@ -210,19 +319,24 @@ static const char* KEYSTORE_ALLOWED_PREFIXES[] = {
|
|||||||
|
|
||||||
// Transform base64 certification data into DER format
|
// Transform base64 certification data into DER format
|
||||||
void
|
void
|
||||||
FormatCaData(const uint8_t *aCaData, int aCaDataLength,
|
FormatCaData(const char *aCaData, int aCaDataLength,
|
||||||
const char *aName, const uint8_t **aFormatData,
|
const char *aName, const uint8_t **aFormatData,
|
||||||
int *aFormatDataLength)
|
size_t *aFormatDataLength)
|
||||||
{
|
{
|
||||||
int bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 +
|
size_t bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 +
|
||||||
strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE + 2;
|
strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE
|
||||||
char *buf = (char *)malloc(bufSize);
|
+ 2;
|
||||||
|
char *buf = (char *)moz_malloc(bufSize);
|
||||||
|
if (!buf) {
|
||||||
|
*aFormatData = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
*aFormatDataLength = bufSize;
|
*aFormatDataLength = bufSize;
|
||||||
*aFormatData = (const uint8_t *)buf;
|
*aFormatData = (const uint8_t *)buf;
|
||||||
|
|
||||||
char *ptr = buf;
|
char *ptr = buf;
|
||||||
int len;
|
size_t len;
|
||||||
|
|
||||||
// Create DER header.
|
// Create DER header.
|
||||||
len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER);
|
len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER);
|
||||||
@ -250,7 +364,8 @@ FormatCaData(const uint8_t *aCaData, int aCaDataLength,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResponseCode
|
ResponseCode
|
||||||
getCertificate(const char *aCertName, const uint8_t **aCertData, int *aCertDataLength)
|
getCertificate(const char *aCertName, const uint8_t **aCertData,
|
||||||
|
size_t *aCertDataLength)
|
||||||
{
|
{
|
||||||
// certificate name prefix check.
|
// certificate name prefix check.
|
||||||
if (!aCertName) {
|
if (!aCertName) {
|
||||||
@ -281,10 +396,266 @@ getCertificate(const char *aCertName, const uint8_t **aCertData, int *aCertDataL
|
|||||||
return SYSTEM_ERROR;
|
return SYSTEM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
FormatCaData((const uint8_t *)certDER, strlen(certDER), "CERTIFICATE",
|
FormatCaData(certDER, strlen(certDER), "CERTIFICATE", aCertData,
|
||||||
aCertData, aCertDataLength);
|
aCertDataLength);
|
||||||
PL_strfree(certDER);
|
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 *)moz_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 *)moz_malloc(signItem->len);
|
||||||
|
if (!buf) {
|
||||||
|
return SYSTEM_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf, signItem->data, signItem->len);
|
||||||
|
*out = buf;
|
||||||
|
*outLength = signItem->len;
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,8 +836,15 @@ KeyStore::KeyStore()
|
|||||||
|
|
||||||
KeyStore::~KeyStore()
|
KeyStore::~KeyStore()
|
||||||
{
|
{
|
||||||
|
nsNSSShutDownPreventionLock locker;
|
||||||
MOZ_COUNT_DTOR(KeyStore);
|
MOZ_COUNT_DTOR(KeyStore);
|
||||||
|
|
||||||
|
if (isAlreadyShutDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown(calledFromObject);
|
||||||
|
|
||||||
MOZ_ASSERT(!mListenSocket);
|
MOZ_ASSERT(!mListenSocket);
|
||||||
MOZ_ASSERT(!mStreamSocket);
|
MOZ_ASSERT(!mStreamSocket);
|
||||||
}
|
}
|
||||||
@ -671,20 +1049,31 @@ KeyStore::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
|
|||||||
break;
|
break;
|
||||||
case STATE_PROCESSING:
|
case STATE_PROCESSING:
|
||||||
if (mHandlerInfo.command == 'g') {
|
if (mHandlerInfo.command == 'g') {
|
||||||
// Get CA
|
result = SYSTEM_ERROR;
|
||||||
const uint8_t *certData;
|
|
||||||
int certDataLength;
|
|
||||||
const char *certName = (const char *)mHandlerInfo.param[0].data;
|
|
||||||
|
|
||||||
result = getCertificate(certName, &certData, &certDataLength);
|
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) {
|
if (result != SUCCESS) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendResponse(SUCCESS);
|
SendResponse(SUCCESS);
|
||||||
SendData(certData, certDataLength);
|
SendData(data, (int)dataLength);
|
||||||
|
|
||||||
free((void *)certData);
|
moz_free((void *)data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResetHandlerInfo();
|
ResetHandlerInfo();
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "mozilla/ipc/ListenSocket.h"
|
#include "mozilla/ipc/ListenSocket.h"
|
||||||
#include "mozilla/ipc/StreamSocket.h"
|
#include "mozilla/ipc/StreamSocket.h"
|
||||||
#include "mozilla/ipc/UnixSocketConnector.h"
|
#include "mozilla/ipc/UnixSocketConnector.h"
|
||||||
|
#include "nsNSSShutDown.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
@ -36,10 +37,16 @@ enum ResponseCode {
|
|||||||
|
|
||||||
void FormatCaData(const uint8_t *aCaData, int aCaDataLength,
|
void FormatCaData(const uint8_t *aCaData, int aCaDataLength,
|
||||||
const char *aName, const uint8_t **aFormatData,
|
const char *aName, const uint8_t **aFormatData,
|
||||||
int *aFormatDataLength);
|
size_t *aFormatDataLength);
|
||||||
|
|
||||||
ResponseCode getCertificate(const char *aCertName, const uint8_t **aCertData,
|
ResponseCode getCertificate(const char *aCertName, const uint8_t **aCertData,
|
||||||
int *aCertDataLength);
|
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);
|
bool checkPermission(uid_t uid);
|
||||||
|
|
||||||
@ -92,7 +99,7 @@ public:
|
|||||||
nsAString& aAddrStr);
|
nsAString& aAddrStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeyStore MOZ_FINAL
|
class KeyStore MOZ_FINAL : public nsNSSShutDownObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(KeyStore)
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(KeyStore)
|
||||||
@ -101,6 +108,9 @@ public:
|
|||||||
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void virtualDestroyNSSReference() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum SocketType {
|
enum SocketType {
|
||||||
LISTEN_SOCKET,
|
LISTEN_SOCKET,
|
||||||
|
@ -311,6 +311,11 @@ inline void SECOID_DestroyAlgorithmID_true(SECAlgorithmID * a)
|
|||||||
return SECOID_DestroyAlgorithmID(a, true);
|
return SECOID_DestroyAlgorithmID(a, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void SECKEYEncryptedPrivateKeyInfo_true(SECKEYEncryptedPrivateKeyInfo * epki)
|
||||||
|
{
|
||||||
|
return SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECItem,
|
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECItem,
|
||||||
@ -320,6 +325,9 @@ MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECItem,
|
|||||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPrivateKey,
|
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPrivateKey,
|
||||||
SECKEYPrivateKey,
|
SECKEYPrivateKey,
|
||||||
SECKEY_DestroyPrivateKey)
|
SECKEY_DestroyPrivateKey)
|
||||||
|
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYEncryptedPrivateKeyInfo,
|
||||||
|
SECKEYEncryptedPrivateKeyInfo,
|
||||||
|
internal::SECKEYEncryptedPrivateKeyInfo_true)
|
||||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPublicKey,
|
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSECKEYPublicKey,
|
||||||
SECKEYPublicKey,
|
SECKEYPublicKey,
|
||||||
SECKEY_DestroyPublicKey)
|
SECKEY_DestroyPublicKey)
|
||||||
|
Loading…
Reference in New Issue
Block a user