Vectorize website settings icons in omnibox
[chromium-blink-merge.git] / components / proximity_auth / device_to_device_responder_operations.cc
blobc1b3ec1cd3fbd2d3d02e14b0078cf93b40330af9
1 // Copyright 2015 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.
5 #include "components/proximity_auth/device_to_device_responder_operations.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "components/proximity_auth/cryptauth/proto/cryptauth_api.pb.h"
10 #include "components/proximity_auth/cryptauth/proto/securemessage.pb.h"
11 #include "components/proximity_auth/cryptauth/secure_message_delegate.h"
12 #include "components/proximity_auth/logging/logging.h"
14 namespace proximity_auth {
16 namespace {
18 // TODO(tengs): Due to a bug with the ChromeOS secure message daemon, we cannot
19 // create SecureMessages with empty payloads. To workaround this bug, this value
20 // is put into the payload if it would otherwise be empty.
21 // See crbug.com/512894.
22 const char kPayloadFiller[] = "\xae";
24 // The version to put in the GcmMetadata field.
25 const int kGcmMetadataVersion = 1;
27 // Callback for DeviceToDeviceResponderOperations::ValidateHelloMessage(),
28 // after the [Hello] message is unwrapped.
29 void OnHelloMessageUnwrapped(
30 const DeviceToDeviceResponderOperations::ValidateHelloCallback& callback,
31 bool verified,
32 const std::string& payload,
33 const securemessage::Header& header) {
34 securemessage::InitiatorHello initiator_hello;
35 if (!verified || !initiator_hello.ParseFromString(header.public_metadata())) {
36 callback.Run(false, std::string());
37 return;
40 callback.Run(true, initiator_hello.public_dh_key().SerializeAsString());
43 // Helper struct containing all the context needed to create the [Responder
44 // Auth] message.
45 struct CreateResponderAuthMessageContext {
46 std::string hello_message;
47 std::string session_public_key;
48 std::string session_private_key;
49 std::string persistent_private_key;
50 std::string persistent_symmetric_key;
51 SecureMessageDelegate* secure_message_delegate;
52 DeviceToDeviceResponderOperations::MessageCallback callback;
53 std::string hello_public_key;
54 std::string middle_message;
57 // Forward declarations of functions used to create the [Responder Auth]
58 // message, declared in order in which they are called during the creation flow.
59 void OnHelloMessageValidatedForResponderAuth(
60 CreateResponderAuthMessageContext context,
61 bool hello_message_validated,
62 const std::string& hello_public_key);
63 void OnInnerMessageCreatedForResponderAuth(
64 CreateResponderAuthMessageContext context,
65 const std::string& inner_message);
66 void OnMiddleMessageCreatedForResponderAuth(
67 CreateResponderAuthMessageContext context,
68 const std::string& middle_message);
69 void OnSessionSymmetricKeyDerivedForResponderAuth(
70 CreateResponderAuthMessageContext context,
71 const std::string& session_symmetric_key);
73 // Called after the initiator's [Hello] message is unwrapped.
74 void OnHelloMessageValidatedForResponderAuth(
75 CreateResponderAuthMessageContext context,
76 bool hello_message_validated,
77 const std::string& hello_public_key) {
78 if (!hello_message_validated) {
79 PA_LOG(INFO) << "Invalid [Hello] while creating [Responder Auth]";
80 context.callback.Run(std::string());
81 return;
84 context.hello_public_key = hello_public_key;
86 // Create the inner most wrapped message of [Responder Auth].
87 cryptauth::GcmMetadata gcm_metadata;
88 gcm_metadata.set_type(cryptauth::UNLOCK_KEY_SIGNED_CHALLENGE);
89 gcm_metadata.set_version(kGcmMetadataVersion);
91 SecureMessageDelegate::CreateOptions create_options;
92 create_options.encryption_scheme = securemessage::NONE;
93 create_options.signature_scheme = securemessage::ECDSA_P256_SHA256;
94 gcm_metadata.SerializeToString(&create_options.public_metadata);
95 create_options.associated_data = context.hello_message;
97 context.secure_message_delegate->CreateSecureMessage(
98 kPayloadFiller, context.persistent_private_key, create_options,
99 base::Bind(&OnInnerMessageCreatedForResponderAuth, context));
102 // Called after the inner-most layer of [Responder Auth] is created.
103 void OnInnerMessageCreatedForResponderAuth(
104 CreateResponderAuthMessageContext context,
105 const std::string& inner_message) {
106 if (inner_message.empty()) {
107 PA_LOG(INFO) << "Failed to create middle message for [Responder Auth]";
108 context.callback.Run(std::string());
109 return;
112 // Create the middle message.
113 SecureMessageDelegate::CreateOptions create_options;
114 create_options.encryption_scheme = securemessage::AES_256_CBC;
115 create_options.signature_scheme = securemessage::HMAC_SHA256;
116 create_options.associated_data = context.hello_message;
117 context.secure_message_delegate->CreateSecureMessage(
118 inner_message, context.persistent_symmetric_key, create_options,
119 base::Bind(&OnMiddleMessageCreatedForResponderAuth, context));
122 // Called after the middle layer of [Responder Auth] is created.
123 void OnMiddleMessageCreatedForResponderAuth(
124 CreateResponderAuthMessageContext context,
125 const std::string& middle_message) {
126 if (middle_message.empty()) {
127 PA_LOG(ERROR) << "Error inner message while creating [Responder Auth]";
128 context.callback.Run(std::string());
129 return;
132 // Before we can create the outer-most message layer, we need to perform a key
133 // agreement for the session symmetric key.
134 context.middle_message = middle_message;
135 context.secure_message_delegate->DeriveKey(
136 context.session_private_key, context.hello_public_key,
137 base::Bind(&OnSessionSymmetricKeyDerivedForResponderAuth, context));
140 // Called after the session symmetric key is derived, so we can create the outer
141 // most layer of [Responder Auth].
142 void OnSessionSymmetricKeyDerivedForResponderAuth(
143 CreateResponderAuthMessageContext context,
144 const std::string& session_symmetric_key) {
145 if (session_symmetric_key.empty()) {
146 PA_LOG(ERROR) << "Error inner message while creating [Responder Auth]";
147 context.callback.Run(std::string());
148 return;
151 cryptauth::GcmMetadata gcm_metadata;
152 gcm_metadata.set_type(cryptauth::DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD);
153 gcm_metadata.set_version(kGcmMetadataVersion);
155 // Store the responder's session public key in plaintext in the header.
156 securemessage::ResponderHello responder_hello;
157 if (!responder_hello.mutable_public_dh_key()->ParseFromString(
158 context.session_public_key)) {
159 PA_LOG(ERROR) << "Error parsing public key while creating [Responder Auth]";
160 PA_LOG(ERROR) << context.session_public_key;
161 context.callback.Run(std::string());
162 return;
165 // Create the outer most message, wrapping the other messages created
166 // previously.
167 securemessage::DeviceToDeviceMessage device_to_device_message;
168 device_to_device_message.set_message(context.middle_message);
169 device_to_device_message.set_sequence_number(1);
171 SecureMessageDelegate::CreateOptions create_options;
172 create_options.encryption_scheme = securemessage::AES_256_CBC;
173 create_options.signature_scheme = securemessage::HMAC_SHA256;
174 create_options.public_metadata = gcm_metadata.SerializeAsString();
175 responder_hello.SerializeToString(&create_options.decryption_key_id);
177 context.secure_message_delegate->CreateSecureMessage(
178 device_to_device_message.SerializeAsString(), session_symmetric_key,
179 create_options, context.callback);
182 // Helper struct containing all the context needed to validate the [Initiator
183 // Auth] message.
184 struct ValidateInitiatorAuthMessageContext {
185 std::string persistent_symmetric_key;
186 std::string responder_auth_message;
187 SecureMessageDelegate* secure_message_delegate;
188 DeviceToDeviceResponderOperations::ValidationCallback callback;
191 // Called after the inner-most layer of [Initiator Auth] is unwrapped.
192 void OnInnerMessageUnwrappedForInitiatorAuth(
193 const ValidateInitiatorAuthMessageContext& context,
194 bool verified,
195 const std::string& payload,
196 const securemessage::Header& header) {
197 if (!verified)
198 PA_LOG(INFO) << "Failed to inner [Initiator Auth] message.";
199 context.callback.Run(verified);
202 // Called after the outer-most layer of [Initiator Auth] is unwrapped.
203 void OnOuterMessageUnwrappedForInitiatorAuth(
204 const ValidateInitiatorAuthMessageContext& context,
205 bool verified,
206 const std::string& payload,
207 const securemessage::Header& header) {
208 if (!verified) {
209 PA_LOG(INFO) << "Failed to verify outer [Initiator Auth] message";
210 context.callback.Run(false);
211 return;
214 // Parse the decrypted payload.
215 securemessage::DeviceToDeviceMessage device_to_device_message;
216 if (!device_to_device_message.ParseFromString(payload) ||
217 device_to_device_message.sequence_number() != 2) {
218 PA_LOG(INFO) << "Failed to validate DeviceToDeviceMessage payload.";
219 context.callback.Run(false);
220 return;
223 // Unwrap the inner message of [Initiator Auth].
224 SecureMessageDelegate::UnwrapOptions unwrap_options;
225 unwrap_options.encryption_scheme = securemessage::AES_256_CBC;
226 unwrap_options.signature_scheme = securemessage::HMAC_SHA256;
227 unwrap_options.associated_data = context.responder_auth_message;
228 context.secure_message_delegate->UnwrapSecureMessage(
229 device_to_device_message.message(), context.persistent_symmetric_key,
230 unwrap_options,
231 base::Bind(&OnInnerMessageUnwrappedForInitiatorAuth, context));
234 } // namespace
236 // static
237 void DeviceToDeviceResponderOperations::ValidateHelloMessage(
238 const std::string& hello_message,
239 const std::string& persistent_symmetric_key,
240 SecureMessageDelegate* secure_message_delegate,
241 const ValidateHelloCallback& callback) {
242 // The [Hello] message has the structure:
243 // {
244 // header: <session_public_key>,
245 // Sig(<session_public_key>, persistent_symmetric_key)
246 // payload: ""
247 // }
248 SecureMessageDelegate::UnwrapOptions unwrap_options;
249 unwrap_options.encryption_scheme = securemessage::NONE;
250 unwrap_options.signature_scheme = securemessage::HMAC_SHA256;
251 secure_message_delegate->UnwrapSecureMessage(
252 hello_message, persistent_symmetric_key, unwrap_options,
253 base::Bind(&OnHelloMessageUnwrapped, callback));
256 // static
257 void DeviceToDeviceResponderOperations::CreateResponderAuthMessage(
258 const std::string& hello_message,
259 const std::string& session_public_key,
260 const std::string& session_private_key,
261 const std::string& persistent_private_key,
262 const std::string& persistent_symmetric_key,
263 SecureMessageDelegate* secure_message_delegate,
264 const MessageCallback& callback) {
265 // The [Responder Auth] message has the structure:
266 // {
267 // header: <responder_public_key>,
268 // Sig(<responder_public_key> + payload1,
269 // session_symmetric_key),
270 // payload1: Enc({
271 // header: Sig(payload2 + <hello_message>, persistent_symmetric_key),
272 // payload2: {
273 // sequence_number: 1,
274 // body: Enc({
275 // header: Sig(payload3 + <hello_message>,
276 // persistent_responder_public_key),
277 // payload3: ""
278 // }, persistent_symmetric_key)
279 // }
280 // }, session_symmetric_key),
281 // }
282 CreateResponderAuthMessageContext context = {hello_message,
283 session_public_key,
284 session_private_key,
285 persistent_private_key,
286 persistent_symmetric_key,
287 secure_message_delegate,
288 callback};
290 // To create the [Responder Auth] message, we need to first parse the
291 // initiator's [Hello] message and extract the initiator's session public key.
292 DeviceToDeviceResponderOperations::ValidateHelloMessage(
293 hello_message, persistent_symmetric_key, secure_message_delegate,
294 base::Bind(&OnHelloMessageValidatedForResponderAuth, context));
297 // static
298 void DeviceToDeviceResponderOperations::ValidateInitiatorAuthMessage(
299 const std::string& initiator_auth_message,
300 const std::string& session_symmetric_key,
301 const std::string& persistent_symmetric_key,
302 const std::string& responder_auth_message,
303 SecureMessageDelegate* secure_message_delegate,
304 const ValidationCallback& callback) {
305 // The [Initiator Auth] message has the structure:
306 // {
307 // header: Sig(payload1, session_symmetric_key)
308 // payload1: Enc({
309 // sequence_number: 2,
310 // body: {
311 // header: Sig(payload2 + responder_auth_message,
312 // persistent_symmetric_key)
313 // payload2: ""
314 // }
315 // }, session_symmetric_key)
316 // }
317 ValidateInitiatorAuthMessageContext context = {
318 persistent_symmetric_key, responder_auth_message, secure_message_delegate,
319 callback};
321 SecureMessageDelegate::UnwrapOptions unwrap_options;
322 unwrap_options.encryption_scheme = securemessage::AES_256_CBC;
323 unwrap_options.signature_scheme = securemessage::HMAC_SHA256;
324 secure_message_delegate->UnwrapSecureMessage(
325 initiator_auth_message, session_symmetric_key, unwrap_options,
326 base::Bind(&OnOuterMessageUnwrappedForInitiatorAuth, context));
329 } // proximity_auth