summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-29 21:45:51 +0000
committerabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-29 21:45:51 +0000
commit4eb4f8ba70cd40195461d4981c90e55bc95c07d3 (patch)
tree1bc9d4122856035d767b334e358dfd1b767b5323 /net
parent5c8eb2e6b391311f02b6aafd4e19421f70367313 (diff)
downloadchromium_src-4eb4f8ba70cd40195461d4981c90e55bc95c07d3.zip
chromium_src-4eb4f8ba70cd40195461d4981c90e55bc95c07d3.tar.gz
chromium_src-4eb4f8ba70cd40195461d4981c90e55bc95c07d3.tar.bz2
MAC Cookies (2 of N)
This CL contains the algorithmic guts of MAC cookies, including generating the canonical represntation of the request and signing it using HMAC. This CL does not include support for body_hash, which requires some more thought. Review URL: http://codereview.chromium.org/6901121 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@83600 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/http/http_mac_signature.cc172
-rw-r--r--net/http/http_mac_signature.h64
-rw-r--r--net/http/http_mac_signature_unittest.cc109
-rw-r--r--net/net.gyp3
4 files changed, 348 insertions, 0 deletions
diff --git a/net/http/http_mac_signature.cc b/net/http/http_mac_signature.cc
new file mode 100644
index 0000000..76cbe51
--- /dev/null
+++ b/net/http/http_mac_signature.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2011 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/http/http_mac_signature.h"
+
+#include "base/base64.h"
+#include "base/rand_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "crypto/hmac.h"
+
+namespace net {
+
+namespace {
+
+const char kSHA1Name[] = "hmac-sha-1";
+const char kSHA256Name[] = "hmac-sha-256";
+const int kNonceLength = 256 / 8;
+
+size_t LengthForHMACAlgorithm(crypto::HMAC::HashAlgorithm algorithm) {
+ if (algorithm == crypto::HMAC::SHA1)
+ return 20;
+ if (algorithm == crypto::HMAC::SHA256)
+ return 32;
+ NOTREACHED();
+ return 20;
+}
+
+bool IsPlainStringCharacter(char character) {
+ return character == 0x20 || character == 0x21 ||
+ (character >= 0x23 && character <= 0x5B) ||
+ (character >= 0x5D && character <= 0x7E);
+}
+
+bool IsPlainString(const std::string& string) {
+ for (size_t i = 0; i < string.size(); ++i) {
+ if (!IsPlainStringCharacter(string[i]))
+ return false;
+ }
+ return true;
+}
+
+std::string GenerateNonce() {
+ std::string nonce;
+ bool result = base::Base64Encode(
+ base::RandBytesAsString(kNonceLength), &nonce);
+ DCHECK(result);
+ return nonce;
+}
+
+}
+
+HttpMacSignature::HttpMacSignature()
+ : mac_algorithm_(crypto::HMAC::SHA1) {
+}
+
+HttpMacSignature::~HttpMacSignature() {
+}
+
+bool HttpMacSignature::AddStateInfo(const std::string& id,
+ const std::string& mac_key,
+ const std::string& mac_algorithm,
+ const std::string& issuer) {
+ DCHECK(id_.empty());
+
+ if (!IsPlainString(id) || id.empty()
+ || mac_key.empty()
+ || mac_algorithm.empty()
+ || !IsPlainString(issuer) || issuer.empty())
+ return false;
+
+ if (mac_algorithm == kSHA1Name)
+ mac_algorithm_ = crypto::HMAC::SHA1;
+ else if (mac_algorithm == kSHA256Name)
+ mac_algorithm_ = crypto::HMAC::SHA256;
+ else
+ return false;
+
+ id_ = id;
+ mac_key_ = mac_key;
+ issuer_ = issuer;
+ return true;
+}
+
+bool HttpMacSignature::AddHttpInfo(const std::string& method,
+ const std::string& request_uri,
+ const std::string& host,
+ int port) {
+ DCHECK(method_.empty());
+
+ if (!IsPlainString(method) || method.empty()
+ || !IsPlainString(request_uri) || request_uri.empty()
+ || !IsPlainString(host) || host.empty()
+ || port <= 0
+ || port > 65535)
+ return false;
+
+ method_ = StringToUpperASCII(method);
+ request_uri_ = request_uri;
+ host_ = StringToLowerASCII(host);
+ port_ = base::IntToString(port);
+ return true;
+}
+
+std::string HttpMacSignature::GenerateAuthorizationHeader() {
+ DCHECK(!id_.empty()) << "Call AddStateInfo first.";
+ DCHECK(!method_.empty()) << "Call AddHttpInfo first.";
+
+ std::string timestamp = base::IntToString((base::Time::Now() -
+ base::Time::UnixEpoch()).InSeconds());
+ std::string nonce = GenerateNonce();
+
+ return GenerateHeaderString(timestamp, nonce);
+}
+
+std::string HttpMacSignature::GenerateHeaderString(
+ const std::string& timestamp,
+ const std::string& nonce) {
+ std::string mac = GenerateMAC(timestamp, nonce);
+
+ DCHECK(IsPlainString(timestamp));
+ DCHECK(IsPlainString(nonce));
+ DCHECK(IsPlainString(mac));
+
+ return "MAC id=\"" + id_ +
+ "\", issuer=\"" + issuer_ +
+ "\", timestamp=\"" + timestamp +
+ "\", nonce=\"" + nonce +
+ "\", mac=\"" + mac + "\"";
+}
+
+std::string HttpMacSignature::GenerateNormalizedRequest(
+ const std::string& timestamp,
+ const std::string& nonce) {
+ static const std::string kNewLine = "\n";
+
+ std::string normalized_request = id_ + kNewLine;
+ normalized_request += issuer_ + kNewLine;
+ normalized_request += timestamp + kNewLine;
+ normalized_request += nonce + kNewLine;
+ normalized_request += method_ + kNewLine;
+ normalized_request += request_uri_ + kNewLine;
+ normalized_request += host_ + kNewLine;
+ normalized_request += port_ + kNewLine;
+
+ return normalized_request;
+}
+
+std::string HttpMacSignature::GenerateMAC(const std::string& timestamp,
+ const std::string& nonce) {
+ std::string request = GenerateNormalizedRequest(timestamp, nonce);
+
+ crypto::HMAC hmac(mac_algorithm_);
+ hmac.Init(mac_key_);
+
+ std::string signature;
+ size_t length = LengthForHMACAlgorithm(mac_algorithm_);
+ char* buffer = WriteInto(&signature, length);
+ bool result = hmac.Sign(request,
+ reinterpret_cast<unsigned char*>(buffer),
+ length);
+ DCHECK(result);
+
+ std::string encoded_signature;
+ result = base::Base64Encode(signature, &encoded_signature);
+ DCHECK(result);
+ return encoded_signature;
+}
+
+} // namespace net
diff --git a/net/http/http_mac_signature.h b/net/http/http_mac_signature.h
new file mode 100644
index 0000000..1049240
--- /dev/null
+++ b/net/http/http_mac_signature.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2011 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_HTTP_MAC_SIGNATURE_H_
+#define NET_HTTP_MAC_SIGNATURE_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "crypto/hmac.h"
+
+namespace net {
+
+class HttpMacSignature {
+ public:
+ HttpMacSignature();
+ ~HttpMacSignature();
+
+ // Returns whether this information is valid.
+ bool AddStateInfo(const std::string& id,
+ const std::string& mac_key,
+ const std::string& mac_algorithm,
+ const std::string& issuer);
+
+ // Returns whether this information is valid.
+ bool AddHttpInfo(const std::string& method,
+ const std::string& request_uri,
+ const std::string& host,
+ int port);
+
+ std::string GenerateAuthorizationHeader();
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(HttpMacSignatureTest, GenerateHeaderString);
+ FRIEND_TEST_ALL_PREFIXES(HttpMacSignatureTest, GenerateNormalizedRequest);
+ FRIEND_TEST_ALL_PREFIXES(HttpMacSignatureTest, GenerateMAC);
+
+ std::string GenerateHeaderString(const std::string& timestamp,
+ const std::string& nonce);
+ std::string GenerateNormalizedRequest(const std::string& timestamp,
+ const std::string& nonce);
+ std::string GenerateMAC(const std::string& timestamp,
+ const std::string& nonce);
+
+ std::string id_;
+ std::string mac_key_;
+ crypto::HMAC::HashAlgorithm mac_algorithm_;
+ std::string issuer_;
+
+ std::string method_;
+ std::string request_uri_;
+ std::string host_;
+ std::string port_;
+ // TODO(abarth): body_hash_
+
+ DISALLOW_COPY_AND_ASSIGN(HttpMacSignature);
+};
+
+} // namespace net
+
+#endif // NET_HTTP_MAC_SIGNATURE_H_
diff --git a/net/http/http_mac_signature_unittest.cc b/net/http/http_mac_signature_unittest.cc
new file mode 100644
index 0000000..5019e4b9
--- /dev/null
+++ b/net/http/http_mac_signature_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h"
+#include "net/http/http_mac_signature.h"
+
+namespace net {
+
+TEST(HttpMacSignatureTest, BogusAddStateInfo) {
+ HttpMacSignature signature;
+ EXPECT_FALSE(signature.AddStateInfo("exciting-id",
+ "the-mac-key",
+ "bogus-hmac-algorithm",
+ "the-issuer"));
+ EXPECT_FALSE(signature.AddStateInfo("",
+ "the-mac-key",
+ "hmac-sha-1",
+ "the-issuer"));
+ EXPECT_FALSE(signature.AddStateInfo("exciting-id",
+ "",
+ "hmac-sha-1",
+ "the-issuer"));
+ EXPECT_FALSE(signature.AddStateInfo("exciting-id",
+ "the-mac-key",
+ "",
+ "the-issuer"));
+ EXPECT_FALSE(signature.AddStateInfo("exciting-id",
+ "the-mac-key",
+ "hmac-sha-1",
+ ""));
+}
+
+TEST(HttpMacSignatureTest, BogusAddHttpInfo) {
+ HttpMacSignature signature;
+ EXPECT_FALSE(signature.AddHttpInfo("GET", "/requested", "example.com", 0));
+ EXPECT_FALSE(signature.AddHttpInfo(
+ "GET", "/requested", "example.com", 29088983));
+ EXPECT_FALSE(signature.AddHttpInfo("", "/requested", "example.com", 80));
+ EXPECT_FALSE(signature.AddHttpInfo("GET", "", "example.com", 80));
+ EXPECT_FALSE(signature.AddHttpInfo("GET", "/requested", "", 80));
+}
+
+TEST(HttpMacSignatureTest, GenerateHeaderString) {
+ HttpMacSignature signature;
+ EXPECT_TRUE(signature.AddStateInfo("dfoi30j0qnf",
+ "adiMf03j0f3nOenc003r",
+ "hmac-sha-1",
+ "login.eXampLe.com:443"));
+ EXPECT_TRUE(signature.AddHttpInfo("GeT",
+ "/pAth?to=%22enlightenment%22&dest=magic",
+ "eXaMple.com",
+ 80));
+
+ std::string timestamp = "239034";
+ std::string nonce = "mn4302j0n+32r2/f3r=";
+
+ EXPECT_EQ("MAC id=\"dfoi30j0qnf\", "
+ "issuer=\"login.eXampLe.com:443\", "
+ "timestamp=\"239034\", "
+ "nonce=\"mn4302j0n+32r2/f3r=\", "
+ "mac=\"zQWLNI5eHOfY5/wCJ6yzZ8bXDw==\"",
+ signature.GenerateHeaderString(timestamp, nonce));
+}
+
+
+TEST(HttpMacSignatureTest, GenerateNormalizedRequest) {
+ HttpMacSignature signature;
+ EXPECT_TRUE(signature.AddStateInfo("dfoi30j0qnf",
+ "adiMf03j0f3nOenc003r",
+ "hmac-sha-1",
+ "login.eXampLe.com:443"));
+ EXPECT_TRUE(signature.AddHttpInfo("GeT",
+ "/pAth?to=%22enlightenment%22&dest=magic",
+ "eXaMple.com",
+ 80));
+
+ std::string timestamp = "239034";
+ std::string nonce = "mn4302j0n+32r2/f3r=";
+
+ EXPECT_EQ("dfoi30j0qnf\n"
+ "login.eXampLe.com:443\n"
+ "239034\n"
+ "mn4302j0n+32r2/f3r=\n"
+ "GET\n"
+ "/pAth?to=%22enlightenment%22&dest=magic\n"
+ "example.com\n"
+ "80\n",
+ signature.GenerateNormalizedRequest(timestamp, nonce));
+}
+
+TEST(HttpMacSignatureTest, GenerateMAC) {
+ HttpMacSignature signature;
+ EXPECT_TRUE(signature.AddStateInfo("dfoi30j0qnf",
+ "adiMf03j0f3nOenc003r",
+ "hmac-sha-1",
+ "login.eXampLe.com:443"));
+ EXPECT_TRUE(signature.AddHttpInfo("GeT",
+ "/pAth?to=%22enlightenment%22&dest=magic",
+ "eXaMple.com",
+ 80));
+
+ std::string timestamp = "239034";
+ std::string nonce = "mn4302j0n+32r2/f3r=";
+
+ EXPECT_EQ("zQWLNI5eHOfY5/wCJ6yzZ8bXDw==",
+ signature.GenerateMAC(timestamp, nonce));
+}
+}
diff --git a/net/net.gyp b/net/net.gyp
index 3254e1b..ea23f7a 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -500,6 +500,8 @@
'http/http_cache_transaction.h',
'http/http_chunked_decoder.cc',
'http/http_chunked_decoder.h',
+ 'http/http_mac_signature.cc',
+ 'http/http_mac_signature.h',
'http/http_net_log_params.cc',
'http/http_net_log_params.h',
'http/http_network_layer.cc',
@@ -967,6 +969,7 @@
'http/http_byte_range_unittest.cc',
'http/http_cache_unittest.cc',
'http/http_chunked_decoder_unittest.cc',
+ 'http/http_mac_signature_unittest.cc',
'http/http_network_layer_unittest.cc',
'http/http_network_transaction_unittest.cc',
'http/http_proxy_client_socket_pool_unittest.cc',