#include "net/quic/crypto/crypto_handshake.h"
-#include <ctype.h>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "crypto/secure_hash.h"
-#include "net/base/net_util.h"
#include "net/quic/crypto/common_cert_set.h"
-#include "net/quic/crypto/crypto_framer.h"
#include "net/quic/crypto/key_exchange.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_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;
-}
-
QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
: key_exchange(0),
aead(0) {