summaryrefslogtreecommitdiffstats
path: root/toolkit/identity
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/identity')
-rw-r--r--toolkit/identity/Identity.jsm309
-rw-r--r--toolkit/identity/IdentityCryptoService.cpp571
-rw-r--r--toolkit/identity/IdentityProvider.jsm496
-rw-r--r--toolkit/identity/IdentityStore.jsm97
-rw-r--r--toolkit/identity/IdentityUtils.jsm111
-rw-r--r--toolkit/identity/LogUtils.jsm103
-rw-r--r--toolkit/identity/MinimalIdentity.jsm242
-rw-r--r--toolkit/identity/RelyingParty.jsm367
-rw-r--r--toolkit/identity/Sandbox.jsm152
-rw-r--r--toolkit/identity/jwcrypto.jsm180
-rw-r--r--toolkit/identity/moz.build25
-rw-r--r--toolkit/identity/nsIIdentityCryptoService.idl106
12 files changed, 0 insertions, 2759 deletions
diff --git a/toolkit/identity/Identity.jsm b/toolkit/identity/Identity.jsm
deleted file mode 100644
index a27b7c93d..000000000
--- a/toolkit/identity/Identity.jsm
+++ /dev/null
@@ -1,309 +0,0 @@
-/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
-/* vim: set ft=javascript 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/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["IdentityService"];
-
-const Cu = Components.utils;
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/identity/LogUtils.jsm");
-Cu.import("resource://gre/modules/identity/IdentityStore.jsm");
-Cu.import("resource://gre/modules/identity/RelyingParty.jsm");
-Cu.import("resource://gre/modules/identity/IdentityProvider.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this,
- "jwcrypto",
- "resource://gre/modules/identity/jwcrypto.jsm");
-
-function log(...aMessageArgs) {
- Logger.log.apply(Logger, ["core"].concat(aMessageArgs));
-}
-function reportError(...aMessageArgs) {
- Logger.reportError.apply(Logger, ["core"].concat(aMessageArgs));
-}
-
-function IDService() {
- Services.obs.addObserver(this, "quit-application-granted", false);
- Services.obs.addObserver(this, "identity-auth-complete", false);
-
- this._store = IdentityStore;
- this.RP = RelyingParty;
- this.IDP = IdentityProvider;
-}
-
-IDService.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
-
- observe: function observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- case "quit-application-granted":
- Services.obs.removeObserver(this, "quit-application-granted");
- this.shutdown();
- break;
- case "identity-auth-complete":
- if (!aSubject || !aSubject.wrappedJSObject)
- break;
- let subject = aSubject.wrappedJSObject;
- log("Auth complete:", aSubject.wrappedJSObject);
- // We have authenticated in order to provision an identity.
- // So try again.
- this.selectIdentity(subject.rpId, subject.identity);
- break;
- }
- },
-
- reset: function reset() {
- // Explicitly call reset() on our RP and IDP classes.
- // This is here to make testing easier. When the
- // quit-application-granted signal is emitted, reset() will be
- // called here, on RP, on IDP, and on the store. So you don't
- // need to use this :)
- this._store.reset();
- this.RP.reset();
- this.IDP.reset();
- },
-
- shutdown: function shutdown() {
- log("shutdown");
- Services.obs.removeObserver(this, "identity-auth-complete");
- // try to prevent abort/crash during shutdown of mochitest-browser2...
- try {
- Services.obs.removeObserver(this, "quit-application-granted");
- } catch (e) {}
- },
-
- /**
- * Parse an email into username and domain if it is valid, else return null
- */
- parseEmail: function parseEmail(email) {
- var match = email.match(/^([^@]+)@([^@^/]+.[a-z]+)$/);
- if (match) {
- return {
- username: match[1],
- domain: match[2]
- };
- }
- return null;
- },
-
- /**
- * The UX wants to add a new identity
- * often followed by selectIdentity()
- *
- * @param aIdentity
- * (string) the email chosen for login
- */
- addIdentity: function addIdentity(aIdentity) {
- if (this._store.fetchIdentity(aIdentity) === null) {
- this._store.addIdentity(aIdentity, null, null);
- }
- },
-
- /**
- * The UX comes back and calls selectIdentity once the user has picked
- * an identity.
- *
- * @param aRPId
- * (integer) the id of the doc object obtained in .watch() and
- * passed to the UX component.
- *
- * @param aIdentity
- * (string) the email chosen for login
- */
- selectIdentity: function selectIdentity(aRPId, aIdentity) {
- log("selectIdentity: RP id:", aRPId, "identity:", aIdentity);
-
- // Get the RP that was stored when watch() was invoked.
- let rp = this.RP._rpFlows[aRPId];
- if (!rp) {
- reportError("selectIdentity", "Invalid RP id: ", aRPId);
- return;
- }
-
- // It's possible that we are in the process of provisioning an
- // identity.
- let provId = rp.provId;
-
- let rpLoginOptions = {
- loggedInUser: aIdentity,
- origin: rp.origin
- };
- log("selectIdentity: provId:", provId, "origin:", rp.origin);
-
- // Once we have a cert, and once the user is authenticated with the
- // IdP, we can generate an assertion and deliver it to the doc.
- let self = this;
- this.RP._generateAssertion(rp.origin, aIdentity, function hadReadyAssertion(err, assertion) {
- if (!err && assertion) {
- self.RP._doLogin(rp, rpLoginOptions, assertion);
- return;
-
- }
- // Need to provision an identity first. Begin by discovering
- // the user's IdP.
- self._discoverIdentityProvider(aIdentity, function gotIDP(err, idpParams) {
- if (err) {
- rp.doError(err);
- return;
- }
-
- // The idpParams tell us where to go to provision and authenticate
- // the identity.
- self.IDP._provisionIdentity(aIdentity, idpParams, provId, function gotID(err, aProvId) {
-
- // Provision identity may have created a new provision flow
- // for us. To make it easier to relate provision flows with
- // RP callers, we cross index the two here.
- rp.provId = aProvId;
- self.IDP._provisionFlows[aProvId].rpId = aRPId;
-
- // At this point, we already have a cert. If the user is also
- // already authenticated with the IdP, then we can try again
- // to generate an assertion and login.
- if (err) {
- // We are not authenticated. If we have already tried to
- // authenticate and failed, then this is a "hard fail" and
- // we give up. Otherwise we try to authenticate with the
- // IdP.
-
- if (self.IDP._provisionFlows[aProvId].didAuthentication) {
- self.IDP._cleanUpProvisionFlow(aProvId);
- self.RP._cleanUpProvisionFlow(aRPId, aProvId);
- log("ERROR: selectIdentity: authentication hard fail");
- rp.doError("Authentication fail.");
- return;
- }
- // Try to authenticate with the IdP. Note that we do
- // not clean up the provision flow here. We will continue
- // to use it.
- self.IDP._doAuthentication(aProvId, idpParams);
- return;
- }
-
- // Provisioning flows end when a certificate has been registered.
- // Thus IdentityProvider's registerCertificate() cleans up the
- // current provisioning flow. We only do this here on error.
- self.RP._generateAssertion(rp.origin, aIdentity, function gotAssertion(err, assertion) {
- if (err) {
- rp.doError(err);
- return;
- }
- self.RP._doLogin(rp, rpLoginOptions, assertion);
- self.RP._cleanUpProvisionFlow(aRPId, aProvId);
- return;
- });
- });
- });
- });
- },
-
- // methods for chrome and add-ons
-
- /**
- * Discover the IdP for an identity
- *
- * @param aIdentity
- * (string) the email we're logging in with
- *
- * @param aCallback
- * (function) callback to invoke on completion
- * with first-positional parameter the error.
- */
- _discoverIdentityProvider: function _discoverIdentityProvider(aIdentity, aCallback) {
- // XXX bug 767610 - validate email address call
- // When that is available, we can remove this custom parser
- var parsedEmail = this.parseEmail(aIdentity);
- if (parsedEmail === null) {
- aCallback("Could not parse email: " + aIdentity);
- return;
- }
- log("_discoverIdentityProvider: identity:", aIdentity, "domain:", parsedEmail.domain);
-
- this._fetchWellKnownFile(parsedEmail.domain, function fetchedWellKnown(err, idpParams) {
- // idpParams includes the pk, authorization url, and
- // provisioning url.
-
- // XXX bug 769861 follow any authority delegations
- // if no well-known at any point in the delegation
- // fall back to browserid.org as IdP
- return aCallback(err, idpParams);
- });
- },
-
- /**
- * Fetch the well-known file from the domain.
- *
- * @param aDomain
- *
- * @param aScheme
- * (string) (optional) Protocol to use. Default is https.
- * This is necessary because we are unable to test
- * https.
- *
- * @param aCallback
- *
- */
- _fetchWellKnownFile: function _fetchWellKnownFile(aDomain, aCallback, aScheme='https') {
- // XXX bug 769854 make tests https and remove aScheme option
- let url = aScheme + '://' + aDomain + "/.well-known/browserid";
- log("_fetchWellKnownFile:", url);
-
- // this appears to be a more successful way to get at xmlhttprequest (which supposedly will close with a window
- let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
- .createInstance(Ci.nsIXMLHttpRequest);
-
- // XXX bug 769865 gracefully handle being off-line
- // XXX bug 769866 decide on how to handle redirects
- req.open("GET", url, true);
- req.responseType = "json";
- req.mozBackgroundRequest = true;
- req.onload = function _fetchWellKnownFile_onload() {
- if (req.status < 200 || req.status >= 400) {
- log("_fetchWellKnownFile", url, ": server returned status:", req.status);
- return aCallback("Error");
- }
- try {
- let idpParams = req.response;
-
- // Verify that the IdP returned a valid configuration
- if (! (idpParams.provisioning &&
- idpParams.authentication &&
- idpParams['public-key'])) {
- let errStr= "Invalid well-known file from: " + aDomain;
- log("_fetchWellKnownFile:", errStr);
- return aCallback(errStr);
- }
-
- let callbackObj = {
- domain: aDomain,
- idpParams: idpParams,
- };
- log("_fetchWellKnownFile result: ", callbackObj);
- // Yay. Valid IdP configuration for the domain.
- return aCallback(null, callbackObj);
-
- } catch (err) {
- reportError("_fetchWellKnownFile", "Bad configuration from", aDomain, err);
- return aCallback(err.toString());
- }
- };
- req.onerror = function _fetchWellKnownFile_onerror() {
- log("_fetchWellKnownFile", "ERROR:", req.status, req.statusText);
- log("ERROR: _fetchWellKnownFile:", err);
- return aCallback("Error");
- };
- req.send(null);
- },
-
-};
-
-this.IdentityService = new IDService();
diff --git a/toolkit/identity/IdentityCryptoService.cpp b/toolkit/identity/IdentityCryptoService.cpp
deleted file mode 100644
index cafe07999..000000000
--- a/toolkit/identity/IdentityCryptoService.cpp
+++ /dev/null
@@ -1,571 +0,0 @@
-/* -*- 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 "mozilla/ModuleUtils.h"
-#include "nsServiceManagerUtils.h"
-#include "nsNSSShutDown.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 "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)
-{
- const char * digits = "0123456789ABCDEF";
- result.SetCapacity((it->len * 2) + 1);
- 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 (NS_LITERAL_CSTRING("DS160"))
-#define RSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("RS256"))
-
-class KeyPair : public nsIIdentityKeyPair, public nsNSSShutDownObject
-{
-public:
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSIIDENTITYKEYPAIR
-
- KeyPair(SECKEYPrivateKey* aPrivateKey, SECKEYPublicKey* aPublicKey,
- nsIEventTarget* aOperationThread);
-
-private:
- ~KeyPair()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return;
- }
- destructorSafeDestroyNSSReference();
- shutdown(ShutdownCalledFrom::Object);
- }
-
- void virtualDestroyNSSReference() override
- {
- destructorSafeDestroyNSSReference();
- }
-
- void destructorSafeDestroyNSSReference()
- {
- SECKEY_DestroyPrivateKey(mPrivateKey);
- mPrivateKey = nullptr;
- SECKEY_DestroyPublicKey(mPublicKey);
- mPublicKey = nullptr;
- }
-
- 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 nsNSSShutDownObject
-{
-public:
- NS_DECL_NSIRUNNABLE
-
- KeyGenRunnable(KeyType keyType, nsIIdentityKeyGenCallback * aCallback,
- nsIEventTarget* aOperationThread);
-
-private:
- ~KeyGenRunnable()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return;
- }
- destructorSafeDestroyNSSReference();
- shutdown(ShutdownCalledFrom::Object);
- }
-
- virtual void virtualDestroyNSSReference() override
- {
- destructorSafeDestroyNSSReference();
- }
-
- void destructorSafeDestroyNSSReference()
- {
- }
-
- 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 nsNSSShutDownObject
-{
-public:
- NS_DECL_NSIRUNNABLE
-
- SignRunnable(const nsACString & textToSign, SECKEYPrivateKey * privateKey,
- nsIIdentitySignCallback * aCallback);
-
-private:
- ~SignRunnable()
- {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return;
- }
- destructorSafeDestroyNSSReference();
- shutdown(ShutdownCalledFrom::Object);
- }
-
- void virtualDestroyNSSReference() override
- {
- destructorSafeDestroyNSSReference();
- }
-
- void destructorSafeDestroyNSSReference()
- {
- SECKEY_DestroyPrivateKey(mPrivateKey);
- mPrivateKey = nullptr;
- }
-
- const nsCString mTextToSign; // in
- SECKEYPrivateKey* mPrivateKey; // in
- nsMainThreadPtrHandle<nsIIdentitySignCallback> mCallback; // in
- nsresult mRv; // out
- nsCString mSignature; // out
-
-private:
- SignRunnable(const SignRunnable &) = delete;
- void operator=(const SignRunnable &) = delete;
-};
-
-class IdentityCryptoService final : public nsIIdentityCryptoService
-{
-public:
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSIIDENTITYCRYPTOSERVICE
-
- IdentityCryptoService() { }
- 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 = thread.forget();
-
- return NS_OK;
- }
-
-private:
- ~IdentityCryptoService() { }
- 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)
- : mKeyType(keyType)
- , mCallback(new nsMainThreadPtrHolder<nsIIdentityKeyGenCallback>(callback))
- , mRv(NS_ERROR_NOT_INITIALIZED)
- , mThread(operationThread)
-{
-}
-
-MOZ_MUST_USE 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;
-}
-
-
-MOZ_MUST_USE 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);
-}
-
-MOZ_MUST_USE 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()) {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- mRv = NS_ERROR_NOT_AVAILABLE;
- } else {
- // 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)
- : mTextToSign(aText)
- , mPrivateKey(SECKEY_CopyPrivateKey(privateKey))
- , mCallback(new nsMainThreadPtrHolder<nsIIdentitySignCallback>(aCallback))
- , mRv(NS_ERROR_NOT_INITIALIZED)
-{
-}
-
-NS_IMETHODIMP
-SignRunnable::Run()
-{
- if (!NS_IsMainThread()) {
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- mRv = NS_ERROR_NOT_AVAILABLE;
- } else {
- // 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;
-}
-
-// XPCOM module registration
-
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(IdentityCryptoService, Init)
-
-#define NS_IDENTITYCRYPTOSERVICE_CID \
- {0xbea13a3a, 0x44e8, 0x4d7f, {0xa0, 0xa2, 0x2c, 0x67, 0xf8, 0x4e, 0x3a, 0x97}}
-
-NS_DEFINE_NAMED_CID(NS_IDENTITYCRYPTOSERVICE_CID);
-
-const mozilla::Module::CIDEntry kCIDs[] = {
- { &kNS_IDENTITYCRYPTOSERVICE_CID, false, nullptr, IdentityCryptoServiceConstructor },
- { nullptr }
-};
-
-const mozilla::Module::ContractIDEntry kContracts[] = {
- { "@mozilla.org/identity/crypto-service;1", &kNS_IDENTITYCRYPTOSERVICE_CID },
- { nullptr }
-};
-
-const mozilla::Module kModule = {
- mozilla::Module::kVersion,
- kCIDs,
- kContracts
-};
-
-} // unnamed namespace
-
-NSMODULE_DEFN(identity) = &kModule;
diff --git a/toolkit/identity/IdentityProvider.jsm b/toolkit/identity/IdentityProvider.jsm
deleted file mode 100644
index 11529bfba..000000000
--- a/toolkit/identity/IdentityProvider.jsm
+++ /dev/null
@@ -1,496 +0,0 @@
-/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
-/* vim: set ft=javascript 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/. */
-
-"use strict";
-
-const Cu = Components.utils;
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/identity/LogUtils.jsm");
-Cu.import("resource://gre/modules/identity/Sandbox.jsm");
-
-this.EXPORTED_SYMBOLS = ["IdentityProvider"];
-const FALLBACK_PROVIDER = "browserid.org";
-
-XPCOMUtils.defineLazyModuleGetter(this,
- "jwcrypto",
- "resource://gre/modules/identity/jwcrypto.jsm");
-
-function log(...aMessageArgs) {
- Logger.log.apply(Logger, ["IDP"].concat(aMessageArgs));
-}
-function reportError(...aMessageArgs) {
- Logger.reportError.apply(Logger, ["IDP"].concat(aMessageArgs));
-}
-
-
-function IdentityProviderService() {
- XPCOMUtils.defineLazyModuleGetter(this,
- "_store",
- "resource://gre/modules/identity/IdentityStore.jsm",
- "IdentityStore");
-
- this.reset();
-}
-
-IdentityProviderService.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
- _sandboxConfigured: false,
-
- observe: function observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- case "quit-application-granted":
- Services.obs.removeObserver(this, "quit-application-granted");
- this.shutdown();
- break;
- }
- },
-
- reset: function IDP_reset() {
- // Clear the provisioning flows. Provision flows contain an
- // identity, idpParams (how to reach the IdP to provision and
- // authenticate), a callback (a completion callback for when things
- // are done), and a provisioningFrame (which is the provisioning
- // sandbox). Additionally, two callbacks will be attached:
- // beginProvisioningCallback and genKeyPairCallback.
- this._provisionFlows = {};
-
- // Clear the authentication flows. Authentication flows attach
- // to provision flows. In the process of provisioning an id, it
- // may be necessary to authenticate with an IdP. The authentication
- // flow maintains the state of that authentication process.
- this._authenticationFlows = {};
- },
-
- getProvisionFlow: function getProvisionFlow(aProvId, aErrBack) {
- let provFlow = this._provisionFlows[aProvId];
- if (provFlow) {
- return provFlow;
- }
-
- let err = "No provisioning flow found with id " + aProvId;
- log("ERROR:", err);
- if (typeof aErrBack === 'function') {
- aErrBack(err);
- }
-
- return undefined;
- },
-
- shutdown: function RP_shutdown() {
- this.reset();
-
- if (this._sandboxConfigured) {
- // Tear down message manager listening on the hidden window
- Cu.import("resource://gre/modules/DOMIdentity.jsm");
- DOMIdentity._configureMessages(Services.appShell.hiddenDOMWindow, false);
- this._sandboxConfigured = false;
- }
-
- Services.obs.removeObserver(this, "quit-application-granted");
- },
-
- get securityLevel() {
- return 1;
- },
-
- get certDuration() {
- switch (this.securityLevel) {
- default:
- return 3600;
- }
- },
-
- /**
- * Provision an Identity
- *
- * @param aIdentity
- * (string) the email we're logging in with
- *
- * @param aIDPParams
- * (object) parameters of the IdP
- *
- * @param aCallback
- * (function) callback to invoke on completion
- * with first-positional parameter the error.
- */
- _provisionIdentity: function _provisionIdentity(aIdentity, aIDPParams, aProvId, aCallback) {
- let provPath = aIDPParams.idpParams.provisioning;
- let url = Services.io.newURI("https://" + aIDPParams.domain, null, null).resolve(provPath);
- log("_provisionIdentity: identity:", aIdentity, "url:", url);
-
- // If aProvId is not null, then we already have a flow
- // with a sandbox. Otherwise, get a sandbox and create a
- // new provision flow.
-
- if (aProvId) {
- // Re-use an existing sandbox
- log("_provisionIdentity: re-using sandbox in provisioning flow with id:", aProvId);
- this._provisionFlows[aProvId].provisioningSandbox.reload();
-
- } else {
- this._createProvisioningSandbox(url, function createdSandbox(aSandbox) {
- // create a provisioning flow, using the sandbox id, and
- // stash callback associated with this provisioning workflow.
-
- let provId = aSandbox.id;
- this._provisionFlows[provId] = {
- identity: aIdentity,
- idpParams: aIDPParams,
- securityLevel: this.securityLevel,
- provisioningSandbox: aSandbox,
- callback: function doCallback(aErr) {
- aCallback(aErr, provId);
- },
- };
-
- log("_provisionIdentity: Created sandbox and provisioning flow with id:", provId);
- // XXX bug 769862 - provisioning flow should timeout after N seconds
-
- }.bind(this));
- }
- },
-
- // DOM Methods
- /**
- * the provisioning iframe sandbox has called navigator.id.beginProvisioning()
- *
- * @param aCaller
- * (object) the iframe sandbox caller with all callbacks and
- * other information. Callbacks include:
- * - doBeginProvisioningCallback(id, duration_s)
- * - doGenKeyPairCallback(pk)
- */
- beginProvisioning: function beginProvisioning(aCaller) {
- log("beginProvisioning:", aCaller.id);
-
- // Expect a flow for this caller already to be underway.
- let provFlow = this.getProvisionFlow(aCaller.id, aCaller.doError);
-
- // keep the caller object around
- provFlow.caller = aCaller;
-
- let identity = provFlow.identity;
- let frame = provFlow.provisioningFrame;
-
- // Determine recommended length of cert.
- let duration = this.certDuration;
-
- // Make a record that we have begun provisioning. This is required
- // for genKeyPair.
- provFlow.didBeginProvisioning = true;
-
- // Let the sandbox know to invoke the callback to beginProvisioning with
- // the identity and cert length.
- return aCaller.doBeginProvisioningCallback(identity, duration);
- },
-
- /**
- * the provisioning iframe sandbox has called
- * navigator.id.raiseProvisioningFailure()
- *
- * @param aProvId
- * (int) the identifier of the provisioning flow tied to that sandbox
- * @param aReason
- */
- raiseProvisioningFailure: function raiseProvisioningFailure(aProvId, aReason) {
- reportError("Provisioning failure", aReason);
-
- // look up the provisioning caller and its callback
- let provFlow = this.getProvisionFlow(aProvId);
-
- // Sandbox is deleted in _cleanUpProvisionFlow in case we re-use it.
-
- // This may be either a "soft" or "hard" fail. If it's a
- // soft fail, we'll flow through setAuthenticationFlow, where
- // the provision flow data will be copied into a new auth
- // flow. If it's a hard fail, then the callback will be
- // responsible for cleaning up the now defunct provision flow.
-
- // invoke the callback with an error.
- provFlow.callback(aReason);
- },
-
- /**
- * When navigator.id.genKeyPair is called from provisioning iframe sandbox.
- * Generates a keypair for the current user being provisioned.
- *
- * @param aProvId
- * (int) the identifier of the provisioning caller tied to that sandbox
- *
- * It is an error to call genKeypair without receiving the callback for
- * the beginProvisioning() call first.
- */
- genKeyPair: function genKeyPair(aProvId) {
- // Look up the provisioning caller and make sure it's valid.
- let provFlow = this.getProvisionFlow(aProvId);
-
- if (!provFlow.didBeginProvisioning) {
- let errStr = "ERROR: genKeyPair called before beginProvisioning";
- log(errStr);
- provFlow.callback(errStr);
- return;
- }
-
- // Ok generate a keypair
- jwcrypto.generateKeyPair(jwcrypto.ALGORITHMS.DS160, function gkpCb(err, kp) {
- log("in gkp callback");
- if (err) {
- log("ERROR: genKeyPair:", err);
- provFlow.callback(err);
- return;
- }
-
- provFlow.kp = kp;
-
- // Serialize the publicKey of the keypair and send it back to the
- // sandbox.
- log("genKeyPair: generated keypair for provisioning flow with id:", aProvId);
- provFlow.caller.doGenKeyPairCallback(provFlow.kp.serializedPublicKey);
- }.bind(this));
- },
-
- /**
- * When navigator.id.registerCertificate is called from provisioning iframe
- * sandbox.
- *
- * Sets the certificate for the user for which a certificate was requested
- * via a preceding call to beginProvisioning (and genKeypair).
- *
- * @param aProvId
- * (integer) the identifier of the provisioning caller tied to that
- * sandbox
- *
- * @param aCert
- * (String) A JWT representing the signed certificate for the user
- * being provisioned, provided by the IdP.
- */
- registerCertificate: function registerCertificate(aProvId, aCert) {
- log("registerCertificate:", aProvId, aCert);
-
- // look up provisioning caller, make sure it's valid.
- let provFlow = this.getProvisionFlow(aProvId);
-
- if (!provFlow.caller) {
- reportError("registerCertificate", "No provision flow or caller");
- return;
- }
- if (!provFlow.kp) {
- let errStr = "Cannot register a certificate without a keypair";
- reportError("registerCertificate", errStr);
- provFlow.callback(errStr);
- return;
- }
-
- // store the keypair and certificate just provided in IDStore.
- this._store.addIdentity(provFlow.identity, provFlow.kp, aCert);
-
- // Great success!
- provFlow.callback(null);
-
- // Clean up the flow.
- this._cleanUpProvisionFlow(aProvId);
- },
-
- /**
- * Begin the authentication process with an IdP
- *
- * @param aProvId
- * (int) the identifier of the provisioning flow which failed
- *
- * @param aCallback
- * (function) to invoke upon completion, with
- * first-positional-param error.
- */
- _doAuthentication: function _doAuthentication(aProvId, aIDPParams) {
- log("_doAuthentication: provId:", aProvId, "idpParams:", aIDPParams);
- // create an authentication caller and its identifier AuthId
- // stash aIdentity, idpparams, and callback in it.
-
- // extract authentication URL from idpParams
- let authPath = aIDPParams.idpParams.authentication;
- let authURI = Services.io.newURI("https://" + aIDPParams.domain, null, null).resolve(authPath);
-
- // beginAuthenticationFlow causes the "identity-auth" topic to be
- // observed. Since it's sending a notification to the DOM, there's
- // no callback. We wait for the DOM to trigger the next phase of
- // provisioning.
- this._beginAuthenticationFlow(aProvId, authURI);
-
- // either we bind the AuthID to the sandbox ourselves, or UX does that,
- // in which case we need to tell UX the AuthId.
- // Currently, the UX creates the UI and gets the AuthId from the window
- // and sets is with setAuthenticationFlow
- },
-
- /**
- * The authentication frame has called navigator.id.beginAuthentication
- *
- * IMPORTANT: the aCaller is *always* non-null, even if this is called from
- * a regular content page. We have to make sure, on every DOM call, that
- * aCaller is an expected authentication-flow identifier. If not, we throw
- * an error or something.
- *
- * @param aCaller
- * (object) the authentication caller
- *
- */
- beginAuthentication: function beginAuthentication(aCaller) {
- log("beginAuthentication: caller id:", aCaller.id);
-
- // Begin the authentication flow after having concluded a provisioning
- // flow. The aCaller that the DOM gives us will have the same ID as
- // the provisioning flow we just concluded. (see setAuthenticationFlow)
- let authFlow = this._authenticationFlows[aCaller.id];
- if (!authFlow) {
- return aCaller.doError("beginAuthentication: no flow for caller id", aCaller.id);
- }
-
- authFlow.caller = aCaller;
-
- let identity = this._provisionFlows[authFlow.provId].identity;
-
- // tell the UI to start the authentication process
- log("beginAuthentication: authFlow:", aCaller.id, "identity:", identity);
- return authFlow.caller.doBeginAuthenticationCallback(identity);
- },
-
- /**
- * The auth frame has called navigator.id.completeAuthentication
- *
- * @param aAuthId
- * (int) the identifier of the authentication caller tied to that sandbox
- *
- */
- completeAuthentication: function completeAuthentication(aAuthId) {
- log("completeAuthentication:", aAuthId);
-
- // look up the AuthId caller, and get its callback.
- let authFlow = this._authenticationFlows[aAuthId];
- if (!authFlow) {
- reportError("completeAuthentication", "No auth flow with id", aAuthId);
- return;
- }
- let provId = authFlow.provId;
-
- // delete caller
- delete authFlow['caller'];
- delete this._authenticationFlows[aAuthId];
-
- let provFlow = this.getProvisionFlow(provId);
- provFlow.didAuthentication = true;
- let subject = {
- rpId: provFlow.rpId,
- identity: provFlow.identity,
- };
- Services.obs.notifyObservers({ wrappedJSObject: subject }, "identity-auth-complete", aAuthId);
- },
-
- /**
- * The auth frame has called navigator.id.cancelAuthentication
- *
- * @param aAuthId
- * (int) the identifier of the authentication caller
- *
- */
- cancelAuthentication: function cancelAuthentication(aAuthId) {
- log("cancelAuthentication:", aAuthId);
-
- // look up the AuthId caller, and get its callback.
- let authFlow = this._authenticationFlows[aAuthId];
- if (!authFlow) {
- reportError("cancelAuthentication", "No auth flow with id:", aAuthId);
- return;
- }
- let provId = authFlow.provId;
-
- // delete caller
- delete authFlow['caller'];
- delete this._authenticationFlows[aAuthId];
-
- let provFlow = this.getProvisionFlow(provId);
- provFlow.didAuthentication = true;
- Services.obs.notifyObservers(null, "identity-auth-complete", aAuthId);
-
- // invoke callback with ERROR.
- let errStr = "Authentication canceled by IDP";
- log("ERROR: cancelAuthentication:", errStr);
- provFlow.callback(errStr);
- },
-
- /**
- * Called by the UI to set the ID and caller for the authentication flow after it gets its ID
- */
- setAuthenticationFlow: function(aAuthId, aProvId) {
- // this is the transition point between the two flows,
- // provision and authenticate. We tell the auth flow which
- // provisioning flow it is started from.
- log("setAuthenticationFlow: authId:", aAuthId, "provId:", aProvId);
- this._authenticationFlows[aAuthId] = { provId: aProvId };
- this._provisionFlows[aProvId].authId = aAuthId;
- },
-
- /**
- * Load the provisioning URL in a hidden frame to start the provisioning
- * process.
- */
- _createProvisioningSandbox: function _createProvisioningSandbox(aURL, aCallback) {
- log("_createProvisioningSandbox:", aURL);
-
- if (!this._sandboxConfigured) {
- // Configure message manager listening on the hidden window
- Cu.import("resource://gre/modules/DOMIdentity.jsm");
- DOMIdentity._configureMessages(Services.appShell.hiddenDOMWindow, true);
- this._sandboxConfigured = true;
- }
-
- new Sandbox(aURL, aCallback);
- },
-
- /**
- * Load the authentication UI to start the authentication process.
- */
- _beginAuthenticationFlow: function _beginAuthenticationFlow(aProvId, aURL) {
- log("_beginAuthenticationFlow:", aProvId, aURL);
- let propBag = {provId: aProvId};
-
- Services.obs.notifyObservers({wrappedJSObject:propBag}, "identity-auth", aURL);
- },
-
- /**
- * Clean up a provision flow and the authentication flow and sandbox
- * that may be attached to it.
- */
- _cleanUpProvisionFlow: function _cleanUpProvisionFlow(aProvId) {
- log('_cleanUpProvisionFlow:', aProvId);
- let prov = this._provisionFlows[aProvId];
-
- // Clean up the sandbox, if there is one.
- if (prov.provisioningSandbox) {
- let sandbox = this._provisionFlows[aProvId]['provisioningSandbox'];
- if (sandbox.free) {
- log('_cleanUpProvisionFlow: freeing sandbox');
- sandbox.free();
- }
- delete this._provisionFlows[aProvId]['provisioningSandbox'];
- }
-
- // Clean up a related authentication flow, if there is one.
- if (this._authenticationFlows[prov.authId]) {
- delete this._authenticationFlows[prov.authId];
- }
-
- // Finally delete the provision flow
- delete this._provisionFlows[aProvId];
- }
-
-};
-
-this.IdentityProvider = new IdentityProviderService();
diff --git a/toolkit/identity/IdentityStore.jsm b/toolkit/identity/IdentityStore.jsm
deleted file mode 100644
index 1827a839e..000000000
--- a/toolkit/identity/IdentityStore.jsm
+++ /dev/null
@@ -1,97 +0,0 @@
-/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
-/* vim: set ft=javascript 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/. */
-
-"use strict";
-
-const Cu = Components.utils;
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-this.EXPORTED_SYMBOLS = ["IdentityStore"];
-
-// the data store for IDService
-// written as a separate thing so it can easily be mocked
-function IDServiceStore() {
- this.reset();
-}
-
-// Note: eventually these methods may be async, but we haven no need for this
-// for now, since we're not storing to disk.
-IDServiceStore.prototype = {
- addIdentity: function addIdentity(aEmail, aKeyPair, aCert) {
- this._identities[aEmail] = {keyPair: aKeyPair, cert: aCert};
- },
- fetchIdentity: function fetchIdentity(aEmail) {
- return aEmail in this._identities ? this._identities[aEmail] : null;
- },
- removeIdentity: function removeIdentity(aEmail) {
- let data = this._identities[aEmail];
- delete this._identities[aEmail];
- return data;
- },
- getIdentities: function getIdentities() {
- // XXX - should clone?
- return this._identities;
- },
- clearCert: function clearCert(aEmail) {
- // XXX - should remove key from store?
- this._identities[aEmail].cert = null;
- this._identities[aEmail].keyPair = null;
- },
-
- /**
- * set the login state for a given origin
- *
- * @param aOrigin
- * (string) a web origin
- *
- * @param aState
- * (boolean) whether or not the user is logged in
- *
- * @param aEmail
- * (email) the email address the user is logged in with,
- * or, if not logged in, the default email for that origin.
- */
- setLoginState: function setLoginState(aOrigin, aState, aEmail) {
- if (aState && !aEmail) {
- throw "isLoggedIn cannot be set to true without an email";
- }
- return this._loginStates[aOrigin] = {isLoggedIn: aState, email: aEmail};
- },
- getLoginState: function getLoginState(aOrigin) {
- return aOrigin in this._loginStates ? this._loginStates[aOrigin] : null;
- },
- clearLoginState: function clearLoginState(aOrigin) {
- delete this._loginStates[aOrigin];
- },
-
- reset: function Store_reset() {
- // _identities associates emails with keypairs and certificates
- this._identities = {};
-
- // _loginStates associates. remote origins with a login status and
- // the email the user has chosen as his or her identity when logging
- // into that origin.
- this._loginStates = {};
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
-
- observe: function observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- case "quit-application-granted":
- Services.obs.removeObserver(this, "quit-application-granted");
- this.reset();
- break;
- }
- },
-};
-
-this.IdentityStore = new IDServiceStore();
diff --git a/toolkit/identity/IdentityUtils.jsm b/toolkit/identity/IdentityUtils.jsm
deleted file mode 100644
index a34c0b133..000000000
--- a/toolkit/identity/IdentityUtils.jsm
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
-/* vim: set ft=javascript 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/. */
-
-// functions common to Identity.jsm and MinimalIdentity.jsm
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = [
- "checkDeprecated",
- "checkRenamed",
- "getRandomId",
- "objectCopy",
- "makeMessageObject",
-];
-
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
- "@mozilla.org/uuid-generator;1",
- "nsIUUIDGenerator");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Logger",
- "resource://gre/modules/identity/LogUtils.jsm");
-
-function log(...aMessageArgs) {
- Logger.log.apply(Logger, ["Identity"].concat(aMessageArgs));
-}
-
-function defined(item) {
- return typeof item !== 'undefined';
-}
-
-var checkDeprecated = this.checkDeprecated = function checkDeprecated(aOptions, aField) {
- if (defined(aOptions[aField])) {
- log("WARNING: field is deprecated:", aField);
- return true;
- }
- return false;
-};
-
-this.checkRenamed = function checkRenamed(aOptions, aOldName, aNewName) {
- if (defined(aOptions[aOldName]) &&
- defined(aOptions[aNewName])) {
- let err = "You cannot provide both " + aOldName + " and " + aNewName;
- Logger.reportError(err);
- throw new Error(err);
- }
-
- if (checkDeprecated(aOptions, aOldName)) {
- aOptions[aNewName] = aOptions[aOldName];
- delete(aOptions[aOldName]);
- }
-};
-
-this.getRandomId = function getRandomId() {
- return uuidgen.generateUUID().toString();
-};
-
-/*
- * copy source object into target, excluding private properties
- * (those whose names begin with an underscore)
- */
-this.objectCopy = function objectCopy(source, target) {
- let desc;
- Object.getOwnPropertyNames(source).forEach(function(name) {
- if (name[0] !== '_') {
- desc = Object.getOwnPropertyDescriptor(source, name);
- Object.defineProperty(target, name, desc);
- }
- });
-};
-
-this.makeMessageObject = function makeMessageObject(aRpCaller) {
- let options = {};
-
- options.id = aRpCaller.id;
- options.origin = aRpCaller.origin;
-
- // Backwards compatibility with Persona beta:
- // loggedInUser can be undefined, null, or a string
- options.loggedInUser = aRpCaller.loggedInUser;
-
- // Special flag for internal calls for Persona in b2g
- options._internal = aRpCaller._internal;
-
- Object.keys(aRpCaller).forEach(function(option) {
- // Duplicate the callerobject, scrubbing out functions and other
- // internal variables (like _mm, the message manager object)
- if (!Object.hasOwnProperty(this, option)
- && option[0] !== '_'
- && typeof aRpCaller[option] !== 'function') {
- options[option] = aRpCaller[option];
- }
- });
-
- // check validity of message structure
- if ((typeof options.id === 'undefined') ||
- (typeof options.origin === 'undefined')) {
- let err = "id and origin required in relying-party message: " + JSON.stringify(options);
- reportError(err);
- throw new Error(err);
- }
-
- return options;
-}
-
diff --git a/toolkit/identity/LogUtils.jsm b/toolkit/identity/LogUtils.jsm
deleted file mode 100644
index ec0f4c420..000000000
--- a/toolkit/identity/LogUtils.jsm
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
-/* vim: set ft=javascript 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/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["Logger"];
-const PREF_DEBUG = "toolkit.identity.debug";
-
-const Cu = Components.utils;
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-function IdentityLogger() {
- Services.prefs.addObserver(PREF_DEBUG, this, false);
- this._debug = Services.prefs.getBoolPref(PREF_DEBUG);
- return this;
-}
-
-IdentityLogger.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
-
- observe: function observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- case "nsPref:changed":
- this._debug = Services.prefs.getBoolPref(PREF_DEBUG);
- break;
-
- case "quit-application-granted":
- Services.prefs.removeObserver(PREF_DEBUG, this);
- break;
-
- default:
- this.log("Logger observer", "Unknown topic:", aTopic);
- break;
- }
- },
-
- _generateLogMessage: function _generateLogMessage(aPrefix, args) {
- // create a string representation of a list of arbitrary things
- let strings = [];
-
- // XXX bug 770418 - args look like flattened array, not list of strings
-
- args.forEach(function(arg) {
- if (typeof arg === 'string') {
- strings.push(arg);
- } else if (typeof arg === 'undefined') {
- strings.push('undefined');
- } else if (arg === null) {
- strings.push('null');
- } else {
- try {
- strings.push(JSON.stringify(arg, null, 2));
- } catch (err) {
- strings.push("<<something>>");
- }
- }
- });
- return 'Identity ' + aPrefix + ': ' + strings.join(' ');
- },
-
- /**
- * log() - utility function to print a list of arbitrary things
- *
- * Enable with about:config pref toolkit.identity.debug
- */
- log: function log(aPrefix, ...args) {
- if (!this._debug) {
- return;
- }
- let output = this._generateLogMessage(aPrefix, args);
- dump(output + "\n");
-
- // Additionally, make the output visible in the Error Console
- Services.console.logStringMessage(output);
- },
-
- /**
- * reportError() - report an error through component utils as well as
- * our log function
- */
- reportError: function reportError(aPrefix, ...aArgs) {
- let prefix = aPrefix + ' ERROR';
-
- // Report the error in the browser
- let output = this._generateLogMessage(aPrefix, aArgs);
- Cu.reportError(output);
- dump("ERROR: " + output + "\n");
- for (let frame = Components.stack.caller; frame; frame = frame.caller) {
- dump(frame + "\n");
- }
- }
-
-};
-
-this.Logger = new IdentityLogger();
diff --git a/toolkit/identity/MinimalIdentity.jsm b/toolkit/identity/MinimalIdentity.jsm
deleted file mode 100644
index bceb65659..000000000
--- a/toolkit/identity/MinimalIdentity.jsm
+++ /dev/null
@@ -1,242 +0,0 @@
-/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
-/* vim: set ft=javascript 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/. */
-
-/*
- * This alternate implementation of IdentityService provides just the
- * channels for navigator.id, leaving the certificate storage to a
- * server-provided app.
- *
- * On b2g, the messages identity-controller-watch, -request, and
- * -logout, are observed by the component SignInToWebsite.jsm.
- */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["IdentityService"];
-
-const Cu = Components.utils;
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/identity/LogUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
- "resource://gre/modules/identity/IdentityUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "makeMessageObject",
- "resource://gre/modules/identity/IdentityUtils.jsm");
-
-function log(...aMessageArgs) {
- Logger.log.apply(Logger, ["minimal core"].concat(aMessageArgs));
-}
-function reportError(...aMessageArgs) {
- Logger.reportError.apply(Logger, ["core"].concat(aMessageArgs));
-}
-
-function IDService() {
- Services.obs.addObserver(this, "quit-application-granted", false);
-
- // simplify, it's one object
- this.RP = this;
- this.IDP = this;
-
- // keep track of flows
- this._rpFlows = {};
- this._authFlows = {};
- this._provFlows = {};
-}
-
-IDService.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
-
- observe: function observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- case "quit-application-granted":
- this.shutdown();
- break;
- }
- },
-
- shutdown: function() {
- Services.obs.removeObserver(this, "quit-application-granted");
- },
-
- /**
- * Parse an email into username and domain if it is valid, else return null
- */
- parseEmail: function parseEmail(email) {
- var match = email.match(/^([^@]+)@([^@^/]+.[a-z]+)$/);
- if (match) {
- return {
- username: match[1],
- domain: match[2]
- };
- }
- return null;
- },
-
- /**
- * Register a listener for a given windowID as a result of a call to
- * navigator.id.watch().
- *
- * @param aCaller
- * (Object) an object that represents the caller document, and
- * is expected to have properties:
- * - id (unique, e.g. uuid)
- * - loggedInUser (string or null)
- * - origin (string)
- *
- * and a bunch of callbacks
- * - doReady()
- * - doLogin()
- * - doLogout()
- * - doError()
- * - doCancel()
- *
- */
- watch: function watch(aRpCaller) {
- // store the caller structure and notify the UI observers
- this._rpFlows[aRpCaller.id] = aRpCaller;
-
- log("flows:", Object.keys(this._rpFlows).join(', '));
-
- let options = makeMessageObject(aRpCaller);
- log("sending identity-controller-watch:", options);
- Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-watch", null);
- },
-
- /*
- * The RP has gone away; remove handles to the hidden iframe.
- * It's probable that the frame will already have been cleaned up.
- */
- unwatch: function unwatch(aRpId, aTargetMM) {
- let rp = this._rpFlows[aRpId];
- if (!rp) {
- return;
- }
-
- let options = makeMessageObject({
- id: aRpId,
- origin: rp.origin,
- messageManager: aTargetMM
- });
- log("sending identity-controller-unwatch for id", options.id, options.origin);
- Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-unwatch", null);
-
- // Stop sending messages to this window
- delete this._rpFlows[aRpId];
- },
-
- /**
- * Initiate a login with user interaction as a result of a call to
- * navigator.id.request().
- *
- * @param aRPId
- * (integer) the id of the doc object obtained in .watch()
- *
- * @param aOptions
- * (Object) options including privacyPolicy, termsOfService
- */
- request: function request(aRPId, aOptions) {
- let rp = this._rpFlows[aRPId];
- if (!rp) {
- reportError("request() called before watch()");
- return;
- }
-
- // Notify UX to display identity picker.
- // Pass the doc id to UX so it can pass it back to us later.
- let options = makeMessageObject(rp);
- objectCopy(aOptions, options);
- Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-request", null);
- },
-
- /**
- * Invoked when a user wishes to logout of a site (for instance, when clicking
- * on an in-content logout button).
- *
- * @param aRpCallerId
- * (integer) the id of the doc object obtained in .watch()
- *
- */
- logout: function logout(aRpCallerId) {
- let rp = this._rpFlows[aRpCallerId];
- if (!rp) {
- reportError("logout() called before watch()");
- return;
- }
-
- let options = makeMessageObject(rp);
- Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-logout", null);
- },
-
- childProcessShutdown: function childProcessShutdown(messageManager) {
- Object.keys(this._rpFlows).forEach(function(key) {
- if (this._rpFlows[key]._mm === messageManager) {
- log("child process shutdown for rp", key, "- deleting flow");
- delete this._rpFlows[key];
- }
- }, this);
- },
-
- /*
- * once the UI-and-display-logic components have received
- * notifications, they call back with direct invocation of the
- * following functions (doLogin, doLogout, or doReady)
- */
-
- doLogin: function doLogin(aRpCallerId, aAssertion, aInternalParams) {
- let rp = this._rpFlows[aRpCallerId];
- if (!rp) {
- log("WARNING: doLogin found no rp to go with callerId " + aRpCallerId);
- return;
- }
-
- rp.doLogin(aAssertion, aInternalParams);
- },
-
- doLogout: function doLogout(aRpCallerId) {
- let rp = this._rpFlows[aRpCallerId];
- if (!rp) {
- log("WARNING: doLogout found no rp to go with callerId " + aRpCallerId);
- return;
- }
-
- // Logout from every site with the same origin
- let origin = rp.origin;
- Object.keys(this._rpFlows).forEach(function(key) {
- let rp = this._rpFlows[key];
- if (rp.origin === origin) {
- rp.doLogout();
- }
- }.bind(this));
- },
-
- doReady: function doReady(aRpCallerId) {
- let rp = this._rpFlows[aRpCallerId];
- if (!rp) {
- log("WARNING: doReady found no rp to go with callerId " + aRpCallerId);
- return;
- }
-
- rp.doReady();
- },
-
- doCancel: function doCancel(aRpCallerId) {
- let rp = this._rpFlows[aRpCallerId];
- if (!rp) {
- log("WARNING: doCancel found no rp to go with callerId " + aRpCallerId);
- return;
- }
-
- rp.doCancel();
- }
-};
-
-this.IdentityService = new IDService();
diff --git a/toolkit/identity/RelyingParty.jsm b/toolkit/identity/RelyingParty.jsm
deleted file mode 100644
index 5996383ca..000000000
--- a/toolkit/identity/RelyingParty.jsm
+++ /dev/null
@@ -1,367 +0,0 @@
-/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
-/* vim: set ft=javascript 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/. */
-
-"use strict";
-
-const Cu = Components.utils;
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/identity/LogUtils.jsm");
-Cu.import("resource://gre/modules/identity/IdentityStore.jsm");
-
-this.EXPORTED_SYMBOLS = ["RelyingParty"];
-
-XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
- "resource://gre/modules/identity/IdentityUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this,
- "jwcrypto",
- "resource://gre/modules/identity/jwcrypto.jsm");
-
-function log(...aMessageArgs) {
- Logger.log.apply(Logger, ["RP"].concat(aMessageArgs));
-}
-function reportError(...aMessageArgs) {
- Logger.reportError.apply(Logger, ["RP"].concat(aMessageArgs));
-}
-
-function IdentityRelyingParty() {
- // The store is a singleton shared among Identity, RelyingParty, and
- // IdentityProvider. The Identity module takes care of resetting
- // state in the _store on shutdown.
- this._store = IdentityStore;
-
- this.reset();
-}
-
-IdentityRelyingParty.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
-
- observe: function observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- case "quit-application-granted":
- Services.obs.removeObserver(this, "quit-application-granted");
- this.shutdown();
- break;
-
- }
- },
-
- reset: function RP_reset() {
- // Forget all documents that call in. (These are sometimes
- // referred to as callers.)
- this._rpFlows = {};
- },
-
- shutdown: function RP_shutdown() {
- this.reset();
- Services.obs.removeObserver(this, "quit-application-granted");
- },
-
- /**
- * Register a listener for a given windowID as a result of a call to
- * navigator.id.watch().
- *
- * @param aCaller
- * (Object) an object that represents the caller document, and
- * is expected to have properties:
- * - id (unique, e.g. uuid)
- * - loggedInUser (string or null)
- * - origin (string)
- *
- * and a bunch of callbacks
- * - doReady()
- * - doLogin()
- * - doLogout()
- * - doError()
- * - doCancel()
- *
- */
- watch: function watch(aRpCaller) {
- this._rpFlows[aRpCaller.id] = aRpCaller;
- let origin = aRpCaller.origin;
- let state = this._store.getLoginState(origin) || { isLoggedIn: false, email: null };
-
- log("watch: rpId:", aRpCaller.id,
- "origin:", origin,
- "loggedInUser:", aRpCaller.loggedInUser,
- "loggedIn:", state.isLoggedIn,
- "email:", state.email);
-
- // If the user is already logged in, then there are three cases
- // to deal with:
- //
- // 1. the email is valid and unchanged: 'ready'
- // 2. the email is null: 'login'; 'ready'
- // 3. the email has changed: 'login'; 'ready'
- if (state.isLoggedIn) {
- if (state.email && aRpCaller.loggedInUser === state.email) {
- this._notifyLoginStateChanged(aRpCaller.id, state.email);
- return aRpCaller.doReady();
-
- } else if (aRpCaller.loggedInUser === null) {
- // Generate assertion for existing login
- let options = {loggedInUser: state.email, origin: origin};
- return this._doLogin(aRpCaller, options);
- }
- // A loggedInUser different from state.email has been specified.
- // Change login identity.
-
- let options = {loggedInUser: state.email, origin: origin};
- return this._doLogin(aRpCaller, options);
-
- // If the user is not logged in, there are two cases:
- //
- // 1. a logged in email was provided: 'ready'; 'logout'
- // 2. not logged in, no email given: 'ready';
-
- }
- if (aRpCaller.loggedInUser) {
- return this._doLogout(aRpCaller, {origin: origin});
- }
- return aRpCaller.doReady();
- },
-
- /**
- * A utility for watch() to set state and notify the dom
- * on login
- *
- * Note that this calls _getAssertion
- */
- _doLogin: function _doLogin(aRpCaller, aOptions, aAssertion) {
- log("_doLogin: rpId:", aRpCaller.id, "origin:", aOptions.origin);
-
- let loginWithAssertion = function loginWithAssertion(assertion) {
- this._store.setLoginState(aOptions.origin, true, aOptions.loggedInUser);
- this._notifyLoginStateChanged(aRpCaller.id, aOptions.loggedInUser);
- aRpCaller.doLogin(assertion);
- aRpCaller.doReady();
- }.bind(this);
-
- if (aAssertion) {
- loginWithAssertion(aAssertion);
- } else {
- this._getAssertion(aOptions, function gotAssertion(err, assertion) {
- if (err) {
- reportError("_doLogin:", "Failed to get assertion on login attempt:", err);
- this._doLogout(aRpCaller);
- } else {
- loginWithAssertion(assertion);
- }
- }.bind(this));
- }
- },
-
- /**
- * A utility for watch() to set state and notify the dom
- * on logout.
- */
- _doLogout: function _doLogout(aRpCaller, aOptions) {
- log("_doLogout: rpId:", aRpCaller.id, "origin:", aOptions.origin);
-
- let state = this._store.getLoginState(aOptions.origin) || {};
-
- state.isLoggedIn = false;
- this._notifyLoginStateChanged(aRpCaller.id, null);
-
- aRpCaller.doLogout();
- aRpCaller.doReady();
- },
-
- /**
- * For use with login or logout, emit 'identity-login-state-changed'
- *
- * The notification will send the rp caller id in the properties,
- * and the email of the user in the message.
- *
- * @param aRpCallerId
- * (integer) The id of the RP caller
- *
- * @param aIdentity
- * (string) The email of the user whose login state has changed
- */
- _notifyLoginStateChanged: function _notifyLoginStateChanged(aRpCallerId, aIdentity) {
- log("_notifyLoginStateChanged: rpId:", aRpCallerId, "identity:", aIdentity);
-
- let options = {rpId: aRpCallerId};
- Services.obs.notifyObservers({wrappedJSObject: options},
- "identity-login-state-changed",
- aIdentity);
- },
-
- /**
- * Initiate a login with user interaction as a result of a call to
- * navigator.id.request().
- *
- * @param aRPId
- * (integer) the id of the doc object obtained in .watch()
- *
- * @param aOptions
- * (Object) options including privacyPolicy, termsOfService
- */
- request: function request(aRPId, aOptions) {
- log("request: rpId:", aRPId);
- let rp = this._rpFlows[aRPId];
-
- // Notify UX to display identity picker.
- // Pass the doc id to UX so it can pass it back to us later.
- let options = {rpId: aRPId, origin: rp.origin};
- objectCopy(aOptions, options);
-
- // Append URLs after resolving
- let baseURI = Services.io.newURI(rp.origin, null, null);
- for (let optionName of ["privacyPolicy", "termsOfService"]) {
- if (aOptions[optionName]) {
- options[optionName] = baseURI.resolve(aOptions[optionName]);
- }
- }
-
- Services.obs.notifyObservers({wrappedJSObject: options}, "identity-request", null);
- },
-
- /**
- * Invoked when a user wishes to logout of a site (for instance, when clicking
- * on an in-content logout button).
- *
- * @param aRpCallerId
- * (integer) the id of the doc object obtained in .watch()
- *
- */
- logout: function logout(aRpCallerId) {
- log("logout: RP caller id:", aRpCallerId);
- let rp = this._rpFlows[aRpCallerId];
- if (rp && rp.origin) {
- let origin = rp.origin;
- log("logout: origin:", origin);
- this._doLogout(rp, {origin: origin});
- } else {
- log("logout: no RP found with id:", aRpCallerId);
- }
- // We don't delete this._rpFlows[aRpCallerId], because
- // the user might log back in again.
- },
-
- getDefaultEmailForOrigin: function getDefaultEmailForOrigin(aOrigin) {
- let identities = this.getIdentitiesForSite(aOrigin);
- let result = identities.lastUsed || null;
- log("getDefaultEmailForOrigin:", aOrigin, "->", result);
- return result;
- },
-
- /**
- * Return the list of identities a user may want to use to login to aOrigin.
- */
- getIdentitiesForSite: function getIdentitiesForSite(aOrigin) {
- let rv = { result: [] };
- for (let id in this._store.getIdentities()) {
- rv.result.push(id);
- }
- let loginState = this._store.getLoginState(aOrigin);
- if (loginState && loginState.email)
- rv.lastUsed = loginState.email;
- return rv;
- },
-
- /**
- * Obtain a BrowserID assertion with the specified characteristics.
- *
- * @param aCallback
- * (Function) Callback to be called with (err, assertion) where 'err'
- * can be an Error or NULL, and 'assertion' can be NULL or a valid
- * BrowserID assertion. If no callback is provided, an exception is
- * thrown.
- *
- * @param aOptions
- * (Object) An object that may contain the following properties:
- *
- * "audience" : The audience for which the assertion is to be
- * issued. If this property is not set an exception
- * will be thrown.
- *
- * Any properties not listed above will be ignored.
- */
- _getAssertion: function _getAssertion(aOptions, aCallback) {
- let audience = aOptions.origin;
- let email = aOptions.loggedInUser || this.getDefaultEmailForOrigin(audience);
- log("_getAssertion: audience:", audience, "email:", email);
- if (!audience) {
- throw "audience required for _getAssertion";
- }
-
- // We might not have any identity info for this email
- if (!this._store.fetchIdentity(email)) {
- this._store.addIdentity(email, null, null);
- }
-
- let cert = this._store.fetchIdentity(email)['cert'];
- if (cert) {
- this._generateAssertion(audience, email, function generatedAssertion(err, assertion) {
- if (err) {
- log("ERROR: _getAssertion:", err);
- }
- log("_getAssertion: generated assertion:", assertion);
- return aCallback(err, assertion);
- });
- }
- },
-
- /**
- * Generate an assertion, including provisioning via IdP if necessary,
- * but no user interaction, so if provisioning fails, aCallback is invoked
- * with an error.
- *
- * @param aAudience
- * (string) web origin
- *
- * @param aIdentity
- * (string) the email we're logging in with
- *
- * @param aCallback
- * (function) callback to invoke on completion
- * with first-positional parameter the error.
- */
- _generateAssertion: function _generateAssertion(aAudience, aIdentity, aCallback) {
- log("_generateAssertion: audience:", aAudience, "identity:", aIdentity);
-
- let id = this._store.fetchIdentity(aIdentity);
- if (! (id && id.cert)) {
- let errStr = "Cannot generate an assertion without a certificate";
- log("ERROR: _generateAssertion:", errStr);
- aCallback(errStr);
- return;
- }
-
- let kp = id.keyPair;
-
- if (!kp) {
- let errStr = "Cannot generate an assertion without a keypair";
- log("ERROR: _generateAssertion:", errStr);
- aCallback(errStr);
- return;
- }
-
- jwcrypto.generateAssertion(id.cert, kp, aAudience, aCallback);
- },
-
- /**
- * Clean up references to the provisioning flow for the specified RP.
- */
- _cleanUpProvisionFlow: function RP_cleanUpProvisionFlow(aRPId, aProvId) {
- let rp = this._rpFlows[aRPId];
- if (rp) {
- delete rp['provId'];
- } else {
- log("Error: Couldn't delete provision flow ", aProvId, " for RP ", aRPId);
- }
- },
-
-};
-
-this.RelyingParty = new IdentityRelyingParty();
diff --git a/toolkit/identity/Sandbox.jsm b/toolkit/identity/Sandbox.jsm
deleted file mode 100644
index 68757c212..000000000
--- a/toolkit/identity/Sandbox.jsm
+++ /dev/null
@@ -1,152 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["Sandbox"];
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-const XHTML_NS = "http://www.w3.org/1999/xhtml";
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this,
- "Logger",
- "resource://gre/modules/identity/LogUtils.jsm");
-
-/**
- * An object that represents a sandbox in an iframe loaded with aURL. The
- * callback provided to the constructor will be invoked when the sandbox is
- * ready to be used. The callback will receive this object as its only argument.
- *
- * You must call free() when you are finished with the sandbox to explicitly
- * free up all associated resources.
- *
- * @param aURL
- * (string) URL to load in the sandbox.
- *
- * @param aCallback
- * (function) Callback to be invoked with a Sandbox, when ready.
- */
-this.Sandbox = function Sandbox(aURL, aCallback) {
- // Normalize the URL so the comparison in _makeSandboxContentLoaded works
- this._url = Services.io.newURI(aURL, null, null).spec;
- this._log("Creating sandbox for:", this._url);
- this._createFrame();
- this._createSandbox(aCallback);
-};
-
-this.Sandbox.prototype = {
-
- /**
- * Use the outer window ID as the identifier of the sandbox.
- */
- get id() {
- return this._frame.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
- },
-
- /**
- * Reload the URL in the sandbox. This is useful to reuse a Sandbox (same
- * id and URL).
- */
- reload: function Sandbox_reload(aCallback) {
- this._log("reload:", this.id, ":", this._url);
- this._createSandbox(function createdSandbox(aSandbox) {
- this._log("reloaded sandbox id:", aSandbox.id);
- aCallback(aSandbox);
- }.bind(this));
- },
-
- /**
- * Frees the sandbox and releases the iframe created to host it.
- */
- free: function Sandbox_free() {
- this._log("free:", this.id);
- this._container.removeChild(this._frame);
- this._frame = null;
- this._container = null;
- this._url = null;
- },
-
- /**
- * Creates an empty, hidden iframe and sets it to the _frame
- * property of this object.
- */
- _createFrame: function Sandbox__createFrame() {
- let hiddenWindow = Services.appShell.hiddenDOMWindow;
- let doc = hiddenWindow.document;
-
- // Insert iframe in to create docshell.
- let frame = doc.createElementNS(XHTML_NS, "iframe");
- frame.setAttribute("mozframetype", "content");
- frame.sandbox = "allow-forms allow-scripts allow-same-origin";
- frame.style.visibility = "collapse";
- doc.documentElement.appendChild(frame);
-
- let docShell = frame.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDocShell);
-
- // Stop about:blank from being loaded.
- docShell.stop(Ci.nsIWebNavigation.STOP_NETWORK);
-
- // Disable some types of content
- docShell.allowAuth = false;
- docShell.allowPlugins = false;
- docShell.allowImages = false;
- docShell.allowMedia = false;
- docShell.allowWindowControl = false;
-
- // Disable stylesheet loading since the document is not visible.
- let markupDocViewer = docShell.contentViewer;
- markupDocViewer.authorStyleDisabled = true;
-
- // Set instance properties.
- this._frame = frame;
- this._container = doc.documentElement;
- },
-
- _createSandbox: function Sandbox__createSandbox(aCallback) {
- let self = this;
- function _makeSandboxContentLoaded(event) {
- self._log("_makeSandboxContentLoaded:", self.id,
- event.target.location.toString());
- if (event.target != self._frame.contentDocument) {
- return;
- }
- self._frame.removeEventListener(
- "DOMWindowCreated", _makeSandboxContentLoaded, true
- );
-
- aCallback(self);
- }
-
- this._frame.addEventListener("DOMWindowCreated",
- _makeSandboxContentLoaded,
- true);
-
- // Load the iframe.
- let webNav = this._frame.contentWindow
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation);
-
- webNav.loadURI(
- this._url,
- Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE,
- null, // referrer
- null, // postData
- null // headers
- );
-
- },
-
- _log: function Sandbox__log(...aMessageArgs) {
- Logger.log.apply(Logger, ["sandbox"].concat(aMessageArgs));
- },
-
-};
diff --git a/toolkit/identity/jwcrypto.jsm b/toolkit/identity/jwcrypto.jsm
deleted file mode 100644
index 4bcba730f..000000000
--- a/toolkit/identity/jwcrypto.jsm
+++ /dev/null
@@ -1,180 +0,0 @@
-/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
-/* vim: set ft=javascript 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/. */
-
-"use strict";
-
-
-const Cu = Components.utils;
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/identity/LogUtils.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this,
- "IdentityCryptoService",
- "@mozilla.org/identity/crypto-service;1",
- "nsIIdentityCryptoService");
-
-this.EXPORTED_SYMBOLS = ["jwcrypto"];
-
-const ALGORITHMS = { RS256: "RS256", DS160: "DS160" };
-const DURATION_MS = 1000 * 60 * 2; // 2 minutes default assertion lifetime
-
-function log(...aMessageArgs) {
- Logger.log.apply(Logger, ["jwcrypto"].concat(aMessageArgs));
-}
-
-function generateKeyPair(aAlgorithmName, aCallback) {
- log("Generate key pair; alg =", aAlgorithmName);
-
- IdentityCryptoService.generateKeyPair(aAlgorithmName, function(rv, aKeyPair) {
- if (!Components.isSuccessCode(rv)) {
- return aCallback("key generation failed");
- }
-
- var publicKey;
-
- switch (aKeyPair.keyType) {
- case ALGORITHMS.RS256:
- publicKey = {
- algorithm: "RS",
- exponent: aKeyPair.hexRSAPublicKeyExponent,
- modulus: aKeyPair.hexRSAPublicKeyModulus
- };
- break;
-
- case ALGORITHMS.DS160:
- publicKey = {
- algorithm: "DS",
- y: aKeyPair.hexDSAPublicValue,
- p: aKeyPair.hexDSAPrime,
- q: aKeyPair.hexDSASubPrime,
- g: aKeyPair.hexDSAGenerator
- };
- break;
-
- default:
- return aCallback("unknown key type");
- }
-
- let keyWrapper = {
- serializedPublicKey: JSON.stringify(publicKey),
- _kp: aKeyPair
- };
-
- return aCallback(null, keyWrapper);
- });
-}
-
-function sign(aPayload, aKeypair, aCallback) {
- aKeypair._kp.sign(aPayload, function(rv, signature) {
- if (!Components.isSuccessCode(rv)) {
- log("ERROR: signer.sign failed");
- return aCallback("Sign failed");
- }
- log("signer.sign: success");
- return aCallback(null, signature);
- });
-}
-
-function jwcryptoClass()
-{
-}
-
-jwcryptoClass.prototype = {
- /*
- * Determine the expiration of the assertion. Returns expiry date
- * in milliseconds as integer.
- *
- * @param localtimeOffsetMsec (optional)
- * The number of milliseconds that must be added to the local clock
- * for it to agree with the server. For example, if the local clock
- * if two minutes fast, localtimeOffsetMsec would be -120000
- *
- * @param now (options)
- * Current date in milliseconds. Useful for mocking clock
- * skew in testing.
- */
- getExpiration: function(duration=DURATION_MS, localtimeOffsetMsec=0, now=Date.now()) {
- return now + localtimeOffsetMsec + duration;
- },
-
- isCertValid: function(aCert, aCallback) {
- // XXX check expiration, bug 769850
- aCallback(true);
- },
-
- generateKeyPair: function(aAlgorithmName, aCallback) {
- log("generating");
- generateKeyPair(aAlgorithmName, aCallback);
- },
-
- /*
- * Generate an assertion and return it through the provided callback.
- *
- * @param aCert
- * Identity certificate
- *
- * @param aKeyPair
- * KeyPair object
- *
- * @param aAudience
- * Audience of the assertion
- *
- * @param aOptions (optional)
- * Can include:
- * {
- * localtimeOffsetMsec: <clock offset in milliseconds>,
- * now: <current date in milliseconds>
- * duration: <validity duration for this assertion in milliseconds>
- * }
- *
- * localtimeOffsetMsec is the number of milliseconds that need to be
- * added to the local clock time to make it concur with the server.
- * For example, if the local clock is two minutes fast, the offset in
- * milliseconds would be -120000.
- *
- * @param aCallback
- * Function to invoke with resulting assertion. Assertion
- * will be string or null on failure.
- */
- generateAssertion: function(aCert, aKeyPair, aAudience, aOptions, aCallback) {
- if (typeof aOptions == "function") {
- aCallback = aOptions;
- aOptions = { };
- }
-
- // for now, we hack the algorithm name
- // XXX bug 769851
- var header = {"alg": "DS128"};
- var headerBytes = IdentityCryptoService.base64UrlEncode(
- JSON.stringify(header));
-
- var payload = {
- exp: this.getExpiration(
- aOptions.duration, aOptions.localtimeOffsetMsec, aOptions.now),
- aud: aAudience
- };
- var payloadBytes = IdentityCryptoService.base64UrlEncode(
- JSON.stringify(payload));
-
- log("payload bytes", payload, payloadBytes);
- sign(headerBytes + "." + payloadBytes, aKeyPair, function(err, signature) {
- if (err)
- return aCallback(err);
-
- var signedAssertion = headerBytes + "." + payloadBytes + "." + signature;
- return aCallback(null, aCert + "~" + signedAssertion);
- });
- }
-
-};
-
-this.jwcrypto = new jwcryptoClass();
-this.jwcrypto.ALGORITHMS = ALGORITHMS;
diff --git a/toolkit/identity/moz.build b/toolkit/identity/moz.build
deleted file mode 100644
index fd2ba9c8c..000000000
--- a/toolkit/identity/moz.build
+++ /dev/null
@@ -1,25 +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/.
-
-XPIDL_SOURCES += ['nsIIdentityCryptoService.idl']
-
-XPIDL_MODULE = 'identity'
-
-SOURCES += ['IdentityCryptoService.cpp']
-
-EXTRA_JS_MODULES.identity += [
- 'Identity.jsm',
- 'IdentityProvider.jsm',
- 'IdentityStore.jsm',
- 'IdentityUtils.jsm',
- 'jwcrypto.jsm',
- 'LogUtils.jsm',
- 'MinimalIdentity.jsm',
- 'RelyingParty.jsm',
- 'Sandbox.jsm',
-]
-
-FINAL_LIBRARY = 'xul'
diff --git a/toolkit/identity/nsIIdentityCryptoService.idl b/toolkit/identity/nsIIdentityCryptoService.idl
deleted file mode 100644
index 90149e2e8..000000000
--- a/toolkit/identity/nsIIdentityCryptoService.idl
+++ /dev/null
@@ -1,106 +0,0 @@
-/* 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);
-};