summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-02 17:43:35 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-02 17:43:35 +0000
commit6f54ab335c8794b0b93fe9473adadd27e95b5cf8 (patch)
tree6a12370c1597daef4f7d7e13fa5e4180e0aef7d5 /net
parent0622b36cbdbbbf942f1bdcc3c74f658e2517c104 (diff)
downloadchromium_src-6f54ab335c8794b0b93fe9473adadd27e95b5cf8.zip
chromium_src-6f54ab335c8794b0b93fe9473adadd27e95b5cf8.tar.gz
chromium_src-6f54ab335c8794b0b93fe9473adadd27e95b5cf8.tar.bz2
QUIC - Some sketching of the crypto handshake.
Merge internal CL: 42490294 R=wtc@chromium.org, agl@chromium.org Review URL: https://chromiumcodereview.appspot.com/12381018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@185726 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/net.gyp6
-rw-r--r--net/quic/crypto/crypto_framer.cc42
-rw-r--r--net/quic/crypto/crypto_framer.h8
-rw-r--r--net/quic/crypto/crypto_handshake.cc143
-rw-r--r--net/quic/crypto/crypto_handshake.h117
-rw-r--r--net/quic/crypto/crypto_handshake_test.cc14
-rw-r--r--net/quic/crypto/crypto_protocol.cc153
-rw-r--r--net/quic/crypto/crypto_protocol.h80
-rw-r--r--net/quic/crypto/crypto_utils.cc93
-rw-r--r--net/quic/crypto/crypto_utils.h33
-rw-r--r--net/quic/crypto/curve25519_key_exchange.cc101
-rw-r--r--net/quic/crypto/curve25519_key_exchange.h51
-rw-r--r--net/quic/crypto/key_exchange.h40
-rw-r--r--net/quic/quic_crypto_client_stream.cc5
-rw-r--r--net/quic/quic_crypto_client_stream.h3
-rw-r--r--net/quic/test_tools/quic_test_utils.cc18
16 files changed, 672 insertions, 235 deletions
diff --git a/net/net.gyp b/net/net.gyp
index 1eb30ac..8bacb46 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -695,10 +695,15 @@
'quic/congestion_control/tcp_receiver.h',
'quic/crypto/crypto_framer.cc',
'quic/crypto/crypto_framer.h',
+ 'quic/crypto/crypto_handshake.cc',
+ 'quic/crypto/crypto_handshake.h',
'quic/crypto/crypto_protocol.cc',
'quic/crypto/crypto_protocol.h',
'quic/crypto/crypto_utils.cc',
'quic/crypto/crypto_utils.h',
+ 'quic/crypto/curve25519_key_exchange.cc',
+ 'quic/crypto/curve25519_key_exchange.h',
+ 'quic/crypto/key_exchange.h',
'quic/crypto/null_decrypter.cc',
'quic/crypto/null_decrypter.h',
'quic/crypto/null_encrypter.cc',
@@ -1519,6 +1524,7 @@
'quic/congestion_control/tcp_cubic_sender_test.cc',
'quic/congestion_control/tcp_receiver_test.cc',
'quic/crypto/crypto_framer_test.cc',
+ 'quic/crypto/crypto_handshake_test.cc',
'quic/crypto/null_decrypter_test.cc',
'quic/crypto/null_encrypter_test.cc',
'quic/crypto/quic_random_test.cc',
diff --git a/net/quic/crypto/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc
index db1bb6f..86b2df7 100644
--- a/net/quic/crypto/crypto_framer.cc
+++ b/net/quic/crypto/crypto_framer.cc
@@ -18,6 +18,31 @@ const size_t kCryptoTagSize = sizeof(uint32);
const size_t kNumEntriesSize = sizeof(uint16);
const size_t kValueLenSize = sizeof(uint16);
+// OneShotVisitor is a framer visitor that records a single handshake message.
+class OneShotVisitor : public CryptoFramerVisitorInterface {
+ public:
+ explicit OneShotVisitor(CryptoHandshakeMessage* out)
+ : out_(out),
+ error_(false) {
+ }
+
+ void OnError(CryptoFramer* framer) {
+ error_ = true;
+ }
+
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) {
+ *out_ = message;
+ }
+
+ bool error() const {
+ return error_;
+ }
+
+ private:
+ CryptoHandshakeMessage* const out_;
+ bool error_;
+};
+
} // namespace
CryptoFramer::CryptoFramer()
@@ -30,6 +55,22 @@ CryptoFramer::CryptoFramer()
CryptoFramer::~CryptoFramer() {}
+// static
+CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) {
+ scoped_ptr<CryptoHandshakeMessage> msg(new CryptoHandshakeMessage);
+ OneShotVisitor visitor(msg.get());
+ CryptoFramer framer;
+
+ framer.set_visitor(&visitor);
+ if (!framer.ProcessInput(in) ||
+ visitor.error() ||
+ framer.InputBytesRemaining()) {
+ return NULL;
+ }
+
+ return msg.release();
+}
+
bool CryptoFramer::ProcessInput(StringPiece input) {
DCHECK_EQ(QUIC_NO_ERROR, error_);
if (error_ != QUIC_NO_ERROR) {
@@ -119,6 +160,7 @@ bool CryptoFramer::ProcessInput(StringPiece input) {
return true;
}
+// static
QuicData* CryptoFramer::ConstructHandshakeMessage(
const CryptoHandshakeMessage& message) {
if (message.tag_value_map.size() > kMaxEntries) {
diff --git a/net/quic/crypto/crypto_framer.h b/net/quic/crypto/crypto_framer.h
index 34966fc..efa5259 100644
--- a/net/quic/crypto/crypto_framer.h
+++ b/net/quic/crypto/crypto_framer.h
@@ -42,6 +42,11 @@ class NET_EXPORT_PRIVATE CryptoFramer {
virtual ~CryptoFramer();
+ // ParseMessage parses exactly one message from the given StringPiece. If
+ // there is an error, the message is truncated, or the message has trailing
+ // garbage then NULL will be returned.
+ static CryptoHandshakeMessage* ParseMessage(base::StringPiece in);
+
// Set callbacks to be called from the framer. A visitor must be set, or
// else the framer will crash. It is acceptable for the visitor to do
// nothing. If this is called multiple times, only the last visitor
@@ -66,7 +71,8 @@ class NET_EXPORT_PRIVATE CryptoFramer {
// Returns a new QuicData owned by the caller that contains a serialized
// |message|, or NULL if there was an error.
- QuicData* ConstructHandshakeMessage(const CryptoHandshakeMessage& message);
+ static QuicData* ConstructHandshakeMessage(
+ const CryptoHandshakeMessage& message);
private:
// Clears per-message state. Does not clear the visitor.
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
new file mode 100644
index 0000000..48c9645
--- /dev/null
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -0,0 +1,143 @@
+// 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.h"
+
+#include "base/stl_util.h"
+#include "net/base/net_util.h"
+#include "net/quic/crypto/key_exchange.h"
+#include "net/quic/crypto/quic_random.h"
+#include "net/quic/quic_protocol.h"
+
+using std::string;
+
+namespace net {
+
+QuicCryptoClientConfig::QuicCryptoClientConfig()
+ : version(0),
+ idle_connection_state_lifetime(QuicTime::Delta::Zero()),
+ keepalive_timeout(QuicTime::Delta::Zero()) {
+}
+
+QuicCryptoClientConfig::~QuicCryptoClientConfig() {}
+
+void QuicCryptoClientConfig::SetDefaults() {
+ // Version must be 0.
+ version = 0;
+
+ // Key exchange methods.
+ key_exchange.resize(2);
+ key_exchange[0] = kC255;
+ key_exchange[1] = kP256;
+
+ // Authenticated encryption algorithms.
+ aead.resize(2);
+ aead[0] = kAESG;
+ aead[1] = kAESH;
+
+ // Congestion control feedback types.
+ // TODO(wtc): add kINAR when inter-arrival is supported.
+ congestion_control.resize(1);
+ congestion_control[0] = kQBIC;
+
+ // Idle connection state lifetime.
+ idle_connection_state_lifetime = QuicTime::Delta::FromSeconds(300);
+
+ // Keepalive timeout.
+ keepalive_timeout = QuicTime::Delta::Zero(); // Don't send keepalive probes.
+}
+
+void QuicCryptoClientConfig::FillClientHello(const string& nonce,
+ const string& server_hostname,
+ CryptoHandshakeMessage* out) {
+ out->tag = kCHLO;
+
+ out->SetValue(kVERS, version);
+ out->SetVector(kKEXS, key_exchange);
+ out->SetVector(kAEAD, aead);
+ out->SetVector(kCGST, congestion_control);
+ out->tag_value_map[kNONC] = nonce;
+
+ // Idle connection state lifetime.
+ uint32 idle_connection_state_lifetime_secs =
+ idle_connection_state_lifetime.ToSeconds();
+ out->SetValue(kICSL, idle_connection_state_lifetime_secs);
+
+ // Keepalive timeout.
+ uint32 keepalive_timeout_secs = keepalive_timeout.ToSeconds();
+ out->SetValue(kKATO, keepalive_timeout_secs);
+
+ // Server name indication.
+ // If server_hostname is not an IP address literal, it is a DNS hostname.
+ IPAddressNumber ip_number;
+ if (!server_hostname.empty() &&
+ !ParseIPLiteralToNumber(server_hostname, &ip_number)) {
+ out->tag_value_map[kSNI] = server_hostname;
+ }
+}
+
+// TODO(rtenneti): Delete QuicCryptoServerConfig.
+QuicCryptoServerConfig::QuicCryptoServerConfig() {
+}
+
+QuicCryptoServerConfig::~QuicCryptoServerConfig() {
+ STLDeleteValues(&configs_);
+}
+
+void QuicCryptoServerConfig::AddTestingConfig(QuicRandom* rand,
+ const QuicClock* clock) {
+}
+
+bool QuicCryptoServerConfig::ProcessClientHello(
+ const CryptoHandshakeMessage& client_hello,
+ const string& nonce,
+ CryptoHandshakeMessage* out) {
+ CHECK(!configs_.empty());
+ const Config* config(configs_[active_config_]);
+
+ // TODO(agl): This is obviously missing most of the handshake.
+ out->tag = kSHLO;
+ out->tag_value_map[kNONC] = nonce;
+ out->tag_value_map[kSCFG] = config->serialized;
+ return true;
+}
+
+QuicCryptoServerConfig::Config::Config() {
+}
+
+QuicCryptoServerConfig::Config::~Config() {
+ STLDeleteValues(&key_exchanges);
+}
+
+QuicCryptoNegotiatedParams::QuicCryptoNegotiatedParams()
+ : version(0),
+ key_exchange(0),
+ aead(0),
+ congestion_control(0),
+ idle_connection_state_lifetime(QuicTime::Delta::Zero()) {
+}
+
+QuicCryptoNegotiatedParams::~QuicCryptoNegotiatedParams() {}
+
+void QuicCryptoNegotiatedParams::SetDefaults() {
+ // TODO(wtc): actually negotiate the parameters using client defaults
+ // and server defaults.
+
+ // Version must be 0.
+ version = 0;
+
+ // Key exchange method.
+ key_exchange = kP256;
+
+ // Authenticated encryption algorithm.
+ aead = kAESG;
+
+ // Congestion control feedback type.
+ congestion_control = kQBIC;
+
+ // Idle connection state lifetime.
+ idle_connection_state_lifetime = QuicTime::Delta::FromSeconds(300);
+}
+
+} // namespace net
diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h
new file mode 100644
index 0000000..06b2103
--- /dev/null
+++ b/net/quic/crypto/crypto_handshake.h
@@ -0,0 +1,117 @@
+// 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_H_
+#define NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_
+
+#include <map>
+#include <string>
+
+#include "net/base/net_export.h"
+#include "net/quic/crypto/crypto_protocol.h"
+
+namespace net {
+
+class KeyExchange;
+class QuicRandom;
+class QuicClock;
+
+// QuicCryptoClientConfig contains crypto-related configuration settings for a
+// client.
+class NET_EXPORT_PRIVATE QuicCryptoClientConfig {
+ public:
+ // Initializes the members to 0 or empty values.
+ QuicCryptoClientConfig();
+ ~QuicCryptoClientConfig();
+
+ // Sets the members to reasonable, default values.
+ void SetDefaults();
+
+ // FillClientHello sets |out| to be a CHLO message based on the configuration
+ // of this object.
+ void FillClientHello(const std::string& nonce,
+ const std::string& server_hostname,
+ CryptoHandshakeMessage* out);
+
+ // Protocol version
+ uint16 version;
+ // Key exchange methods
+ CryptoTagVector key_exchange;
+ // Authenticated encryption with associated data (AEAD) algorithms
+ CryptoTagVector aead;
+ // Congestion control feedback types
+ CryptoTagVector congestion_control;
+ // Idle connection state lifetime
+ QuicTime::Delta idle_connection_state_lifetime;
+ // Keepalive timeout, or 0 to turn off keepalive probes
+ QuicTime::Delta keepalive_timeout;
+};
+
+// TODO(rtenneti): Delete QuicCryptoServerConfig.
+//
+// QuicCryptoServerConfig contains the crypto configuration of a QUIC server.
+// Unlike a client, a QUIC server can have multiple configurations active in
+// order to support clients resuming with a previous configuration.
+// TODO(agl): when adding configurations at runtime is added, this object will
+// need to consider locking.
+class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
+ public:
+ QuicCryptoServerConfig();
+ ~QuicCryptoServerConfig();
+
+ // AddTestingConfig adds a single, testing config.
+ void AddTestingConfig(QuicRandom* rand, const QuicClock* clock);
+
+ // ProcessClientHello processes |client_hello| and decides whether to accept
+ // or reject the connection. If the connection is to be accepted, |out| is
+ // set to the contents of the ServerHello and true is returned. |nonce| is
+ // used as the server's nonce. Otherwise |out| is set to be a REJ message
+ // and false is returned.
+ bool ProcessClientHello(const CryptoHandshakeMessage& client_hello,
+ const std::string& nonce,
+ CryptoHandshakeMessage* out);
+
+ private:
+ // Config represents a server config: a collection of preferences and
+ // Diffie-Hellman public values.
+ struct Config {
+ Config();
+ ~Config();
+
+ // serialized contains the bytes of this server config, suitable for sending
+ // on the wire.
+ std::string serialized;
+ // key_exchange_tags contains the key exchange methods from the config,
+ // in preference order.
+ CryptoTagVector key_exchange_tags;
+ // key_exchanges maps from elements of |key_exchange_tags| to the object
+ // that implements the specific key exchange.
+ std::map<CryptoTag, KeyExchange*> key_exchanges;
+ };
+
+ std::map<ServerConfigID, Config*> configs_;
+
+ std::string active_config_;
+};
+
+// Parameters negotiated by the crypto handshake.
+struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParams {
+ // Initializes the members to 0 or empty values.
+ QuicCryptoNegotiatedParams();
+ ~QuicCryptoNegotiatedParams();
+
+ // Sets the members to the values that would be negotiated from the default
+ // client-side and server-side configuration settings.
+ void SetDefaults();
+
+ uint16 version;
+ CryptoTag key_exchange;
+ CryptoTag aead;
+ CryptoTag congestion_control;
+ QuicTime::Delta idle_connection_state_lifetime;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_
diff --git a/net/quic/crypto/crypto_handshake_test.cc b/net/quic/crypto/crypto_handshake_test.cc
new file mode 100644
index 0000000..0ce2ed4
--- /dev/null
+++ b/net/quic/crypto/crypto_handshake_test.cc
@@ -0,0 +1,14 @@
+// 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.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+} // namespace test
+} // namespace net
diff --git a/net/quic/crypto/crypto_protocol.cc b/net/quic/crypto/crypto_protocol.cc
index 30a1cdc..435fe78 100644
--- a/net/quic/crypto/crypto_protocol.cc
+++ b/net/quic/crypto/crypto_protocol.cc
@@ -4,99 +4,94 @@
#include "net/quic/crypto/crypto_protocol.h"
-namespace net {
-
-CryptoHandshakeMessage::CryptoHandshakeMessage() {}
-CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
-
-QuicCryptoConfig::QuicCryptoConfig()
- : version(0),
- idle_connection_state_lifetime(QuicTime::Delta::Zero()),
- keepalive_timeout(QuicTime::Delta::Zero()) {
-}
-
-QuicCryptoConfig::~QuicCryptoConfig() {}
-
-void QuicCryptoConfig::SetClientDefaults() {
- // Version must be 0.
- version = 0;
+#include <stdarg.h>
+#include <string.h>
- // Key exchange methods.
- key_exchange.resize(2);
- key_exchange[0] = kC255;
- key_exchange[1] = kP256;
+#include "base/memory/scoped_ptr.h"
- // Authenticated encryption algorithms.
- aead.resize(2);
- aead[0] = kAESG;
- aead[1] = kAESH;
+using std::string;
- // Congestion control feedback types.
- // TODO(wtc): add kINAR when inter-arrival is supported.
- congestion_control.resize(1);
- congestion_control[0] = kQBIC;
+namespace net {
- // Idle connection state lifetime.
- idle_connection_state_lifetime = QuicTime::Delta::FromSeconds(300);
+CryptoHandshakeMessage::CryptoHandshakeMessage() {}
+CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
- // Keepalive timeout.
- keepalive_timeout = QuicTime::Delta::Zero(); // Don't send keepalive probes.
+void CryptoHandshakeMessage::SetTaglist(CryptoTag tag, ...) {
+ // Warning, if sizeof(CryptoTag) > sizeof(int) then this function will break
+ // because the terminating 0 will only be promoted to int.
+ COMPILE_ASSERT(sizeof(CryptoTag) <= sizeof(int),
+ crypto_tag_not_be_larger_than_int_or_varargs_will_break);
+
+ std::vector<CryptoTag> tags;
+ va_list ap;
+
+ va_start(ap, tag);
+ for (;;) {
+ CryptoTag tag = va_arg(ap, CryptoTag);
+ if (tag == 0) {
+ break;
+ }
+ tags.push_back(tag);
+ }
+
+ // 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 QuicCryptoConfig::SetServerDefaults() {
- // Version must be 0.
- version = 0;
-
- // Key exchange methods.
- // Add only NIST curve P-256 for now to ensure it is selected.
- key_exchange.resize(1);
- key_exchange[0] = kP256;
-
- // Authenticated encryption algorithms.
- // Add only AES-GCM for now to ensure it is selected.
- aead.resize(1);
- aead[0] = kAESG;
-
- // Congestion control feedback types.
- // TODO(wtc): add kINAR when inter-arrival is supported.
- congestion_control.resize(1);
- congestion_control[0] = kQBIC;
-
- // Idle connection state lifetime.
- idle_connection_state_lifetime = QuicTime::Delta::FromSeconds(300);
-
- // Keepalive timeout.
- keepalive_timeout = QuicTime::Delta::Zero(); // Don't send keepalive probes.
+QuicErrorCode CryptoHandshakeMessage::GetTaglist(CryptoTag tag,
+ const CryptoTag** out_tags,
+ size_t* out_len) const {
+ CryptoTagValueMap::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(CryptoTag) != 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 CryptoTag*>(it->second.data());
+ *out_len = it->second.size() / sizeof(CryptoTag);
+ return ret;
}
-QuicCryptoNegotiatedParams::QuicCryptoNegotiatedParams()
- : version(0),
- key_exchange(0),
- aead(0),
- congestion_control(0),
- idle_connection_state_lifetime(QuicTime::Delta::Zero()) {
+bool CryptoHandshakeMessage::GetString(CryptoTag tag, string* out) const {
+ CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
+ if (it == tag_value_map.end()) {
+ return false;
+ }
+ *out = it->second;
+ return true;
}
-QuicCryptoNegotiatedParams::~QuicCryptoNegotiatedParams() {}
-
-void QuicCryptoNegotiatedParams::SetDefaults() {
- // TODO(wtc): actually negotiate the parameters using client defaults
- // and server defaults.
-
- // Version must be 0.
- version = 0;
-
- // Key exchange method.
- key_exchange = kP256;
+QuicErrorCode CryptoHandshakeMessage::GetUint32(CryptoTag tag,
+ uint32* out) const {
+ CryptoTagValueMap::const_iterator it = tag_value_map.find(tag);
+ QuicErrorCode ret = QUIC_NO_ERROR;
- // Authenticated encryption algorithm.
- aead = kAESG;
+ if (it == tag_value_map.end()) {
+ ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ } else if (it->second.size() != sizeof(uint32)) {
+ ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
- // Congestion control feedback type.
- congestion_control = kQBIC;
+ if (ret != QUIC_NO_ERROR) {
+ *out = 0;
+ return ret;
+ }
- // Idle connection state lifetime.
- idle_connection_state_lifetime = QuicTime::Delta::FromSeconds(300);
+ memcpy(out, it->second.data(), sizeof(uint32));
+ return ret;
}
} // namespace net
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index f3fde8b..64b258c 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -12,11 +12,14 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "net/base/net_export.h"
+#include "net/quic/quic_protocol.h"
#include "net/quic/quic_time.h"
namespace net {
+// CryptoTag is the type of a tag in the wire protocol.
typedef uint32 CryptoTag;
+typedef std::string ServerConfigID;
typedef std::map<CryptoTag, std::string> CryptoTagValueMap;
typedef std::vector<CryptoTag> CryptoTagVector;
// An intermediate format of a handshake message that's convenient for a
@@ -24,6 +27,40 @@ typedef std::vector<CryptoTag> CryptoTagVector;
struct NET_EXPORT_PRIVATE CryptoHandshakeMessage {
CryptoHandshakeMessage();
~CryptoHandshakeMessage();
+
+ // SetValue sets an element with the given tag to the raw, memory contents of
+ // |v|.
+ template<class T> void SetValue(CryptoTag 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(CryptoTag 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));
+ }
+ }
+
+ // 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(CryptoTag 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(CryptoTag tag, const CryptoTag** out_tags,
+ size_t* out_len) const;
+
+ bool GetString(CryptoTag tag, std::string* out) const;
+ QuicErrorCode GetUint32(CryptoTag tag, uint32* out) const;
+
CryptoTag tag;
CryptoTagValueMap tag_value_map;
};
@@ -38,6 +75,7 @@ struct NET_EXPORT_PRIVATE CryptoHandshakeMessage {
const CryptoTag kCHLO = MAKE_TAG('C', 'H', 'L', 'O'); // Client hello
const CryptoTag kSHLO = MAKE_TAG('S', 'H', 'L', 'O'); // Server hello
+const CryptoTag kSCFG = MAKE_TAG('S', 'H', 'L', 'O'); // Server config
// Key exchange methods
const CryptoTag kP256 = MAKE_TAG('P', '2', '5', '6'); // ECDH, Curve P-256
@@ -67,52 +105,12 @@ const CryptoTag kKATO = MAKE_TAG('K', 'A', 'T', 'O'); // Keepalive timeout
const CryptoTag kSNI = MAKE_TAG('S', 'N', 'I', '\0'); // Server name
// indication
const CryptoTag kPUBS = MAKE_TAG('P', 'U', 'B', 'S'); // Public key values
+const CryptoTag kSCID = MAKE_TAG('S', 'C', 'I', 'D'); // Server config id
const size_t kMaxEntries = 16; // Max number of entries in a message.
const size_t kNonceSize = 32; // Size in bytes of the connection nonce.
-// Crypto configuration settings.
-struct NET_EXPORT_PRIVATE QuicCryptoConfig {
- // Initializes the members to 0 or empty values.
- QuicCryptoConfig();
- ~QuicCryptoConfig();
-
- // Sets the members to client-side or server-side default values.
- void SetClientDefaults();
- void SetServerDefaults();
-
- // Protocol version
- uint16 version;
- // Key exchange methods
- CryptoTagVector key_exchange;
- // Authenticated encryption with associated data (AEAD) algorithms
- CryptoTagVector aead;
- // Congestion control feedback types
- CryptoTagVector congestion_control;
- // Idle connection state lifetime
- QuicTime::Delta idle_connection_state_lifetime;
- // Keepalive timeout, or 0 to turn off keepalive probes
- QuicTime::Delta keepalive_timeout;
-};
-
-// Parameters negotiated by the crypto handshake.
-struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParams {
- // Initializes the members to 0 or empty values.
- QuicCryptoNegotiatedParams();
- ~QuicCryptoNegotiatedParams();
-
- // Sets the members to the values that would be negotiated from the default
- // client-side and server-side configuration settings.
- void SetDefaults();
-
- uint16 version;
- CryptoTag key_exchange;
- CryptoTag aead;
- CryptoTag congestion_control;
- QuicTime::Delta idle_connection_state_lifetime;
-};
-
} // namespace net
#endif // NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
diff --git a/net/quic/crypto/crypto_utils.cc b/net/quic/crypto/crypto_utils.cc
index b381682..ce5002a 100644
--- a/net/quic/crypto/crypto_utils.cc
+++ b/net/quic/crypto/crypto_utils.cc
@@ -5,7 +5,6 @@
#include "net/quic/crypto/crypto_utils.h"
#include "base/string_piece.h"
-#include "net/base/net_util.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_clock.h"
@@ -15,6 +14,24 @@ using std::string;
namespace net {
+// static
+bool CryptoUtils::FindMutualTag(const CryptoTagVector& preference,
+ const CryptoTagVector& supported,
+ CryptoTag* out_result) {
+ for (CryptoTagVector::const_iterator i = preference.begin();
+ i != preference.end(); i++) {
+ for (CryptoTagVector::const_iterator j = supported.begin();
+ j != supported.end(); j++) {
+ if (*i == *j) {
+ *out_result = *i;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
void CryptoUtils::GenerateNonce(const QuicClock* clock,
QuicRandom* random_generator,
string* nonce) {
@@ -28,78 +45,4 @@ void CryptoUtils::GenerateNonce(const QuicClock* clock,
random_generator->RandBytes(&(*nonce)[time_size], kNonceSize - time_size);
}
-void CryptoUtils::FillClientHelloMessage(
- const QuicCryptoConfig& client_config,
- const string& nonce,
- const string& server_hostname,
- CryptoHandshakeMessage* message) {
- message->tag = kCHLO;
-
- // Version.
- message->tag_value_map[kVERS] = EncodeSingleValue(client_config.version);
-
- // Key exchange methods.
- message->tag_value_map[kKEXS] = EncodeVectorValue(client_config.key_exchange);
-
- // Authenticated encryption algorithms.
- message->tag_value_map[kAEAD] = EncodeVectorValue(client_config.aead);
-
- // Congestion control feedback types.
- message->tag_value_map[kCGST] =
- EncodeVectorValue(client_config.congestion_control);
-
- // Idle connection state lifetime.
- uint32 idle_connection_state_lifetime_secs =
- client_config.idle_connection_state_lifetime.ToSeconds();
- message->tag_value_map[kICSL] =
- EncodeSingleValue(idle_connection_state_lifetime_secs);
-
- // Keepalive timeout.
- uint32 keepalive_timeout_secs = client_config.keepalive_timeout.ToSeconds();
- message->tag_value_map[kKATO] = EncodeSingleValue(keepalive_timeout_secs);
-
- // Connection nonce.
- message->tag_value_map[kNONC] = nonce;
-
- // Server name indication.
- // If server_hostname is not an IP address literal, it is a DNS hostname.
- IPAddressNumber ip_number;
- if (!server_hostname.empty() &&
- !ParseIPLiteralToNumber(server_hostname, &ip_number)) {
- message->tag_value_map[kSNI] = server_hostname;
- }
-}
-
-void CryptoUtils::FillServerHelloMessage(
- const QuicCryptoNegotiatedParams& negotiated_params,
- const string& nonce,
- CryptoHandshakeMessage* message) {
- message->tag = kSHLO;
-
- // Version.
- message->tag_value_map[kVERS] = EncodeSingleValue(negotiated_params.version);
-
- // Key exchange method.
- message->tag_value_map[kKEXS] =
- EncodeSingleValue(negotiated_params.key_exchange);
-
- // Authenticated encryption algorithm.
- message->tag_value_map[kAEAD] = EncodeSingleValue(negotiated_params.aead);
-
- // Congestion control feedback type.
- message->tag_value_map[kCGST] =
- EncodeSingleValue(negotiated_params.congestion_control);
-
- // Idle connection state lifetime.
- uint32 idle_connection_state_lifetime_secs =
- negotiated_params.idle_connection_state_lifetime.ToSeconds();
- message->tag_value_map[kICSL] =
- EncodeSingleValue(idle_connection_state_lifetime_secs);
-
- // Keepalive timeout?
-
- // Connection nonce.
- message->tag_value_map[kNONC] = nonce;
-}
-
} // namespace net
diff --git a/net/quic/crypto/crypto_utils.h b/net/quic/crypto/crypto_utils.h
index 496ad79..ff8111e 100644
--- a/net/quic/crypto/crypto_utils.h
+++ b/net/quic/crypto/crypto_utils.h
@@ -8,47 +8,28 @@
#define NET_QUIC_CRYPTO_CRYPTO_UTILS_H_
#include <string>
-#include <vector>
#include "net/base/net_export.h"
+#include "net/quic/crypto/crypto_protocol.h"
namespace net {
class QuicClock;
class QuicRandom;
-struct CryptoHandshakeMessage;
-struct QuicCryptoConfig;
-struct QuicCryptoNegotiatedParams;
class NET_EXPORT_PRIVATE CryptoUtils {
public:
- // Encodes a single value as a string for CryptoTagValueMap.
- template <class T>
- static std::string EncodeSingleValue(const T& value) {
- return std::string(reinterpret_cast<const char*>(&value), sizeof(value));
- }
-
- // Encodes a vector value as a string for CryptoTagValueMap.
- template <class T>
- static std::string EncodeVectorValue(const std::vector<T>& value) {
- return std::string(reinterpret_cast<const char*>(&value[0]),
- value.size() * sizeof(value[0]));
- }
+ // FindMutualTag sets |out_result| to the first tag in |preference| that is
+ // also in |supported| and returns true. If there is no intersection between
+ // |preference| and |supported| it returns false.
+ static bool FindMutualTag(const CryptoTagVector& preference,
+ const CryptoTagVector& supported,
+ CryptoTag* out_result);
// Generates the connection nonce.
static void GenerateNonce(const QuicClock* clock,
QuicRandom* random_generator,
std::string* nonce);
-
- static void FillClientHelloMessage(const QuicCryptoConfig& client_config,
- const std::string& nonce,
- const std::string& server_hostname,
- CryptoHandshakeMessage* message);
-
- static void FillServerHelloMessage(
- const QuicCryptoNegotiatedParams& negotiated_params,
- const std::string& nonce,
- CryptoHandshakeMessage* message);
};
} // namespace net
diff --git a/net/quic/crypto/curve25519_key_exchange.cc b/net/quic/crypto/curve25519_key_exchange.cc
new file mode 100644
index 0000000..548c758
--- /dev/null
+++ b/net/quic/crypto/curve25519_key_exchange.cc
@@ -0,0 +1,101 @@
+// 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/curve25519_key_exchange.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "net/quic/crypto/quic_random.h"
+
+// TODO(rtenneti): Remove the following line after support for curve25519 is
+// added.
+#define crypto_scalarmult_curve25519_SCALARBYTES 32
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+Curve25519KeyExchange::Curve25519KeyExchange() {
+}
+
+Curve25519KeyExchange::~Curve25519KeyExchange() {
+}
+
+// static
+Curve25519KeyExchange* Curve25519KeyExchange::New(
+ const StringPiece& private_key) {
+// TODO(rtenneti): Add support for curve25519.
+#if 0
+ crypto_scalarmult_curve25519_base(ka->public_key_, ka->private_key_);
+ Curve25519KeyExchange* ka;
+
+ // We don't want to #include the NaCl headers in the public header file, so
+ // we use literals for the sizes of private_key_ and public_key_. Here we
+ // assert that those values are equal to the values from the NaCl header.
+ COMPILE_ASSERT(
+ sizeof(ka->private_key_) == crypto_scalarmult_curve25519_SCALARBYTES,
+ header_out_of_sync);
+ COMPILE_ASSERT(
+ sizeof(ka->public_key_) == crypto_scalarmult_curve25519_BYTES,
+ header_out_of_sync);
+
+ if (private_key.size() != crypto_scalarmult_curve25519_SCALARBYTES) {
+ return NULL;
+ }
+
+ ka = new Curve25519KeyExchange();
+ memcpy(ka->private_key_, private_key.data(),
+ crypto_scalarmult_curve25519_SCALARBYTES);
+ return ka;
+#else
+ return NULL;
+#endif
+}
+
+// static
+string Curve25519KeyExchange::NewPrivateKey(QuicRandom* rand) {
+ uint8 private_key[crypto_scalarmult_curve25519_SCALARBYTES];
+ rand->RandBytes(private_key, sizeof(private_key));
+
+ // This makes |private_key| a valid scalar, as specified on
+ // http://cr.yp.to/ecdh.html
+ private_key[0] &= 248;
+ private_key[31] &= 127;
+ private_key[31] |= 64;
+ return string(reinterpret_cast<char*>(private_key), sizeof(private_key));
+}
+
+bool Curve25519KeyExchange::CalculateSharedKey(
+ const StringPiece& public_value,
+ string* out_result) const {
+// TODO(rtenneti): Add support for curve25519.
+#if 0
+ if (public_value.size() != crypto_scalarmult_curve25519_BYTES) {
+ return false;
+ }
+
+ uint8 result[crypto_scalarmult_curve25519_BYTES];
+ crypto_scalarmult_curve25519(
+ result, private_key_,
+ reinterpret_cast<const uint8*>(public_value.data()));
+ out_result->assign(reinterpret_cast<char*>(result), sizeof(result));
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+StringPiece Curve25519KeyExchange::public_value() const {
+ return StringPiece(reinterpret_cast<const char*>(public_key_),
+ sizeof(public_key_));
+}
+
+CryptoTag Curve25519KeyExchange::tag() const {
+ return kC255;
+}
+
+} // namespace net
diff --git a/net/quic/crypto/curve25519_key_exchange.h b/net/quic/crypto/curve25519_key_exchange.h
new file mode 100644
index 0000000..7a05a36
--- /dev/null
+++ b/net/quic/crypto/curve25519_key_exchange.h
@@ -0,0 +1,51 @@
+// 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_CURVE25519_KEY_EXCHANGE_H_
+#define NET_QUIC_CRYPTO_CURVE25519_KEY_EXCHANGE_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/crypto/key_exchange.h"
+
+namespace net {
+
+class QuicRandom;
+
+// Curve25519KeyExchange implements a KeyExchange using elliptic-curve
+// Diffie-Hellman on curve25519. See http://cr.yp.to/ecdh.html
+class NET_EXPORT_PRIVATE Curve25519KeyExchange : public KeyExchange {
+ public:
+ virtual ~Curve25519KeyExchange();
+
+ // New creates a new object from a private key. If the private key is
+ // invalid, NULL is returned.
+ static Curve25519KeyExchange* New(const base::StringPiece& private_key);
+
+ // NewPrivateKey returns a private key, generated from |rand|, suitable for
+ // passing to |New|.
+ static std::string NewPrivateKey(QuicRandom* rand);
+
+ // KeyExchange interface.
+ virtual bool CalculateSharedKey(const base::StringPiece& their_public_value,
+ std::string* shared_key) const OVERRIDE;
+ virtual base::StringPiece public_value() const OVERRIDE;
+ virtual CryptoTag tag() const OVERRIDE;
+
+ private:
+ Curve25519KeyExchange();
+
+// TODO(rtenneti): Add support for curve25519.
+#if 0
+ uint8 private_key_[32];
+#endif
+ uint8 public_key_[32];
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CURVE25519_KEY_EXCHANGE_H_
diff --git a/net/quic/crypto/key_exchange.h b/net/quic/crypto/key_exchange.h
new file mode 100644
index 0000000..c1028ca
--- /dev/null
+++ b/net/quic/crypto/key_exchange.h
@@ -0,0 +1,40 @@
+// 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_KEY_EXCHANGE_H_
+#define NET_QUIC_CRYPTO_KEY_EXCHANGE_H_
+
+#include <string>
+
+#include "base/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/crypto/crypto_protocol.h"
+
+namespace net {
+
+// KeyExchange is an abstract class that provides an interface to a
+// key-exchange primitive.
+class NET_EXPORT_PRIVATE KeyExchange {
+ public:
+ virtual ~KeyExchange() { }
+
+ // CalculateSharedKey computes the shared key between the local private key
+ // (which is implicitly known by a KeyExchange object) and a public value
+ // from the peer.
+ virtual bool CalculateSharedKey(const base::StringPiece& peer_public_value,
+ std::string* shared_key) const = 0;
+
+ // public_value returns the local public key which can be sent to a peer in
+ // order to complete a key exchange. The returned StringPiece is a reference
+ // to a member of the KeyExchange and is only valid for as long as the
+ // KeyExchange exists.
+ virtual base::StringPiece public_value() const = 0;
+
+ // tag returns the tag value that identifies this key exchange function.
+ virtual CryptoTag tag() const = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_KEY_EXCHANGE_H_
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 8f06abd..b9d6ebe 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -37,13 +37,12 @@ void QuicCryptoClientStream::OnHandshakeMessage(
}
bool QuicCryptoClientStream::CryptoConnect() {
- crypto_config_.SetClientDefaults();
+ crypto_config_.SetDefaults();
CryptoUtils::GenerateNonce(session()->connection()->clock(),
session()->connection()->random_generator(),
&nonce_);
CryptoHandshakeMessage message;
- CryptoUtils::FillClientHelloMessage(crypto_config_, nonce_,
- server_hostname_, &message);
+ crypto_config_.FillClientHello(nonce_, server_hostname_, &message);
SendHandshakeMessage(message);
return true;
}
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index 1bdcb2a..2c0d7913 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -7,6 +7,7 @@
#include <string>
+#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/quic_crypto_stream.h"
namespace net {
@@ -28,7 +29,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
bool CryptoConnect();
private:
- QuicCryptoConfig crypto_config_;
+ QuicCryptoClientConfig crypto_config_;
// Client's connection nonce (4-byte timestamp + 28 random bytes)
std::string nonce_;
// Server's hostname
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index ea15c97..0f265a5 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -6,6 +6,7 @@
#include "base/stl_util.h"
#include "net/quic/crypto/crypto_framer.h"
+#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
@@ -277,28 +278,27 @@ QuicPacket* ConstructClientHelloPacket(QuicGuid guid,
const QuicClock* clock,
QuicRandom* random_generator,
const string& server_hostname) {
- QuicCryptoConfig config;
- config.SetClientDefaults();
+ QuicCryptoClientConfig config;
+ config.SetDefaults();
string nonce;
CryptoUtils::GenerateNonce(clock, random_generator, &nonce);
CryptoHandshakeMessage message;
- CryptoUtils::FillClientHelloMessage(config, nonce, server_hostname,
- &message);
+ config.FillClientHello(nonce, server_hostname, &message);
return ConstructPacketFromHandshakeMessage(guid, message);
}
QuicPacket* ConstructServerHelloPacket(QuicGuid guid,
const QuicClock* clock,
QuicRandom* random_generator) {
- QuicCryptoNegotiatedParams negotiated_params;
- negotiated_params.SetDefaults();
string nonce;
CryptoUtils::GenerateNonce(clock, random_generator, &nonce);
- CryptoHandshakeMessage message;
- CryptoUtils::FillServerHelloMessage(negotiated_params, nonce, &message);
- return ConstructPacketFromHandshakeMessage(guid, message);
+ CryptoHandshakeMessage dummy_client_hello, server_hello;
+ QuicCryptoServerConfig server_config;
+ server_config.AddTestingConfig(random_generator, clock);
+ server_config.ProcessClientHello(dummy_client_hello, nonce, &server_hello);
+ return ConstructPacketFromHandshakeMessage(guid, server_hello);
}
QuicPacketEntropyHash TestEntropyCalculator::ReceivedEntropyHash(