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 "chromeos/dbus/easy_unlock_client.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/compiler_specific.h"
11#include "dbus/bus.h"
12#include "dbus/message.h"
13#include "dbus/object_path.h"
14#include "dbus/object_proxy.h"
15#include "third_party/cros_system_api/dbus/service_constants.h"
16
17namespace chromeos {
18
19namespace {
20
21// Reads array of bytes from a dbus message reader and converts it to string.
22std::string PopResponseData(dbus::MessageReader* reader) {
23  const uint8* bytes = NULL;
24  size_t length = 0;
25  if (!reader->PopArrayOfBytes(&bytes, &length))
26    return "";
27
28  return std::string(reinterpret_cast<const char*>(bytes), length);
29}
30
31// Converts string to array of bytes and writes it using dbus meddage writer.
32void AppendStringAsByteArray(const std::string& data,
33                             dbus::MessageWriter* writer) {
34  writer->AppendArrayOfBytes(reinterpret_cast<const uint8*>(data.data()),
35                             data.length());
36}
37
38// The EasyUnlockClient used in production (and returned by
39// EasyUnlockClient::Create).
40class EasyUnlockClientImpl : public EasyUnlockClient {
41 public:
42  EasyUnlockClientImpl() : proxy_(NULL), weak_ptr_factory_(this) {}
43
44  virtual ~EasyUnlockClientImpl() {}
45
46  // EasyUnlockClient override.
47  virtual void PerformECDHKeyAgreement(const std::string& private_key,
48                                       const std::string& public_key,
49                                       const DataCallback& callback) OVERRIDE {
50    dbus::MethodCall method_call(
51        easy_unlock::kEasyUnlockServiceInterface,
52        easy_unlock::kPerformECDHKeyAgreementMethod);
53    dbus::MessageWriter writer(&method_call);
54    // NOTE: DBus expects that data sent as string is UTF-8 encoded. This is
55    //     not guaranteed here, so the method uses byte arrays.
56    AppendStringAsByteArray(private_key, &writer);
57    AppendStringAsByteArray(public_key, &writer);
58    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
59                       base::Bind(&EasyUnlockClientImpl::OnData,
60                                  weak_ptr_factory_.GetWeakPtr(),
61                                  callback));
62  }
63
64  // EasyUnlockClient override.
65  virtual void GenerateEcP256KeyPair(const KeyPairCallback& callback) OVERRIDE {
66    dbus::MethodCall method_call(
67        easy_unlock::kEasyUnlockServiceInterface,
68        easy_unlock::kGenerateEcP256KeyPairMethod);
69    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
70                       base::Bind(&EasyUnlockClientImpl::OnKeyPair,
71                                  weak_ptr_factory_.GetWeakPtr(),
72                                  callback));
73  }
74
75  // EasyUnlockClient override.
76  virtual void CreateSecureMessage(const std::string& payload,
77                                   const CreateSecureMessageOptions& options,
78                                   const DataCallback& callback) OVERRIDE {
79    dbus::MethodCall method_call(
80        easy_unlock::kEasyUnlockServiceInterface,
81        easy_unlock::kCreateSecureMessageMethod);
82    dbus::MessageWriter writer(&method_call);
83    // NOTE: DBus expects that data sent as string is UTF-8 encoded. This is
84    //     not guaranteed here, so the method uses byte arrays.
85    AppendStringAsByteArray(payload, &writer);
86    AppendStringAsByteArray(options.key, &writer);
87    AppendStringAsByteArray(options.associated_data, &writer);
88    AppendStringAsByteArray(options.public_metadata, &writer);
89    AppendStringAsByteArray(options.verification_key_id, &writer);
90    AppendStringAsByteArray(options.decryption_key_id, &writer);
91    writer.AppendString(options.encryption_type);
92    writer.AppendString(options.signature_type);
93    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
94                       base::Bind(&EasyUnlockClientImpl::OnData,
95                                  weak_ptr_factory_.GetWeakPtr(),
96                                  callback));
97  }
98
99  // EasyUnlockClient override.
100  virtual void UnwrapSecureMessage(const std::string& message,
101                                   const UnwrapSecureMessageOptions& options,
102                                   const DataCallback& callback) OVERRIDE {
103    dbus::MethodCall method_call(
104        easy_unlock::kEasyUnlockServiceInterface,
105        easy_unlock::kUnwrapSecureMessageMethod);
106    dbus::MessageWriter writer(&method_call);
107    // NOTE: DBus expects that data sent as string is UTF-8 encoded. This is
108    //     not guaranteed here, so the method uses byte arrays.
109    AppendStringAsByteArray(message, &writer);
110    AppendStringAsByteArray(options.key, &writer);
111    AppendStringAsByteArray(options.associated_data, &writer);
112    writer.AppendString(options.encryption_type);
113    writer.AppendString(options.signature_type);
114    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
115                       base::Bind(&EasyUnlockClientImpl::OnData,
116                                  weak_ptr_factory_.GetWeakPtr(),
117                                  callback));
118  }
119
120 protected:
121  virtual void Init(dbus::Bus* bus) OVERRIDE {
122    proxy_ =
123        bus->GetObjectProxy(
124            easy_unlock::kEasyUnlockServiceName,
125            dbus::ObjectPath(easy_unlock::kEasyUnlockServicePath));
126  }
127
128 private:
129  void OnData(const DataCallback& callback, dbus::Response* response) {
130    if (!response) {
131      callback.Run("");
132      return;
133    }
134
135    dbus::MessageReader reader(response);
136    callback.Run(PopResponseData(&reader));
137  }
138
139  void OnKeyPair(const KeyPairCallback& callback, dbus::Response* response) {
140    if (!response) {
141      callback.Run("", "");
142      return;
143    }
144
145    dbus::MessageReader reader(response);
146    std::string private_key = PopResponseData(&reader);
147    std::string public_key = PopResponseData(&reader);
148
149    if (public_key.empty() || private_key.empty()) {
150      callback.Run("", "");
151      return;
152    }
153
154    callback.Run(private_key, public_key);
155  }
156
157  dbus::ObjectProxy* proxy_;
158
159  // Note: This should remain the last member so it'll be destroyed and
160  // invalidate its weak pointers before any other members are destroyed.
161  base::WeakPtrFactory<EasyUnlockClientImpl> weak_ptr_factory_;
162
163  DISALLOW_COPY_AND_ASSIGN(EasyUnlockClientImpl);
164};
165
166}  // namespace
167
168EasyUnlockClient::CreateSecureMessageOptions::CreateSecureMessageOptions() {}
169
170EasyUnlockClient::CreateSecureMessageOptions::~CreateSecureMessageOptions() {}
171
172EasyUnlockClient::UnwrapSecureMessageOptions::UnwrapSecureMessageOptions() {}
173
174EasyUnlockClient::UnwrapSecureMessageOptions::~UnwrapSecureMessageOptions() {}
175
176EasyUnlockClient::EasyUnlockClient() {
177}
178
179EasyUnlockClient::~EasyUnlockClient() {
180}
181
182// static
183EasyUnlockClient* EasyUnlockClient::Create() {
184  return new EasyUnlockClientImpl();
185}
186
187}  // namespace chromeos
188