|
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/http/http_mac_signature.h" | |
6 | |
7 #include "base/base64.h" | |
8 #include "base/rand_util.h" | |
9 #include "base/string_number_conversions.h" | |
10 #include "base/string_util.h" | |
11 #include "base/time.h" | |
12 #include "crypto/hmac.h" | |
13 | |
14 namespace net { | |
15 | |
16 namespace { | |
17 | |
18 const char kSHA1Name[] = "hmac-sha-1"; | |
19 const char kSHA256Name[] = "hmac-sha-256"; | |
20 const int kNonceLength = 256 / 8; | |
21 | |
22 size_t LengthForHMACAlgorithm(crypto::HMAC::HashAlgorithm algorithm) { | |
cbentzel
2011/04/29 14:44:49
I'm kind of surprised this isn't an HMAC method. S
abarth-chromium
2011/04/29 18:16:01
Yes. I'll add it.
| |
23 if (algorithm == crypto::HMAC::SHA1) | |
24 return 20; | |
25 if (algorithm == crypto::HMAC::SHA256) | |
26 return 32; | |
27 NOTREACHED(); | |
28 return 20; | |
29 } | |
30 | |
31 bool IsPlainStringCharacter(char character) { | |
32 return character == 0x20 || character == 0x21 || | |
33 (character >= 0x23 && character <= 0x5B) || | |
34 (character >= 0x5D && character <= 0x7E); | |
35 } | |
36 | |
37 bool IsPlainString(const std::string& string) { | |
38 for (size_t i = 0; i < string.size(); ++i) { | |
39 if (!IsPlainStringCharacter(string[i])) | |
40 return false; | |
41 } | |
42 return true; | |
43 } | |
44 | |
45 std::string GenerateNonce() { | |
46 std::string nonce; | |
47 bool result = base::Base64Encode(base::RandString(kNonceLength), &nonce); | |
48 DCHECK(result); | |
49 return nonce; | |
50 } | |
51 | |
52 } | |
53 | |
54 HttpMacSignature::HttpMacSignature() | |
55 : mac_algorithm_(crypto::HMAC::SHA1) | |
56 { | |
cbentzel
2011/04/29 14:44:49
Nit: { typically on same line as the last initiali
abarth-chromium
2011/04/29 18:16:01
Fixed. (WebKit style leaking in.)
| |
57 } | |
58 | |
59 HttpMacSignature::~HttpMacSignature() { | |
60 } | |
61 | |
62 bool HttpMacSignature::AddStateInfo(const std::string& id, | |
cbentzel
2011/04/29 14:44:49
Should this be callable multiple times?
abarth-chromium
2011/04/29 18:16:01
Not if it returns true. DCHECK added.
| |
63 const std::string& mac_key, | |
64 const std::string& mac_algorithm, | |
65 const std::string& issuer) { | |
66 if (!IsPlainString(id) || id.empty() | |
67 || !IsPlainString(mac_key) || mac_key.empty() | |
68 || !IsPlainString(issuer) || issuer.empty()) | |
69 return false; | |
70 | |
71 if (mac_algorithm == kSHA1Name) | |
cbentzel
2011/04/29 14:44:49
Very tiny issue: maybe do input validity checking
abarth-chromium
2011/04/29 18:16:01
Do you mean checking for IsPlainString ? The mac_
cbentzel
2011/04/29 18:37:56
Sorry, I just meant moving this into
if (!IsPlain
| |
72 mac_algorithm_ = crypto::HMAC::SHA1; | |
73 else if (mac_algorithm == kSHA256Name) | |
74 mac_algorithm_ = crypto::HMAC::SHA256; | |
75 else | |
76 return false; | |
77 | |
78 id_ = id; | |
79 mac_key_ = mac_key; | |
80 issuer_ = issuer; | |
81 return true; | |
82 } | |
83 | |
84 bool HttpMacSignature::AddHttpInfo(const std::string& method, | |
85 const std::string& request_uri, | |
86 const std::string& host, | |
87 int port) { | |
88 if (!IsPlainString(method) || method.empty() | |
89 || !IsPlainString(request_uri) || request_uri.empty() | |
90 || !IsPlainString(host) || host.empty() | |
91 || port <= 0) | |
cbentzel
2011/04/29 14:44:49
Add a port > 65535 check as well.
abarth-chromium
2011/04/29 18:16:01
Done.
| |
92 return false; | |
93 | |
94 method_ = StringToUpperASCII(method); | |
95 request_uri_ = request_uri; | |
96 host_ = StringToLowerASCII(host); | |
97 port_ = base::IntToString(port); | |
98 return true; | |
99 } | |
100 | |
101 std::string HttpMacSignature::GenerateAuthorizationHeader() { | |
102 DCHECK(!id_.empty()) << "Call AddStateInfo first."; | |
103 DCHECK(port_.empty()) << "Call AddHttpInfo first."; | |
cbentzel
2011/04/29 14:44:49
!port_.empty()
abarth-chromium
2011/04/29 18:16:01
I've changed this to used method_, actually, which
| |
104 | |
105 std::string timestamp = base::IntToString((base::Time::Now() - | |
106 base::Time::UnixEpoch()).InSeconds()); | |
107 std::string nonce = GenerateNonce(); | |
108 std::string mac = GenerateMAC(timestamp, nonce); | |
109 | |
110 DCHECK(IsPlainString(timestamp)); | |
111 DCHECK(IsPlainString(nonce)); | |
112 DCHECK(IsPlainString(mac)); | |
113 | |
114 std::string header = "MAC id=\"" + id_ + | |
115 "\", issuer=\"" + issuer_ + | |
116 "\", timestamp=\"" + timestamp + | |
117 "\", nonce=\"" + nonce + | |
118 "\", mac=\"" + mac + "\""; | |
119 | |
120 return header; | |
121 } | |
122 | |
123 std::string HttpMacSignature::GenerateNormalizedRequest( | |
124 const std::string& timestamp, | |
125 const std::string& nonce) { | |
126 static const std::string kNewLine = "\n"; | |
127 | |
128 std::string normalized_request = id_ + kNewLine; | |
129 normalized_request += issuer_ + kNewLine; | |
130 normalized_request += timestamp + kNewLine; | |
131 normalized_request += nonce + kNewLine; | |
132 normalized_request += method_ + kNewLine; | |
133 normalized_request += request_uri_ + kNewLine; | |
134 normalized_request += host_ + kNewLine; | |
135 normalized_request += port_ + kNewLine; | |
136 | |
137 return normalized_request; | |
138 } | |
139 | |
140 std::string HttpMacSignature::GenerateMAC(const std::string& timestamp, | |
cbentzel
2011/04/29 14:44:49
Should these be returning a bool in case hmac.Sign
abarth-chromium
2011/04/29 18:16:01
Base64Encode can't fail in these cases because the
cbentzel
2011/04/29 18:37:56
DCHECK seems fine, although I have not looked at w
| |
141 const std::string& nonce) { | |
142 std::string request = GenerateNormalizedRequest(timestamp, nonce); | |
143 | |
144 crypto::HMAC hmac(mac_algorithm_); | |
145 hmac.Init(mac_key_); | |
146 | |
147 std::string signature; | |
148 size_t length = LengthForHMACAlgorithm(mac_algorithm_); | |
149 char* buffer = WriteInto(&signature, length); | |
150 hmac.Sign(request, reinterpret_cast<unsigned char*>(buffer), length); | |
cbentzel
2011/04/29 14:44:49
You should check the result of hmac.Sign
abarth-chromium
2011/04/29 18:16:01
I've added a DCHECK.
| |
151 | |
152 std::string encoded_signature; | |
153 bool result = base::Base64Encode(signature, &encoded_signature); | |
154 DCHECK(result); | |
155 return encoded_signature; | |
156 } | |
157 | |
158 } // namespace net | |
OLD | NEW |