OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/cryptauth/wire_message.h" | 5 #include "components/cryptauth/wire_message.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <limits> | 10 #include <limits> |
11 | 11 |
12 #include "base/base64url.h" | 12 #include "base/base64url.h" |
13 #include "base/json/json_reader.h" | 13 #include "base/json/json_reader.h" |
14 #include "base/json/json_writer.h" | 14 #include "base/json/json_writer.h" |
15 #include "base/macros.h" | 15 #include "base/macros.h" |
16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
17 #include "base/values.h" | 17 #include "base/values.h" |
18 #include "components/proximity_auth/logging/logging.h" | 18 #include "components/proximity_auth/logging/logging.h" |
19 | 19 |
20 // The wire messages have a simple format: | 20 // The wire messages have a simple format: |
21 // [ message version ] [ body length ] [ JSON body ] | 21 // [ message version ] [ body length ] [ JSON body ] |
22 // 1 byte 2 bytes body length | 22 // 1 byte 2 bytes body length |
23 // The JSON body contains two fields: an optional permit_id field and a required | 23 // When sending encrypted messages, the JSON body contains two fields: an |
24 // data field. | 24 // optional |permit_id| field and a required |payload| field. |
| 25 // |
| 26 // For non-encrypted messages, the message itself is the JSON body, and it |
| 27 // doesn't have a |payload| field. |
25 | 28 |
26 namespace cryptauth { | 29 namespace cryptauth { |
27 namespace { | 30 namespace { |
28 | 31 |
29 // The length of the message header, in bytes. | 32 // The length of the message header, in bytes. |
30 const size_t kHeaderLength = 3; | 33 const size_t kHeaderLength = 3; |
31 | 34 |
32 // The protocol version of the message format. | 35 // The protocol version of the message format. |
33 const int kMessageFormatVersionThree = 3; | 36 const int kMessageFormatVersionThree = 3; |
34 | 37 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 if (!body_value || !body_value->IsType(base::Value::Type::DICTIONARY)) { | 100 if (!body_value || !body_value->IsType(base::Value::Type::DICTIONARY)) { |
98 PA_LOG(WARNING) << "Error: Unable to parse message as JSON."; | 101 PA_LOG(WARNING) << "Error: Unable to parse message as JSON."; |
99 return nullptr; | 102 return nullptr; |
100 } | 103 } |
101 | 104 |
102 base::DictionaryValue* body; | 105 base::DictionaryValue* body; |
103 bool success = body_value->GetAsDictionary(&body); | 106 bool success = body_value->GetAsDictionary(&body); |
104 DCHECK(success); | 107 DCHECK(success); |
105 | 108 |
106 std::string payload_base64; | 109 std::string payload_base64; |
107 if (!body->GetString(kPayloadKey, &payload_base64) || | 110 if (!body->GetString(kPayloadKey, &payload_base64)) { |
108 payload_base64.empty()) { | 111 // The body is a valid JSON, but it doesn't contain a |payload| field. It |
| 112 // must be a non-encrypted message. |
| 113 return base::WrapUnique( |
| 114 new WireMessage(serialized_message.substr(kHeaderLength))); |
| 115 } |
| 116 |
| 117 if (payload_base64.empty()) { |
109 PA_LOG(WARNING) << "Error: Missing payload."; | 118 PA_LOG(WARNING) << "Error: Missing payload."; |
110 return nullptr; | 119 return nullptr; |
111 } | 120 } |
112 | 121 |
113 std::string payload; | 122 std::string payload; |
114 if (!base::Base64UrlDecode(payload_base64, | 123 if (!base::Base64UrlDecode(payload_base64, |
115 base::Base64UrlDecodePolicy::REQUIRE_PADDING, | 124 base::Base64UrlDecodePolicy::REQUIRE_PADDING, |
116 &payload)) { | 125 &payload)) { |
117 PA_LOG(WARNING) << "Error: Invalid base64 encoding for payload."; | 126 PA_LOG(WARNING) << "Error: Invalid base64 encoding for payload."; |
118 return nullptr; | 127 return nullptr; |
119 } | 128 } |
120 | 129 |
121 std::string feature; | 130 std::string feature; |
122 if (!body->GetString(kFeatureKey, &feature) || feature.empty()) { | 131 if (!body->GetString(kFeatureKey, &feature) || feature.empty()) { |
123 feature = std::string(kDefaultFeature); | 132 feature = std::string(kDefaultFeature); |
124 } | 133 } |
125 | 134 |
126 return base::WrapUnique(new WireMessage(payload, feature)); | 135 return base::WrapUnique(new WireMessage(payload, feature)); |
127 } | 136 } |
128 | 137 |
129 std::string WireMessage::Serialize() const { | 138 std::string WireMessage::Serialize() const { |
130 if (payload_.empty()) { | 139 std::string json_body; |
131 PA_LOG(ERROR) << "Failed to serialize empty wire message."; | 140 if (body_.empty()) { |
132 return std::string(); | 141 if (payload_.empty()) { |
133 } | 142 PA_LOG(ERROR) << "Failed to serialize empty wire message."; |
| 143 return std::string(); |
| 144 } |
134 | 145 |
135 // Create JSON body containing permit id and payload. | 146 // Create JSON body containing permit id and payload. |
136 base::DictionaryValue body; | 147 base::DictionaryValue body; |
137 | 148 |
138 std::string base64_payload; | 149 std::string base64_payload; |
139 base::Base64UrlEncode(payload_, base::Base64UrlEncodePolicy::INCLUDE_PADDING, | 150 base::Base64UrlEncode(payload_, |
140 &base64_payload); | 151 base::Base64UrlEncodePolicy::INCLUDE_PADDING, |
141 body.SetString(kPayloadKey, base64_payload); | 152 &base64_payload); |
142 body.SetString(kFeatureKey, feature_); | 153 body.SetString(kPayloadKey, base64_payload); |
| 154 body.SetString(kFeatureKey, feature_); |
143 | 155 |
144 std::string json_body; | 156 if (!base::JSONWriter::Write(body, &json_body)) { |
145 if (!base::JSONWriter::Write(body, &json_body)) { | 157 PA_LOG(ERROR) << "Failed to convert WireMessage body to JSON: " << body; |
146 PA_LOG(ERROR) << "Failed to convert WireMessage body to JSON: " << body; | 158 return std::string(); |
147 return std::string(); | 159 } |
| 160 } else { |
| 161 json_body = body_; |
148 } | 162 } |
149 | 163 |
150 // Create header containing version and payload size. | 164 // Create header containing version and payload size. |
151 size_t body_size = json_body.size(); | 165 size_t body_size = json_body.size(); |
152 if (body_size > std::numeric_limits<uint16_t>::max()) { | 166 if (body_size > std::numeric_limits<uint16_t>::max()) { |
153 PA_LOG(ERROR) << "Can not create WireMessage because body size exceeds " | 167 PA_LOG(ERROR) << "Can not create WireMessage because body size exceeds " |
154 << "16-bit unsigned integer: " << body_size; | 168 << "16-bit unsigned integer: " << body_size; |
155 return std::string(); | 169 return std::string(); |
156 } | 170 } |
157 | 171 |
158 uint8_t header[] = { | 172 uint8_t header[] = { |
159 static_cast<uint8_t>(kMessageFormatVersionThree), | 173 static_cast<uint8_t>(kMessageFormatVersionThree), |
160 static_cast<uint8_t>((body_size >> 8) & 0xFF), | 174 static_cast<uint8_t>((body_size >> 8) & 0xFF), |
161 static_cast<uint8_t>(body_size & 0xFF), | 175 static_cast<uint8_t>(body_size & 0xFF), |
162 }; | 176 }; |
163 static_assert(sizeof(header) == kHeaderLength, "Malformed header."); | 177 static_assert(sizeof(header) == kHeaderLength, "Malformed header."); |
164 | 178 |
165 std::string header_string(kHeaderLength, 0); | 179 std::string header_string(kHeaderLength, 0); |
166 std::memcpy(&header_string[0], header, kHeaderLength); | 180 std::memcpy(&header_string[0], header, kHeaderLength); |
167 return header_string + json_body; | 181 return header_string + json_body; |
168 } | 182 } |
169 | 183 |
170 WireMessage::WireMessage(const std::string& payload, const std::string& feature) | 184 WireMessage::WireMessage(const std::string& payload, const std::string& feature) |
171 : payload_(payload), feature_(feature) {} | 185 : payload_(payload), feature_(feature) {} |
172 | 186 |
| 187 WireMessage::WireMessage(const std::string& body) : body_(body) {} |
| 188 |
173 } // namespace cryptauth | 189 } // namespace cryptauth |
OLD | NEW |