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;
}