TLSContent EncryptedWriteRecordLayer::write()

in fizz/record/EncryptedRecordLayer.cpp [169:254]


TLSContent EncryptedWriteRecordLayer::write(
    TLSMessage&& msg,
    Aead::AeadOptions options) const {
  folly::IOBufQueue queue;
  queue.append(std::move(msg.fragment));
  std::unique_ptr<folly::IOBuf> outBuf;
  std::array<uint8_t, kEncryptedHeaderSize> headerBuf;
  auto header = folly::IOBuf::wrapBufferAsValue(folly::range(headerBuf));
  aead_->setEncryptedBufferHeadroom(kEncryptedHeaderSize);
  while (!queue.empty()) {
    Buf dataBuf;
    uint16_t paddingSize;
    std::tie(dataBuf, paddingSize) =
        bufAndPaddingPolicy_->getBufAndPaddingToEncrypt(queue, maxRecord_);

    // check if we have enough room to add padding and the encrypted footer.
    if (!dataBuf->isShared() &&
        dataBuf->prev()->tailroom() >= sizeof(ContentType) + paddingSize) {
      // extend it and add padding and footer
      folly::io::Appender appender(dataBuf.get(), 0);
      appender.writeBE(static_cast<ContentTypeType>(msg.type));
      memset(appender.writableData(), 0, paddingSize);
      appender.append(paddingSize);
    } else {
      // not enough or shared - let's add enough for the tag as well
      auto encryptedFooter = folly::IOBuf::create(
          sizeof(ContentType) + paddingSize + aead_->getCipherOverhead());
      folly::io::Appender appender(encryptedFooter.get(), 0);
      appender.writeBE(static_cast<ContentTypeType>(msg.type));
      memset(appender.writableData(), 0, paddingSize);
      appender.append(paddingSize);
      dataBuf->prependChain(std::move(encryptedFooter));
    }

    if (seqNum_ == std::numeric_limits<uint64_t>::max()) {
      throw std::runtime_error("max write seq num");
    }

    // we will either be able to memcpy directly into the ciphertext or
    // need to create a new buf to insert before the ciphertext but we need
    // it for additional data
    header.clear();
    folly::io::Appender appender(&header, 0);
    appender.writeBE(
        static_cast<ContentTypeType>(ContentType::application_data));
    appender.writeBE(
        static_cast<ProtocolVersionType>(ProtocolVersion::tls_1_2));
    auto ciphertextLength =
        dataBuf->computeChainDataLength() + aead_->getCipherOverhead();
    appender.writeBE<uint16_t>(ciphertextLength);

    auto cipherText = aead_->encrypt(
        std::move(dataBuf),
        useAdditionalData_ ? &header : nullptr,
        seqNum_++,
        options);

    std::unique_ptr<folly::IOBuf> record;
    if (!cipherText->isShared() &&
        cipherText->headroom() >= kEncryptedHeaderSize) {
      // prepend and then write it in
      cipherText->prepend(kEncryptedHeaderSize);
      memcpy(cipherText->writableData(), header.data(), header.length());
      record = std::move(cipherText);
    } else {
      record = folly::IOBuf::copyBuffer(header.data(), header.length());
      record->prependChain(std::move(cipherText));
    }

    if (!outBuf) {
      outBuf = std::move(record);
    } else {
      outBuf->prependChain(std::move(record));
    }
  }

  if (!outBuf) {
    outBuf = folly::IOBuf::create(0);
  }

  TLSContent content;
  content.data = std::move(outBuf);
  content.contentType = msg.type;
  content.encryptionLevel = encryptionLevel_;
  return content;
}