Stack sampling profiler: add fire-and-forget interface
[chromium-blink-merge.git] / components / proximity_auth / device_to_device_initiator_operations.cc
blobd0560cad7eed7f16ec6748b988c29d04459a68dc
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_initiator_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 DeviceToDeviceInitiatorOperations::CreateInitiatorAuthMessage(),
28 // after the inner message is created.
29 void OnInnerMessageCreatedForInitiatorAuth(
30 const std::string& session_symmetric_key,
31 SecureMessageDelegate* secure_message_delegate,
32 const DeviceToDeviceInitiatorOperations::MessageCallback& callback,
33 const std::string& inner_message) {
34 if (inner_message.empty()) {
35 PA_LOG(INFO) << "Failed to create inner message for [Initiator Auth].";
36 callback.Run(std::string());
37 return;
40 cryptauth::GcmMetadata gcm_metadata;
41 gcm_metadata.set_type(cryptauth::DEVICE_TO_DEVICE_MESSAGE);
42 gcm_metadata.set_version(kGcmMetadataVersion);
44 // Store the inner message inside a DeviceToDeviceMessage proto.
45 securemessage::DeviceToDeviceMessage device_to_device_message;
46 device_to_device_message.set_message(inner_message);
47 device_to_device_message.set_sequence_number(2);
49 // Create and return the outer message, which wraps the inner message.
50 SecureMessageDelegate::CreateOptions create_options;
51 create_options.encryption_scheme = securemessage::AES_256_CBC;
52 create_options.signature_scheme = securemessage::HMAC_SHA256;
53 gcm_metadata.SerializeToString(&create_options.public_metadata);
54 secure_message_delegate->CreateSecureMessage(
55 device_to_device_message.SerializeAsString(), session_symmetric_key,
56 create_options, callback);
59 // Helper struct containing all the context needed to validate the
60 // [Responder Auth] message.
61 struct ValidateResponderAuthMessageContext {
62 std::string responder_auth_message;
63 std::string persistent_responder_public_key;
64 std::string persistent_symmetric_key;
65 std::string session_private_key;
66 std::string hello_message;
67 SecureMessageDelegate* secure_message_delegate;
68 DeviceToDeviceInitiatorOperations::ValidateResponderAuthCallback callback;
69 std::string responder_session_public_key;
70 std::string session_symmetric_key;
73 // Forward declarations of functions used in the [Responder Auth] validation
74 // flow. These functions are declared in order in which they are called during
75 // the flow.
76 void BeginResponderAuthValidation(ValidateResponderAuthMessageContext context);
77 void OnSessionSymmetricKeyDerived(ValidateResponderAuthMessageContext context,
78 const std::string& session_symmetric_key);
79 void OnOuterMessageUnwrappedForResponderAuth(
80 const ValidateResponderAuthMessageContext& context,
81 bool verified,
82 const std::string& payload,
83 const securemessage::Header& header);
84 void OnMiddleMessageUnwrappedForResponderAuth(
85 const ValidateResponderAuthMessageContext& context,
86 bool verified,
87 const std::string& payload,
88 const securemessage::Header& header);
89 void OnInnerMessageUnwrappedForResponderAuth(
90 const ValidateResponderAuthMessageContext& context,
91 bool verified,
92 const std::string& payload,
93 const securemessage::Header& header);
95 // Begins the [Responder Auth] validation flow by validating the header.
96 void BeginResponderAuthValidation(ValidateResponderAuthMessageContext context) {
97 // Parse the encrypted SecureMessage so we can get plaintext data from the
98 // header. Note that the payload will be encrypted.
99 securemessage::SecureMessage encrypted_message;
100 securemessage::HeaderAndBody header_and_body;
101 if (!encrypted_message.ParseFromString(context.responder_auth_message) ||
102 !header_and_body.ParseFromString(encrypted_message.header_and_body())) {
103 PA_LOG(WARNING) << "Failed to parse [Responder Hello] message";
104 context.callback.Run(false, std::string());
105 return;
108 // Check that header public_metadata contains the correct metadata fields.
109 securemessage::Header header = header_and_body.header();
110 cryptauth::GcmMetadata gcm_metadata;
111 if (!gcm_metadata.ParseFromString(header.public_metadata()) ||
112 gcm_metadata.type() !=
113 cryptauth::DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD ||
114 gcm_metadata.version() != kGcmMetadataVersion) {
115 PA_LOG(WARNING) << "Failed to validate GcmMetadata in "
116 << "[Responder Auth] header.";
117 context.callback.Run(false, std::string());
118 return;
121 // Extract responder session public key from |decryption_key_id| field.
122 securemessage::ResponderHello responder_hello;
123 if (!responder_hello.ParseFromString(header.decryption_key_id()) ||
124 !responder_hello.public_dh_key().SerializeToString(
125 &context.responder_session_public_key)) {
126 PA_LOG(INFO) << "Failed to extract responder session public key in "
127 << "[Responder Auth] header.";
128 context.callback.Run(false, std::string());
129 return;
132 // Perform a Diffie-Helmann key exchange to get the session symmetric key.
133 context.secure_message_delegate->DeriveKey(
134 context.session_private_key, context.responder_session_public_key,
135 base::Bind(&OnSessionSymmetricKeyDerived, context));
138 // Called after the session symmetric key is derived, so now we can unwrap the
139 // outer message of [Responder Auth].
140 void OnSessionSymmetricKeyDerived(ValidateResponderAuthMessageContext context,
141 const std::string& session_symmetric_key) {
142 context.session_symmetric_key = session_symmetric_key;
144 // Unwrap the outer message, using symmetric key encryption and signature.
145 SecureMessageDelegate::UnwrapOptions unwrap_options;
146 unwrap_options.encryption_scheme = securemessage::AES_256_CBC;
147 unwrap_options.signature_scheme = securemessage::HMAC_SHA256;
148 context.secure_message_delegate->UnwrapSecureMessage(
149 context.responder_auth_message, session_symmetric_key, unwrap_options,
150 base::Bind(&OnOuterMessageUnwrappedForResponderAuth, context));
153 // Called after the outer-most layer of [Responder Auth] is unwrapped.
154 void OnOuterMessageUnwrappedForResponderAuth(
155 const ValidateResponderAuthMessageContext& context,
156 bool verified,
157 const std::string& payload,
158 const securemessage::Header& header) {
159 if (!verified) {
160 PA_LOG(INFO) << "Failed to unwrap outer [Responder Auth] message.";
161 context.callback.Run(false, std::string());
162 return;
165 // Parse the decrypted payload.
166 securemessage::DeviceToDeviceMessage device_to_device_message;
167 if (!device_to_device_message.ParseFromString(payload) ||
168 device_to_device_message.sequence_number() != 1) {
169 PA_LOG(INFO) << "Failed to validate DeviceToDeviceMessage payload.";
170 context.callback.Run(false, std::string());
171 return;
174 // Unwrap the middle level SecureMessage, using symmetric key encryption and
175 // signature.
176 SecureMessageDelegate::UnwrapOptions unwrap_options;
177 unwrap_options.encryption_scheme = securemessage::AES_256_CBC;
178 unwrap_options.signature_scheme = securemessage::HMAC_SHA256;
179 unwrap_options.associated_data = context.hello_message;
180 context.secure_message_delegate->UnwrapSecureMessage(
181 device_to_device_message.message(), context.persistent_symmetric_key,
182 unwrap_options,
183 base::Bind(&OnMiddleMessageUnwrappedForResponderAuth, context));
186 // Called after the middle layer of [Responder Auth] is unwrapped.
187 void OnMiddleMessageUnwrappedForResponderAuth(
188 const ValidateResponderAuthMessageContext& context,
189 bool verified,
190 const std::string& payload,
191 const securemessage::Header& header) {
192 if (!verified) {
193 PA_LOG(INFO) << "Failed to unwrap middle [Responder Auth] message.";
194 context.callback.Run(false, std::string());
195 return;
198 // Unwrap the inner-most SecureMessage, using no encryption and an asymmetric
199 // key signature.
200 SecureMessageDelegate::UnwrapOptions unwrap_options;
201 unwrap_options.encryption_scheme = securemessage::NONE;
202 unwrap_options.signature_scheme = securemessage::ECDSA_P256_SHA256;
203 unwrap_options.associated_data = context.hello_message;
204 context.secure_message_delegate->UnwrapSecureMessage(
205 payload, context.persistent_responder_public_key, unwrap_options,
206 base::Bind(&OnInnerMessageUnwrappedForResponderAuth, context));
209 // Called after the inner-most layer of [Responder Auth] is unwrapped.
210 void OnInnerMessageUnwrappedForResponderAuth(
211 const ValidateResponderAuthMessageContext& context,
212 bool verified,
213 const std::string& payload,
214 const securemessage::Header& header) {
215 if (!verified)
216 PA_LOG(INFO) << "Failed to unwrap inner [Responder Auth] message.";
218 cryptauth::GcmMetadata gcm_metadata;
219 if (!gcm_metadata.ParseFromString(header.public_metadata()) ||
220 gcm_metadata.type() != cryptauth::UNLOCK_KEY_SIGNED_CHALLENGE ||
221 gcm_metadata.version() != kGcmMetadataVersion) {
222 PA_LOG(WARNING) << "Failed to validate GcmMetadata in inner-most "
223 << "[Responder Auth] message.";
224 context.callback.Run(false, std::string());
225 return;
228 context.callback.Run(verified, context.session_symmetric_key);
231 } // namespace
233 // static
234 void DeviceToDeviceInitiatorOperations::CreateHelloMessage(
235 const std::string& session_public_key,
236 const std::string& persistent_symmetric_key,
237 SecureMessageDelegate* secure_message_delegate,
238 const MessageCallback& callback) {
239 // Decode public key into the |initator_hello| proto.
240 securemessage::InitiatorHello initator_hello;
241 if (!initator_hello.mutable_public_dh_key()->ParseFromString(
242 session_public_key)) {
243 PA_LOG(ERROR) << "Unable to parse user's public key";
244 callback.Run(std::string());
245 return;
248 // The [Hello] message has the structure:
249 // {
250 // header: <session_public_key>,
251 // Sig(<session_public_key>, persistent_symmetric_key)
252 // payload: ""
253 // }
254 SecureMessageDelegate::CreateOptions create_options;
255 create_options.encryption_scheme = securemessage::NONE;
256 create_options.signature_scheme = securemessage::HMAC_SHA256;
257 initator_hello.SerializeToString(&create_options.public_metadata);
258 secure_message_delegate->CreateSecureMessage(
259 kPayloadFiller, persistent_symmetric_key, create_options, callback);
262 // static
263 void DeviceToDeviceInitiatorOperations::ValidateResponderAuthMessage(
264 const std::string& responder_auth_message,
265 const std::string& persistent_responder_public_key,
266 const std::string& persistent_symmetric_key,
267 const std::string& session_private_key,
268 const std::string& hello_message,
269 SecureMessageDelegate* secure_message_delegate,
270 const ValidateResponderAuthCallback& callback) {
271 // The [Responder Auth] message has the structure:
272 // {
273 // header: <responder_public_key>,
274 // Sig(<responder_public_key> + payload1,
275 // session_symmetric_key),
276 // payload1: Enc({
277 // header: Sig(payload2 + <hello_message>, persistent_symmetric_key),
278 // payload2: {
279 // sequence_number: 1,
280 // body: Enc({
281 // header: Sig(payload3 + <hello_message>,
282 // persistent_responder_public_key),
283 // payload3: ""
284 // }, persistent_symmetric_key)
285 // }
286 // }, session_symmetric_key),
287 // }
288 struct ValidateResponderAuthMessageContext context = {
289 responder_auth_message,
290 persistent_responder_public_key,
291 persistent_symmetric_key,
292 session_private_key,
293 hello_message,
294 secure_message_delegate,
295 callback};
296 BeginResponderAuthValidation(context);
299 // static
300 void DeviceToDeviceInitiatorOperations::CreateInitiatorAuthMessage(
301 const std::string& session_symmetric_key,
302 const std::string& persistent_symmetric_key,
303 const std::string& responder_auth_message,
304 SecureMessageDelegate* secure_message_delegate,
305 const MessageCallback& callback) {
306 // The [Initiator Auth] message has the structure:
307 // {
308 // header: Sig(payload1, session_symmetric_key)
309 // payload1: Enc({
310 // sequence_number: 2,
311 // body: {
312 // header: Sig(payload2 + responder_auth_message,
313 // persistent_symmetric_key)
314 // payload2: ""
315 // }
316 // }, session_symmetric_key)
317 // }
318 SecureMessageDelegate::CreateOptions create_options;
319 create_options.encryption_scheme = securemessage::AES_256_CBC;
320 create_options.signature_scheme = securemessage::HMAC_SHA256;
321 create_options.associated_data = responder_auth_message;
322 secure_message_delegate->CreateSecureMessage(
323 kPayloadFiller, persistent_symmetric_key, create_options,
324 base::Bind(&OnInnerMessageCreatedForInitiatorAuth, session_symmetric_key,
325 secure_message_delegate, callback));
328 } // proximity_auth