summaryrefslogtreecommitdiffstats
path: root/net/quic/crypto/crypto_framer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/quic/crypto/crypto_framer.cc')
-rw-r--r--net/quic/crypto/crypto_framer.cc91
1 files changed, 77 insertions, 14 deletions
diff --git a/net/quic/crypto/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc
index 4b3ce64..6307d82 100644
--- a/net/quic/crypto/crypto_framer.cc
+++ b/net/quic/crypto/crypto_framer.cc
@@ -160,26 +160,36 @@ bool CryptoFramer::ProcessInput(StringPiece input) {
// static
QuicData* CryptoFramer::ConstructHandshakeMessage(
const CryptoHandshakeMessage& message) {
- if (message.tag_value_map().size() > kMaxEntries) {
- return NULL;
+ size_t num_entries = message.tag_value_map().size();
+ size_t pad_length = 0;
+ bool need_pad_tag = false;
+ bool need_pad_value = false;
+
+ size_t len = message.size();
+ if (len < message.minimum_size()) {
+ need_pad_tag = true;
+ need_pad_value = true;
+ num_entries++;
+
+ size_t delta = message.minimum_size() - len;
+ const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize;
+ if (delta > overhead) {
+ pad_length = delta - overhead;
+ }
+ len += overhead + pad_length;
}
- size_t len = kQuicTagSize; // message tag
- len += sizeof(uint16); // number of map entries
- len += sizeof(uint16); // padding.
- QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
- while (it != message.tag_value_map().end()) {
- len += kQuicTagSize; // tag
- len += kCryptoEndOffsetSize; // end offset
- len += it->second.length(); // value
- ++it;
+
+ if (num_entries > kMaxEntries) {
+ return NULL;
}
+
QuicDataWriter writer(len);
if (!writer.WriteUInt32(message.tag())) {
DCHECK(false) << "Failed to write message tag.";
return NULL;
}
- if (!writer.WriteUInt16(message.tag_value_map().size())) {
+ if (!writer.WriteUInt16(num_entries)) {
DCHECK(false) << "Failed to write size.";
return NULL;
}
@@ -190,8 +200,23 @@ QuicData* CryptoFramer::ConstructHandshakeMessage(
uint32 end_offset = 0;
// Tags and offsets
- for (it = message.tag_value_map().begin();
+ for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
it != message.tag_value_map().end(); ++it) {
+ if (it->first == kPAD && need_pad_tag) {
+ // Existing PAD tags are only checked when padding needs to be added
+ // because parts of the code may need to reserialize received messages
+ // and those messages may, legitimately include padding.
+ DCHECK(false) << "Message needed padding but already contained a PAD tag";
+ return NULL;
+ }
+
+ if (it->first > kPAD && need_pad_tag) {
+ need_pad_tag = false;
+ if (!WritePadTag(&writer, pad_length, &end_offset)) {
+ return NULL;
+ }
+ }
+
if (!writer.WriteUInt32(it->first)) {
DCHECK(false) << "Failed to write tag.";
return NULL;
@@ -203,14 +228,36 @@ QuicData* CryptoFramer::ConstructHandshakeMessage(
}
}
+ if (need_pad_tag) {
+ if (!WritePadTag(&writer, pad_length, &end_offset)) {
+ return NULL;
+ }
+ }
+
// Values
- for (it = message.tag_value_map().begin();
+ for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
it != message.tag_value_map().end(); ++it) {
+ if (it->first > kPAD && need_pad_value) {
+ need_pad_value = false;
+ if (!writer.WriteRepeatedByte('-', pad_length)) {
+ DCHECK(false) << "Failed to write padding.";
+ return NULL;
+ }
+ }
+
if (!writer.WriteBytes(it->second.data(), it->second.length())) {
DCHECK(false) << "Failed to write value.";
return NULL;
}
}
+
+ if (need_pad_value) {
+ if (!writer.WriteRepeatedByte('-', pad_length)) {
+ DCHECK(false) << "Failed to write padding.";
+ return NULL;
+ }
+ }
+
return new QuicData(writer.take(), len, true);
}
@@ -221,4 +268,20 @@ void CryptoFramer::Clear() {
state_ = STATE_READING_TAG;
}
+// static
+bool CryptoFramer::WritePadTag(QuicDataWriter* writer,
+ size_t pad_length,
+ uint32* end_offset) {
+ if (!writer->WriteUInt32(kPAD)) {
+ DCHECK(false) << "Failed to write tag.";
+ return false;
+ }
+ *end_offset += pad_length;
+ if (!writer->WriteUInt32(*end_offset)) {
+ DCHECK(false) << "Failed to write end offset.";
+ return false;
+ }
+ return true;
+}
+
} // namespace net