import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,19 @@
# -*- 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 += [
'nsISyncJPAKE.idl',
]
XPIDL_MODULE = 'services-crypto-component'
SOURCES += [
'nsSyncJPAKE.cpp',
]
FINAL_LIBRARY = 'xul'

View file

@ -0,0 +1,103 @@
/* 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);
};

View file

@ -0,0 +1,484 @@
/* 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, &paramsItem,
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,
&paramsItem,
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,
&paramsItem, 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,
&paramsItem, 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, &paramsItem,
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;

View file

@ -0,0 +1,38 @@
/* 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__

View file

@ -0,0 +1,289 @@
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();
}

View file

@ -0,0 +1,6 @@
[DEFAULT]
head =
tail =
firefox-appdir = browser
[test_jpake.js]