tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

NSSCipherStrategy.cpp (4898B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "NSSCipherStrategy.h"
      8 
      9 #include <algorithm>
     10 #include <cstdlib>
     11 #include <cstring>
     12 #include <utility>
     13 
     14 #include "mozilla/Assertions.h"
     15 
     16 // NSS includes
     17 #include "blapit.h"
     18 #include "nsNSSComponent.h"
     19 #include "pk11pub.h"
     20 #include "pkcs11t.h"
     21 #include "seccomon.h"
     22 #include "secmodt.h"
     23 
     24 namespace mozilla::dom::quota {
     25 
     26 static_assert(sizeof(NSSCipherStrategy::KeyType) == 32);
     27 static_assert(NSSCipherStrategy::BlockPrefixLength == 32);
     28 static_assert(NSSCipherStrategy::BasicBlockSize == 16);
     29 
     30 Result<NSSCipherStrategy::KeyType, nsresult> NSSCipherStrategy::GenerateKey() {
     31  const auto slot = UniquePK11SlotInfo{PK11_GetInternalSlot()};
     32  if (slot == nullptr) {
     33    return Err(NS_ERROR_FAILURE);
     34  }
     35  const auto symKey = UniquePK11SymKey{PK11_KeyGen(
     36      slot.get(), CKM_CHACHA20_KEY_GEN, nullptr, sizeof(KeyType), nullptr)};
     37  if (symKey == nullptr) {
     38    return Err(NS_ERROR_FAILURE);
     39  }
     40  if (PK11_ExtractKeyValue(symKey.get()) != SECSuccess) {
     41    return Err(NS_ERROR_FAILURE);
     42  }
     43  // No need to free keyData as it is a buffer managed by symKey.
     44  SECItem* keyData = PK11_GetKeyData(symKey.get());
     45  if (keyData == nullptr) {
     46    return Err(NS_ERROR_FAILURE);
     47  }
     48  KeyType key;
     49  MOZ_RELEASE_ASSERT(keyData->len == key.size());
     50  std::copy(keyData->data, keyData->data + key.size(), key.data());
     51  return key;
     52 }
     53 
     54 nsresult NSSCipherStrategy::Init(const CipherMode aMode,
     55                                 const Span<const uint8_t> aKey,
     56                                 const Span<const uint8_t> aInitialIv) {
     57  MOZ_ASSERT_IF(CipherMode::Encrypt == aMode, aInitialIv.Length() == 32);
     58  MOZ_RELEASE_ASSERT(EnsureNSSInitializedChromeOrContent(),
     59                     "Could not initialize NSS.");
     60 
     61  mMode.init(aMode);
     62 
     63  mIv.AppendElements(aInitialIv);
     64 
     65  const auto slot = UniquePK11SlotInfo{PK11_GetInternalSlot()};
     66  if (slot == nullptr) {
     67    return NS_ERROR_FAILURE;
     68  }
     69 
     70  SECItem keyItem;
     71  keyItem.data = const_cast<uint8_t*>(aKey.Elements());
     72  keyItem.len = aKey.Length();
     73  const auto symKey = UniquePK11SymKey{
     74      PK11_ImportSymKey(slot.get(), CKM_CHACHA20_POLY1305, PK11_OriginUnwrap,
     75                        CKA_ENCRYPT, &keyItem, nullptr)};
     76  if (symKey == nullptr) {
     77    return NS_ERROR_FAILURE;
     78  }
     79 
     80  SECItem empty = {siBuffer, nullptr, 0};
     81  auto pk11Context = UniquePK11Context{PK11_CreateContextBySymKey(
     82      CKM_CHACHA20_POLY1305,
     83      CKA_NSS_MESSAGE |
     84          (CipherMode::Encrypt == aMode ? CKA_ENCRYPT : CKA_DECRYPT),
     85      symKey.get(), &empty)};
     86  if (pk11Context == nullptr) {
     87    return NS_ERROR_FAILURE;
     88  }
     89 
     90  mPK11Context.init(std::move(pk11Context));
     91  return NS_OK;
     92 }
     93 
     94 nsresult NSSCipherStrategy::Cipher(const Span<uint8_t> aIv,
     95                                   const Span<const uint8_t> aIn,
     96                                   const Span<uint8_t> aOut) {
     97  if (CipherMode::Encrypt == *mMode) {
     98    MOZ_RELEASE_ASSERT(aIv.Length() == mIv.Length());
     99    memcpy(aIv.Elements(), mIv.Elements(), aIv.Length());
    100  }
    101 
    102  // XXX make tag a separate parameter
    103  constexpr size_t tagLen = 16;
    104  const auto tag = aIv.Last(tagLen);
    105  // tag is const on decrypt, but returned on encrypt
    106 
    107  const auto iv = aIv.First(12);
    108  MOZ_ASSERT(tag.Length() + iv.Length() <= aIv.Length());
    109 
    110  int outLen;
    111  // aIn and aOut may not overlap resp. be the same, so we can't do this
    112  // in-place.
    113  const SECStatus rv = PK11_AEADOp(
    114      mPK11Context->get(), CKG_GENERATE_COUNTER, 0, iv.Elements(), iv.Length(),
    115      nullptr, 0, aOut.Elements(), &outLen, aOut.Length(), tag.Elements(),
    116      tag.Length(), aIn.Elements(), aIn.Length());
    117 
    118  if (CipherMode::Encrypt == *mMode) {
    119    memcpy(mIv.Elements(), aIv.Elements(), aIv.Length());
    120  }
    121 
    122  return MapSECStatus(rv);
    123 }
    124 
    125 template <size_t N>
    126 static std::array<uint8_t, N> MakeRandomData() {
    127  std::array<uint8_t, N> res;
    128 
    129  const auto rv = PK11_GenerateRandom(res.data(), res.size());
    130  /// XXX Allow return of error code to handle this gracefully.
    131  MOZ_RELEASE_ASSERT(rv == SECSuccess);
    132 
    133  return res;
    134 }
    135 
    136 std::array<uint8_t, NSSCipherStrategy::BlockPrefixLength>
    137 NSSCipherStrategy::MakeBlockPrefix() {
    138  return MakeRandomData<BlockPrefixLength>();
    139 }
    140 
    141 Span<const uint8_t> NSSCipherStrategy::SerializeKey(const KeyType& aKey) {
    142  return Span(aKey);
    143 }
    144 
    145 Maybe<NSSCipherStrategy::KeyType> NSSCipherStrategy::DeserializeKey(
    146    const Span<const uint8_t>& aSerializedKey) {
    147  KeyType res;
    148  if (res.size() != aSerializedKey.size()) {
    149    return Nothing();
    150  }
    151  std::copy(aSerializedKey.cbegin(), aSerializedKey.cend(), res.begin());
    152  return Some(res);
    153 }
    154 
    155 }  // namespace mozilla::dom::quota