diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /services/crypto/component | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | services/crypto/component/IdentityCryptoService.cpp | 461 | ||||
-rw-r--r-- | services/crypto/component/components.conf | 13 | ||||
-rw-r--r-- | services/crypto/component/moz.build | 21 | ||||
-rw-r--r-- | services/crypto/component/nsIIdentityCryptoService.idl | 106 |
4 files changed, 601 insertions, 0 deletions
diff --git a/services/crypto/component/IdentityCryptoService.cpp b/services/crypto/component/IdentityCryptoService.cpp new file mode 100644 index 0000000000..f2c59eb9d5 --- /dev/null +++ b/services/crypto/component/IdentityCryptoService.cpp @@ -0,0 +1,461 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 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 "nsIIdentityCryptoService.h" +#include "nsServiceManagerUtils.h" +#include "nsIThread.h" +#include "nsThreadUtils.h" +#include "nsCOMPtr.h" +#include "nsProxyRelease.h" +#include "nsString.h" +#include "mozilla/ArrayUtils.h" // ArrayLength +#include "mozilla/Base64.h" +#include "mozilla/Components.h" +#include "ScopedNSSTypes.h" +#include "NSSErrorsService.h" + +#include "nss.h" +#include "pk11pub.h" +#include "secmod.h" +#include "secerr.h" +#include "keyhi.h" +#include "cryptohi.h" + +#include <limits.h> + +using namespace mozilla; + +namespace { + +void HexEncode(const SECItem* it, nsACString& result) { + static const char digits[] = "0123456789ABCDEF"; + result.SetLength(it->len * 2); + char* p = result.BeginWriting(); + for (unsigned int i = 0; i < it->len; ++i) { + *p++ = digits[it->data[i] >> 4]; + *p++ = digits[it->data[i] & 0x0f]; + } +} + +#define DSA_KEY_TYPE_STRING ("DS160"_ns) +#define RSA_KEY_TYPE_STRING ("RS256"_ns) + +class KeyPair : public nsIIdentityKeyPair { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIIDENTITYKEYPAIR + + KeyPair(SECKEYPrivateKey* aPrivateKey, SECKEYPublicKey* aPublicKey, + nsIEventTarget* aOperationThread); + + private: + virtual ~KeyPair() { + if (mPrivateKey) { + SECKEY_DestroyPrivateKey(mPrivateKey); + } + if (mPublicKey) { + SECKEY_DestroyPublicKey(mPublicKey); + } + } + + SECKEYPrivateKey* mPrivateKey; + SECKEYPublicKey* mPublicKey; + nsCOMPtr<nsIEventTarget> mThread; + + KeyPair(const KeyPair&) = delete; + void operator=(const KeyPair&) = delete; +}; + +NS_IMPL_ISUPPORTS(KeyPair, nsIIdentityKeyPair) + +class KeyGenRunnable : public Runnable { + public: + NS_DECL_NSIRUNNABLE + + KeyGenRunnable(KeyType keyType, nsIIdentityKeyGenCallback* aCallback, + nsIEventTarget* aOperationThread); + + private: + const KeyType mKeyType; // in + nsMainThreadPtrHandle<nsIIdentityKeyGenCallback> mCallback; // in + nsresult mRv; // out + nsCOMPtr<nsIIdentityKeyPair> mKeyPair; // out + nsCOMPtr<nsIEventTarget> mThread; + + KeyGenRunnable(const KeyGenRunnable&) = delete; + void operator=(const KeyGenRunnable&) = delete; +}; + +class SignRunnable : public Runnable { + public: + NS_DECL_NSIRUNNABLE + + SignRunnable(const nsACString& textToSign, SECKEYPrivateKey* privateKey, + nsIIdentitySignCallback* aCallback); + + private: + ~SignRunnable() override { + if (mPrivateKey) { + SECKEY_DestroyPrivateKey(mPrivateKey); + } + } + + const nsCString mTextToSign; // in + SECKEYPrivateKey* mPrivateKey; // in + nsMainThreadPtrHandle<nsIIdentitySignCallback> mCallback; // in + nsresult mRv; // out + nsCString mSignature; // out + + SignRunnable(const SignRunnable&) = delete; + void operator=(const SignRunnable&) = delete; +}; + +class IdentityCryptoService final : public nsIIdentityCryptoService { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIIDENTITYCRYPTOSERVICE + + IdentityCryptoService() = default; + nsresult Init() { + nsresult rv; + nsCOMPtr<nsISupports> dummyUsedToEnsureNSSIsInitialized = + do_GetService("@mozilla.org/psm;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIThread> thread; + rv = NS_NewNamedThread("IdentityCrypto", getter_AddRefs(thread)); + NS_ENSURE_SUCCESS(rv, rv); + + mThread = std::move(thread); + + return NS_OK; + } + + private: + ~IdentityCryptoService() = default; + IdentityCryptoService(const KeyPair&) = delete; + void operator=(const IdentityCryptoService&) = delete; + + nsCOMPtr<nsIEventTarget> mThread; +}; + +NS_IMPL_ISUPPORTS(IdentityCryptoService, nsIIdentityCryptoService) + +NS_IMETHODIMP +IdentityCryptoService::GenerateKeyPair(const nsACString& keyTypeString, + nsIIdentityKeyGenCallback* callback) { + KeyType keyType; + if (keyTypeString.Equals(RSA_KEY_TYPE_STRING)) { + keyType = rsaKey; + } else if (keyTypeString.Equals(DSA_KEY_TYPE_STRING)) { + keyType = dsaKey; + } else { + return NS_ERROR_UNEXPECTED; + } + + nsCOMPtr<nsIRunnable> r = new KeyGenRunnable(keyType, callback, mThread); + nsresult rv = mThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +NS_IMETHODIMP +IdentityCryptoService::Base64UrlEncode(const nsACString& utf8Input, + nsACString& result) { + return Base64URLEncode( + utf8Input.Length(), + reinterpret_cast<const uint8_t*>(utf8Input.BeginReading()), + Base64URLEncodePaddingPolicy::Include, result); +} + +KeyPair::KeyPair(SECKEYPrivateKey* privateKey, SECKEYPublicKey* publicKey, + nsIEventTarget* operationThread) + : mPrivateKey(privateKey), mPublicKey(publicKey), mThread(operationThread) { + MOZ_ASSERT(!NS_IsMainThread()); +} + +NS_IMETHODIMP +KeyPair::GetHexRSAPublicKeyExponent(nsACString& result) { + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); + NS_ENSURE_TRUE(mPublicKey->keyType == rsaKey, NS_ERROR_NOT_AVAILABLE); + HexEncode(&mPublicKey->u.rsa.publicExponent, result); + return NS_OK; +} + +NS_IMETHODIMP +KeyPair::GetHexRSAPublicKeyModulus(nsACString& result) { + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); + NS_ENSURE_TRUE(mPublicKey->keyType == rsaKey, NS_ERROR_NOT_AVAILABLE); + HexEncode(&mPublicKey->u.rsa.modulus, result); + return NS_OK; +} + +NS_IMETHODIMP +KeyPair::GetHexDSAPrime(nsACString& result) { + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); + NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); + HexEncode(&mPublicKey->u.dsa.params.prime, result); + return NS_OK; +} + +NS_IMETHODIMP +KeyPair::GetHexDSASubPrime(nsACString& result) { + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); + NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); + HexEncode(&mPublicKey->u.dsa.params.subPrime, result); + return NS_OK; +} + +NS_IMETHODIMP +KeyPair::GetHexDSAGenerator(nsACString& result) { + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); + NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); + HexEncode(&mPublicKey->u.dsa.params.base, result); + return NS_OK; +} + +NS_IMETHODIMP +KeyPair::GetHexDSAPublicValue(nsACString& result) { + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); + NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); + HexEncode(&mPublicKey->u.dsa.publicValue, result); + return NS_OK; +} + +NS_IMETHODIMP +KeyPair::GetKeyType(nsACString& result) { + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); + + switch (mPublicKey->keyType) { + case rsaKey: + result = RSA_KEY_TYPE_STRING; + return NS_OK; + case dsaKey: + result = DSA_KEY_TYPE_STRING; + return NS_OK; + default: + return NS_ERROR_UNEXPECTED; + } +} + +NS_IMETHODIMP +KeyPair::Sign(const nsACString& textToSign, nsIIdentitySignCallback* callback) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsIRunnable> r = new SignRunnable(textToSign, mPrivateKey, callback); + + return mThread->Dispatch(r, NS_DISPATCH_NORMAL); +} + +KeyGenRunnable::KeyGenRunnable(KeyType keyType, + nsIIdentityKeyGenCallback* callback, + nsIEventTarget* operationThread) + : mozilla::Runnable("KeyGenRunnable"), + mKeyType(keyType), + mCallback(new nsMainThreadPtrHolder<nsIIdentityKeyGenCallback>( + "KeyGenRunnable::mCallback", callback)), + mRv(NS_ERROR_NOT_INITIALIZED), + mThread(operationThread) {} + +[[nodiscard]] nsresult GenerateKeyPair(PK11SlotInfo* slot, + SECKEYPrivateKey** privateKey, + SECKEYPublicKey** publicKey, + CK_MECHANISM_TYPE mechanism, + void* params) { + *publicKey = nullptr; + *privateKey = PK11_GenerateKeyPair( + slot, mechanism, params, publicKey, PR_FALSE /*isPerm*/, + PR_TRUE /*isSensitive*/, nullptr /*&pwdata*/); + if (!*privateKey) { + MOZ_ASSERT(!*publicKey); + return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); + } + if (!*publicKey) { + SECKEY_DestroyPrivateKey(*privateKey); + *privateKey = nullptr; + MOZ_CRASH("PK11_GnerateKeyPair returned private key without public key"); + } + + return NS_OK; +} + +[[nodiscard]] nsresult GenerateRSAKeyPair(PK11SlotInfo* slot, + SECKEYPrivateKey** privateKey, + SECKEYPublicKey** publicKey) { + MOZ_ASSERT(!NS_IsMainThread()); + + PK11RSAGenParams rsaParams; + rsaParams.keySizeInBits = 2048; + rsaParams.pe = 0x10001; + return GenerateKeyPair(slot, privateKey, publicKey, CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsaParams); +} + +[[nodiscard]] nsresult GenerateDSAKeyPair(PK11SlotInfo* slot, + SECKEYPrivateKey** privateKey, + SECKEYPublicKey** publicKey) { + MOZ_ASSERT(!NS_IsMainThread()); + + // XXX: These could probably be static const arrays, but this way we avoid + // compiler warnings and also we avoid having to worry much about whether the + // functions that take these inputs will (unexpectedly) modify them. + + // Using NIST parameters. Some other BrowserID components require that these + // exact parameters are used. + uint8_t P[] = { + 0xFF, 0x60, 0x04, 0x83, 0xDB, 0x6A, 0xBF, 0xC5, 0xB4, 0x5E, 0xAB, 0x78, + 0x59, 0x4B, 0x35, 0x33, 0xD5, 0x50, 0xD9, 0xF1, 0xBF, 0x2A, 0x99, 0x2A, + 0x7A, 0x8D, 0xAA, 0x6D, 0xC3, 0x4F, 0x80, 0x45, 0xAD, 0x4E, 0x6E, 0x0C, + 0x42, 0x9D, 0x33, 0x4E, 0xEE, 0xAA, 0xEF, 0xD7, 0xE2, 0x3D, 0x48, 0x10, + 0xBE, 0x00, 0xE4, 0xCC, 0x14, 0x92, 0xCB, 0xA3, 0x25, 0xBA, 0x81, 0xFF, + 0x2D, 0x5A, 0x5B, 0x30, 0x5A, 0x8D, 0x17, 0xEB, 0x3B, 0xF4, 0xA0, 0x6A, + 0x34, 0x9D, 0x39, 0x2E, 0x00, 0xD3, 0x29, 0x74, 0x4A, 0x51, 0x79, 0x38, + 0x03, 0x44, 0xE8, 0x2A, 0x18, 0xC4, 0x79, 0x33, 0x43, 0x8F, 0x89, 0x1E, + 0x22, 0xAE, 0xEF, 0x81, 0x2D, 0x69, 0xC8, 0xF7, 0x5E, 0x32, 0x6C, 0xB7, + 0x0E, 0xA0, 0x00, 0xC3, 0xF7, 0x76, 0xDF, 0xDB, 0xD6, 0x04, 0x63, 0x8C, + 0x2E, 0xF7, 0x17, 0xFC, 0x26, 0xD0, 0x2E, 0x17}; + + uint8_t Q[] = {0xE2, 0x1E, 0x04, 0xF9, 0x11, 0xD1, 0xED, 0x79, 0x91, 0x00, + 0x8E, 0xCA, 0xAB, 0x3B, 0xF7, 0x75, 0x98, 0x43, 0x09, 0xC3}; + + uint8_t G[] = { + 0xC5, 0x2A, 0x4A, 0x0F, 0xF3, 0xB7, 0xE6, 0x1F, 0xDF, 0x18, 0x67, 0xCE, + 0x84, 0x13, 0x83, 0x69, 0xA6, 0x15, 0x4F, 0x4A, 0xFA, 0x92, 0x96, 0x6E, + 0x3C, 0x82, 0x7E, 0x25, 0xCF, 0xA6, 0xCF, 0x50, 0x8B, 0x90, 0xE5, 0xDE, + 0x41, 0x9E, 0x13, 0x37, 0xE0, 0x7A, 0x2E, 0x9E, 0x2A, 0x3C, 0xD5, 0xDE, + 0xA7, 0x04, 0xD1, 0x75, 0xF8, 0xEB, 0xF6, 0xAF, 0x39, 0x7D, 0x69, 0xE1, + 0x10, 0xB9, 0x6A, 0xFB, 0x17, 0xC7, 0xA0, 0x32, 0x59, 0x32, 0x9E, 0x48, + 0x29, 0xB0, 0xD0, 0x3B, 0xBC, 0x78, 0x96, 0xB1, 0x5B, 0x4A, 0xDE, 0x53, + 0xE1, 0x30, 0x85, 0x8C, 0xC3, 0x4D, 0x96, 0x26, 0x9A, 0xA8, 0x90, 0x41, + 0xF4, 0x09, 0x13, 0x6C, 0x72, 0x42, 0xA3, 0x88, 0x95, 0xC9, 0xD5, 0xBC, + 0xCA, 0xD4, 0xF3, 0x89, 0xAF, 0x1D, 0x7A, 0x4B, 0xD1, 0x39, 0x8B, 0xD0, + 0x72, 0xDF, 0xFA, 0x89, 0x62, 0x33, 0x39, 0x7A}; + + static_assert(MOZ_ARRAY_LENGTH(P) == 1024 / CHAR_BIT, "bad DSA P"); + static_assert(MOZ_ARRAY_LENGTH(Q) == 160 / CHAR_BIT, "bad DSA Q"); + static_assert(MOZ_ARRAY_LENGTH(G) == 1024 / CHAR_BIT, "bad DSA G"); + + PQGParams pqgParams = { + nullptr /*arena*/, + {siBuffer, P, static_cast<unsigned int>(mozilla::ArrayLength(P))}, + {siBuffer, Q, static_cast<unsigned int>(mozilla::ArrayLength(Q))}, + {siBuffer, G, static_cast<unsigned int>(mozilla::ArrayLength(G))}}; + + return GenerateKeyPair(slot, privateKey, publicKey, CKM_DSA_KEY_PAIR_GEN, + &pqgParams); +} + +NS_IMETHODIMP +KeyGenRunnable::Run() { + if (!NS_IsMainThread()) { + // We always want to use the internal slot for BrowserID; in particular, + // we want to avoid smartcard slots. + PK11SlotInfo* slot = PK11_GetInternalSlot(); + if (!slot) { + mRv = NS_ERROR_UNEXPECTED; + } else { + SECKEYPrivateKey* privk = nullptr; + SECKEYPublicKey* pubk = nullptr; + + switch (mKeyType) { + case rsaKey: + mRv = GenerateRSAKeyPair(slot, &privk, &pubk); + break; + case dsaKey: + mRv = GenerateDSAKeyPair(slot, &privk, &pubk); + break; + default: + MOZ_CRASH("unknown key type"); + } + + PK11_FreeSlot(slot); + + if (NS_SUCCEEDED(mRv)) { + MOZ_ASSERT(privk); + MOZ_ASSERT(pubk); + // mKeyPair will take over ownership of privk and pubk + mKeyPair = new KeyPair(privk, pubk, mThread); + } + } + + NS_DispatchToMainThread(this); + } else { + // Back on Main Thread + (void)mCallback->GenerateKeyPairFinished(mRv, mKeyPair); + } + return NS_OK; +} + +SignRunnable::SignRunnable(const nsACString& aText, + SECKEYPrivateKey* privateKey, + nsIIdentitySignCallback* aCallback) + : mozilla::Runnable("SignRunnable"), + mTextToSign(aText), + mPrivateKey(SECKEY_CopyPrivateKey(privateKey)), + mCallback(new nsMainThreadPtrHolder<nsIIdentitySignCallback>( + "SignRunnable::mCallback", aCallback)), + mRv(NS_ERROR_NOT_INITIALIZED) {} + +NS_IMETHODIMP +SignRunnable::Run() { + if (!NS_IsMainThread()) { + // We need the output in PKCS#11 format, not DER encoding, so we must use + // PK11_HashBuf and PK11_Sign instead of SEC_SignData. + + SECItem sig = {siBuffer, nullptr, 0}; + int sigLength = PK11_SignatureLen(mPrivateKey); + if (sigLength <= 0) { + mRv = mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); + } else if (!SECITEM_AllocItem(nullptr, &sig, sigLength)) { + mRv = mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); + } else { + uint8_t hash[32]; // big enough for SHA-1 or SHA-256 + SECOidTag hashAlg = + mPrivateKey->keyType == dsaKey ? SEC_OID_SHA1 : SEC_OID_SHA256; + SECItem hashItem = {siBuffer, hash, hashAlg == SEC_OID_SHA1 ? 20u : 32u}; + + mRv = MapSECStatus( + PK11_HashBuf(hashAlg, hash, + const_cast<uint8_t*>( + reinterpret_cast<const uint8_t*>(mTextToSign.get())), + mTextToSign.Length())); + if (NS_SUCCEEDED(mRv)) { + mRv = MapSECStatus(PK11_Sign(mPrivateKey, &sig, &hashItem)); + } + if (NS_SUCCEEDED(mRv)) { + mRv = + Base64URLEncode(sig.len, sig.data, + Base64URLEncodePaddingPolicy::Include, mSignature); + } + SECITEM_FreeItem(&sig, false); + } + + NS_DispatchToMainThread(this); + } else { + // Back on Main Thread + (void)mCallback->SignFinished(mRv, mSignature); + } + + return NS_OK; +} +} // unnamed namespace + +// XPCOM module registration + +NS_IMPL_COMPONENT_FACTORY(nsIIdentityCryptoService) { + auto inst = MakeRefPtr<IdentityCryptoService>(); + if (NS_SUCCEEDED(inst->Init())) { + return inst.forget().downcast<nsIIdentityCryptoService>(); + } + return nullptr; +} diff --git a/services/crypto/component/components.conf b/services/crypto/component/components.conf new file mode 100644 index 0000000000..49a4b74d7a --- /dev/null +++ b/services/crypto/component/components.conf @@ -0,0 +1,13 @@ +# -*- 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/. + +Classes = [ + { + 'cid': '{bea13a3a-44e8-4d7f-a0a2-2c67f84e3a97}', + 'contract_ids': ['@mozilla.org/identity/crypto-service;1'], + 'type': 'nsIIdentityCryptoService', + }, +] diff --git a/services/crypto/component/moz.build b/services/crypto/component/moz.build new file mode 100644 index 0000000000..41b47f25c6 --- /dev/null +++ b/services/crypto/component/moz.build @@ -0,0 +1,21 @@ +# -*- 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/. + +XPIDL_SOURCES += [ + "nsIIdentityCryptoService.idl", +] + +XPIDL_MODULE = "services-crypto-component" + +SOURCES += [ + "IdentityCryptoService.cpp", +] + +XPCOM_MANIFESTS += [ + "components.conf", +] + +FINAL_LIBRARY = "xul" diff --git a/services/crypto/component/nsIIdentityCryptoService.idl b/services/crypto/component/nsIIdentityCryptoService.idl new file mode 100644 index 0000000000..90149e2e82 --- /dev/null +++ b/services/crypto/component/nsIIdentityCryptoService.idl @@ -0,0 +1,106 @@ +/* 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 "nsISupports.idl" + +interface nsIURI; +interface nsIIdentityKeyGenCallback; +interface nsIIdentitySignCallback; + +/* Naming and calling conventions: + * + * A"hex" prefix means "hex-encoded string representation of a byte sequence" + * e.g. "ae34bcdf123" + * + * A "base64url" prefix means "base-64-URL-encoded string repressentation of a + * byte sequence. + * e.g. "eyJhbGciOiJSUzI1NiJ9" + * http://en.wikipedia.org/wiki/Base64#Variants_summary_table + * we use the padded approach to base64-url-encoding + * + * Callbacks take an "in nsresult rv" argument that indicates whether the async + * operation succeeded. On success, rv will be a success code + * (NS_SUCCEEDED(rv) / Components.isSuccessCode(rv)) and the remaining + * arguments are as defined in the documentation for the callback. When the + * operation fails, rv will be a failure code (NS_FAILED(rv) / + * !Components.isSuccessCode(rv)) and the values of the remaining arguments will + * be unspecified. + * + * Key Types: + * + * "RS256": RSA + SHA-256. + * + * "DS160": DSA with SHA-1. A 1024-bit prime and a 160-bit subprime with SHA-1. + * + * we use these abbreviated algorithm names as per the JWA spec + * http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-02 + */ + +// "@mozilla.org/identity/crypto-service;1" +[scriptable, builtinclass, uuid(f087e6bc-dd33-4f6c-a106-dd786e052ee9)] +interface nsIIdentityCryptoService : nsISupports +{ + void generateKeyPair(in AUTF8String algorithm, + in nsIIdentityKeyGenCallback callback); + + ACString base64UrlEncode(in AUTF8String toEncode); +}; + +/** + * This interface provides a keypair and signing interface for Identity functionality + */ +[scriptable, uuid(73962dc7-8ee7-4346-a12b-b039e1d9b54d)] +interface nsIIdentityKeyPair : nsISupports +{ + readonly attribute AUTF8String keyType; + + // RSA properties, only accessible when keyType == "RS256" + + readonly attribute AUTF8String hexRSAPublicKeyExponent; + readonly attribute AUTF8String hexRSAPublicKeyModulus; + + // DSA properties, only accessible when keyType == "DS128" + readonly attribute AUTF8String hexDSAPrime; // p + readonly attribute AUTF8String hexDSASubPrime; // q + readonly attribute AUTF8String hexDSAGenerator; // g + readonly attribute AUTF8String hexDSAPublicValue; // y + + void sign(in AUTF8String aText, + in nsIIdentitySignCallback callback); + + // XXX implement verification bug 769856 + // AUTF8String verify(in AUTF8String aSignature, in AUTF8String encodedPublicKey); + +}; + +/** + * This interface provides a JavaScript callback object used to collect the + * nsIIdentityServeKeyPair when the keygen operation is complete + * + * though there is discussion as to whether we need the nsresult, + * we keep it so we can track deeper crypto errors. + */ +[scriptable, function, uuid(90f24ca2-2b05-4ca9-8aec-89d38e2f905a)] +interface nsIIdentityKeyGenCallback : nsISupports +{ + void generateKeyPairFinished(in nsresult rv, + in nsIIdentityKeyPair keyPair); +}; + +/** + * This interface provides a JavaScript callback object used to collect the + * AUTF8String signature + */ +[scriptable, function, uuid(2d3e5036-374b-4b47-a430-1196b67b890f)] +interface nsIIdentitySignCallback : nsISupports +{ + /** On success, base64urlSignature is the base-64-URL-encoded signature + * + * For RS256 signatures, XXX bug 769858 + * + * For DSA128 signatures, the signature is the r value concatenated with the + * s value, each component padded with leading zeroes as necessary. + */ + void signFinished(in nsresult rv, in ACString base64urlSignature); +}; |