Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(201)

Side by Side Diff: components/proximity_auth/wire_message.cc

Issue 2561203002: Migrate weave-related classes from proximity_auth/ble to cryptauth/ble. (Closed)
Patch Set: Rebase. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/proximity_auth/wire_message.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <limits>
11
12 #include "base/base64url.h"
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/macros.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/values.h"
18 #include "components/proximity_auth/logging/logging.h"
19
20 // The wire messages have a simple format:
21 // [ message version ] [ body length ] [ JSON body ]
22 // 1 byte 2 bytes body length
23 // The JSON body contains two fields: an optional permit_id field and a required
24 // data field.
25
26 namespace proximity_auth {
27 namespace {
28
29 // The length of the message header, in bytes.
30 const size_t kHeaderLength = 3;
31
32 // The protocol version of the message format.
33 const int kMessageFormatVersionThree = 3;
34
35 const char kPayloadKey[] = "payload";
36 const char kPermitIdKey[] = "permit_id";
37
38 // Parses the |serialized_message|'s header. Returns |true| iff the message has
39 // a valid header, is complete, and is well-formed according to the header. Sets
40 // |is_incomplete_message| to true iff the message does not have enough data to
41 // parse the header, or if the message length encoded in the message header
42 // exceeds the size of the |serialized_message|.
43 bool ParseHeader(const std::string& serialized_message,
44 bool* is_incomplete_message) {
45 *is_incomplete_message = false;
46 if (serialized_message.size() < kHeaderLength) {
47 *is_incomplete_message = true;
48 return false;
49 }
50
51 static_assert(kHeaderLength > 2, "kHeaderLength too small");
52 size_t version = serialized_message[0];
53 if (version != kMessageFormatVersionThree) {
54 PA_LOG(WARNING) << "Error: Invalid message version. Got " << version
55 << ", expected " << kMessageFormatVersionThree;
56 return false;
57 }
58
59 uint16_t expected_body_length =
60 (static_cast<uint8_t>(serialized_message[1]) << 8) |
61 (static_cast<uint8_t>(serialized_message[2]) << 0);
62 size_t expected_message_length = kHeaderLength + expected_body_length;
63 if (serialized_message.size() < expected_message_length) {
64 *is_incomplete_message = true;
65 return false;
66 }
67 if (serialized_message.size() != expected_message_length) {
68 PA_LOG(WARNING) << "Error: Invalid message length. Got "
69 << serialized_message.size() << ", expected "
70 << expected_message_length;
71 return false;
72 }
73
74 return true;
75 }
76
77 } // namespace
78
79 WireMessage::~WireMessage() {
80 }
81
82 // static
83 std::unique_ptr<WireMessage> WireMessage::Deserialize(
84 const std::string& serialized_message,
85 bool* is_incomplete_message) {
86 if (!ParseHeader(serialized_message, is_incomplete_message))
87 return std::unique_ptr<WireMessage>();
88
89 std::unique_ptr<base::Value> body_value =
90 base::JSONReader::Read(serialized_message.substr(kHeaderLength));
91 if (!body_value || !body_value->IsType(base::Value::Type::DICTIONARY)) {
92 PA_LOG(WARNING) << "Error: Unable to parse message as JSON.";
93 return std::unique_ptr<WireMessage>();
94 }
95
96 base::DictionaryValue* body;
97 bool success = body_value->GetAsDictionary(&body);
98 DCHECK(success);
99
100 // The permit ID is optional. In the Easy Unlock protocol, only the first
101 // message includes this field.
102 std::string permit_id;
103 body->GetString(kPermitIdKey, &permit_id);
104
105 std::string payload_base64;
106 if (!body->GetString(kPayloadKey, &payload_base64) ||
107 payload_base64.empty()) {
108 PA_LOG(WARNING) << "Error: Missing payload.";
109 return std::unique_ptr<WireMessage>();
110 }
111
112 std::string payload;
113 if (!base::Base64UrlDecode(payload_base64,
114 base::Base64UrlDecodePolicy::REQUIRE_PADDING,
115 &payload)) {
116 PA_LOG(WARNING) << "Error: Invalid base64 encoding for payload.";
117 return std::unique_ptr<WireMessage>();
118 }
119
120 return base::WrapUnique(new WireMessage(payload, permit_id));
121 }
122
123 std::string WireMessage::Serialize() const {
124 if (payload_.empty()) {
125 PA_LOG(ERROR) << "Failed to serialize empty wire message.";
126 return std::string();
127 }
128
129 // Create JSON body containing permit id and payload.
130 base::DictionaryValue body;
131 if (!permit_id_.empty())
132 body.SetString(kPermitIdKey, permit_id_);
133
134 std::string base64_payload;
135 base::Base64UrlEncode(payload_, base::Base64UrlEncodePolicy::INCLUDE_PADDING,
136 &base64_payload);
137 body.SetString(kPayloadKey, base64_payload);
138
139 std::string json_body;
140 if (!base::JSONWriter::Write(body, &json_body)) {
141 PA_LOG(ERROR) << "Failed to convert WireMessage body to JSON: " << body;
142 return std::string();
143 }
144
145 // Create header containing version and payload size.
146 size_t body_size = json_body.size();
147 if (body_size > std::numeric_limits<uint16_t>::max()) {
148 PA_LOG(ERROR) << "Can not create WireMessage because body size exceeds "
149 << "16-bit unsigned integer: " << body_size;
150 return std::string();
151 }
152
153 uint8_t header[] = {
154 static_cast<uint8_t>(kMessageFormatVersionThree),
155 static_cast<uint8_t>((body_size >> 8) & 0xFF),
156 static_cast<uint8_t>(body_size & 0xFF),
157 };
158 static_assert(sizeof(header) == kHeaderLength, "Malformed header.");
159
160 std::string header_string(kHeaderLength, 0);
161 std::memcpy(&header_string[0], header, kHeaderLength);
162 return header_string + json_body;
163 }
164
165 WireMessage::WireMessage(const std::string& payload)
166 : WireMessage(payload, std::string()) {}
167
168 WireMessage::WireMessage(const std::string& payload,
169 const std::string& permit_id)
170 : payload_(payload), permit_id_(permit_id) {}
171
172 } // namespace proximity_auth
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698