summaryrefslogtreecommitdiffstats
path: root/services/crypto/component
diff options
context:
space:
mode:
Diffstat (limited to 'services/crypto/component')
-rw-r--r--services/crypto/component/IdentityCryptoService.cpp461
-rw-r--r--services/crypto/component/components.conf13
-rw-r--r--services/crypto/component/moz.build21
-rw-r--r--services/crypto/component/nsIIdentityCryptoService.idl106
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);
+};