| 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 |