--- a/services/crypto/component/moz.build
+++ b/services/crypto/component/moz.build
@@ -1,21 +1,17 @@
# -*- 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/.
-XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
-
XPIDL_SOURCES += [
'nsIIdentityCryptoService.idl',
- 'nsISyncJPAKE.idl',
]
XPIDL_MODULE = 'services-crypto-component'
SOURCES += [
'IdentityCryptoService.cpp',
- 'nsSyncJPAKE.cpp',
]
FINAL_LIBRARY = 'xul'
deleted file mode 100644
--- a/services/crypto/component/nsISyncJPAKE.idl
+++ /dev/null
@@ -1,103 +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"
-
-[scriptable, uuid(5ab02a98-5122-4b90-93cd-f259c4b42e3a)]
-interface nsISyncJPAKE : nsISupports
-{
- /**
- * Perform first round of the JPAKE exchange.
- *
- * @param aSignerID
- * String identifying the signer.
- * @param aGX1
- * Schnorr signature value g^x1, in hex representation.
- * @param aGV1
- * Schnorr signature value g^v1 (v1 is a random value), in hex
- * representation.
- * @param aR1
- * Schnorr signature value r1 = v1 - x1 * h, in hex representation.
- * @param aGX2
- * Schnorr signature value g^x2, in hex representation.
- * @param aGV2
- * Schnorr signature value g^v2 (v2 is a random value), in hex
- * representation.
- * @param aR2
- * Schnorr signature value r2 = v2 - x2 * h, in hex representation.
- */
- void round1(in ACString aSignerID,
- out ACString aGX1,
- out ACString aGV1,
- out ACString aR1,
- out ACString aGX2,
- out ACString aGV2,
- out ACString aR2);
-
- /**
- * Perform second round of the JPAKE exchange.
- *
- * @param aPeerID
- * String identifying the peer.
- * @param aPIN
- * String containing the weak secret (PIN).
- * @param aGX3
- * Schnorr signature value g^x3, in hex representation.
- * @param aGV3
- * Schnorr signature value g^v3 (v3 is a random value), in hex
- * representation.
- * @param aR3
- * Schnorr signature value r3 = v3 - x3 * h, in hex representation.
- * @param aGX4
- * Schnorr signature value g^x4, in hex representation.
- * @param aGV4
- * Schnorr signature value g^v4 (v4 is a random value), in hex
- * representation.
- * @param aR4
- * Schnorr signature value r4 = v4 - x4 * h, in hex representation.
- * @param aA
- * Schnorr signature value A, in hex representation.
- * @param aGVA
- * Schnorr signature value g^va (va is a random value), in hex
- * representation.
- * @param aRA
- * Schnorr signature value ra = va - xa * h, in hex representation.
- */
- void round2(in ACString aPeerID,
- in ACString aPIN,
- in ACString aGX3,
- in ACString aGV3,
- in ACString aR3,
- in ACString aGX4,
- in ACString aGV4,
- in ACString aR4,
- out ACString aA,
- out ACString aGVA,
- out ACString aRA);
-
- /**
- * Perform the final step of the JPAKE exchange. This will compute
- * the key and expand the key to two keys, an AES256 encryption key
- * and a 256 bit HMAC key. It returns a key confirmation value
- * (SHA256d of the key) and the encryption and HMAC keys.
- *
- * @param aB
- * Schnorr signature value B, in hex representation.
- * @param aGVB
- * Schnorr signature value g^vb (vb is a random value), in hex
- * representation.
- * @param aRB
- * Schnorr signature value rb = vb - xb * h, in hex representation.
- * @param aAES256Key
- * The AES 256 encryption key, in base64 representation.
- * @param aHMAC256Key
- * The 256 bit HMAC key, in base64 representation.
- */
- void final(in ACString aB,
- in ACString aGVB,
- in ACString aRB,
- in ACString aHkdfInfo,
- out ACString aAES256Key,
- out ACString aHMAC256Key);
-};
deleted file mode 100644
--- a/services/crypto/component/nsSyncJPAKE.cpp
+++ /dev/null
@@ -1,484 +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 "nsSyncJPAKE.h"
-
-#include "base64.h"
-#include "keyhi.h"
-#include "mozilla/ModuleUtils.h"
-#include "mozilla/Move.h"
-#include "nsDebug.h"
-#include "nsError.h"
-#include "nsString.h"
-#include "nscore.h"
-#include "pk11pub.h"
-#include "pkcs11.h"
-#include "secerr.h"
-#include "secmodt.h"
-#include "secport.h"
-
-using mozilla::fallible;
-
-static bool
-hex_from_2char(const unsigned char *c2, unsigned char *byteval)
-{
- int i;
- unsigned char offset;
- *byteval = 0;
- for (i=0; i<2; i++) {
- if (c2[i] >= '0' && c2[i] <= '9') {
- offset = c2[i] - '0';
- *byteval |= offset << 4*(1-i);
- } else if (c2[i] >= 'a' && c2[i] <= 'f') {
- offset = c2[i] - 'a';
- *byteval |= (offset + 10) << 4*(1-i);
- } else if (c2[i] >= 'A' && c2[i] <= 'F') {
- offset = c2[i] - 'A';
- *byteval |= (offset + 10) << 4*(1-i);
- } else {
- return false;
- }
- }
- return true;
-}
-
-static bool
-fromHex(const char * str, unsigned char * p, size_t sLen)
-{
- size_t i;
- if (sLen & 1)
- return false;
-
- for (i = 0; i < sLen / 2; ++i) {
- if (!hex_from_2char((const unsigned char *) str + (2*i),
- (unsigned char *) p + i)) {
- return false;
- }
- }
- return true;
-}
-
-static nsresult
-fromHexString(const nsACString & str, unsigned char * p, size_t pMaxLen)
-{
- char * strData = (char *) str.Data();
- unsigned len = str.Length();
- NS_ENSURE_ARG(len / 2 <= pMaxLen);
- if (!fromHex(strData, p, len)) {
- return NS_ERROR_INVALID_ARG;
- }
- return NS_OK;
-}
-
-static bool
-toHexString(const unsigned char * str, unsigned len, nsACString & out)
-{
- static const char digits[] = "0123456789ABCDEF";
- if (!out.SetCapacity(2 * len, fallible))
- return false;
- out.SetLength(0);
- for (unsigned i = 0; i < len; ++i) {
- out.Append(digits[str[i] >> 4]);
- out.Append(digits[str[i] & 0x0f]);
- }
- return true;
-}
-
-static nsresult
-mapErrno()
-{
- int err = PORT_GetError();
- switch (err) {
- case SEC_ERROR_NO_MEMORY: return NS_ERROR_OUT_OF_MEMORY;
- default: return NS_ERROR_UNEXPECTED;
- }
-}
-
-#define NUM_ELEM(x) (sizeof(x) / sizeof (x)[0])
-
-static const char p[] =
- "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD61037E56258A7795A1C"
- "7AD46076982CE6BB956936C6AB4DCFE05E6784586940CA544B9B2140E1EB523F"
- "009D20A7E7880E4E5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1"
- "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D3485261CD068699B"
- "6BA58A1DDBBEF6DB51E8FE34E8A78E542D7BA351C21EA8D8F1D29F5D5D159394"
- "87E27F4416B0CA632C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0"
- "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0EE6F29AF7F642773E"
- "BE8CD5402415A01451A840476B2FCEB0E388D30D4B376C37FE401C2A2C2F941D"
- "AD179C540C1C8CE030D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F"
- "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C560EA878DE87C11E3D"
- "597F1FEA742D73EEC7F37BE43949EF1A0D15C3F3E3FC0A8335617055AC91328E"
- "C22B50FC15B941D3D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73";
-static const char q[] =
- "CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D";
-static const char g[] =
- "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE3B7ACCC54D521E37"
- "F84A4BDD5B06B0970CC2D2BBB715F7B82846F9A0C393914C792E6A923E2117AB"
- "805276A975AADB5261D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1"
- "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A60126FEB2CF05DB8"
- "A7F0F09B3397F3937F2E90B9E5B9C9B6EFEF642BC48351C46FB171B9BFA9EF17"
- "A961CE96C7E7A7CC3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C"
- "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B67299E231F8BD90B3"
- "9AC3AE3BE0C6B6CACEF8289A2E2873D58E51E029CAFBD55E6841489AB66B5B4B"
- "9BA6E2F784660896AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8"
- "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B988567A88126B914D7828"
- "E2B63A6D7ED0747EC59E0E0A23CE7D8A74C1D2C2A7AFB6A29799620F00E11C33"
- "787F7DED3B30E1A22D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B";
-
-NS_IMETHODIMP nsSyncJPAKE::Round1(const nsACString & aSignerID,
- nsACString & aGX1,
- nsACString & aGV1,
- nsACString & aR1,
- nsACString & aGX2,
- nsACString & aGV2,
- nsACString & aR2)
-{
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- NS_ENSURE_STATE(round == JPAKENotStarted);
- NS_ENSURE_STATE(key == nullptr);
-
- static CK_MECHANISM_TYPE mechanisms[] = {
- CKM_NSS_JPAKE_ROUND1_SHA256,
- CKM_NSS_JPAKE_ROUND2_SHA256,
- CKM_NSS_JPAKE_FINAL_SHA256
- };
-
- UniquePK11SlotInfo slot(PK11_GetBestSlotMultiple(mechanisms,
- NUM_ELEM(mechanisms),
- nullptr));
- NS_ENSURE_STATE(slot != nullptr);
-
- CK_BYTE pBuf[(NUM_ELEM(p) - 1) / 2];
- CK_BYTE qBuf[(NUM_ELEM(q) - 1) / 2];
- CK_BYTE gBuf[(NUM_ELEM(g) - 1) / 2];
-
- CK_KEY_TYPE keyType = CKK_NSS_JPAKE_ROUND1;
- NS_ENSURE_STATE(fromHex(p, pBuf, (NUM_ELEM(p) - 1)));
- NS_ENSURE_STATE(fromHex(q, qBuf, (NUM_ELEM(q) - 1)));
- NS_ENSURE_STATE(fromHex(g, gBuf, (NUM_ELEM(g) - 1)));
- CK_ATTRIBUTE keyTemplate[] = {
- { CKA_NSS_JPAKE_SIGNERID, (CK_BYTE *) aSignerID.Data(),
- aSignerID.Length() },
- { CKA_KEY_TYPE, &keyType, sizeof keyType },
- { CKA_PRIME, pBuf, sizeof pBuf },
- { CKA_SUBPRIME, qBuf, sizeof qBuf },
- { CKA_BASE, gBuf, sizeof gBuf }
- };
-
- CK_BYTE gx1Buf[NUM_ELEM(p) / 2];
- CK_BYTE gv1Buf[NUM_ELEM(p) / 2];
- CK_BYTE r1Buf [NUM_ELEM(p) / 2];
- CK_BYTE gx2Buf[NUM_ELEM(p) / 2];
- CK_BYTE gv2Buf[NUM_ELEM(p) / 2];
- CK_BYTE r2Buf [NUM_ELEM(p) / 2];
- CK_NSS_JPAKERound1Params rp = {
- { gx1Buf, sizeof gx1Buf, gv1Buf, sizeof gv1Buf, r1Buf, sizeof r1Buf },
- { gx2Buf, sizeof gx2Buf, gv2Buf, sizeof gv2Buf, r2Buf, sizeof r2Buf }
- };
- SECItem paramsItem;
- paramsItem.data = (unsigned char *) &rp;
- paramsItem.len = sizeof rp;
- key = UniquePK11SymKey(
- PK11_KeyGenWithTemplate(slot.get(), CKM_NSS_JPAKE_ROUND1_SHA256,
- CKM_NSS_JPAKE_ROUND1_SHA256, ¶msItem,
- keyTemplate, NUM_ELEM(keyTemplate), nullptr));
- nsresult rv = key != nullptr
- ? NS_OK
- : mapErrno();
- if (rv == NS_OK) {
- NS_ENSURE_TRUE(toHexString(rp.gx1.pGX, rp.gx1.ulGXLen, aGX1) &&
- toHexString(rp.gx1.pGV, rp.gx1.ulGVLen, aGV1) &&
- toHexString(rp.gx1.pR, rp.gx1.ulRLen, aR1) &&
- toHexString(rp.gx2.pGX, rp.gx2.ulGXLen, aGX2) &&
- toHexString(rp.gx2.pGV, rp.gx2.ulGVLen, aGV2) &&
- toHexString(rp.gx2.pR, rp.gx2.ulRLen, aR2),
- NS_ERROR_OUT_OF_MEMORY);
- round = JPAKEBeforeRound2;
- }
- return rv;
-}
-
-NS_IMETHODIMP nsSyncJPAKE::Round2(const nsACString & aPeerID,
- const nsACString & aPIN,
- const nsACString & aGX3,
- const nsACString & aGV3,
- const nsACString & aR3,
- const nsACString & aGX4,
- const nsACString & aGV4,
- const nsACString & aR4,
- nsACString & aA,
- nsACString & aGVA,
- nsACString & aRA)
-{
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- NS_ENSURE_STATE(round == JPAKEBeforeRound2);
- NS_ENSURE_STATE(key != nullptr);
- NS_ENSURE_ARG(!aPeerID.IsEmpty());
-
- /* PIN cannot be equal to zero when converted to a bignum. NSS 3.12.9 J-PAKE
- assumes that the caller has already done this check. Future versions of
- NSS J-PAKE will do this check internally. See Bug 609068 Comment 4 */
- bool foundNonZero = false;
- for (size_t i = 0; i < aPIN.Length(); ++i) {
- if (aPIN[i] != 0) {
- foundNonZero = true;
- break;
- }
- }
- NS_ENSURE_ARG(foundNonZero);
-
- CK_BYTE gx3Buf[NUM_ELEM(p)/2], gv3Buf[NUM_ELEM(p)/2], r3Buf [NUM_ELEM(p)/2];
- CK_BYTE gx4Buf[NUM_ELEM(p)/2], gv4Buf[NUM_ELEM(p)/2], r4Buf [NUM_ELEM(p)/2];
- CK_BYTE gxABuf[NUM_ELEM(p)/2], gvABuf[NUM_ELEM(p)/2], rABuf [NUM_ELEM(p)/2];
- nsresult rv = fromHexString(aGX3, gx3Buf, sizeof gx3Buf);
- if (rv == NS_OK) rv = fromHexString(aGV3, gv3Buf, sizeof gv3Buf);
- if (rv == NS_OK) rv = fromHexString(aR3, r3Buf, sizeof r3Buf);
- if (rv == NS_OK) rv = fromHexString(aGX4, gx4Buf, sizeof gx4Buf);
- if (rv == NS_OK) rv = fromHexString(aGV4, gv4Buf, sizeof gv4Buf);
- if (rv == NS_OK) rv = fromHexString(aR4, r4Buf, sizeof r4Buf);
- if (rv != NS_OK)
- return rv;
-
- CK_NSS_JPAKERound2Params rp;
- rp.pSharedKey = (CK_BYTE *) aPIN.Data();
- rp.ulSharedKeyLen = aPIN.Length();
- rp.gx3.pGX = gx3Buf; rp.gx3.ulGXLen = aGX3.Length() / 2;
- rp.gx3.pGV = gv3Buf; rp.gx3.ulGVLen = aGV3.Length() / 2;
- rp.gx3.pR = r3Buf; rp.gx3.ulRLen = aR3 .Length() / 2;
- rp.gx4.pGX = gx4Buf; rp.gx4.ulGXLen = aGX4.Length() / 2;
- rp.gx4.pGV = gv4Buf; rp.gx4.ulGVLen = aGV4.Length() / 2;
- rp.gx4.pR = r4Buf; rp.gx4.ulRLen = aR4 .Length() / 2;
- rp.A.pGX = gxABuf; rp.A .ulGXLen = sizeof gxABuf;
- rp.A.pGV = gvABuf; rp.A .ulGVLen = sizeof gxABuf;
- rp.A.pR = rABuf; rp.A .ulRLen = sizeof gxABuf;
-
- // Bug 629090: NSS 3.12.9 J-PAKE fails to check that gx^4 != 1, so check here.
- bool gx4Good = false;
- for (unsigned i = 0; i < rp.gx4.ulGXLen; ++i) {
- if (rp.gx4.pGX[i] > 1 || (rp.gx4.pGX[i] != 0 && i < rp.gx4.ulGXLen - 1)) {
- gx4Good = true;
- break;
- }
- }
- NS_ENSURE_ARG(gx4Good);
-
- SECItem paramsItem;
- paramsItem.data = (unsigned char *) &rp;
- paramsItem.len = sizeof rp;
- CK_KEY_TYPE keyType = CKK_NSS_JPAKE_ROUND2;
- CK_ATTRIBUTE keyTemplate[] = {
- { CKA_NSS_JPAKE_PEERID, (CK_BYTE *) aPeerID.Data(), aPeerID.Length(), },
- { CKA_KEY_TYPE, &keyType, sizeof keyType }
- };
- UniquePK11SymKey newKey(PK11_DeriveWithTemplate(key.get(),
- CKM_NSS_JPAKE_ROUND2_SHA256,
- ¶msItem,
- CKM_NSS_JPAKE_FINAL_SHA256,
- CKA_DERIVE, 0,
- keyTemplate,
- NUM_ELEM(keyTemplate),
- false));
- if (newKey != nullptr) {
- if (toHexString(rp.A.pGX, rp.A.ulGXLen, aA) &&
- toHexString(rp.A.pGV, rp.A.ulGVLen, aGVA) &&
- toHexString(rp.A.pR, rp.A.ulRLen, aRA)) {
- round = JPAKEAfterRound2;
- key = Move(newKey);
- return NS_OK;
- } else {
- rv = NS_ERROR_OUT_OF_MEMORY;
- }
- } else {
- rv = mapErrno();
- }
-
- return rv;
-}
-
-static nsresult
-setBase64(const unsigned char * data, unsigned len, nsACString & out)
-{
- nsresult rv = NS_OK;
- const char * base64 = BTOA_DataToAscii(data, len);
-
- if (base64 != nullptr) {
- size_t len = PORT_Strlen(base64);
- if (out.SetCapacity(len, fallible)) {
- out.SetLength(0);
- out.Append(base64, len);
- } else {
- rv = NS_ERROR_OUT_OF_MEMORY;
- }
- PORT_Free((void*) base64);
- } else {
- rv = NS_ERROR_OUT_OF_MEMORY;
- }
- return rv;
-}
-
-static nsresult
-base64KeyValue(PK11SymKey * key, nsACString & keyString)
-{
- nsresult rv = NS_OK;
- if (PK11_ExtractKeyValue(key) == SECSuccess) {
- const SECItem * value = PK11_GetKeyData(key);
- rv = value != nullptr && value->data != nullptr && value->len > 0
- ? setBase64(value->data, value->len, keyString)
- : NS_ERROR_UNEXPECTED;
- } else {
- rv = mapErrno();
- }
- return rv;
-}
-
-static nsresult
-extractBase64KeyValue(UniquePK11SymKey & keyBlock, CK_ULONG bitPosition,
- CK_MECHANISM_TYPE destMech, int keySize,
- nsACString & keyString)
-{
- SECItem paramsItem;
- paramsItem.data = (CK_BYTE *) &bitPosition;
- paramsItem.len = sizeof bitPosition;
- PK11SymKey * key = PK11_Derive(keyBlock.get(), CKM_EXTRACT_KEY_FROM_KEY,
- ¶msItem, destMech,
- CKA_SIGN, keySize);
- if (key == nullptr)
- return mapErrno();
- nsresult rv = base64KeyValue(key, keyString);
- PK11_FreeSymKey(key);
- return rv;
-}
-
-
-NS_IMETHODIMP nsSyncJPAKE::Final(const nsACString & aB,
- const nsACString & aGVB,
- const nsACString & aRB,
- const nsACString & aHKDFInfo,
- nsACString & aAES256Key,
- nsACString & aHMAC256Key)
-{
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- static const unsigned AES256_KEY_SIZE = 256 / 8;
- static const unsigned HMAC_SHA256_KEY_SIZE = 256 / 8;
- CK_EXTRACT_PARAMS aesBitPosition = 0;
- CK_EXTRACT_PARAMS hmacBitPosition = aesBitPosition + (AES256_KEY_SIZE * 8);
-
- NS_ENSURE_STATE(round == JPAKEAfterRound2);
- NS_ENSURE_STATE(key != nullptr);
-
- CK_BYTE gxBBuf[NUM_ELEM(p)/2], gvBBuf[NUM_ELEM(p)/2], rBBuf [NUM_ELEM(p)/2];
- nsresult rv = fromHexString(aB, gxBBuf, sizeof gxBBuf);
- if (rv == NS_OK) rv = fromHexString(aGVB, gvBBuf, sizeof gvBBuf);
- if (rv == NS_OK) rv = fromHexString(aRB, rBBuf, sizeof rBBuf);
- if (rv != NS_OK)
- return rv;
-
- CK_NSS_JPAKEFinalParams rp;
- rp.B.pGX = gxBBuf; rp.B.ulGXLen = aB .Length() / 2;
- rp.B.pGV = gvBBuf; rp.B.ulGVLen = aGVB.Length() / 2;
- rp.B.pR = rBBuf; rp.B.ulRLen = aRB .Length() / 2;
- SECItem paramsItem;
- paramsItem.data = (unsigned char *) &rp;
- paramsItem.len = sizeof rp;
- UniquePK11SymKey keyMaterial(PK11_Derive(key.get(), CKM_NSS_JPAKE_FINAL_SHA256,
- ¶msItem, CKM_NSS_HKDF_SHA256,
- CKA_DERIVE, 0));
- UniquePK11SymKey keyBlock;
-
- if (keyMaterial == nullptr)
- rv = mapErrno();
-
- if (rv == NS_OK) {
- CK_NSS_HKDFParams hkdfParams;
- hkdfParams.bExtract = CK_TRUE;
- hkdfParams.pSalt = nullptr;
- hkdfParams.ulSaltLen = 0;
- hkdfParams.bExpand = CK_TRUE;
- hkdfParams.pInfo = (CK_BYTE *) aHKDFInfo.Data();
- hkdfParams.ulInfoLen = aHKDFInfo.Length();
- paramsItem.data = (unsigned char *) &hkdfParams;
- paramsItem.len = sizeof hkdfParams;
- keyBlock = UniquePK11SymKey(
- PK11_Derive(keyMaterial.get(), CKM_NSS_HKDF_SHA256, ¶msItem,
- CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE,
- AES256_KEY_SIZE + HMAC_SHA256_KEY_SIZE));
- if (keyBlock == nullptr)
- rv = mapErrno();
- }
-
- if (rv == NS_OK) {
- rv = extractBase64KeyValue(keyBlock, aesBitPosition, CKM_AES_CBC,
- AES256_KEY_SIZE, aAES256Key);
- }
- if (rv == NS_OK) {
- rv = extractBase64KeyValue(keyBlock, hmacBitPosition, CKM_SHA256_HMAC,
- HMAC_SHA256_KEY_SIZE, aHMAC256Key);
- }
-
- if (rv == NS_OK) {
- SECStatus srv = PK11_ExtractKeyValue(keyMaterial.get());
- NS_ENSURE_TRUE(srv == SECSuccess, NS_ERROR_UNEXPECTED);
- SECItem * keyMaterialBytes = PK11_GetKeyData(keyMaterial.get());
- NS_ENSURE_TRUE(keyMaterialBytes != nullptr, NS_ERROR_UNEXPECTED);
- }
-
- return rv;
-}
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsSyncJPAKE)
-NS_DEFINE_NAMED_CID(NS_SYNCJPAKE_CID);
-
-nsSyncJPAKE::nsSyncJPAKE() : round(JPAKENotStarted), key(nullptr) { }
-
-nsSyncJPAKE::~nsSyncJPAKE()
-{
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
- return;
- }
- destructorSafeDestroyNSSReference();
- shutdown(ShutdownCalledFrom::Object);
-}
-
-void
-nsSyncJPAKE::virtualDestroyNSSReference()
-{
- destructorSafeDestroyNSSReference();
-}
-
-void
-nsSyncJPAKE::destructorSafeDestroyNSSReference()
-{
- key = nullptr;
-}
-
-static const mozilla::Module::CIDEntry kServicesCryptoCIDs[] = {
- { &kNS_SYNCJPAKE_CID, false, nullptr, nsSyncJPAKEConstructor },
- { nullptr }
-};
-
-static const mozilla::Module::ContractIDEntry kServicesCryptoContracts[] = {
- { NS_SYNCJPAKE_CONTRACTID, &kNS_SYNCJPAKE_CID },
- { nullptr }
-};
-
-static const mozilla::Module kServicesCryptoModule = {
- mozilla::Module::kVersion,
- kServicesCryptoCIDs,
- kServicesCryptoContracts
-};
-
-NSMODULE_DEFN(nsServicesCryptoModule) = &kServicesCryptoModule;
deleted file mode 100644
--- a/services/crypto/component/nsSyncJPAKE.h
+++ /dev/null
@@ -1,38 +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/. */
-#ifndef nsSyncJPAKE_h__
-#define nsSyncJPAKE_h__
-
-#include "ScopedNSSTypes.h"
-#include "nsISyncJPAKE.h"
-#include "nsNSSShutDown.h"
-
-#define NS_SYNCJPAKE_CONTRACTID \
- "@mozilla.org/services-crypto/sync-jpake;1"
-
-#define NS_SYNCJPAKE_CID \
- {0x0b9721c0, 0x1805, 0x47c3, {0x86, 0xce, 0x68, 0x13, 0x79, 0x5a, 0x78, 0x3f}}
-
-using namespace mozilla;
-
-class nsSyncJPAKE : public nsISyncJPAKE
- , public nsNSSShutDownObject
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSISYNCJPAKE
- nsSyncJPAKE();
-protected:
- virtual ~nsSyncJPAKE();
-private:
- virtual void virtualDestroyNSSReference() override;
- void destructorSafeDestroyNSSReference();
-
- enum { JPAKENotStarted, JPAKEBeforeRound2, JPAKEAfterRound2 } round;
- UniquePK11SymKey key;
-};
-
-NS_IMPL_ISUPPORTS(nsSyncJPAKE, nsISyncJPAKE)
-
-#endif // nsSyncJPAKE_h__
deleted file mode 100644
--- a/services/crypto/component/tests/unit/test_jpake.js
+++ /dev/null
@@ -1,289 +0,0 @@
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-
-// Ensure PSM is initialized.
-Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
-
-function do_check_throws(func) {
- let have_error = false;
- try {
- func();
- } catch (ex) {
- dump("Was expecting an exception. Caught: " + ex + "\n");
- have_error = true;
- }
- do_check_true(have_error);
-}
-
-function test_success() {
- let a = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
- let b = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
-
- let a_gx1 = {};
- let a_gv1 = {};
- let a_r1 = {};
- let a_gx2 = {};
- let a_gv2 = {};
- let a_r2 = {};
-
- let b_gx1 = {};
- let b_gv1 = {};
- let b_r1 = {};
- let b_gx2 = {};
- let b_gv2 = {};
- let b_r2 = {};
-
- a.round1("alice", a_gx1, a_gv1, a_r1, a_gx2, a_gv2, a_r2);
- b.round1("bob", b_gx1, b_gv1, b_r1, b_gx2, b_gv2, b_r2);
-
- let a_A = {};
- let a_gva = {};
- let a_ra = {};
-
- let b_A = {};
- let b_gva = {};
- let b_ra = {};
-
- a.round2("bob", "sekrit", b_gx1.value, b_gv1.value, b_r1.value,
- b_gx2.value, b_gv2.value, b_r2.value, a_A, a_gva, a_ra);
- b.round2("alice", "sekrit", a_gx1.value, a_gv1.value, a_r1.value,
- a_gx2.value, a_gv2.value, a_r2.value, b_A, b_gva, b_ra);
-
- let a_aes = {};
- let a_hmac = {};
- let b_aes = {};
- let b_hmac = {};
-
- a.final(b_A.value, b_gva.value, b_ra.value, "ohai", a_aes, a_hmac);
- b.final(a_A.value, a_gva.value, a_ra.value, "ohai", b_aes, b_hmac);
-
- do_check_eq(a_aes.value, b_aes.value);
- do_check_eq(a_hmac.value, b_hmac.value);
-}
-
-function test_failure(modlen) {
- let a = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
- let b = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
-
- let a_gx1 = {};
- let a_gv1 = {};
- let a_r1 = {};
- let a_gx2 = {};
- let a_gv2 = {};
- let a_r2 = {};
-
- let b_gx1 = {};
- let b_gv1 = {};
- let b_r1 = {};
- let b_gx2 = {};
- let b_gv2 = {};
- let b_r2 = {};
-
- a.round1("alice", a_gx1, a_gv1, a_r1, a_gx2, a_gv2, a_r2);
- b.round1("bob", b_gx1, b_gv1, b_r1, b_gx2, b_gv2, b_r2);
-
- let a_A = {};
- let a_gva = {};
- let a_ra = {};
-
- let b_A = {};
- let b_gva = {};
- let b_ra = {};
-
- // Note how the PINs are different (secret vs. sekrit)
- a.round2("bob", "secret", b_gx1.value, b_gv1.value, b_r1.value,
- b_gx2.value, b_gv2.value, b_r2.value, a_A, a_gva, a_ra);
- b.round2("alice", "sekrit", a_gx1.value, a_gv1.value, a_r1.value,
- a_gx2.value, a_gv2.value, a_r2.value, b_A, b_gva, b_ra);
-
- let a_aes = {};
- let a_hmac = {};
- let b_aes = {};
- let b_hmac = {};
-
- a.final(b_A.value, b_gva.value, b_ra.value, "ohai", a_aes, a_hmac);
- b.final(a_A.value, a_gva.value, a_ra.value, "ohai", b_aes, b_hmac);
-
- do_check_neq(a_aes.value, b_aes.value);
- do_check_neq(a_hmac.value, b_hmac.value);
-}
-
-function test_same_signerids() {
- let a = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
- let b = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
-
- let gx1 = {};
- let gv1 = {};
- let r1 = {};
- let gx2 = {};
- let gv2 = {};
- let r2 = {};
-
- a.round1("alice", {}, {}, {}, {}, {}, {});
- b.round1("alice", gx1, gv1, r1, gx2, gv2, r2);
- do_check_throws(function() {
- a.round2("alice", "sekrit", gx1.value, gv1.value, r1.value,
- gx2.value, gv2.value, r2.value, {}, {}, {});
- });
-}
-
-function test_bad_zkp() {
- let a = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
- let b = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
-
- let gx1 = {};
- let gv1 = {};
- let r1 = {};
- let gx2 = {};
- let gv2 = {};
- let r2 = {};
-
- a.round1("alice", {}, {}, {}, {}, {}, {});
- b.round1("bob", gx1, gv1, r1, gx2, gv2, r2);
- do_check_throws(function() {
- a.round2("invalid", "sekrit", gx1.value, gv1.value, r1.value,
- gx2.value, gv2.value, r2.value, {}, {}, {});
- });
-}
-
-function test_x4_zero() {
- // The PKCS#11 API for J-PAKE does not allow us to choose any of the nonces.
- // In order to test the defence against x4 (mod p) == 1, we had to generate
- // our own signed nonces using a the FreeBL JPAKE_Sign function directly.
- // To verify the signatures are accurate, pass the given value of R as the
- // "testRandom" parameter to FreeBL's JPAKE_Sign, along with the given values
- // for X and GX, using signerID "alice". Then verify that each GV returned
- // from JPAKE_Sign matches the value specified here.
- let test = function(badGX, badX_GV, badX_R) {
- let a = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
- let b = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
-
- let a_gx1 = {};
- let a_gv1 = {};
- let a_r1 = {};
- let a_gx2 = {};
- let a_gv2 = {};
- let a_r2 = {};
-
- let b_gx1 = {};
- let b_gv1 = {};
- let b_r1 = {};
- let b_gx2 = {};
- let b_gv2 = {};
- let b_r2 = {};
-
- a.round1("alice", a_gx1, a_gv1, a_r1, a_gx2, a_gv2, a_r2);
- b.round1("bob", b_gx1, b_gv1, b_r1, b_gx2, b_gv2, b_r2);
-
- // Replace the g^x2 generated by A with the given illegal value.
- a_gx2.value = badGX;
- a_gv2.value = badX_GV;
- a_r2.value = badX_R;
-
- let b_A = {};
- let b_gva = {};
- let b_ra = {};
-
- do_check_throws(function() {
- b.round2("alice", "secret", a_gx1.value, a_gv1.value, a_r1.value,
- a_gx2.value, a_gv2.value, a_r2.value, b_A, b_gva, b_ra);
- });
- };
-
- // g^x is NIST 3072's p + 1, (p + 1) mod p == 1, x == 0
- test("90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD61037E56258A7795A1C"
- + "7AD46076982CE6BB956936C6AB4DCFE05E6784586940CA544B9B2140E1EB523F"
- + "009D20A7E7880E4E5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1"
- + "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D3485261CD068699B"
- + "6BA58A1DDBBEF6DB51E8FE34E8A78E542D7BA351C21EA8D8F1D29F5D5D159394"
- + "87E27F4416B0CA632C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0"
- + "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0EE6F29AF7F642773E"
- + "BE8CD5402415A01451A840476B2FCEB0E388D30D4B376C37FE401C2A2C2F941D"
- + "AD179C540C1C8CE030D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F"
- + "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C560EA878DE87C11E3D"
- + "597F1FEA742D73EEC7F37BE43949EF1A0D15C3F3E3FC0A8335617055AC91328E"
- + "C22B50FC15B941D3D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB74",
- "5386107A0DD4A96ECF8D9BCF864BDE23AAEF13351F5550D777A32C1FEC165ED67AE51"
- + "66C3876AABC1FED1A0993754F3AEE256530F529548F8FE010BC0D070175569845"
- + "CF009AD24BC897A9CA1F18E1A9CE421DD54FD93AB528BC2594B47791713165276"
- + "7B76903190C3DCD2076FEC1E61FFFC32D1B07273B06EA2889E66FCBFD41FE8984"
- + "5FCE36056B09D1F20E58BB6BAA07A32796F11998BEF0AB3D387E2FB4FE3073FEB"
- + "634BA91709010A70DA29C06F8F92D638C4F158680EAFEB5E0E323BD7DACB671C0"
- + "BA3EDEEAB5CAA243CABAB28E7205AC9A0AAEAFE132635DAC7FE001C19F880A96E"
- + "395C42536D694F81B4F44DC66D7D6FBE933C56ABF585837291D8751C18EB1F3FB"
- + "620582E6A7B795D699E38C270863A289583CB9D07651E6BA3B82BC656B49BD09B"
- + "6B8C27F370120C7CB89D0829BE51D56356EA836012E9204FF4D1CA8B1B7F9C768"
- + "4BB2B0F226FD4042EEBAD931FDBD4F81F8425B305752F5E37FFA2B73BB5A034EC"
- + "7EEF5AAC92EA212897E3A2B8961D2147710ECCE127B942AB2",
- "05CC4DF005FE006C11111624E14806E4A904A4D1D6A53E795AC7867A960CD4FD");
-
- // x == 0 implies g^x == 1
- test("01",
- "488759644532FA7C53E5239F2A365D4B9189582BDD2967A1852FE56568382B65"
- + "C66BDFCD9B581EAEF4BB497CAF1290ECDFA47A1D1658DC5DC9248D9A4135"
- + "DC70B6A8497CDF117236841FA18500DC696A92EEF5000ABE68E9C75B37BC"
- + "6A722126BE728163AA90A6B03D5585994D3403557EEF08E819C72D143BBC"
- + "CDF74559645066CB3607E1B0430365356389FC8FB3D66FD2B6E2E834EC23"
- + "0B0234956752D07F983C918488C8E5A124B062D50B44C5E6FB36BCB03E39"
- + "0385B17CF8062B6688371E6AF5915C2B1AAA31C9294943CC6DC1B994FC09"
- + "49CA31828B83F3D6DFB081B26045DFD9F10092588B63F1D6E68881A06522"
- + "5A417CA9555B036DE89D349AC794A43EB28FE320F9A321F06A9364C88B54"
- + "99EEF4816375B119824ACC9AA56D1340B6A49D05F855DE699B351012028C"
- + "CA43001F708CC61E71CA3849935BEEBABC0D268CD41B8D2B8DCA705FDFF8"
- + "1DAA772DA96EDEA0B291FD5C0C1B8EFE5318D37EBC1BFF53A9DDEC4171A6"
- + "479E341438970058E25C8F2BCDA6166C8BF1B065C174",
- "8B2BACE575179D762F6F2FFDBFF00B497C07766AB3EED9961447CF6F43D06A97");
-}
-
-function test_invalid_input_round2() {
- let a = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
-
- a.round1("alice", {}, {}, {}, {}, {}, {});
- do_check_throws(function() {
- a.round2("invalid", "sekrit", "some", "real", "garbage",
- "even", "more", "garbage", {}, {}, {});
- });
-}
-
-function test_invalid_input_final() {
- let a = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
- let b = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
-
- let gx1 = {};
- let gv1 = {};
- let r1 = {};
- let gx2 = {};
- let gv2 = {};
- let r2 = {};
-
- a.round1("alice", {}, {}, {}, {}, {}, {});
- b.round1("bob", gx1, gv1, r1, gx2, gv2, r2);
- a.round2("bob", "sekrit", gx1.value, gv1.value, r1.value,
- gx2.value, gv2.value, r2.value, {}, {}, {});
- do_check_throws(function() {
- a.final("some", "garbage", "alright", "foobar-info", {}, {});
- });
-}
-
-function run_test() {
- test_x4_zero();
- test_success();
- test_failure();
- test_same_signerids();
- test_bad_zkp();
- test_invalid_input_round2();
- test_invalid_input_final();
-}
deleted file mode 100644
--- a/services/crypto/component/tests/unit/xpcshell.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[DEFAULT]
-head =
-firefox-appdir = browser
-
-[test_jpake.js]
--- a/services/sync/modules/constants.js
+++ b/services/sync/modules/constants.js
@@ -119,17 +119,16 @@ MASTER_PASSWORD_LOCKED: "
// success states
LOGIN_SUCCEEDED: "success.login",
SYNC_SUCCEEDED: "success.sync",
ENGINE_SUCCEEDED: "success.engine",
// login failure status codes:
LOGIN_FAILED_NO_USERNAME: "error.login.reason.no_username",
-LOGIN_FAILED_NO_PASSWORD: "error.login.reason.no_password2",
LOGIN_FAILED_NO_PASSPHRASE: "error.login.reason.no_recoverykey",
LOGIN_FAILED_NETWORK_ERROR: "error.login.reason.network",
LOGIN_FAILED_SERVER_ERROR: "error.login.reason.server",
LOGIN_FAILED_INVALID_PASSPHRASE: "error.login.reason.recoverykey",
LOGIN_FAILED_LOGIN_REJECTED: "error.login.reason.account",
// sync failure status codes
METARECORD_DOWNLOAD_FAIL: "error.sync.reason.metarecord_download_fail",
@@ -150,28 +149,16 @@ ENGINE_UPLOAD_FAIL: "
ENGINE_DOWNLOAD_FAIL: "error.engine.reason.record_download_fail",
ENGINE_UNKNOWN_FAIL: "error.engine.reason.unknown_fail",
ENGINE_APPLY_FAIL: "error.engine.reason.apply_fail",
ENGINE_METARECORD_DOWNLOAD_FAIL: "error.engine.reason.metarecord_download_fail",
ENGINE_METARECORD_UPLOAD_FAIL: "error.engine.reason.metarecord_upload_fail",
// an upload failure where the batch was interrupted with a 412
ENGINE_BATCH_INTERRUPTED: "error.engine.reason.batch_interrupted",
-JPAKE_ERROR_CHANNEL: "jpake.error.channel",
-JPAKE_ERROR_NETWORK: "jpake.error.network",
-JPAKE_ERROR_SERVER: "jpake.error.server",
-JPAKE_ERROR_TIMEOUT: "jpake.error.timeout",
-JPAKE_ERROR_INTERNAL: "jpake.error.internal",
-JPAKE_ERROR_INVALID: "jpake.error.invalid",
-JPAKE_ERROR_NODATA: "jpake.error.nodata",
-JPAKE_ERROR_KEYMISMATCH: "jpake.error.keymismatch",
-JPAKE_ERROR_WRONGMESSAGE: "jpake.error.wrongmessage",
-JPAKE_ERROR_USERABORT: "jpake.error.userabort",
-JPAKE_ERROR_DELAYUNSUPPORTED: "jpake.error.delayunsupported",
-
// info types for Service.getStorageInfo
INFO_COLLECTIONS: "collections",
INFO_COLLECTION_USAGE: "collection_usage",
INFO_COLLECTION_COUNTS: "collection_counts",
INFO_QUOTA: "quota",
// Ways that a sync can be disabled (messages only to be printed in debug log)
kSyncMasterPasswordLocked: "User elected to leave Master Password locked",
deleted file mode 100644
--- a/services/sync/modules/jpakeclient.js
+++ /dev/null
@@ -1,773 +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/. */
-
-this.EXPORTED_SYMBOLS = ["JPAKEClient", "SendCredentialsController"];
-
-var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-common/rest.js");
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/util.js");
-
-const REQUEST_TIMEOUT = 60; // 1 minute
-const KEYEXCHANGE_VERSION = 3;
-
-const JPAKE_SIGNERID_SENDER = "sender";
-const JPAKE_SIGNERID_RECEIVER = "receiver";
-const JPAKE_LENGTH_SECRET = 8;
-const JPAKE_LENGTH_CLIENTID = 256;
-const JPAKE_VERIFY_VALUE = "0123456789ABCDEF";
-
-
-/**
- * Client to exchange encrypted data using the J-PAKE algorithm.
- * The exchange between two clients of this type looks like this:
- *
- *
- * Mobile Server Desktop
- * ===================================================================
- * |
- * retrieve channel <---------------|
- * generate random secret |
- * show PIN = secret + channel | ask user for PIN
- * upload Mobile's message 1 ------>|
- * |----> retrieve Mobile's message 1
- * |<----- upload Desktop's message 1
- * retrieve Desktop's message 1 <---|
- * upload Mobile's message 2 ------>|
- * |----> retrieve Mobile's message 2
- * | compute key
- * |<----- upload Desktop's message 2
- * retrieve Desktop's message 2 <---|
- * compute key |
- * encrypt known value ------------>|
- * |-------> retrieve encrypted value
- * | verify against local known value
- *
- * At this point Desktop knows whether the PIN was entered correctly.
- * If it wasn't, Desktop deletes the session. If it was, the account
- * setup can proceed. If Desktop doesn't yet have an account set up,
- * it will keep the channel open and let the user connect to or
- * create an account.
- *
- * | encrypt credentials
- * |<------------- upload credentials
- * retrieve credentials <-----------|
- * verify HMAC |
- * decrypt credentials |
- * delete session ----------------->|
- * start syncing |
- *
- *
- * Create a client object like so:
- *
- * let client = new JPAKEClient(controller);
- *
- * The 'controller' object must implement the following methods:
- *
- * displayPIN(pin) -- Called when a PIN has been generated and is ready to
- * be displayed to the user. Only called on the client where the pairing
- * was initiated with 'receiveNoPIN()'.
- *
- * onPairingStart() -- Called when the pairing has started and messages are
- * being sent back and forth over the channel. Only called on the client
- * where the pairing was initiated with 'receiveNoPIN()'.
- *
- * onPaired() -- Called when the device pairing has been established and
- * we're ready to send the credentials over. To do that, the controller
- * must call 'sendAndComplete()' while the channel is active.
- *
- * onComplete(data) -- Called after transfer has been completed. On
- * the sending side this is called with no parameter and as soon as the
- * data has been uploaded. This does not mean the receiving side has
- * actually retrieved them yet.
- *
- * onAbort(error) -- Called whenever an error is encountered. All errors lead
- * to an abort and the process has to be started again on both sides.
- *
- * To start the data transfer on the receiving side, call
- *
- * client.receiveNoPIN();
- *
- * This will allocate a new channel on the server, generate a PIN, have it
- * displayed and then do the transfer once the protocol has been completed
- * with the sending side.
- *
- * To initiate the transfer from the sending side, call
- *
- * client.pairWithPIN(pin, true);
- *
- * Once the pairing has been established, the controller's 'onPaired()' method
- * will be called. To then transmit the data, call
- *
- * client.sendAndComplete(data);
- *
- * To abort the process, call
- *
- * client.abort();
- *
- * Note that after completion or abort, the 'client' instance may not be reused.
- * You will have to create a new one in case you'd like to restart the process.
- */
-this.JPAKEClient = function JPAKEClient(controller) {
- this.controller = controller;
-
- this._log = Log.repository.getLogger("Sync.JPAKEClient");
- this._log.level = Log.Level[Svc.Prefs.get(
- "log.logger.service.jpakeclient", "Debug")];
-
- this._serverURL = Svc.Prefs.get("jpake.serverURL");
- this._pollInterval = Svc.Prefs.get("jpake.pollInterval");
- this._maxTries = Svc.Prefs.get("jpake.maxTries");
- if (this._serverURL.slice(-1) != "/") {
- this._serverURL += "/";
- }
-
- this._jpake = Cc["@mozilla.org/services-crypto/sync-jpake;1"]
- .createInstance(Ci.nsISyncJPAKE);
-
- this._setClientID();
-}
-JPAKEClient.prototype = {
-
- _chain: Async.chain,
-
- /*
- * Public API
- */
-
- /**
- * Initiate pairing and receive data without providing a PIN. The PIN will
- * be generated and passed on to the controller to be displayed to the user.
- *
- * This is typically called on mobile devices where typing is tedious.
- */
- receiveNoPIN: function receiveNoPIN() {
- this._my_signerid = JPAKE_SIGNERID_RECEIVER;
- this._their_signerid = JPAKE_SIGNERID_SENDER;
-
- this._secret = this._createSecret();
-
- // Allow a large number of tries first while we wait for the PIN
- // to be entered on the other device.
- this._maxTries = Svc.Prefs.get("jpake.firstMsgMaxTries");
- this._chain(this._getChannel,
- this._computeStepOne,
- this._putStep,
- this._getStep,
- function(callback) {
- // We fetched the first response from the other client.
- // Notify controller of the pairing starting.
- Utils.nextTick(this.controller.onPairingStart,
- this.controller);
-
- // Now we can switch back to the smaller timeout.
- this._maxTries = Svc.Prefs.get("jpake.maxTries");
- callback();
- },
- this._computeStepTwo,
- this._putStep,
- this._getStep,
- this._computeFinal,
- this._computeKeyVerification,
- this._putStep,
- function(callback) {
- // Allow longer time-out for the last message.
- this._maxTries = Svc.Prefs.get("jpake.lastMsgMaxTries");
- callback();
- },
- this._getStep,
- this._decryptData,
- this._complete)();
- },
-
- /**
- * Initiate pairing based on the PIN entered by the user.
- *
- * This is typically called on desktop devices where typing is easier than
- * on mobile.
- *
- * @param pin
- * 12 character string (in human-friendly base32) containing the PIN
- * entered by the user.
- * @param expectDelay
- * Flag that indicates that a significant delay between the pairing
- * and the sending should be expected. v2 and earlier of the protocol
- * did not allow for this and the pairing to a v2 or earlier client
- * will be aborted if this flag is 'true'.
- */
- pairWithPIN: function pairWithPIN(pin, expectDelay) {
- this._my_signerid = JPAKE_SIGNERID_SENDER;
- this._their_signerid = JPAKE_SIGNERID_RECEIVER;
-
- this._channel = pin.slice(JPAKE_LENGTH_SECRET);
- this._channelURL = this._serverURL + this._channel;
- this._secret = pin.slice(0, JPAKE_LENGTH_SECRET);
-
- this._chain(this._computeStepOne,
- this._getStep,
- function(callback) {
- // Ensure that the other client can deal with a delay for
- // the last message if that's requested by the caller.
- if (!expectDelay) {
- return callback();
- }
- if (!this._incoming.version || this._incoming.version < 3) {
- return this.abort(JPAKE_ERROR_DELAYUNSUPPORTED);
- }
- return callback();
- },
- this._putStep,
- this._computeStepTwo,
- this._getStep,
- this._putStep,
- this._computeFinal,
- this._getStep,
- this._verifyPairing)();
- },
-
- /**
- * Send data after a successful pairing.
- *
- * @param obj
- * Object containing the data to send. It will be serialized as JSON.
- */
- sendAndComplete: function sendAndComplete(obj) {
- if (!this._paired || this._finished) {
- this._log.error("Can't send data, no active pairing!");
- throw "No active pairing!";
- }
- this._data = JSON.stringify(obj);
- this._chain(this._encryptData,
- this._putStep,
- this._complete)();
- },
-
- /**
- * Abort the current pairing. The channel on the server will be deleted
- * if the abort wasn't due to a network or server error. The controller's
- * 'onAbort()' method is notified in all cases.
- *
- * @param error [optional]
- * Error constant indicating the reason for the abort. Defaults to
- * user abort.
- */
- abort: function abort(error) {
- this._log.debug("Aborting...");
- this._finished = true;
- let self = this;
-
- // Default to "user aborted".
- if (!error) {
- error = JPAKE_ERROR_USERABORT;
- }
-
- if (error == JPAKE_ERROR_CHANNEL ||
- error == JPAKE_ERROR_NETWORK ||
- error == JPAKE_ERROR_NODATA) {
- Utils.nextTick(function() { this.controller.onAbort(error); }, this);
- } else {
- this._reportFailure(error, function() { self.controller.onAbort(error); });
- }
- },
-
- /*
- * Utilities
- */
-
- _setClientID: function _setClientID() {
- let rng = Cc["@mozilla.org/security/random-generator;1"]
- .createInstance(Ci.nsIRandomGenerator);
- let bytes = rng.generateRandomBytes(JPAKE_LENGTH_CLIENTID / 2);
- this._clientID = bytes.map(byte => ("0" + byte.toString(16)).slice(-2)).join("");
- },
-
- _createSecret: function _createSecret() {
- // 0-9a-z without 1,l,o,0
- const key = "23456789abcdefghijkmnpqrstuvwxyz";
- let rng = Cc["@mozilla.org/security/random-generator;1"]
- .createInstance(Ci.nsIRandomGenerator);
- let bytes = rng.generateRandomBytes(JPAKE_LENGTH_SECRET);
- return bytes.map(byte => key[Math.floor(byte * key.length / 256)]).join("");
- },
-
- _newRequest: function _newRequest(uri) {
- let request = new RESTRequest(uri);
- request.setHeader("X-KeyExchange-Id", this._clientID);
- request.timeout = REQUEST_TIMEOUT;
- return request;
- },
-
- /*
- * Steps of J-PAKE procedure
- */
-
- _getChannel: function _getChannel(callback) {
- this._log.trace("Requesting channel.");
- let request = this._newRequest(this._serverURL + "new_channel");
- request.get(Utils.bind2(this, function handleChannel(error) {
- if (this._finished) {
- return;
- }
-
- if (error) {
- this._log.error("Error acquiring channel ID. " + error);
- this.abort(JPAKE_ERROR_CHANNEL);
- return;
- }
- if (request.response.status != 200) {
- this._log.error("Error acquiring channel ID. Server responded with HTTP "
- + request.response.status);
- this.abort(JPAKE_ERROR_CHANNEL);
- return;
- }
-
- try {
- this._channel = JSON.parse(request.response.body);
- } catch (ex) {
- this._log.error("Server responded with invalid JSON.");
- this.abort(JPAKE_ERROR_CHANNEL);
- return;
- }
- this._log.debug("Using channel " + this._channel);
- this._channelURL = this._serverURL + this._channel;
-
- // Don't block on UI code.
- let pin = this._secret + this._channel;
- Utils.nextTick(function() { this.controller.displayPIN(pin); }, this);
- callback();
- }));
- },
-
- // Generic handler for uploading data.
- _putStep: function _putStep(callback) {
- this._log.trace("Uploading message " + this._outgoing.type);
- let request = this._newRequest(this._channelURL);
- if (this._their_etag) {
- request.setHeader("If-Match", this._their_etag);
- } else {
- request.setHeader("If-None-Match", "*");
- }
- request.put(this._outgoing, Utils.bind2(this, function(error) {
- if (this._finished) {
- return;
- }
-
- if (error) {
- this._log.error("Error uploading data. " + error);
- this.abort(JPAKE_ERROR_NETWORK);
- return;
- }
- if (request.response.status != 200) {
- this._log.error("Could not upload data. Server responded with HTTP "
- + request.response.status);
- this.abort(JPAKE_ERROR_SERVER);
- return;
- }
- // There's no point in returning early here since the next step will
- // always be a GET so let's pause for twice the poll interval.
- this._my_etag = request.response.headers["etag"];
- Utils.namedTimer(function() { callback(); }, this._pollInterval * 2,
- this, "_pollTimer");
- }));
- },
-
- // Generic handler for polling for and retrieving data.
- _pollTries: 0,
- _getStep: function _getStep(callback) {
- this._log.trace("Retrieving next message.");
- let request = this._newRequest(this._channelURL);
- if (this._my_etag) {
- request.setHeader("If-None-Match", this._my_etag);
- }
-
- request.get(Utils.bind2(this, function(error) {
- if (this._finished) {
- return;
- }
-
- if (error) {
- this._log.error("Error fetching data. " + error);
- this.abort(JPAKE_ERROR_NETWORK);
- return;
- }
-
- if (request.response.status == 304) {
- this._log.trace("Channel hasn't been updated yet. Will try again later.");
- if (this._pollTries >= this._maxTries) {
- this._log.error("Tried for " + this._pollTries + " times, aborting.");
- this.abort(JPAKE_ERROR_TIMEOUT);
- return;
- }
- this._pollTries += 1;
- Utils.namedTimer(function() { this._getStep(callback); },
- this._pollInterval, this, "_pollTimer");
- return;
- }
- this._pollTries = 0;
-
- if (request.response.status == 404) {
- this._log.error("No data found in the channel.");
- this.abort(JPAKE_ERROR_NODATA);
- return;
- }
- if (request.response.status != 200) {
- this._log.error("Could not retrieve data. Server responded with HTTP "
- + request.response.status);
- this.abort(JPAKE_ERROR_SERVER);
- return;
- }
-
- this._their_etag = request.response.headers["etag"];
- if (!this._their_etag) {
- this._log.error("Server did not supply ETag for message: "
- + request.response.body);
- this.abort(JPAKE_ERROR_SERVER);
- return;
- }
-
- try {
- this._incoming = JSON.parse(request.response.body);
- } catch (ex) {
- this._log.error("Server responded with invalid JSON.");
- this.abort(JPAKE_ERROR_INVALID);
- return;
- }
- this._log.trace("Fetched message " + this._incoming.type);
- callback();
- }));
- },
-
- _reportFailure: function _reportFailure(reason, callback) {
- this._log.debug("Reporting failure to server.");
- let request = this._newRequest(this._serverURL + "report");
- request.setHeader("X-KeyExchange-Cid", this._channel);
- request.setHeader("X-KeyExchange-Log", reason);
- request.post("", Utils.bind2(this, function(error) {
- if (error) {
- this._log.warn("Report failed: " + error);
- } else if (request.response.status != 200) {
- this._log.warn("Report failed. Server responded with HTTP "
- + request.response.status);
- }
-
- // Do not block on errors, we're done or aborted by now anyway.
- callback();
- }));
- },
-
- _computeStepOne: function _computeStepOne(callback) {
- this._log.trace("Computing round 1.");
- let gx1 = {};
- let gv1 = {};
- let r1 = {};
- let gx2 = {};
- let gv2 = {};
- let r2 = {};
- try {
- this._jpake.round1(this._my_signerid, gx1, gv1, r1, gx2, gv2, r2);
- } catch (ex) {
- this._log.error("JPAKE round 1 threw: " + ex);
- this.abort(JPAKE_ERROR_INTERNAL);
- return;
- }
- let one = {gx1: gx1.value,
- gx2: gx2.value,
- zkp_x1: {gr: gv1.value, b: r1.value, id: this._my_signerid},
- zkp_x2: {gr: gv2.value, b: r2.value, id: this._my_signerid}};
- this._outgoing = {type: this._my_signerid + "1",
- version: KEYEXCHANGE_VERSION,
- payload: one};
- this._log.trace("Generated message " + this._outgoing.type);
- callback();
- },
-
- _computeStepTwo: function _computeStepTwo(callback) {
- this._log.trace("Computing round 2.");
- if (this._incoming.type != this._their_signerid + "1") {
- this._log.error("Invalid round 1 message: "
- + JSON.stringify(this._incoming));
- this.abort(JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- let step1 = this._incoming.payload;
- if (!step1 || !step1.zkp_x1 || step1.zkp_x1.id != this._their_signerid
- || !step1.zkp_x2 || step1.zkp_x2.id != this._their_signerid) {
- this._log.error("Invalid round 1 payload: " + JSON.stringify(step1));
- this.abort(JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- let A = {};
- let gvA = {};
- let rA = {};
-
- try {
- this._jpake.round2(this._their_signerid, this._secret,
- step1.gx1, step1.zkp_x1.gr, step1.zkp_x1.b,
- step1.gx2, step1.zkp_x2.gr, step1.zkp_x2.b,
- A, gvA, rA);
- } catch (ex) {
- this._log.error("JPAKE round 2 threw: " + ex);
- this.abort(JPAKE_ERROR_INTERNAL);
- return;
- }
- let two = {A: A.value,
- zkp_A: {gr: gvA.value, b: rA.value, id: this._my_signerid}};
- this._outgoing = {type: this._my_signerid + "2",
- version: KEYEXCHANGE_VERSION,
- payload: two};
- this._log.trace("Generated message " + this._outgoing.type);
- callback();
- },
-
- _computeFinal: function _computeFinal(callback) {
- if (this._incoming.type != this._their_signerid + "2") {
- this._log.error("Invalid round 2 message: "
- + JSON.stringify(this._incoming));
- this.abort(JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- let step2 = this._incoming.payload;
- if (!step2 || !step2.zkp_A || step2.zkp_A.id != this._their_signerid) {
- this._log.error("Invalid round 2 payload: " + JSON.stringify(step1));
- this.abort(JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- let aes256Key = {};
- let hmac256Key = {};
-
- try {
- this._jpake.final(step2.A, step2.zkp_A.gr, step2.zkp_A.b, HMAC_INPUT,
- aes256Key, hmac256Key);
- } catch (ex) {
- this._log.error("JPAKE final round threw: " + ex);
- this.abort(JPAKE_ERROR_INTERNAL);
- return;
- }
-
- this._crypto_key = aes256Key.value;
- let hmac_key = Utils.makeHMACKey(Utils.safeAtoB(hmac256Key.value));
- this._hmac_hasher = Utils.makeHMACHasher(Ci.nsICryptoHMAC.SHA256, hmac_key);
-
- callback();
- },
-
- _computeKeyVerification: function _computeKeyVerification(callback) {
- this._log.trace("Encrypting key verification value.");
- let iv, ciphertext;
- try {
- iv = Svc.Crypto.generateRandomIV();
- ciphertext = Svc.Crypto.encrypt(JPAKE_VERIFY_VALUE,
- this._crypto_key, iv);
- } catch (ex) {
- this._log.error("Failed to encrypt key verification value.");
- this.abort(JPAKE_ERROR_INTERNAL);
- return;
- }
- this._outgoing = {type: this._my_signerid + "3",
- version: KEYEXCHANGE_VERSION,
- payload: {ciphertext, IV: iv}};
- this._log.trace("Generated message " + this._outgoing.type);
- callback();
- },
-
- _verifyPairing: function _verifyPairing(callback) {
- this._log.trace("Verifying their key.");
- if (this._incoming.type != this._their_signerid + "3") {
- this._log.error("Invalid round 3 data: " +
- JSON.stringify(this._incoming));
- this.abort(JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
- let step3 = this._incoming.payload;
- let ciphertext;
- try {
- ciphertext = Svc.Crypto.encrypt(JPAKE_VERIFY_VALUE,
- this._crypto_key, step3.IV);
- if (ciphertext != step3.ciphertext) {
- throw "Key mismatch!";
- }
- } catch (ex) {
- this._log.error("Keys don't match!");
- this.abort(JPAKE_ERROR_KEYMISMATCH);
- return;
- }
-
- this._log.debug("Verified pairing!");
- this._paired = true;
- Utils.nextTick(function() { this.controller.onPaired(); }, this);
- callback();
- },
-
- _encryptData: function _encryptData(callback) {
- this._log.trace("Encrypting data.");
- let iv, ciphertext, hmac;
- try {
- iv = Svc.Crypto.generateRandomIV();
- ciphertext = Svc.Crypto.encrypt(this._data, this._crypto_key, iv);
- hmac = Utils.bytesAsHex(Utils.digestUTF8(ciphertext, this._hmac_hasher));
- } catch (ex) {
- this._log.error("Failed to encrypt data.");
- this.abort(JPAKE_ERROR_INTERNAL);
- return;
- }
- this._outgoing = {type: this._my_signerid + "3",
- version: KEYEXCHANGE_VERSION,
- payload: {ciphertext, IV: iv, hmac}};
- this._log.trace("Generated message " + this._outgoing.type);
- callback();
- },
-
- _decryptData: function _decryptData(callback) {
- this._log.trace("Verifying their key.");
- if (this._incoming.type != this._their_signerid + "3") {
- this._log.error("Invalid round 3 data: "
- + JSON.stringify(this._incoming));
- this.abort(JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
- let step3 = this._incoming.payload;
- try {
- let hmac = Utils.bytesAsHex(
- Utils.digestUTF8(step3.ciphertext, this._hmac_hasher));
- if (hmac != step3.hmac) {
- throw "HMAC validation failed!";
- }
- } catch (ex) {
- this._log.error("HMAC validation failed.");
- this.abort(JPAKE_ERROR_KEYMISMATCH);
- return;
- }
-
- this._log.trace("Decrypting data.");
- let cleartext;
- try {
- cleartext = Svc.Crypto.decrypt(step3.ciphertext, this._crypto_key,
- step3.IV);
- } catch (ex) {
- this._log.error("Failed to decrypt data.");
- this.abort(JPAKE_ERROR_INTERNAL);
- return;
- }
-
- try {
- this._newData = JSON.parse(cleartext);
- } catch (ex) {
- this._log.error("Invalid data data: " + JSON.stringify(cleartext));
- this.abort(JPAKE_ERROR_INVALID);
- return;
- }
-
- this._log.trace("Decrypted data.");
- callback();
- },
-
- _complete: function _complete() {
- this._log.debug("Exchange completed.");
- this._finished = true;
- Utils.nextTick(function() { this.controller.onComplete(this._newData); },
- this);
- }
-
-};
-
-
-/**
- * Send credentials over an active J-PAKE channel.
- *
- * This object is designed to take over as the JPAKEClient controller,
- * presumably replacing one that is UI-based which would either cause
- * DOM objects to leak or the JPAKEClient to be GC'ed when the DOM
- * context disappears. This object stays alive for the duration of the
- * transfer by being strong-ref'ed as an nsIObserver.
- *
- * Credentials are sent after the first sync has been completed
- * (successfully or not.)
- *
- * Usage:
- *
- * jpakeclient.controller = new SendCredentialsController(jpakeclient,
- * service);
- *
- */
-this.SendCredentialsController =
- function SendCredentialsController(jpakeclient, service) {
- this._log = Log.repository.getLogger("Sync.SendCredentialsController");
- this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.main")];
-
- this._log.trace("Loading.");
- this.jpakeclient = jpakeclient;
- this.service = service;
-
- // Register ourselves as observers the first Sync finishing (either
- // successfully or unsuccessfully, we don't care) or for removing
- // this device's sync configuration, in case that happens while we
- // haven't finished the first sync yet.
- Services.obs.addObserver(this, "weave:service:sync:finish", false);
- Services.obs.addObserver(this, "weave:service:sync:error", false);
- Services.obs.addObserver(this, "weave:service:start-over", false);
-}
-SendCredentialsController.prototype = {
-
- unload: function unload() {
- this._log.trace("Unloading.");
- try {
- Services.obs.removeObserver(this, "weave:service:sync:finish");
- Services.obs.removeObserver(this, "weave:service:sync:error");
- Services.obs.removeObserver(this, "weave:service:start-over");
- } catch (ex) {
- // Ignore.
- }
- },
-
- observe: function observe(subject, topic, data) {
- switch (topic) {
- case "weave:service:sync:finish":
- case "weave:service:sync:error":
- Utils.nextTick(this.sendCredentials, this);
- break;
- case "weave:service:start-over":
- // This will call onAbort which will call unload().
- this.jpakeclient.abort();
- break;
- }
- },
-
- sendCredentials: function sendCredentials() {
- this._log.trace("Sending credentials.");
- let credentials = {account: this.service.identity.account,
- password: this.service.identity.basicPassword,
- synckey: this.service.identity.syncKey,
- serverURL: this.service.serverURL};
- this.jpakeclient.sendAndComplete(credentials);
- },
-
- // JPAKEClient controller API
-
- onComplete: function onComplete() {
- this._log.debug("Exchange was completed successfully!");
- this.unload();
-
- // Schedule a Sync for soonish to fetch the data uploaded by the
- // device with which we just paired.
- this.service.scheduler.scheduleNextSync(this.service.scheduler.activeInterval);
- },
-
- onAbort: function onAbort(error) {
- // It doesn't really matter why we aborted, but the channel is closed
- // for sure, so we won't be able to do anything with it.
- this._log.debug("Exchange was aborted with error: " + error);
- this.unload();
- },
-
- // Irrelevant methods for this controller:
- displayPIN: function displayPIN() {},
- onPairingStart: function onPairingStart() {},
- onPaired: function onPaired() {},
-};
--- a/services/sync/modules/main.js
+++ b/services/sync/modules/main.js
@@ -2,17 +2,16 @@
* 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.EXPORTED_SYMBOLS = ["Weave"];
this.Weave = {};
Components.utils.import("resource://services-sync/constants.js", Weave);
var lazies = {
- "jpakeclient.js": ["JPAKEClient", "SendCredentialsController"],
"service.js": ["Service"],
"status.js": ["Status"],
"util.js": ["Utils", "Svc"]
};
function lazyImport(module, dest, props) {
function getter(prop) {
return function() {
--- a/services/sync/modules/policies.js
+++ b/services/sync/modules/policies.js
@@ -31,17 +31,16 @@ function getThrottledIntervalPreference(
this.SyncScheduler = function SyncScheduler(service) {
this.service = service;
this.init();
}
SyncScheduler.prototype = {
_log: Log.repository.getLogger("Sync.SyncScheduler"),
_fatalLoginStatus: [LOGIN_FAILED_NO_USERNAME,
- LOGIN_FAILED_NO_PASSWORD,
LOGIN_FAILED_NO_PASSPHRASE,
LOGIN_FAILED_INVALID_PASSPHRASE,
LOGIN_FAILED_LOGIN_REJECTED],
/**
* The nsITimer object that schedules the next sync. See scheduleNextSync().
*/
syncTimer: null,
--- a/services/sync/modules/status.js
+++ b/services/sync/modules/status.js
@@ -47,17 +47,16 @@ this.Status = {
return this._login;
},
set login(code) {
this._log.debug("Status.login: " + this._login + " => " + code);
this._login = code;
if (code == LOGIN_FAILED_NO_USERNAME ||
- code == LOGIN_FAILED_NO_PASSWORD ||
code == LOGIN_FAILED_NO_PASSPHRASE) {
this.service = CLIENT_NOT_CONFIGURED;
} else if (code != LOGIN_SUCCEEDED) {
this.service = LOGIN_FAILED;
} else {
this.service = STATUS_OK;
}
},
--- a/services/sync/moz.build
+++ b/services/sync/moz.build
@@ -20,17 +20,16 @@ EXTRA_JS_MODULES['services-sync'] += [
'modules/addonsreconciler.js',
'modules/addonutils.js',
'modules/bookmark_validator.js',
'modules/browserid_identity.js',
'modules/collection_validator.js',
'modules/engines.js',
'modules/FxaMigrator.jsm',
'modules/identity.js',
- 'modules/jpakeclient.js',
'modules/keys.js',
'modules/main.js',
'modules/policies.js',
'modules/record.js',
'modules/resource.js',
'modules/rest.js',
'modules/service.js',
'modules/status.js',
--- a/services/sync/services-sync.js
+++ b/services/sync/services-sync.js
@@ -27,22 +27,16 @@ pref("services.sync.errorhandler.network
pref("services.sync.engine.addons", true);
pref("services.sync.engine.bookmarks", true);
pref("services.sync.engine.history", true);
pref("services.sync.engine.passwords", true);
pref("services.sync.engine.prefs", true);
pref("services.sync.engine.tabs", true);
pref("services.sync.engine.tabs.filteredUrls", "^(about:.*|resource:.*|chrome:.*|wyciwyg:.*|file:.*|blob:.*)$");
-pref("services.sync.jpake.serverURL", "https://setup.services.mozilla.com/");
-pref("services.sync.jpake.pollInterval", 1000);
-pref("services.sync.jpake.firstMsgMaxTries", 300); // 5 minutes
-pref("services.sync.jpake.lastMsgMaxTries", 300); // 5 minutes
-pref("services.sync.jpake.maxTries", 10);
-
// If true, add-on sync ignores changes to the user-enabled flag. This
// allows people to have the same set of add-ons installed across all
// profiles while maintaining different enabled states.
pref("services.sync.addons.ignoreUserEnabledChanges", false);
// Comma-delimited list of hostnames to trust for add-on install.
pref("services.sync.addons.trustedSourceHostnames", "addons.mozilla.org");
@@ -54,17 +48,16 @@ pref("services.sync.log.appender.file.lo
pref("services.sync.log.appender.file.maxErrorAge", 864000); // 10 days
pref("services.sync.log.rootLogger", "Debug");
pref("services.sync.log.logger.addonutils", "Debug");
pref("services.sync.log.logger.declined", "Debug");
pref("services.sync.log.logger.service.main", "Debug");
pref("services.sync.log.logger.status", "Debug");
pref("services.sync.log.logger.authenticator", "Debug");
pref("services.sync.log.logger.network.resources", "Debug");
-pref("services.sync.log.logger.service.jpakeclient", "Debug");
pref("services.sync.log.logger.engine.bookmarks", "Debug");
pref("services.sync.log.logger.engine.clients", "Debug");
pref("services.sync.log.logger.engine.forms", "Debug");
pref("services.sync.log.logger.engine.history", "Debug");
pref("services.sync.log.logger.engine.passwords", "Debug");
pref("services.sync.log.logger.engine.prefs", "Debug");
pref("services.sync.log.logger.engine.tabs", "Debug");
pref("services.sync.log.logger.engine.addons", "Debug");
deleted file mode 100644
--- a/services/sync/tests/unit/test_jpakeclient.js
+++ /dev/null
@@ -1,562 +0,0 @@
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-sync/identity.js");
-Cu.import("resource://services-sync/jpakeclient.js");
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-
-const JPAKE_LENGTH_SECRET = 8;
-const JPAKE_LENGTH_CLIENTID = 256;
-const KEYEXCHANGE_VERSION = 3;
-
-/*
- * Simple server.
- */
-
-const SERVER_MAX_GETS = 6;
-
-function check_headers(request) {
- let stack = Components.stack.caller;
-
- // There shouldn't be any Basic auth
- do_check_false(request.hasHeader("Authorization"), stack);
-
- // Ensure key exchange ID is set and the right length
- do_check_true(request.hasHeader("X-KeyExchange-Id"), stack);
- do_check_eq(request.getHeader("X-KeyExchange-Id").length,
- JPAKE_LENGTH_CLIENTID, stack);
-}
-
-function new_channel() {
- // Create a new channel and register it with the server.
- let cid = Math.floor(Math.random() * 10000);
- while (channels[cid]) {
- cid = Math.floor(Math.random() * 10000);
- }
- let channel = channels[cid] = new ServerChannel();
- server.registerPathHandler("/" + cid, channel.handler());
- return cid;
-}
-
-var server;
-var channels = {}; // Map channel -> ServerChannel object
-function server_new_channel(request, response) {
- check_headers(request);
- let cid = new_channel();
- let body = JSON.stringify("" + cid);
- response.setStatusLine(request.httpVersion, 200, "OK");
- response.bodyOutputStream.write(body, body.length);
-}
-
-var error_report;
-function server_report(request, response) {
- check_headers(request);
-
- if (request.hasHeader("X-KeyExchange-Log")) {
- error_report = request.getHeader("X-KeyExchange-Log");
- }
-
- if (request.hasHeader("X-KeyExchange-Cid")) {
- let cid = request.getHeader("X-KeyExchange-Cid");
- let channel = channels[cid];
- if (channel) {
- channel.clear();
- }
- }
-
- response.setStatusLine(request.httpVersion, 200, "OK");
-}
-
-// Hook for test code.
-var hooks = {};
-function initHooks() {
- hooks.onGET = function onGET(request) {};
-}
-initHooks();
-
-function ServerChannel() {
- this.data = "";
- this.etag = "";
- this.getCount = 0;
-}
-ServerChannel.prototype = {
-
- GET: function GET(request, response) {
- if (!this.data) {
- response.setStatusLine(request.httpVersion, 404, "Not Found");
- return;
- }
-
- if (request.hasHeader("If-None-Match")) {
- let etag = request.getHeader("If-None-Match");
- if (etag == this.etag) {
- response.setStatusLine(request.httpVersion, 304, "Not Modified");
- hooks.onGET(request);
- return;
- }
- }
- response.setHeader("ETag", this.etag);
- response.setStatusLine(request.httpVersion, 200, "OK");
- response.bodyOutputStream.write(this.data, this.data.length);
-
- // Automatically clear the channel after 6 successful GETs.
- this.getCount += 1;
- if (this.getCount == SERVER_MAX_GETS) {
- this.clear();
- }
- hooks.onGET(request);
- },
-
- PUT: function PUT(request, response) {
- if (this.data) {
- do_check_true(request.hasHeader("If-Match"));
- let etag = request.getHeader("If-Match");
- if (etag != this.etag) {
- response.setHeader("ETag", this.etag);
- response.setStatusLine(request.httpVersion, 412, "Precondition Failed");
- return;
- }
- } else {
- do_check_true(request.hasHeader("If-None-Match"));
- do_check_eq(request.getHeader("If-None-Match"), "*");
- }
-
- this.data = readBytesFromInputStream(request.bodyInputStream);
- this.etag = '"' + Utils.sha1(this.data) + '"';
- response.setHeader("ETag", this.etag);
- response.setStatusLine(request.httpVersion, 200, "OK");
- },
-
- clear: function clear() {
- delete this.data;
- },
-
- handler: function handler() {
- let self = this;
- return function(request, response) {
- check_headers(request);
- let method = self[request.method];
- return method.apply(self, arguments);
- };
- }
-
-};
-
-
-/**
- * Controller that throws for everything.
- */
-var BaseController = {
- displayPIN: function displayPIN() {
- do_throw("displayPIN() shouldn't have been called!");
- },
- onPairingStart: function onPairingStart() {
- do_throw("onPairingStart shouldn't have been called!");
- },
- onAbort: function onAbort(error) {
- do_throw("Shouldn't have aborted with " + error + "!");
- },
- onPaired: function onPaired() {
- do_throw("onPaired() shouldn't have been called!");
- },
- onComplete: function onComplete(data) {
- do_throw("Shouldn't have completed with " + data + "!");
- }
-};
-
-
-const DATA = {"msg": "eggstreamly sekrit"};
-const POLLINTERVAL = 50;
-
-function run_test() {
- server = httpd_setup({"/new_channel": server_new_channel,
- "/report": server_report});
- Svc.Prefs.set("jpake.serverURL", server.baseURI + "/");
- Svc.Prefs.set("jpake.pollInterval", POLLINTERVAL);
- Svc.Prefs.set("jpake.maxTries", 2);
- Svc.Prefs.set("jpake.firstMsgMaxTries", 5);
- Svc.Prefs.set("jpake.lastMsgMaxTries", 5);
- // Ensure clean up
- Svc.Obs.add("profile-before-change", function() {
- Svc.Prefs.resetBranch("");
- });
-
- // Ensure PSM is initialized.
- Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
-
- // Simulate Sync setup with credentials in place. We want to make
- // sure the J-PAKE requests don't include those data.
- ensureLegacyIdentityManager();
- setBasicCredentials("johndoe", "ilovejane");
-
- initTestLogging("Trace");
- Log.repository.getLogger("Sync.JPAKEClient").level = Log.Level.Trace;
- Log.repository.getLogger("Common.RESTRequest").level =
- Log.Level.Trace;
- run_next_test();
-}
-
-
-add_test(function test_success_receiveNoPIN() {
- _("Test a successful exchange started by receiveNoPIN().");
-
- let snd = new JPAKEClient({
- __proto__: BaseController,
- onPaired: function onPaired() {
- _("Pairing successful, sending final payload.");
- do_check_true(pairingStartCalledOnReceiver);
- Utils.nextTick(function() { snd.sendAndComplete(DATA); });
- },
- onComplete: function onComplete() {}
- });
-
- let pairingStartCalledOnReceiver = false;
- let rec = new JPAKEClient({
- __proto__: BaseController,
- displayPIN: function displayPIN(pin) {
- _("Received PIN " + pin + ". Entering it in the other computer...");
- this.cid = pin.slice(JPAKE_LENGTH_SECRET);
- Utils.nextTick(function() { snd.pairWithPIN(pin, false); });
- },
- onPairingStart: function onPairingStart() {
- pairingStartCalledOnReceiver = true;
- },
- onComplete: function onComplete(data) {
- do_check_true(Utils.deepEquals(DATA, data));
- // Ensure channel was cleared, no error report.
- do_check_eq(channels[this.cid].data, undefined);
- do_check_eq(error_report, undefined);
- run_next_test();
- }
- });
- rec.receiveNoPIN();
-});
-
-
-add_test(function test_firstMsgMaxTries_timeout() {
- _("Test abort when sender doesn't upload anything.");
-
- let rec = new JPAKEClient({
- __proto__: BaseController,
- displayPIN: function displayPIN(pin) {
- _("Received PIN " + pin + ". Doing nothing...");
- this.cid = pin.slice(JPAKE_LENGTH_SECRET);
- },
- onAbort: function onAbort(error) {
- do_check_eq(error, JPAKE_ERROR_TIMEOUT);
- // Ensure channel was cleared, error report was sent.
- do_check_eq(channels[this.cid].data, undefined);
- do_check_eq(error_report, JPAKE_ERROR_TIMEOUT);
- error_report = undefined;
- run_next_test();
- }
- });
- rec.receiveNoPIN();
-});
-
-
-add_test(function test_firstMsgMaxTries() {
- _("Test that receiver can wait longer for the first message.");
-
- let snd = new JPAKEClient({
- __proto__: BaseController,
- onPaired: function onPaired() {
- _("Pairing successful, sending final payload.");
- Utils.nextTick(function() { snd.sendAndComplete(DATA); });
- },
- onComplete: function onComplete() {}
- });
-
- let rec = new JPAKEClient({
- __proto__: BaseController,
- displayPIN: function displayPIN(pin) {
- // For the purpose of the tests, the poll interval is 50ms and
- // we're polling up to 5 times for the first exchange (as
- // opposed to 2 times for most of the other exchanges). So let's
- // pretend it took 150ms to enter the PIN on the sender, which should
- // require 3 polls.
- // Rather than using an imprecise timer, we hook into the channel's
- // GET handler to know how long to wait.
- _("Received PIN " + pin + ". Waiting for three polls before entering it into sender...");
- this.cid = pin.slice(JPAKE_LENGTH_SECRET);
- let count = 0;
- hooks.onGET = function onGET(request) {
- if (++count == 3) {
- _("Third GET. Triggering pair.");
- Utils.nextTick(function() { snd.pairWithPIN(pin, false); });
- }
- };
- },
- onPairingStart: function onPairingStart(pin) {},
- onComplete: function onComplete(data) {
- do_check_true(Utils.deepEquals(DATA, data));
- // Ensure channel was cleared, no error report.
- do_check_eq(channels[this.cid].data, undefined);
- do_check_eq(error_report, undefined);
-
- // Clean up.
- initHooks();
- run_next_test();
- }
- });
- rec.receiveNoPIN();
-});
-
-
-add_test(function test_lastMsgMaxTries() {
- _("Test that receiver can wait longer for the last message.");
-
- let snd = new JPAKEClient({
- __proto__: BaseController,
- onPaired: function onPaired() {
- // For the purpose of the tests, the poll interval is 50ms and
- // we're polling up to 5 times for the last exchange (as opposed
- // to 2 times for other exchanges). So let's pretend it took
- // 150ms to come up with the final payload, which should require
- // 3 polls.
- // Rather than using an imprecise timer, we hook into the channel's
- // GET handler to know how long to wait.
- let count = 0;
- hooks.onGET = function onGET(request) {
- if (++count == 3) {
- _("Third GET. Triggering send.");
- Utils.nextTick(function() { snd.sendAndComplete(DATA); });
- }
- };
- },
- onComplete: function onComplete() {}
- });
-
- let rec = new JPAKEClient({
- __proto__: BaseController,
- displayPIN: function displayPIN(pin) {
- _("Received PIN " + pin + ". Entering it in the other computer...");
- this.cid = pin.slice(JPAKE_LENGTH_SECRET);
- Utils.nextTick(function() { snd.pairWithPIN(pin, false); });
- },
- onPairingStart: function onPairingStart(pin) {},
- onComplete: function onComplete(data) {
- do_check_true(Utils.deepEquals(DATA, data));
- // Ensure channel was cleared, no error report.
- do_check_eq(channels[this.cid].data, undefined);
- do_check_eq(error_report, undefined);
-
- // Clean up.
- initHooks();
- run_next_test();
- }
- });
-
- rec.receiveNoPIN();
-});
-
-
-add_test(function test_wrongPIN() {
- _("Test abort when PINs don't match.");
-
- let snd = new JPAKEClient({
- __proto__: BaseController,
- onAbort: function onAbort(error) {
- do_check_eq(error, JPAKE_ERROR_KEYMISMATCH);
- do_check_eq(error_report, JPAKE_ERROR_KEYMISMATCH);
- error_report = undefined;
- }
- });
-
- let pairingStartCalledOnReceiver = false;
- let rec = new JPAKEClient({
- __proto__: BaseController,
- displayPIN: function displayPIN(pin) {
- this.cid = pin.slice(JPAKE_LENGTH_SECRET);
- let secret = pin.slice(0, JPAKE_LENGTH_SECRET);
- secret = Array.prototype.slice.call(secret).reverse().join("");
- let new_pin = secret + this.cid;
- _("Received PIN " + pin + ", but I'm entering " + new_pin);
-
- Utils.nextTick(function() { snd.pairWithPIN(new_pin, false); });
- },
- onPairingStart: function onPairingStart() {
- pairingStartCalledOnReceiver = true;
- },
- onAbort: function onAbort(error) {
- do_check_true(pairingStartCalledOnReceiver);
- do_check_eq(error, JPAKE_ERROR_NODATA);
- // Ensure channel was cleared.
- do_check_eq(channels[this.cid].data, undefined);
- run_next_test();
- }
- });
- rec.receiveNoPIN();
-});
-
-
-add_test(function test_abort_receiver() {
- _("Test user abort on receiving side.");
-
- let rec = new JPAKEClient({
- __proto__: BaseController,
- onAbort: function onAbort(error) {
- // Manual abort = userabort.
- do_check_eq(error, JPAKE_ERROR_USERABORT);
- // Ensure channel was cleared.
- do_check_eq(channels[this.cid].data, undefined);
- do_check_eq(error_report, JPAKE_ERROR_USERABORT);
- error_report = undefined;
- run_next_test();
- },
- displayPIN: function displayPIN(pin) {
- this.cid = pin.slice(JPAKE_LENGTH_SECRET);
- Utils.nextTick(function() { rec.abort(); });
- }
- });
- rec.receiveNoPIN();
-});
-
-
-add_test(function test_abort_sender() {
- _("Test user abort on sending side.");
-
- let snd = new JPAKEClient({
- __proto__: BaseController,
- onAbort: function onAbort(error) {
- // Manual abort == userabort.
- do_check_eq(error, JPAKE_ERROR_USERABORT);
- do_check_eq(error_report, JPAKE_ERROR_USERABORT);
- error_report = undefined;
- }
- });
-
- let rec = new JPAKEClient({
- __proto__: BaseController,
- onAbort: function onAbort(error) {
- do_check_eq(error, JPAKE_ERROR_NODATA);
- // Ensure channel was cleared, no error report.
- do_check_eq(channels[this.cid].data, undefined);
- do_check_eq(error_report, undefined);
- initHooks();
- run_next_test();
- },
- displayPIN: function displayPIN(pin) {
- _("Received PIN " + pin + ". Entering it in the other computer...");
- this.cid = pin.slice(JPAKE_LENGTH_SECRET);
- Utils.nextTick(function() { snd.pairWithPIN(pin, false); });
-
- // Abort after the first poll.
- let count = 0;
- hooks.onGET = function onGET(request) {
- if (++count >= 1) {
- _("First GET. Aborting.");
- Utils.nextTick(function() { snd.abort(); });
- }
- };
- },
- onPairingStart: function onPairingStart(pin) {}
- });
- rec.receiveNoPIN();
-});
-
-
-add_test(function test_wrongmessage() {
- let cid = new_channel();
- let channel = channels[cid];
- channel.data = JSON.stringify({type: "receiver2",
- version: KEYEXCHANGE_VERSION,
- payload: {}});
- channel.etag = '"fake-etag"';
- let snd = new JPAKEClient({
- __proto__: BaseController,
- onComplete: function onComplete(data) {
- do_throw("onComplete shouldn't be called.");
- },
- onAbort: function onAbort(error) {
- do_check_eq(error, JPAKE_ERROR_WRONGMESSAGE);
- run_next_test();
- }
- });
- snd.pairWithPIN("01234567" + cid, false);
-});
-
-
-add_test(function test_error_channel() {
- let serverURL = Svc.Prefs.get("jpake.serverURL");
- Svc.Prefs.set("jpake.serverURL", "http://localhost:12345/");
-
- let rec = new JPAKEClient({
- __proto__: BaseController,
- onAbort: function onAbort(error) {
- do_check_eq(error, JPAKE_ERROR_CHANNEL);
- Svc.Prefs.set("jpake.serverURL", serverURL);
- run_next_test();
- },
- onPairingStart: function onPairingStart(pin) {},
- displayPIN: function displayPIN(pin) {}
- });
- rec.receiveNoPIN();
-});
-
-
-add_test(function test_error_network() {
- let serverURL = Svc.Prefs.get("jpake.serverURL");
- Svc.Prefs.set("jpake.serverURL", "http://localhost:12345/");
-
- let snd = new JPAKEClient({
- __proto__: BaseController,
- onAbort: function onAbort(error) {
- do_check_eq(error, JPAKE_ERROR_NETWORK);
- Svc.Prefs.set("jpake.serverURL", serverURL);
- run_next_test();
- }
- });
- snd.pairWithPIN("0123456789ab", false);
-});
-
-
-add_test(function test_error_server_noETag() {
- let cid = new_channel();
- let channel = channels[cid];
- channel.data = JSON.stringify({type: "receiver1",
- version: KEYEXCHANGE_VERSION,
- payload: {}});
- // This naughty server doesn't supply ETag (well, it supplies empty one).
- channel.etag = "";
- let snd = new JPAKEClient({
- __proto__: BaseController,
- onAbort: function onAbort(error) {
- do_check_eq(error, JPAKE_ERROR_SERVER);
- run_next_test();
- }
- });
- snd.pairWithPIN("01234567" + cid, false);
-});
-
-
-add_test(function test_error_delayNotSupported() {
- let cid = new_channel();
- let channel = channels[cid];
- channel.data = JSON.stringify({type: "receiver1",
- version: 2,
- payload: {}});
- channel.etag = '"fake-etag"';
- let snd = new JPAKEClient({
- __proto__: BaseController,
- onAbort: function onAbort(error) {
- do_check_eq(error, JPAKE_ERROR_DELAYUNSUPPORTED);
- run_next_test();
- }
- });
- snd.pairWithPIN("01234567" + cid, true);
-});
-
-
-add_test(function test_sendAndComplete_notPaired() {
- let snd = new JPAKEClient({__proto__: BaseController});
- do_check_throws(function() {
- snd.sendAndComplete(DATA);
- });
- run_next_test();
-});
-
-
-add_test(function tearDown() {
- server.stop(run_next_test);
-});
--- a/services/sync/tests/unit/test_load_modules.js
+++ b/services/sync/tests/unit/test_load_modules.js
@@ -12,17 +12,16 @@ const modules = [
"engines/extension-storage.js",
"engines/forms.js",
"engines/history.js",
"engines/passwords.js",
"engines/prefs.js",
"engines/tabs.js",
"engines.js",
"identity.js",
- "jpakeclient.js",
"keys.js",
"main.js",
"policies.js",
"record.js",
"resource.js",
"rest.js",
"service.js",
"stages/cluster.js",
deleted file mode 100644
--- a/services/sync/tests/unit/test_sendcredentials_controller.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/jpakeclient.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-
-function run_test() {
- ensureLegacyIdentityManager();
- setBasicCredentials("johndoe", "ilovejane", Utils.generatePassphrase());
- Service.serverURL = "http://weave.server/";
-
- initTestLogging("Trace");
- Log.repository.getLogger("Sync.SendCredentialsController").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
- run_next_test();
-}
-
-function make_sendCredentials_test(topic) {
- return function test_sendCredentials() {
- _("Test sending credentials on " + topic + " observer notification.");
-
- let sendAndCompleteCalled = false;
- let jpakeclient = {
- sendAndComplete: function sendAndComplete(data) {
- // Verify that the controller unregisters itself as an observer
- // when the exchange is complete by faking another notification.
- do_check_false(sendAndCompleteCalled);
- sendAndCompleteCalled = true;
-
- // Verify it sends the correct data.
- do_check_eq(data.account, Service.identity.account);
- do_check_eq(data.password, Service.identity.basicPassword);
- do_check_eq(data.synckey, Service.identity.syncKey);
- do_check_eq(data.serverURL, Service.serverURL);
-
- this.controller.onComplete();
- // Verify it schedules a sync for the expected interval.
- let expectedInterval = Service.scheduler.activeInterval;
- do_check_true(Service.scheduler.nextSync - Date.now() <= expectedInterval);
-
- // Signal the end of another sync. We shouldn't be registered anymore,
- // so we shouldn't re-enter this method (cf sendAndCompleteCalled above)
- Svc.Obs.notify(topic);
-
- Service.scheduler.setDefaults();
- Utils.nextTick(run_next_test);
- }
- };
- jpakeclient.controller = new SendCredentialsController(jpakeclient, Service);
- Svc.Obs.notify(topic);
- };
-}
-
-add_test(make_sendCredentials_test("weave:service:sync:finish"));
-add_test(make_sendCredentials_test("weave:service:sync:error"));
-
-
-add_test(function test_abort() {
- _("Test aborting the J-PAKE exchange.");
-
- let jpakeclient = {
- sendAndComplete: function sendAndComplete() {
- do_throw("Shouldn't get here!");
- }
- };
- jpakeclient.controller = new SendCredentialsController(jpakeclient, Service);
-
- // Verify that the controller unregisters itself when the exchange
- // was aborted.
- jpakeclient.controller.onAbort(JPAKE_ERROR_USERABORT);
- Svc.Obs.notify("weave:service:sync:finish");
- Utils.nextTick(run_next_test);
-});
-
-
-add_test(function test_startOver() {
- _("Test wiping local Sync config aborts transaction.");
-
- let abortCalled = false;
- let jpakeclient = {
- abort: function abort() {
- abortCalled = true;
- this.controller.onAbort(JPAKE_ERROR_USERABORT);
- },
- sendAndComplete: function sendAndComplete() {
- do_throw("Shouldn't get here!");
- }
- };
- jpakeclient.controller = new SendCredentialsController(jpakeclient, Service);
-
- Svc.Obs.notify("weave:service:start-over");
- do_check_true(abortCalled);
-
- // Ensure that the controller no longer does anything if a sync
- // finishes now or -- more likely -- errors out.
- Svc.Obs.notify("weave:service:sync:error");
-
- Utils.nextTick(run_next_test);
-});
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -36,20 +36,16 @@ support-files =
[test_utils_notify.js]
[test_utils_passphrase.js]
# We have a number of other libraries that are pretty much standalone.
[test_addon_utils.js]
run-sequentially = Restarts server, can't change pref.
tags = addons
[test_httpd_sync_server.js]
-[test_jpakeclient.js]
-# Bug 618233: this test produces random failures on Windows 7.
-# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
-skip-if = os == "win" || os == "android"
# HTTP layers.
[test_resource.js]
[test_resource_async.js]
[test_resource_header.js]
[test_resource_ua.js]
[test_syncstoragerequest.js]
@@ -117,17 +113,16 @@ skip-if = os == "android"
[test_errorhandler_sync_checkServerError.js]
# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
skip-if = os == "android"
[test_errorhandler_eol.js]
[test_hmac_error.js]
[test_interval_triggers.js]
[test_node_reassignment.js]
[test_score_triggers.js]
-[test_sendcredentials_controller.js]
[test_status.js]
[test_status_checkSetup.js]
[test_syncscheduler.js]
[test_upgrade_old_sync_key.js]
# Firefox Accounts specific tests
[test_fxa_startOver.js]
[test_fxa_service_cluster.js]
--- a/tools/lint/eslint/modules.json
+++ b/tools/lint/eslint/modules.json
@@ -105,17 +105,16 @@
"history.jsm": ["HistoryEntry", "DumpHistory"],
"Http.jsm": ["httpRequest", "percentEncode"],
"httpd.js": ["HTTP_400", "HTTP_401", "HTTP_402", "HTTP_403", "HTTP_404", "HTTP_405", "HTTP_406", "HTTP_407", "HTTP_408", "HTTP_409", "HTTP_410", "HTTP_411", "HTTP_412", "HTTP_413", "HTTP_414", "HTTP_415", "HTTP_417", "HTTP_500", "HTTP_501", "HTTP_502", "HTTP_503", "HTTP_504", "HTTP_505", "HttpError", "HttpServer"],
"identity.js": ["IdentityManager"],
"import_module.jsm": ["MODULE_IMPORTED", "MODULE_URI", "SUBMODULE_IMPORTED", "same_scope", "SUBMODULE_IMPORTED_TO_SCOPE"],
"import_sub_module.jsm": ["SUBMODULE_IMPORTED", "test_obj"],
"InlineSpellChecker.jsm": ["InlineSpellChecker", "SpellCheckHelper"],
"JNI.jsm": ["JNI", "android_log"],
- "jpakeclient.js": ["JPAKEClient", "SendCredentialsController"],
"Jsbeautify.jsm": ["jsBeautify"],
"jsdebugger.jsm": ["addDebuggerToGlobal"],
"json2.js": ["JSON"],
"keys.js": ["BulkKeyBundle", "SyncKeyBundle"],
"KeyValueParser.jsm": ["parseKeyValuePairsFromLines", "parseKeyValuePairs", "parseKeyValuePairsFromFile"],
"kinto-http-client.js": ["KintoHttpClient"],
"kinto-offline-client.js": ["Kinto"],
"kinto-storage-adapter.js": ["FirefoxAdapter"],