michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsIIdentityCryptoService.h" michael@0: #include "mozilla/ModuleUtils.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsNSSShutDown.h" michael@0: #include "nsIThread.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsProxyRelease.h" michael@0: #include "nsString.h" michael@0: #include "mozilla/ArrayUtils.h" // ArrayLength michael@0: #include "mozilla/Base64.h" michael@0: #include "ScopedNSSTypes.h" michael@0: michael@0: #include "nss.h" michael@0: #include "pk11pub.h" michael@0: #include "secmod.h" michael@0: #include "secerr.h" michael@0: #include "keyhi.h" michael@0: #include "cryptohi.h" michael@0: michael@0: #include michael@0: michael@0: using namespace mozilla; michael@0: michael@0: namespace { michael@0: michael@0: void michael@0: HexEncode(const SECItem * it, nsACString & result) michael@0: { michael@0: const char * digits = "0123456789ABCDEF"; michael@0: result.SetCapacity((it->len * 2) + 1); michael@0: result.SetLength(it->len * 2); michael@0: char * p = result.BeginWriting(); michael@0: for (unsigned int i = 0; i < it->len; ++i) { michael@0: *p++ = digits[it->data[i] >> 4]; michael@0: *p++ = digits[it->data[i] & 0x0f]; michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: Base64UrlEncodeImpl(const nsACString & utf8Input, nsACString & result) michael@0: { michael@0: nsresult rv = Base64Encode(utf8Input, result); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsACString::char_type * out = result.BeginWriting(); michael@0: nsACString::size_type length = result.Length(); michael@0: // base64url encoding is defined in RFC 4648. It replaces the last two michael@0: // alphabet characters of base64 encoding with '-' and '_' respectively. michael@0: for (unsigned int i = 0; i < length; ++i) { michael@0: if (out[i] == '+') { michael@0: out[i] = '-'; michael@0: } else if (out[i] == '/') { michael@0: out[i] = '_'; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: #define DSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("DS160")) michael@0: #define RSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("RS256")) michael@0: michael@0: class KeyPair : public nsIIdentityKeyPair, public nsNSSShutDownObject michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIIDENTITYKEYPAIR michael@0: michael@0: KeyPair(SECKEYPrivateKey* aPrivateKey, SECKEYPublicKey* aPublicKey); michael@0: michael@0: private: michael@0: ~KeyPair() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: destructorSafeDestroyNSSReference(); michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: void virtualDestroyNSSReference() MOZ_OVERRIDE michael@0: { michael@0: destructorSafeDestroyNSSReference(); michael@0: } michael@0: michael@0: void destructorSafeDestroyNSSReference() michael@0: { michael@0: SECKEY_DestroyPrivateKey(mPrivateKey); michael@0: mPrivateKey = nullptr; michael@0: SECKEY_DestroyPublicKey(mPublicKey); michael@0: mPublicKey = nullptr; michael@0: } michael@0: michael@0: SECKEYPrivateKey * mPrivateKey; michael@0: SECKEYPublicKey * mPublicKey; michael@0: michael@0: KeyPair(const KeyPair &) MOZ_DELETE; michael@0: void operator=(const KeyPair &) MOZ_DELETE; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(KeyPair, nsIIdentityKeyPair) michael@0: michael@0: class KeyGenRunnable : public nsRunnable, public nsNSSShutDownObject michael@0: { michael@0: public: michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: KeyGenRunnable(KeyType keyType, nsIIdentityKeyGenCallback * aCallback); michael@0: michael@0: private: michael@0: ~KeyGenRunnable() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: destructorSafeDestroyNSSReference(); michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: virtual void virtualDestroyNSSReference() MOZ_OVERRIDE michael@0: { michael@0: destructorSafeDestroyNSSReference(); michael@0: } michael@0: michael@0: void destructorSafeDestroyNSSReference() michael@0: { michael@0: } michael@0: michael@0: const KeyType mKeyType; // in michael@0: nsMainThreadPtrHandle mCallback; // in michael@0: nsresult mRv; // out michael@0: nsCOMPtr mKeyPair; // out michael@0: michael@0: KeyGenRunnable(const KeyGenRunnable &) MOZ_DELETE; michael@0: void operator=(const KeyGenRunnable &) MOZ_DELETE; michael@0: }; michael@0: michael@0: class SignRunnable : public nsRunnable, public nsNSSShutDownObject michael@0: { michael@0: public: michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: SignRunnable(const nsACString & textToSign, SECKEYPrivateKey * privateKey, michael@0: nsIIdentitySignCallback * aCallback); michael@0: michael@0: private: michael@0: ~SignRunnable() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: destructorSafeDestroyNSSReference(); michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: void virtualDestroyNSSReference() MOZ_OVERRIDE michael@0: { michael@0: destructorSafeDestroyNSSReference(); michael@0: } michael@0: michael@0: void destructorSafeDestroyNSSReference() michael@0: { michael@0: SECKEY_DestroyPrivateKey(mPrivateKey); michael@0: mPrivateKey = nullptr; michael@0: } michael@0: michael@0: const nsCString mTextToSign; // in michael@0: SECKEYPrivateKey* mPrivateKey; // in michael@0: nsMainThreadPtrHandle mCallback; // in michael@0: nsresult mRv; // out michael@0: nsCString mSignature; // out michael@0: michael@0: private: michael@0: SignRunnable(const SignRunnable &) MOZ_DELETE; michael@0: void operator=(const SignRunnable &) MOZ_DELETE; michael@0: }; michael@0: michael@0: class IdentityCryptoService MOZ_FINAL : public nsIIdentityCryptoService michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIIDENTITYCRYPTOSERVICE michael@0: michael@0: IdentityCryptoService() { } michael@0: nsresult Init() michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr dummyUsedToEnsureNSSIsInitialized michael@0: = do_GetService("@mozilla.org/psm;1", &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: IdentityCryptoService(const KeyPair &) MOZ_DELETE; michael@0: void operator=(const IdentityCryptoService &) MOZ_DELETE; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(IdentityCryptoService, nsIIdentityCryptoService) michael@0: michael@0: NS_IMETHODIMP michael@0: IdentityCryptoService::GenerateKeyPair( michael@0: const nsACString & keyTypeString, nsIIdentityKeyGenCallback * callback) michael@0: { michael@0: KeyType keyType; michael@0: if (keyTypeString.Equals(RSA_KEY_TYPE_STRING)) { michael@0: keyType = rsaKey; michael@0: } else if (keyTypeString.Equals(DSA_KEY_TYPE_STRING)) { michael@0: keyType = dsaKey; michael@0: } else { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: nsCOMPtr r = new KeyGenRunnable(keyType, callback); michael@0: nsCOMPtr thread; michael@0: nsresult rv = NS_NewThread(getter_AddRefs(thread), r); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: IdentityCryptoService::Base64UrlEncode(const nsACString & utf8Input, michael@0: nsACString & result) michael@0: { michael@0: return Base64UrlEncodeImpl(utf8Input, result); michael@0: } michael@0: michael@0: KeyPair::KeyPair(SECKEYPrivateKey * privateKey, SECKEYPublicKey * publicKey) michael@0: : mPrivateKey(privateKey) michael@0: , mPublicKey(publicKey) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: KeyPair::GetHexRSAPublicKeyExponent(nsACString & result) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); michael@0: NS_ENSURE_TRUE(mPublicKey->keyType == rsaKey, NS_ERROR_NOT_AVAILABLE); michael@0: HexEncode(&mPublicKey->u.rsa.publicExponent, result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: KeyPair::GetHexRSAPublicKeyModulus(nsACString & result) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); michael@0: NS_ENSURE_TRUE(mPublicKey->keyType == rsaKey, NS_ERROR_NOT_AVAILABLE); michael@0: HexEncode(&mPublicKey->u.rsa.modulus, result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: KeyPair::GetHexDSAPrime(nsACString & result) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); michael@0: NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); michael@0: HexEncode(&mPublicKey->u.dsa.params.prime, result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: KeyPair::GetHexDSASubPrime(nsACString & result) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); michael@0: NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); michael@0: HexEncode(&mPublicKey->u.dsa.params.subPrime, result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: KeyPair::GetHexDSAGenerator(nsACString & result) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); michael@0: NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); michael@0: HexEncode(&mPublicKey->u.dsa.params.base, result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: KeyPair::GetHexDSAPublicValue(nsACString & result) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); michael@0: NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); michael@0: HexEncode(&mPublicKey->u.dsa.publicValue, result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: KeyPair::GetKeyType(nsACString & result) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: switch (mPublicKey->keyType) { michael@0: case rsaKey: result = RSA_KEY_TYPE_STRING; return NS_OK; michael@0: case dsaKey: result = DSA_KEY_TYPE_STRING; return NS_OK; michael@0: default: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: KeyPair::Sign(const nsACString & textToSign, michael@0: nsIIdentitySignCallback* callback) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: nsCOMPtr r = new SignRunnable(textToSign, mPrivateKey, michael@0: callback); michael@0: michael@0: nsCOMPtr thread; michael@0: nsresult rv = NS_NewThread(getter_AddRefs(thread), r); michael@0: return rv; michael@0: } michael@0: michael@0: KeyGenRunnable::KeyGenRunnable(KeyType keyType, michael@0: nsIIdentityKeyGenCallback * callback) michael@0: : mKeyType(keyType) michael@0: , mCallback(new nsMainThreadPtrHolder(callback)) michael@0: , mRv(NS_ERROR_NOT_INITIALIZED) michael@0: { michael@0: } michael@0: michael@0: MOZ_WARN_UNUSED_RESULT nsresult michael@0: GenerateKeyPair(PK11SlotInfo * slot, michael@0: SECKEYPrivateKey ** privateKey, michael@0: SECKEYPublicKey ** publicKey, michael@0: CK_MECHANISM_TYPE mechanism, michael@0: void * params) michael@0: { michael@0: *publicKey = nullptr; michael@0: *privateKey = PK11_GenerateKeyPair(slot, mechanism, params, publicKey, michael@0: PR_FALSE /*isPerm*/, michael@0: PR_TRUE /*isSensitive*/, michael@0: nullptr /*&pwdata*/); michael@0: if (!*privateKey) { michael@0: MOZ_ASSERT(!*publicKey); michael@0: return PRErrorCode_to_nsresult(PR_GetError()); michael@0: } michael@0: if (!*publicKey) { michael@0: SECKEY_DestroyPrivateKey(*privateKey); michael@0: *privateKey = nullptr; michael@0: MOZ_CRASH("PK11_GnerateKeyPair returned private key without public key"); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: MOZ_WARN_UNUSED_RESULT nsresult michael@0: GenerateRSAKeyPair(PK11SlotInfo * slot, michael@0: SECKEYPrivateKey ** privateKey, michael@0: SECKEYPublicKey ** publicKey) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: PK11RSAGenParams rsaParams; michael@0: rsaParams.keySizeInBits = 2048; michael@0: rsaParams.pe = 0x10001; michael@0: return GenerateKeyPair(slot, privateKey, publicKey, CKM_RSA_PKCS_KEY_PAIR_GEN, michael@0: &rsaParams); michael@0: } michael@0: michael@0: MOZ_WARN_UNUSED_RESULT nsresult michael@0: GenerateDSAKeyPair(PK11SlotInfo * slot, michael@0: SECKEYPrivateKey ** privateKey, michael@0: SECKEYPublicKey ** publicKey) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: // XXX: These could probably be static const arrays, but this way we avoid michael@0: // compiler warnings and also we avoid having to worry much about whether the michael@0: // functions that take these inputs will (unexpectedly) modify them. michael@0: michael@0: // Using NIST parameters. Some other BrowserID components require that these michael@0: // exact parameters are used. michael@0: uint8_t P[] = { michael@0: 0xFF,0x60,0x04,0x83,0xDB,0x6A,0xBF,0xC5,0xB4,0x5E,0xAB,0x78, michael@0: 0x59,0x4B,0x35,0x33,0xD5,0x50,0xD9,0xF1,0xBF,0x2A,0x99,0x2A, michael@0: 0x7A,0x8D,0xAA,0x6D,0xC3,0x4F,0x80,0x45,0xAD,0x4E,0x6E,0x0C, michael@0: 0x42,0x9D,0x33,0x4E,0xEE,0xAA,0xEF,0xD7,0xE2,0x3D,0x48,0x10, michael@0: 0xBE,0x00,0xE4,0xCC,0x14,0x92,0xCB,0xA3,0x25,0xBA,0x81,0xFF, michael@0: 0x2D,0x5A,0x5B,0x30,0x5A,0x8D,0x17,0xEB,0x3B,0xF4,0xA0,0x6A, michael@0: 0x34,0x9D,0x39,0x2E,0x00,0xD3,0x29,0x74,0x4A,0x51,0x79,0x38, michael@0: 0x03,0x44,0xE8,0x2A,0x18,0xC4,0x79,0x33,0x43,0x8F,0x89,0x1E, michael@0: 0x22,0xAE,0xEF,0x81,0x2D,0x69,0xC8,0xF7,0x5E,0x32,0x6C,0xB7, michael@0: 0x0E,0xA0,0x00,0xC3,0xF7,0x76,0xDF,0xDB,0xD6,0x04,0x63,0x8C, michael@0: 0x2E,0xF7,0x17,0xFC,0x26,0xD0,0x2E,0x17 michael@0: }; michael@0: michael@0: uint8_t Q[] = { michael@0: 0xE2,0x1E,0x04,0xF9,0x11,0xD1,0xED,0x79,0x91,0x00,0x8E,0xCA, michael@0: 0xAB,0x3B,0xF7,0x75,0x98,0x43,0x09,0xC3 michael@0: }; michael@0: michael@0: uint8_t G[] = { michael@0: 0xC5,0x2A,0x4A,0x0F,0xF3,0xB7,0xE6,0x1F,0xDF,0x18,0x67,0xCE, michael@0: 0x84,0x13,0x83,0x69,0xA6,0x15,0x4F,0x4A,0xFA,0x92,0x96,0x6E, michael@0: 0x3C,0x82,0x7E,0x25,0xCF,0xA6,0xCF,0x50,0x8B,0x90,0xE5,0xDE, michael@0: 0x41,0x9E,0x13,0x37,0xE0,0x7A,0x2E,0x9E,0x2A,0x3C,0xD5,0xDE, michael@0: 0xA7,0x04,0xD1,0x75,0xF8,0xEB,0xF6,0xAF,0x39,0x7D,0x69,0xE1, michael@0: 0x10,0xB9,0x6A,0xFB,0x17,0xC7,0xA0,0x32,0x59,0x32,0x9E,0x48, michael@0: 0x29,0xB0,0xD0,0x3B,0xBC,0x78,0x96,0xB1,0x5B,0x4A,0xDE,0x53, michael@0: 0xE1,0x30,0x85,0x8C,0xC3,0x4D,0x96,0x26,0x9A,0xA8,0x90,0x41, michael@0: 0xF4,0x09,0x13,0x6C,0x72,0x42,0xA3,0x88,0x95,0xC9,0xD5,0xBC, michael@0: 0xCA,0xD4,0xF3,0x89,0xAF,0x1D,0x7A,0x4B,0xD1,0x39,0x8B,0xD0, michael@0: 0x72,0xDF,0xFA,0x89,0x62,0x33,0x39,0x7A michael@0: }; michael@0: michael@0: static_assert(MOZ_ARRAY_LENGTH(P) == 1024 / CHAR_BIT, "bad DSA P"); michael@0: static_assert(MOZ_ARRAY_LENGTH(Q) == 160 / CHAR_BIT, "bad DSA Q"); michael@0: static_assert(MOZ_ARRAY_LENGTH(G) == 1024 / CHAR_BIT, "bad DSA G"); michael@0: michael@0: PQGParams pqgParams = { michael@0: nullptr /*arena*/, michael@0: { siBuffer, P, static_cast(mozilla::ArrayLength(P)) }, michael@0: { siBuffer, Q, static_cast(mozilla::ArrayLength(Q)) }, michael@0: { siBuffer, G, static_cast(mozilla::ArrayLength(G)) } michael@0: }; michael@0: michael@0: return GenerateKeyPair(slot, privateKey, publicKey, CKM_DSA_KEY_PAIR_GEN, michael@0: &pqgParams); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: KeyGenRunnable::Run() michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: mRv = NS_ERROR_NOT_AVAILABLE; michael@0: } else { michael@0: // We always want to use the internal slot for BrowserID; in particular, michael@0: // we want to avoid smartcard slots. michael@0: PK11SlotInfo *slot = PK11_GetInternalSlot(); michael@0: if (!slot) { michael@0: mRv = NS_ERROR_UNEXPECTED; michael@0: } else { michael@0: SECKEYPrivateKey *privk = nullptr; michael@0: SECKEYPublicKey *pubk = nullptr; michael@0: michael@0: switch (mKeyType) { michael@0: case rsaKey: michael@0: mRv = GenerateRSAKeyPair(slot, &privk, &pubk); michael@0: break; michael@0: case dsaKey: michael@0: mRv = GenerateDSAKeyPair(slot, &privk, &pubk); michael@0: break; michael@0: default: michael@0: MOZ_CRASH("unknown key type"); michael@0: } michael@0: michael@0: PK11_FreeSlot(slot); michael@0: michael@0: if (NS_SUCCEEDED(mRv)) { michael@0: MOZ_ASSERT(privk); michael@0: MOZ_ASSERT(pubk); michael@0: // mKeyPair will take over ownership of privk and pubk michael@0: mKeyPair = new KeyPair(privk, pubk); michael@0: } michael@0: } michael@0: } michael@0: michael@0: NS_DispatchToMainThread(this); michael@0: } else { michael@0: // Back on Main Thread michael@0: (void) mCallback->GenerateKeyPairFinished(mRv, mKeyPair); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: SignRunnable::SignRunnable(const nsACString & aText, michael@0: SECKEYPrivateKey * privateKey, michael@0: nsIIdentitySignCallback * aCallback) michael@0: : mTextToSign(aText) michael@0: , mPrivateKey(SECKEY_CopyPrivateKey(privateKey)) michael@0: , mCallback(new nsMainThreadPtrHolder(aCallback)) michael@0: , mRv(NS_ERROR_NOT_INITIALIZED) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SignRunnable::Run() michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: mRv = NS_ERROR_NOT_AVAILABLE; michael@0: } else { michael@0: // We need the output in PKCS#11 format, not DER encoding, so we must use michael@0: // PK11_HashBuf and PK11_Sign instead of SEC_SignData. michael@0: michael@0: SECItem sig = { siBuffer, nullptr, 0 }; michael@0: int sigLength = PK11_SignatureLen(mPrivateKey); michael@0: if (sigLength <= 0) { michael@0: mRv = PRErrorCode_to_nsresult(PR_GetError()); michael@0: } else if (!SECITEM_AllocItem(nullptr, &sig, sigLength)) { michael@0: mRv = PRErrorCode_to_nsresult(PR_GetError()); michael@0: } else { michael@0: uint8_t hash[32]; // big enough for SHA-1 or SHA-256 michael@0: SECOidTag hashAlg = mPrivateKey->keyType == dsaKey ? SEC_OID_SHA1 michael@0: : SEC_OID_SHA256; michael@0: SECItem hashItem = { siBuffer, hash, michael@0: hashAlg == SEC_OID_SHA1 ? 20u : 32u }; michael@0: michael@0: mRv = MapSECStatus(PK11_HashBuf(hashAlg, hash, michael@0: const_cast(reinterpret_cast( michael@0: mTextToSign.get())), michael@0: mTextToSign.Length())); michael@0: if (NS_SUCCEEDED(mRv)) { michael@0: mRv = MapSECStatus(PK11_Sign(mPrivateKey, &sig, &hashItem)); michael@0: } michael@0: if (NS_SUCCEEDED(mRv)) { michael@0: nsDependentCSubstring sigString( michael@0: reinterpret_cast(sig.data), sig.len); michael@0: mRv = Base64UrlEncodeImpl(sigString, mSignature); michael@0: } michael@0: SECITEM_FreeItem(&sig, false); michael@0: } michael@0: } michael@0: michael@0: NS_DispatchToMainThread(this); michael@0: } else { michael@0: // Back on Main Thread michael@0: (void) mCallback->SignFinished(mRv, mSignature); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // XPCOM module registration michael@0: michael@0: NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(IdentityCryptoService, Init) michael@0: michael@0: #define NS_IDENTITYCRYPTOSERVICE_CID \ michael@0: {0xbea13a3a, 0x44e8, 0x4d7f, {0xa0, 0xa2, 0x2c, 0x67, 0xf8, 0x4e, 0x3a, 0x97}} michael@0: michael@0: NS_DEFINE_NAMED_CID(NS_IDENTITYCRYPTOSERVICE_CID); michael@0: michael@0: const mozilla::Module::CIDEntry kCIDs[] = { michael@0: { &kNS_IDENTITYCRYPTOSERVICE_CID, false, nullptr, IdentityCryptoServiceConstructor }, michael@0: { nullptr } michael@0: }; michael@0: michael@0: const mozilla::Module::ContractIDEntry kContracts[] = { michael@0: { "@mozilla.org/identity/crypto-service;1", &kNS_IDENTITYCRYPTOSERVICE_CID }, michael@0: { nullptr } michael@0: }; michael@0: michael@0: const mozilla::Module kModule = { michael@0: mozilla::Module::kVersion, michael@0: kCIDs, michael@0: kContracts michael@0: }; michael@0: michael@0: } // unnamed namespace michael@0: michael@0: NSMODULE_DEFN(identity) = &kModule;