services/crypto/component/nsSyncJPAKE.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/services/crypto/component/nsSyncJPAKE.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,456 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "nsSyncJPAKE.h"
     1.9 +#include "mozilla/ModuleUtils.h"
    1.10 +#include <pk11pub.h>
    1.11 +#include <keyhi.h>
    1.12 +#include <pkcs11.h>
    1.13 +#include <nscore.h>
    1.14 +#include <secmodt.h>
    1.15 +#include <secport.h>
    1.16 +#include <secerr.h>
    1.17 +#include <nsDebug.h>
    1.18 +#include <nsError.h>
    1.19 +#include <base64.h>
    1.20 +#include <nsString.h>
    1.21 +
    1.22 +using mozilla::fallible_t;
    1.23 +
    1.24 +static bool
    1.25 +hex_from_2char(const unsigned char *c2, unsigned char *byteval)
    1.26 +{
    1.27 +  int i;
    1.28 +  unsigned char offset;
    1.29 +  *byteval = 0;
    1.30 +  for (i=0; i<2; i++) {
    1.31 +    if (c2[i] >= '0' && c2[i] <= '9') {
    1.32 +      offset = c2[i] - '0';
    1.33 +      *byteval |= offset << 4*(1-i);
    1.34 +    } else if (c2[i] >= 'a' && c2[i] <= 'f') {
    1.35 +      offset = c2[i] - 'a';
    1.36 +      *byteval |= (offset + 10) << 4*(1-i);
    1.37 +    } else if (c2[i] >= 'A' && c2[i] <= 'F') {
    1.38 +      offset = c2[i] - 'A';
    1.39 +      *byteval |= (offset + 10) << 4*(1-i);
    1.40 +    } else {
    1.41 +      return false;
    1.42 +    }
    1.43 +  }
    1.44 +  return true;
    1.45 +}
    1.46 +
    1.47 +static bool
    1.48 +fromHex(const char * str, unsigned char * p, size_t sLen)
    1.49 +{
    1.50 +  size_t i;
    1.51 +  if (sLen & 1)
    1.52 +    return false;
    1.53 +
    1.54 +  for (i = 0; i < sLen / 2; ++i) {
    1.55 +    if (!hex_from_2char((const unsigned char *) str + (2*i),
    1.56 +                        (unsigned char *) p + i)) {
    1.57 +      return false;
    1.58 +    }
    1.59 +  }
    1.60 +  return true;
    1.61 +}
    1.62 +
    1.63 +static nsresult
    1.64 +fromHexString(const nsACString & str, unsigned char * p, size_t pMaxLen)
    1.65 +{
    1.66 +  char * strData = (char *) str.Data();
    1.67 +  unsigned len = str.Length();
    1.68 +  NS_ENSURE_ARG(len / 2 <= pMaxLen);
    1.69 +  if (!fromHex(strData, p, len)) {
    1.70 +    return NS_ERROR_INVALID_ARG;
    1.71 +  }
    1.72 +  return NS_OK;
    1.73 +}
    1.74 +
    1.75 +static bool
    1.76 +toHexString(const unsigned char * str, unsigned len, nsACString & out)
    1.77 +{
    1.78 +  static const char digits[] = "0123456789ABCDEF";
    1.79 +  if (!out.SetCapacity(2 * len, fallible_t()))
    1.80 +    return false;
    1.81 +  out.SetLength(0);
    1.82 +  for (unsigned i = 0; i < len; ++i) {
    1.83 +    out.Append(digits[str[i] >> 4]);
    1.84 +    out.Append(digits[str[i] & 0x0f]);
    1.85 +  }
    1.86 +  return true;
    1.87 +}
    1.88 +
    1.89 +static nsresult
    1.90 +mapErrno()
    1.91 +{
    1.92 +  int err = PORT_GetError();
    1.93 +  switch (err) {
    1.94 +    case SEC_ERROR_NO_MEMORY:   return NS_ERROR_OUT_OF_MEMORY;
    1.95 +    default:                    return NS_ERROR_UNEXPECTED;
    1.96 +  }
    1.97 +}
    1.98 +
    1.99 +#define NUM_ELEM(x) (sizeof(x) / sizeof (x)[0])
   1.100 +
   1.101 +static const char p[] = 
   1.102 +  "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD61037E56258A7795A1C"
   1.103 +  "7AD46076982CE6BB956936C6AB4DCFE05E6784586940CA544B9B2140E1EB523F"
   1.104 +  "009D20A7E7880E4E5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1"
   1.105 +  "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D3485261CD068699B"
   1.106 +  "6BA58A1DDBBEF6DB51E8FE34E8A78E542D7BA351C21EA8D8F1D29F5D5D159394"
   1.107 +  "87E27F4416B0CA632C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0"
   1.108 +  "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0EE6F29AF7F642773E"
   1.109 +  "BE8CD5402415A01451A840476B2FCEB0E388D30D4B376C37FE401C2A2C2F941D"
   1.110 +  "AD179C540C1C8CE030D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F"
   1.111 +  "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C560EA878DE87C11E3D"
   1.112 +  "597F1FEA742D73EEC7F37BE43949EF1A0D15C3F3E3FC0A8335617055AC91328E"
   1.113 +  "C22B50FC15B941D3D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73";
   1.114 +static const char q[] =
   1.115 +  "CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D";
   1.116 +static const char g[] = 
   1.117 +  "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE3B7ACCC54D521E37"
   1.118 +  "F84A4BDD5B06B0970CC2D2BBB715F7B82846F9A0C393914C792E6A923E2117AB"
   1.119 +  "805276A975AADB5261D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1"
   1.120 +  "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A60126FEB2CF05DB8"
   1.121 +  "A7F0F09B3397F3937F2E90B9E5B9C9B6EFEF642BC48351C46FB171B9BFA9EF17"
   1.122 +  "A961CE96C7E7A7CC3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C"
   1.123 +  "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B67299E231F8BD90B3"
   1.124 +  "9AC3AE3BE0C6B6CACEF8289A2E2873D58E51E029CAFBD55E6841489AB66B5B4B"
   1.125 +  "9BA6E2F784660896AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8"
   1.126 +  "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B988567A88126B914D7828"
   1.127 +  "E2B63A6D7ED0747EC59E0E0A23CE7D8A74C1D2C2A7AFB6A29799620F00E11C33"
   1.128 +  "787F7DED3B30E1A22D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B";
   1.129 +
   1.130 +NS_IMETHODIMP nsSyncJPAKE::Round1(const nsACString & aSignerID,
   1.131 +                                  nsACString & aGX1,
   1.132 +                                  nsACString & aGV1,
   1.133 +                                  nsACString & aR1,
   1.134 +                                  nsACString & aGX2,
   1.135 +                                  nsACString & aGV2,
   1.136 +                                  nsACString & aR2)
   1.137 +{
   1.138 +  NS_ENSURE_STATE(round == JPAKENotStarted);
   1.139 +  NS_ENSURE_STATE(key == nullptr);
   1.140 +
   1.141 +  static CK_MECHANISM_TYPE mechanisms[] = {
   1.142 +    CKM_NSS_JPAKE_ROUND1_SHA256,
   1.143 +    CKM_NSS_JPAKE_ROUND2_SHA256,
   1.144 +    CKM_NSS_JPAKE_FINAL_SHA256
   1.145 +  };
   1.146 +
   1.147 +  PK11SlotInfo * slot = PK11_GetBestSlotMultiple(mechanisms,
   1.148 +                                                 NUM_ELEM(mechanisms),
   1.149 +                                                 nullptr);
   1.150 +  NS_ENSURE_STATE(slot != nullptr);
   1.151 +    
   1.152 +  CK_BYTE pBuf[(NUM_ELEM(p) - 1) / 2];
   1.153 +  CK_BYTE qBuf[(NUM_ELEM(q) - 1) / 2];
   1.154 +  CK_BYTE gBuf[(NUM_ELEM(g) - 1) / 2];
   1.155 +    
   1.156 +  CK_KEY_TYPE keyType = CKK_NSS_JPAKE_ROUND1;
   1.157 +  NS_ENSURE_STATE(fromHex(p, pBuf, (NUM_ELEM(p) - 1)));
   1.158 +  NS_ENSURE_STATE(fromHex(q, qBuf, (NUM_ELEM(q) - 1)));
   1.159 +  NS_ENSURE_STATE(fromHex(g, gBuf, (NUM_ELEM(g) - 1)));
   1.160 +  CK_ATTRIBUTE keyTemplate[] = {
   1.161 +    { CKA_NSS_JPAKE_SIGNERID, (CK_BYTE *) aSignerID.Data(),
   1.162 +                              aSignerID.Length() },
   1.163 +    { CKA_KEY_TYPE, &keyType, sizeof keyType },
   1.164 +    { CKA_PRIME,    pBuf,     sizeof pBuf },
   1.165 +    { CKA_SUBPRIME, qBuf,     sizeof qBuf },
   1.166 +    { CKA_BASE,     gBuf,     sizeof gBuf }
   1.167 +  };
   1.168 +
   1.169 +  CK_BYTE gx1Buf[NUM_ELEM(p) / 2];
   1.170 +  CK_BYTE gv1Buf[NUM_ELEM(p) / 2];
   1.171 +  CK_BYTE r1Buf [NUM_ELEM(p) / 2];
   1.172 +  CK_BYTE gx2Buf[NUM_ELEM(p) / 2];
   1.173 +  CK_BYTE gv2Buf[NUM_ELEM(p) / 2];
   1.174 +  CK_BYTE r2Buf [NUM_ELEM(p) / 2];
   1.175 +  CK_NSS_JPAKERound1Params rp = {
   1.176 +      { gx1Buf, sizeof gx1Buf, gv1Buf, sizeof gv1Buf, r1Buf, sizeof r1Buf },
   1.177 +      { gx2Buf, sizeof gx2Buf, gv2Buf, sizeof gv2Buf, r2Buf, sizeof r2Buf }
   1.178 +  };
   1.179 +  SECItem paramsItem;
   1.180 +  paramsItem.data = (unsigned char *) &rp;
   1.181 +  paramsItem.len = sizeof rp;
   1.182 +  key = PK11_KeyGenWithTemplate(slot, CKM_NSS_JPAKE_ROUND1_SHA256,
   1.183 +                                CKM_NSS_JPAKE_ROUND1_SHA256,
   1.184 +                                &paramsItem, keyTemplate,
   1.185 +                                NUM_ELEM(keyTemplate), nullptr);
   1.186 +  nsresult rv = key != nullptr
   1.187 +              ? NS_OK
   1.188 +              : mapErrno();
   1.189 +  if (rv == NS_OK) {
   1.190 +    NS_ENSURE_TRUE(toHexString(rp.gx1.pGX, rp.gx1.ulGXLen, aGX1) &&
   1.191 +                   toHexString(rp.gx1.pGV, rp.gx1.ulGVLen, aGV1) &&
   1.192 +                   toHexString(rp.gx1.pR,  rp.gx1.ulRLen,  aR1)  &&
   1.193 +                   toHexString(rp.gx2.pGX, rp.gx2.ulGXLen, aGX2) &&
   1.194 +                   toHexString(rp.gx2.pGV, rp.gx2.ulGVLen, aGV2) &&
   1.195 +                   toHexString(rp.gx2.pR,  rp.gx2.ulRLen,  aR2),
   1.196 +                   NS_ERROR_OUT_OF_MEMORY);
   1.197 +    round = JPAKEBeforeRound2;
   1.198 +  }
   1.199 +  return rv;
   1.200 +}
   1.201 +
   1.202 +NS_IMETHODIMP nsSyncJPAKE::Round2(const nsACString & aPeerID,
   1.203 +                                  const nsACString & aPIN,
   1.204 +                                  const nsACString & aGX3,
   1.205 +                                  const nsACString & aGV3,
   1.206 +                                  const nsACString & aR3,
   1.207 +                                  const nsACString & aGX4,
   1.208 +                                  const nsACString & aGV4,
   1.209 +                                  const nsACString & aR4,
   1.210 +                                  nsACString & aA,
   1.211 +                                  nsACString & aGVA,
   1.212 +                                  nsACString & aRA)
   1.213 +{
   1.214 +  NS_ENSURE_STATE(round == JPAKEBeforeRound2);
   1.215 +  NS_ENSURE_STATE(key != nullptr);
   1.216 +  NS_ENSURE_ARG(!aPeerID.IsEmpty());
   1.217 +
   1.218 +  /* PIN cannot be equal to zero when converted to a bignum. NSS 3.12.9 J-PAKE
   1.219 +     assumes that the caller has already done this check. Future versions of 
   1.220 +     NSS J-PAKE will do this check internally. See Bug 609068 Comment 4 */
   1.221 +  bool foundNonZero = false;
   1.222 +  for (size_t i = 0; i < aPIN.Length(); ++i) {
   1.223 +    if (aPIN[i] != 0) {
   1.224 +      foundNonZero = true;
   1.225 +      break;
   1.226 +    }
   1.227 +  }
   1.228 +  NS_ENSURE_ARG(foundNonZero);
   1.229 +
   1.230 +  CK_BYTE gx3Buf[NUM_ELEM(p)/2], gv3Buf[NUM_ELEM(p)/2], r3Buf [NUM_ELEM(p)/2];
   1.231 +  CK_BYTE gx4Buf[NUM_ELEM(p)/2], gv4Buf[NUM_ELEM(p)/2], r4Buf [NUM_ELEM(p)/2];
   1.232 +  CK_BYTE gxABuf[NUM_ELEM(p)/2], gvABuf[NUM_ELEM(p)/2], rABuf [NUM_ELEM(p)/2];
   1.233 +  nsresult         rv = fromHexString(aGX3, gx3Buf, sizeof gx3Buf);
   1.234 +  if (rv == NS_OK) rv = fromHexString(aGV3, gv3Buf, sizeof gv3Buf);
   1.235 +  if (rv == NS_OK) rv = fromHexString(aR3,  r3Buf,  sizeof r3Buf);
   1.236 +  if (rv == NS_OK) rv = fromHexString(aGX4, gx4Buf, sizeof gx4Buf);
   1.237 +  if (rv == NS_OK) rv = fromHexString(aGV4, gv4Buf, sizeof gv4Buf);
   1.238 +  if (rv == NS_OK) rv = fromHexString(aR4,  r4Buf,  sizeof r4Buf);
   1.239 +  if (rv != NS_OK)
   1.240 +    return rv;
   1.241 +
   1.242 +  CK_NSS_JPAKERound2Params rp;
   1.243 +  rp.pSharedKey = (CK_BYTE *) aPIN.Data();
   1.244 +  rp.ulSharedKeyLen = aPIN.Length();
   1.245 +  rp.gx3.pGX = gx3Buf; rp.gx3.ulGXLen = aGX3.Length() / 2;
   1.246 +  rp.gx3.pGV = gv3Buf; rp.gx3.ulGVLen = aGV3.Length() / 2;
   1.247 +  rp.gx3.pR  = r3Buf;  rp.gx3.ulRLen  = aR3 .Length() / 2;
   1.248 +  rp.gx4.pGX = gx4Buf; rp.gx4.ulGXLen = aGX4.Length() / 2;
   1.249 +  rp.gx4.pGV = gv4Buf; rp.gx4.ulGVLen = aGV4.Length() / 2;
   1.250 +  rp.gx4.pR  = r4Buf;  rp.gx4.ulRLen  = aR4 .Length() / 2;
   1.251 +  rp.A.pGX   = gxABuf; rp.A  .ulGXLen = sizeof gxABuf;
   1.252 +  rp.A.pGV   = gvABuf; rp.A  .ulGVLen = sizeof gxABuf;
   1.253 +  rp.A.pR    = rABuf;  rp.A  .ulRLen  = sizeof gxABuf;
   1.254 +
   1.255 +  // Bug 629090: NSS 3.12.9 J-PAKE fails to check that gx^4 != 1, so check here.
   1.256 +  bool gx4Good = false;
   1.257 +  for (unsigned i = 0; i < rp.gx4.ulGXLen; ++i) {
   1.258 +    if (rp.gx4.pGX[i] > 1 || (rp.gx4.pGX[i] != 0 && i < rp.gx4.ulGXLen - 1)) {
   1.259 +      gx4Good = true;
   1.260 +      break;
   1.261 +    }
   1.262 +  }
   1.263 +  NS_ENSURE_ARG(gx4Good);
   1.264 +
   1.265 +  SECItem paramsItem;
   1.266 +  paramsItem.data = (unsigned char *) &rp;
   1.267 +  paramsItem.len = sizeof rp;
   1.268 +  CK_KEY_TYPE keyType = CKK_NSS_JPAKE_ROUND2;
   1.269 +  CK_ATTRIBUTE keyTemplate[] = {
   1.270 +    { CKA_NSS_JPAKE_PEERID, (CK_BYTE *) aPeerID.Data(), aPeerID.Length(), },
   1.271 +    { CKA_KEY_TYPE, &keyType, sizeof keyType }
   1.272 +  };
   1.273 +  PK11SymKey * newKey = PK11_DeriveWithTemplate(key,
   1.274 +                                                CKM_NSS_JPAKE_ROUND2_SHA256,
   1.275 +                                                &paramsItem,
   1.276 +                                                CKM_NSS_JPAKE_FINAL_SHA256,
   1.277 +                                                CKA_DERIVE, 0,
   1.278 +                                                keyTemplate,
   1.279 +                                                NUM_ELEM(keyTemplate),
   1.280 +                                                false);
   1.281 +  if (newKey != nullptr) {
   1.282 +    if (toHexString(rp.A.pGX, rp.A.ulGXLen, aA) &&
   1.283 +        toHexString(rp.A.pGV, rp.A.ulGVLen, aGVA) &&
   1.284 +        toHexString(rp.A.pR, rp.A.ulRLen, aRA)) {
   1.285 +      round = JPAKEAfterRound2;
   1.286 +      PK11_FreeSymKey(key);
   1.287 +      key = newKey;
   1.288 +      return NS_OK;
   1.289 +    } else {
   1.290 +      PK11_FreeSymKey(newKey);
   1.291 +      rv = NS_ERROR_OUT_OF_MEMORY;
   1.292 +    }
   1.293 +  } else
   1.294 +    rv = mapErrno();
   1.295 +
   1.296 +  return rv;
   1.297 +}
   1.298 +
   1.299 +static nsresult
   1.300 +setBase64(const unsigned char * data, unsigned len, nsACString & out)
   1.301 +{
   1.302 +  nsresult rv = NS_OK;
   1.303 +  const char * base64 = BTOA_DataToAscii(data, len);
   1.304 +  
   1.305 +  if (base64 != nullptr) {
   1.306 +    size_t len = PORT_Strlen(base64);
   1.307 +    if (out.SetCapacity(len, fallible_t())) {
   1.308 +      out.SetLength(0);
   1.309 +      out.Append(base64, len);
   1.310 +      PORT_Free((void*) base64);
   1.311 +    } else {
   1.312 +      rv = NS_ERROR_OUT_OF_MEMORY;
   1.313 +    }
   1.314 +  } else {
   1.315 +    rv = NS_ERROR_OUT_OF_MEMORY;
   1.316 +  }
   1.317 +  return rv;
   1.318 +}
   1.319 +
   1.320 +static nsresult
   1.321 +base64KeyValue(PK11SymKey * key, nsACString & keyString)
   1.322 +{
   1.323 +  nsresult rv = NS_OK;
   1.324 +  if (PK11_ExtractKeyValue(key) == SECSuccess) {
   1.325 +    const SECItem * value = PK11_GetKeyData(key);
   1.326 +    rv = value != nullptr && value->data != nullptr && value->len > 0
   1.327 +       ? setBase64(value->data, value->len, keyString)
   1.328 +       : NS_ERROR_UNEXPECTED;
   1.329 +  } else {
   1.330 +    rv = mapErrno();
   1.331 +  }
   1.332 +  return rv;
   1.333 +}
   1.334 +
   1.335 +static nsresult
   1.336 +extractBase64KeyValue(PK11SymKey * keyBlock, CK_ULONG bitPosition,
   1.337 +                      CK_MECHANISM_TYPE destMech, int keySize,
   1.338 +                      nsACString & keyString)
   1.339 +{
   1.340 +  SECItem paramsItem;
   1.341 +  paramsItem.data = (CK_BYTE *) &bitPosition;
   1.342 +  paramsItem.len = sizeof bitPosition;
   1.343 +  PK11SymKey * key = PK11_Derive(keyBlock, CKM_EXTRACT_KEY_FROM_KEY,
   1.344 +                                 &paramsItem, destMech,
   1.345 +                                 CKA_SIGN, keySize);
   1.346 +  if (key == nullptr)
   1.347 +    return mapErrno();
   1.348 +  nsresult rv = base64KeyValue(key, keyString);
   1.349 +  PK11_FreeSymKey(key);
   1.350 +  return rv;
   1.351 +}
   1.352 +
   1.353 +
   1.354 +NS_IMETHODIMP nsSyncJPAKE::Final(const nsACString & aB,
   1.355 +                                 const nsACString & aGVB,
   1.356 +                                 const nsACString & aRB,
   1.357 +                                 const nsACString & aHKDFInfo,
   1.358 +                                 nsACString & aAES256Key,
   1.359 +                                 nsACString & aHMAC256Key)
   1.360 +{
   1.361 +  static const unsigned AES256_KEY_SIZE = 256 / 8;
   1.362 +  static const unsigned HMAC_SHA256_KEY_SIZE = 256 / 8;
   1.363 +  CK_EXTRACT_PARAMS aesBitPosition = 0;
   1.364 +  CK_EXTRACT_PARAMS hmacBitPosition = aesBitPosition + (AES256_KEY_SIZE * 8);
   1.365 +
   1.366 +  NS_ENSURE_STATE(round == JPAKEAfterRound2);
   1.367 +  NS_ENSURE_STATE(key != nullptr);
   1.368 +
   1.369 +  CK_BYTE gxBBuf[NUM_ELEM(p)/2], gvBBuf[NUM_ELEM(p)/2], rBBuf [NUM_ELEM(p)/2];
   1.370 +  nsresult         rv = fromHexString(aB,   gxBBuf, sizeof gxBBuf);
   1.371 +  if (rv == NS_OK) rv = fromHexString(aGVB, gvBBuf, sizeof gvBBuf);
   1.372 +  if (rv == NS_OK) rv = fromHexString(aRB,  rBBuf,  sizeof rBBuf);
   1.373 +  if (rv != NS_OK)
   1.374 +    return rv;
   1.375 +
   1.376 +  CK_NSS_JPAKEFinalParams rp;
   1.377 +  rp.B.pGX = gxBBuf; rp.B.ulGXLen = aB  .Length() / 2;
   1.378 +  rp.B.pGV = gvBBuf; rp.B.ulGVLen = aGVB.Length() / 2;
   1.379 +  rp.B.pR  = rBBuf;  rp.B.ulRLen  = aRB .Length() / 2;
   1.380 +  SECItem paramsItem;
   1.381 +  paramsItem.data = (unsigned char *) &rp;
   1.382 +  paramsItem.len = sizeof rp;
   1.383 +  PK11SymKey * keyMaterial = PK11_Derive(key, CKM_NSS_JPAKE_FINAL_SHA256,
   1.384 +                                         &paramsItem, CKM_NSS_HKDF_SHA256,
   1.385 +                                         CKA_DERIVE, 0);
   1.386 +  PK11SymKey * keyBlock = nullptr;
   1.387 +
   1.388 +  if (keyMaterial == nullptr)
   1.389 +    rv = mapErrno();
   1.390 +
   1.391 +  if (rv == NS_OK) {
   1.392 +    CK_NSS_HKDFParams hkdfParams;
   1.393 +    hkdfParams.bExtract = CK_TRUE;
   1.394 +    hkdfParams.pSalt = nullptr;
   1.395 +    hkdfParams.ulSaltLen = 0;
   1.396 +    hkdfParams.bExpand = CK_TRUE;
   1.397 +    hkdfParams.pInfo = (CK_BYTE *) aHKDFInfo.Data();
   1.398 +    hkdfParams.ulInfoLen = aHKDFInfo.Length();
   1.399 +    paramsItem.data = (unsigned char *) &hkdfParams;
   1.400 +    paramsItem.len = sizeof hkdfParams;
   1.401 +    keyBlock = PK11_Derive(keyMaterial, CKM_NSS_HKDF_SHA256,
   1.402 +                           &paramsItem, CKM_EXTRACT_KEY_FROM_KEY,
   1.403 +                           CKA_DERIVE, AES256_KEY_SIZE + HMAC_SHA256_KEY_SIZE);
   1.404 +    if (keyBlock == nullptr)
   1.405 +      rv = mapErrno();
   1.406 +  }
   1.407 +
   1.408 +  if (rv == NS_OK) {
   1.409 +    rv = extractBase64KeyValue(keyBlock, aesBitPosition, CKM_AES_CBC,
   1.410 +                               AES256_KEY_SIZE, aAES256Key);
   1.411 +  }
   1.412 +  if (rv == NS_OK) {
   1.413 +    rv = extractBase64KeyValue(keyBlock, hmacBitPosition, CKM_SHA256_HMAC,
   1.414 +                               HMAC_SHA256_KEY_SIZE, aHMAC256Key);
   1.415 +  }
   1.416 +
   1.417 +  if (rv == NS_OK) {
   1.418 +    SECStatus srv = PK11_ExtractKeyValue(keyMaterial);
   1.419 +    NS_ENSURE_TRUE(srv == SECSuccess, NS_ERROR_UNEXPECTED); // XXX leaks
   1.420 +    SECItem * keyMaterialBytes = PK11_GetKeyData(keyMaterial);
   1.421 +    NS_ENSURE_TRUE(keyMaterialBytes != nullptr, NS_ERROR_UNEXPECTED);
   1.422 +  }
   1.423 +
   1.424 +  if (keyBlock != nullptr)
   1.425 +    PK11_FreeSymKey(keyBlock);
   1.426 +  if (keyMaterial != nullptr)
   1.427 +    PK11_FreeSymKey(keyMaterial);
   1.428 +
   1.429 +  return rv;
   1.430 +}
   1.431 +
   1.432 +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSyncJPAKE)
   1.433 +NS_DEFINE_NAMED_CID(NS_SYNCJPAKE_CID);
   1.434 +
   1.435 +nsSyncJPAKE::nsSyncJPAKE() : round(JPAKENotStarted), key(nullptr) { }
   1.436 +
   1.437 +nsSyncJPAKE::~nsSyncJPAKE()
   1.438 +{
   1.439 +  if (key != nullptr)
   1.440 +    PK11_FreeSymKey(key);
   1.441 +}
   1.442 +
   1.443 +static const mozilla::Module::CIDEntry kServicesCryptoCIDs[] = {
   1.444 +  { &kNS_SYNCJPAKE_CID, false, nullptr, nsSyncJPAKEConstructor },
   1.445 +  { nullptr }
   1.446 +};
   1.447 +
   1.448 +static const mozilla::Module::ContractIDEntry kServicesCryptoContracts[] = {
   1.449 +  { NS_SYNCJPAKE_CONTRACTID, &kNS_SYNCJPAKE_CID },
   1.450 +  { nullptr }
   1.451 +};
   1.452 +
   1.453 +static const mozilla::Module kServicesCryptoModule = {
   1.454 +  mozilla::Module::kVersion,
   1.455 +  kServicesCryptoCIDs,
   1.456 +  kServicesCryptoContracts
   1.457 +};
   1.458 +
   1.459 +NSMODULE_DEFN(nsServicesCryptoModule) = &kServicesCryptoModule;

mercurial