summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-05 01:53:18 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-05 01:53:18 +0000
commitd0e406165adf1ab1180e2f1b4b1536c540a9339f (patch)
treede33107e9415b8a92f2a0718e04151a610fd2d7b /net
parent9475cc7093d44180920046d6ca80aa46e4820562 (diff)
downloadchromium_src-d0e406165adf1ab1180e2f1b4b1536c540a9339f.zip
chromium_src-d0e406165adf1ab1180e2f1b4b1536c540a9339f.tar.gz
chromium_src-d0e406165adf1ab1180e2f1b4b1536c540a9339f.tar.bz2
Add net/quic/crypto/crypto_handshake_message.{cc,h}.
These files are part of https://codereview.chromium.org/147763009/. They are added first so that the rest of that CL can be committed by the commit queue. TBR=rch@chromium.org BUG=none TEST=none Review URL: https://codereview.chromium.org/154643006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@248826 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/quic/crypto/crypto_handshake_message.cc313
-rw-r--r--net/quic/crypto/crypto_handshake_message.h135
2 files changed, 448 insertions, 0 deletions
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc
new file mode 100644
index 0000000..7efa0b5
--- /dev/null
+++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -0,0 +1,313 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/crypto_handshake_message.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/crypto/crypto_framer.h"
+#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/quic_utils.h"
+
+using base::StringPiece;
+using base::StringPrintf;
+using std::string;
+using std::vector;
+
+namespace net {
+
+CryptoHandshakeMessage::CryptoHandshakeMessage()
+ : tag_(0),
+ minimum_size_(0) {}
+
+CryptoHandshakeMessage::CryptoHandshakeMessage(
+ const CryptoHandshakeMessage& other)
+ : tag_(other.tag_),
+ tag_value_map_(other.tag_value_map_),
+ minimum_size_(other.minimum_size_) {
+ // Don't copy serialized_. scoped_ptr doesn't have a copy constructor.
+ // The new object can lazily reconstruct serialized_.
+}
+
+CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
+
+CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
+ const CryptoHandshakeMessage& other) {
+ tag_ = other.tag_;
+ tag_value_map_ = other.tag_value_map_;
+ // Don't copy serialized_. scoped_ptr doesn't have an assignment operator.
+ // However, invalidate serialized_.
+ serialized_.reset();
+ minimum_size_ = other.minimum_size_;
+ return *this;
+}
+
+void CryptoHandshakeMessage::Clear() {
+ tag_ = 0;
+ tag_value_map_.clear();
+ minimum_size_ = 0;
+ serialized_.reset();
+}
+
+const QuicData& CryptoHandshakeMessage::GetSerialized() const {
+ if (!serialized_.get()) {
+ serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this));
+ }
+ return *serialized_.get();
+}
+
+void CryptoHandshakeMessage::MarkDirty() {
+ serialized_.reset();
+}
+
+void CryptoHandshakeMessage::SetTaglist(QuicTag tag, ...) {
+ // Warning, if sizeof(QuicTag) > sizeof(int) then this function will break
+ // because the terminating 0 will only be promoted to int.
+ COMPILE_ASSERT(sizeof(QuicTag) <= sizeof(int),
+ crypto_tag_may_not_be_larger_than_int_or_varargs_will_break);
+
+ vector<QuicTag> tags;
+ va_list ap;
+
+ va_start(ap, tag);
+ for (;;) {
+ QuicTag list_item = va_arg(ap, QuicTag);
+ if (list_item == 0) {
+ break;
+ }
+ tags.push_back(list_item);
+ }
+
+ // Because of the way that we keep tags in memory, we can copy the contents
+ // of the vector and get the correct bytes in wire format. See
+ // crypto_protocol.h. This assumes that the system is little-endian.
+ SetVector(tag, tags);
+
+ va_end(ap);
+}
+
+void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, StringPiece value) {
+ tag_value_map_[tag] = value.as_string();
+}
+
+void CryptoHandshakeMessage::Erase(QuicTag tag) {
+ tag_value_map_.erase(tag);
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag,
+ const QuicTag** out_tags,
+ size_t* out_len) const {
+ QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
+ QuicErrorCode ret = QUIC_NO_ERROR;
+
+ if (it == tag_value_map_.end()) {
+ ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ } else if (it->second.size() % sizeof(QuicTag) != 0) {
+ ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (ret != QUIC_NO_ERROR) {
+ *out_tags = NULL;
+ *out_len = 0;
+ return ret;
+ }
+
+ *out_tags = reinterpret_cast<const QuicTag*>(it->second.data());
+ *out_len = it->second.size() / sizeof(QuicTag);
+ return ret;
+}
+
+bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag,
+ StringPiece* out) const {
+ QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
+ if (it == tag_value_map_.end()) {
+ return false;
+ }
+ *out = it->second;
+ return true;
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetNthValue24(QuicTag tag,
+ unsigned index,
+ StringPiece* out) const {
+ StringPiece value;
+ if (!GetStringPiece(tag, &value)) {
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ }
+
+ for (unsigned i = 0;; i++) {
+ if (value.empty()) {
+ return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
+ }
+ if (value.size() < 3) {
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(value.data());
+ size_t size = static_cast<size_t>(data[0]) |
+ (static_cast<size_t>(data[1]) << 8) |
+ (static_cast<size_t>(data[2]) << 16);
+ value.remove_prefix(3);
+
+ if (value.size() < size) {
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (i == index) {
+ *out = StringPiece(value.data(), size);
+ return QUIC_NO_ERROR;
+ }
+
+ value.remove_prefix(size);
+ }
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetUint16(QuicTag tag,
+ uint16* out) const {
+ return GetPOD(tag, out, sizeof(uint16));
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
+ uint32* out) const {
+ return GetPOD(tag, out, sizeof(uint32));
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
+ uint64* out) const {
+ return GetPOD(tag, out, sizeof(uint64));
+}
+
+size_t CryptoHandshakeMessage::size() const {
+ size_t ret = sizeof(QuicTag) +
+ sizeof(uint16) /* number of entries */ +
+ sizeof(uint16) /* padding */;
+ ret += (sizeof(QuicTag) + sizeof(uint32) /* end offset */) *
+ tag_value_map_.size();
+ for (QuicTagValueMap::const_iterator i = tag_value_map_.begin();
+ i != tag_value_map_.end(); ++i) {
+ ret += i->second.size();
+ }
+
+ return ret;
+}
+
+void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) {
+ if (min_bytes == minimum_size_) {
+ return;
+ }
+ serialized_.reset();
+ minimum_size_ = min_bytes;
+}
+
+size_t CryptoHandshakeMessage::minimum_size() const {
+ return minimum_size_;
+}
+
+string CryptoHandshakeMessage::DebugString() const {
+ return DebugStringInternal(0);
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetPOD(
+ QuicTag tag, void* out, size_t len) const {
+ QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
+ QuicErrorCode ret = QUIC_NO_ERROR;
+
+ if (it == tag_value_map_.end()) {
+ ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ } else if (it->second.size() != len) {
+ ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (ret != QUIC_NO_ERROR) {
+ memset(out, 0, len);
+ return ret;
+ }
+
+ memcpy(out, it->second.data(), len);
+ return ret;
+}
+
+string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
+ string ret = string(2 * indent, ' ') + QuicUtils::TagToString(tag_) + "<\n";
+ ++indent;
+ for (QuicTagValueMap::const_iterator it = tag_value_map_.begin();
+ it != tag_value_map_.end(); ++it) {
+ ret += string(2 * indent, ' ') + QuicUtils::TagToString(it->first) + ": ";
+
+ bool done = false;
+ switch (it->first) {
+ case kICSL:
+ case kIRTT:
+ case kKATO:
+ case kMSPC:
+ case kSWND:
+ // uint32 value
+ if (it->second.size() == 4) {
+ uint32 value;
+ memcpy(&value, it->second.data(), sizeof(value));
+ ret += base::UintToString(value);
+ done = true;
+ }
+ break;
+ case kVERS:
+ // uint16 value
+ if (it->second.size() == 2) {
+ uint16 value;
+ memcpy(&value, it->second.data(), sizeof(value));
+ ret += base::UintToString(value);
+ done = true;
+ }
+ break;
+ case kKEXS:
+ case kAEAD:
+ case kCGST:
+ case kPDMD:
+ case kVER:
+ // tag lists
+ if (it->second.size() % sizeof(QuicTag) == 0) {
+ for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
+ QuicTag tag;
+ memcpy(&tag, it->second.data() + j, sizeof(tag));
+ if (j > 0) {
+ ret += ",";
+ }
+ ret += "'" + QuicUtils::TagToString(tag) + "'";
+ }
+ done = true;
+ }
+ break;
+ case kSCFG:
+ // nested messages.
+ if (!it->second.empty()) {
+ scoped_ptr<CryptoHandshakeMessage> msg(
+ CryptoFramer::ParseMessage(it->second));
+ if (msg.get()) {
+ ret += "\n";
+ ret += msg->DebugStringInternal(indent + 1);
+
+ done = true;
+ }
+ }
+ break;
+ case kPAD:
+ ret += StringPrintf("(%d bytes of padding)",
+ static_cast<int>(it->second.size()));
+ done = true;
+ break;
+ }
+
+ if (!done) {
+ // If there's no specific format for this tag, or the value is invalid,
+ // then just use hex.
+ ret += "0x" + base::HexEncode(it->second.data(), it->second.size());
+ }
+ ret += "\n";
+ }
+ --indent;
+ ret += string(2 * indent, ' ') + ">";
+ return ret;
+}
+
+} // namespace net
diff --git a/net/quic/crypto/crypto_handshake_message.h b/net/quic/crypto/crypto_handshake_message.h
new file mode 100644
index 0000000..fcb3930
--- /dev/null
+++ b/net/quic/crypto/crypto_handshake_message.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_
+#define NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+// An intermediate format of a handshake message that's convenient for a
+// CryptoFramer to serialize from or parse into.
+class NET_EXPORT_PRIVATE CryptoHandshakeMessage {
+ public:
+ CryptoHandshakeMessage();
+ CryptoHandshakeMessage(const CryptoHandshakeMessage& other);
+ ~CryptoHandshakeMessage();
+
+ CryptoHandshakeMessage& operator=(const CryptoHandshakeMessage& other);
+
+ // Clears state.
+ void Clear();
+
+ // GetSerialized returns the serialized form of this message and caches the
+ // result. Subsequently altering the message does not invalidate the cache.
+ const QuicData& GetSerialized() const;
+
+ // MarkDirty invalidates the cache created by |GetSerialized|.
+ void MarkDirty();
+
+ // SetValue sets an element with the given tag to the raw, memory contents of
+ // |v|.
+ template<class T> void SetValue(QuicTag tag, const T& v) {
+ tag_value_map_[tag] =
+ std::string(reinterpret_cast<const char*>(&v), sizeof(v));
+ }
+
+ // SetVector sets an element with the given tag to the raw contents of an
+ // array of elements in |v|.
+ template<class T> void SetVector(QuicTag tag, const std::vector<T>& v) {
+ if (v.empty()) {
+ tag_value_map_[tag] = std::string();
+ } else {
+ tag_value_map_[tag] = std::string(reinterpret_cast<const char*>(&v[0]),
+ v.size() * sizeof(T));
+ }
+ }
+
+ // Returns the message tag.
+ QuicTag tag() const { return tag_; }
+ // Sets the message tag.
+ void set_tag(QuicTag tag) { tag_ = tag; }
+
+ const QuicTagValueMap& tag_value_map() const { return tag_value_map_; }
+
+ // SetTaglist sets an element with the given tag to contain a list of tags,
+ // passed as varargs. The argument list must be terminated with a 0 element.
+ void SetTaglist(QuicTag tag, ...);
+
+ void SetStringPiece(QuicTag tag, base::StringPiece value);
+
+ // Erase removes a tag/value, if present, from the message.
+ void Erase(QuicTag tag);
+
+ // GetTaglist finds an element with the given tag containing zero or more
+ // tags. If such a tag doesn't exist, it returns false. Otherwise it sets
+ // |out_tags| and |out_len| to point to the array of tags and returns true.
+ // The array points into the CryptoHandshakeMessage and is valid only for as
+ // long as the CryptoHandshakeMessage exists and is not modified.
+ QuicErrorCode GetTaglist(QuicTag tag, const QuicTag** out_tags,
+ size_t* out_len) const;
+
+ bool GetStringPiece(QuicTag tag, base::StringPiece* out) const;
+
+ // GetNthValue24 interprets the value with the given tag to be a series of
+ // 24-bit, length prefixed values and it returns the subvalue with the given
+ // index.
+ QuicErrorCode GetNthValue24(QuicTag tag,
+ unsigned index,
+ base::StringPiece* out) const;
+ QuicErrorCode GetUint16(QuicTag tag, uint16* out) const;
+ QuicErrorCode GetUint32(QuicTag tag, uint32* out) const;
+ QuicErrorCode GetUint64(QuicTag tag, uint64* out) const;
+
+ // size returns 4 (message tag) + 2 (uint16, number of entries) +
+ // (4 (tag) + 4 (end offset))*tag_value_map_.size() + ∑ value sizes.
+ size_t size() const;
+
+ // set_minimum_size sets the minimum number of bytes that the message should
+ // consume. The CryptoFramer will add a PAD tag as needed when serializing in
+ // order to ensure this. Setting a value of 0 disables padding.
+ //
+ // Padding is useful in order to ensure that messages are a minimum size. A
+ // QUIC server can require a minimum size in order to reduce the
+ // amplification factor of any mirror DoS attack.
+ void set_minimum_size(size_t min_bytes);
+
+ size_t minimum_size() const;
+
+ // DebugString returns a multi-line, string representation of the message
+ // suitable for including in debug output.
+ std::string DebugString() const;
+
+ private:
+ // GetPOD is a utility function for extracting a plain-old-data value. If
+ // |tag| exists in the message, and has a value of exactly |len| bytes then
+ // it copies |len| bytes of data into |out|. Otherwise |len| bytes at |out|
+ // are zeroed out.
+ //
+ // If used to copy integers then this assumes that the machine is
+ // little-endian.
+ QuicErrorCode GetPOD(QuicTag tag, void* out, size_t len) const;
+
+ std::string DebugStringInternal(size_t indent) const;
+
+ QuicTag tag_;
+ QuicTagValueMap tag_value_map_;
+
+ size_t minimum_size_;
+
+ // The serialized form of the handshake message. This member is constructed
+ // lasily.
+ mutable scoped_ptr<QuicData> serialized_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_