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/cryptohome/homedir_methods.h"
6
7 #include "base/bind.h"
8 #include "chromeos/dbus/cryptohome/key.pb.h"
9 #include "chromeos/dbus/cryptohome/rpc.pb.h"
10 #include "chromeos/dbus/cryptohome_client.h"
11 #include "chromeos/dbus/dbus_thread_manager.h"
12
13 using chromeos::DBusThreadManager;
14
15 namespace cryptohome {
16
17 namespace {
18
19 HomedirMethods* g_homedir_methods = NULL;
20
FillKeyProtobuf(const KeyDefinition & key_def,Key * key)21 void FillKeyProtobuf(const KeyDefinition& key_def, Key* key) {
22 key->set_secret(key_def.key);
23 KeyData* data = key->mutable_data();
24 data->set_label(key_def.label);
25
26 if (key_def.revision > 0)
27 data->set_revision(key_def.revision);
28
29 if (key_def.privileges != 0) {
30 KeyPrivileges* privileges = data->mutable_privileges();
31 privileges->set_mount(key_def.privileges & PRIV_MOUNT);
32 privileges->set_add(key_def.privileges & PRIV_ADD);
33 privileges->set_remove(key_def.privileges & PRIV_REMOVE);
34 privileges->set_update(key_def.privileges & PRIV_MIGRATE);
35 privileges->set_authorized_update(key_def.privileges &
36 PRIV_AUTHORIZED_UPDATE);
37 }
38
39 if (key_def.encryption_key.empty() && key_def.signature_key.empty())
40 return;
41
42 KeyAuthorizationData* auth_data = data->add_authorization_data();
43 auth_data->set_type(KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256);
44 if (!key_def.encryption_key.empty()) {
45 KeyAuthorizationSecret* secret = auth_data->add_secrets();
46 secret->mutable_usage()->set_encrypt(true);
47 secret->set_symmetric_key(key_def.encryption_key);
48 }
49 if (!key_def.signature_key.empty()) {
50 KeyAuthorizationSecret* secret = auth_data->add_secrets();
51 secret->mutable_usage()->set_sign(true);
52 secret->set_symmetric_key(key_def.signature_key);
53 }
54 }
55
56 // Fill identification protobuffer.
FillIdentificationProtobuf(const Identification & id,cryptohome::AccountIdentifier * id_proto)57 void FillIdentificationProtobuf(const Identification& id,
58 cryptohome::AccountIdentifier* id_proto) {
59 id_proto->set_email(id.user_id);
60 }
61
62 // Fill authorization protobuffer.
FillAuthorizationProtobuf(const Authorization & auth,cryptohome::AuthorizationRequest * auth_proto)63 void FillAuthorizationProtobuf(const Authorization& auth,
64 cryptohome::AuthorizationRequest* auth_proto) {
65 Key* key = auth_proto->mutable_key();
66 if (!auth.label.empty()) {
67 key->mutable_data()->set_label(auth.label);
68 }
69 key->set_secret(auth.key);
70 }
71
MapError(CryptohomeErrorCode code)72 MountError MapError(CryptohomeErrorCode code) {
73 switch (code) {
74 case CRYPTOHOME_ERROR_NOT_SET:
75 return MOUNT_ERROR_NONE;
76 case CRYPTOHOME_ERROR_ACCOUNT_NOT_FOUND:
77 return MOUNT_ERROR_USER_DOES_NOT_EXIST;
78 case CRYPTOHOME_ERROR_NOT_IMPLEMENTED:
79 case CRYPTOHOME_ERROR_MOUNT_FATAL:
80 case CRYPTOHOME_ERROR_KEY_QUOTA_EXCEEDED:
81 case CRYPTOHOME_ERROR_BACKING_STORE_FAILURE:
82 return MOUNT_ERROR_FATAL;
83 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_NOT_FOUND:
84 case CRYPTOHOME_ERROR_KEY_NOT_FOUND:
85 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED:
86 return MOUNT_ERROR_KEY_FAILURE;
87 case CRYPTOHOME_ERROR_TPM_COMM_ERROR:
88 return MOUNT_ERROR_TPM_COMM_ERROR;
89 case CRYPTOHOME_ERROR_TPM_DEFEND_LOCK:
90 return MOUNT_ERROR_TPM_DEFEND_LOCK;
91 case CRYPTOHOME_ERROR_MOUNT_MOUNT_POINT_BUSY:
92 return MOUNT_ERROR_MOUNT_POINT_BUSY;
93 case CRYPTOHOME_ERROR_TPM_NEEDS_REBOOT:
94 return MOUNT_ERROR_TPM_NEEDS_REBOOT;
95 case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_DENIED:
96 case CRYPTOHOME_ERROR_KEY_LABEL_EXISTS:
97 case CRYPTOHOME_ERROR_UPDATE_SIGNATURE_INVALID:
98 return MOUNT_ERROR_KEY_FAILURE;
99 default:
100 NOTREACHED();
101 return MOUNT_ERROR_FATAL;
102 }
103 }
104
105 // The implementation of HomedirMethods
106 class HomedirMethodsImpl : public HomedirMethods {
107 public:
HomedirMethodsImpl()108 HomedirMethodsImpl() : weak_ptr_factory_(this) {}
109
~HomedirMethodsImpl()110 virtual ~HomedirMethodsImpl() {}
111
CheckKeyEx(const Identification & id,const Authorization & auth,const Callback & callback)112 virtual void CheckKeyEx(const Identification& id,
113 const Authorization& auth,
114 const Callback& callback) OVERRIDE {
115 cryptohome::AccountIdentifier id_proto;
116 cryptohome::AuthorizationRequest auth_proto;
117 cryptohome::CheckKeyRequest request;
118
119 FillIdentificationProtobuf(id, &id_proto);
120 FillAuthorizationProtobuf(auth, &auth_proto);
121
122 DBusThreadManager::Get()->GetCryptohomeClient()->CheckKeyEx(
123 id_proto,
124 auth_proto,
125 request,
126 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
127 weak_ptr_factory_.GetWeakPtr(),
128 callback));
129 }
130
MountEx(const Identification & id,const Authorization & auth,const MountParameters & request,const MountCallback & callback)131 virtual void MountEx(const Identification& id,
132 const Authorization& auth,
133 const MountParameters& request,
134 const MountCallback& callback) OVERRIDE {
135 cryptohome::AccountIdentifier id_proto;
136 cryptohome::AuthorizationRequest auth_proto;
137 cryptohome::MountRequest request_proto;
138
139 FillIdentificationProtobuf(id, &id_proto);
140 FillAuthorizationProtobuf(auth, &auth_proto);
141
142 if (request.ephemeral)
143 request_proto.set_require_ephemeral(true);
144
145 if (!request.create_keys.empty()) {
146 CreateRequest* create = request_proto.mutable_create();
147 for (size_t i = 0; i < request.create_keys.size(); ++i)
148 FillKeyProtobuf(request.create_keys[i], create->add_keys());
149 }
150
151 DBusThreadManager::Get()->GetCryptohomeClient()->MountEx(
152 id_proto,
153 auth_proto,
154 request_proto,
155 base::Bind(&HomedirMethodsImpl::OnMountExCallback,
156 weak_ptr_factory_.GetWeakPtr(),
157 callback));
158 }
159
AddKeyEx(const Identification & id,const Authorization & auth,const KeyDefinition & new_key,bool clobber_if_exists,const Callback & callback)160 virtual void AddKeyEx(const Identification& id,
161 const Authorization& auth,
162 const KeyDefinition& new_key,
163 bool clobber_if_exists,
164 const Callback& callback) OVERRIDE {
165 cryptohome::AccountIdentifier id_proto;
166 cryptohome::AuthorizationRequest auth_proto;
167 cryptohome::AddKeyRequest request;
168
169 FillIdentificationProtobuf(id, &id_proto);
170 FillAuthorizationProtobuf(auth, &auth_proto);
171 FillKeyProtobuf(new_key, request.mutable_key());
172 request.set_clobber_if_exists(clobber_if_exists);
173
174 DBusThreadManager::Get()->GetCryptohomeClient()->AddKeyEx(
175 id_proto,
176 auth_proto,
177 request,
178 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
179 weak_ptr_factory_.GetWeakPtr(),
180 callback));
181 }
182
RemoveKeyEx(const Identification & id,const Authorization & auth,const std::string & label,const Callback & callback)183 virtual void RemoveKeyEx(const Identification& id,
184 const Authorization& auth,
185 const std::string& label,
186 const Callback& callback) OVERRIDE {
187 cryptohome::AccountIdentifier id_proto;
188 cryptohome::AuthorizationRequest auth_proto;
189 cryptohome::RemoveKeyRequest request;
190
191 FillIdentificationProtobuf(id, &id_proto);
192 FillAuthorizationProtobuf(auth, &auth_proto);
193 request.mutable_key()->mutable_data()->set_label(label);
194
195 DBusThreadManager::Get()->GetCryptohomeClient()->RemoveKeyEx(
196 id_proto,
197 auth_proto,
198 request,
199 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
200 weak_ptr_factory_.GetWeakPtr(),
201 callback));
202 }
203
UpdateKeyEx(const Identification & id,const Authorization & auth,const KeyDefinition & new_key,const std::string & signature,const Callback & callback)204 virtual void UpdateKeyEx(const Identification& id,
205 const Authorization& auth,
206 const KeyDefinition& new_key,
207 const std::string& signature,
208 const Callback& callback) OVERRIDE {
209 cryptohome::AccountIdentifier id_proto;
210 cryptohome::AuthorizationRequest auth_proto;
211 cryptohome::UpdateKeyRequest pb_update_key;
212
213 FillIdentificationProtobuf(id, &id_proto);
214 FillAuthorizationProtobuf(auth, &auth_proto);
215 FillKeyProtobuf(new_key, pb_update_key.mutable_changes());
216 pb_update_key.set_authorization_signature(signature);
217
218 DBusThreadManager::Get()->GetCryptohomeClient()->UpdateKeyEx(
219 id_proto,
220 auth_proto,
221 pb_update_key,
222 base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
223 weak_ptr_factory_.GetWeakPtr(),
224 callback));
225 }
226
227 private:
OnMountExCallback(const MountCallback & callback,chromeos::DBusMethodCallStatus call_status,bool result,const BaseReply & reply)228 void OnMountExCallback(const MountCallback& callback,
229 chromeos::DBusMethodCallStatus call_status,
230 bool result,
231 const BaseReply& reply) {
232 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
233 callback.Run(false, MOUNT_ERROR_FATAL, std::string());
234 return;
235 }
236 if (reply.has_error()) {
237 if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) {
238 callback.Run(false, MapError(reply.error()), std::string());
239 return;
240 }
241 }
242 if (!reply.HasExtension(MountReply::reply)) {
243 callback.Run(false, MOUNT_ERROR_FATAL, std::string());
244 return;
245 }
246
247 std::string mount_hash;
248 mount_hash = reply.GetExtension(MountReply::reply).sanitized_username();
249 callback.Run(true, MOUNT_ERROR_NONE, mount_hash);
250 }
251
OnBaseReplyCallback(const Callback & callback,chromeos::DBusMethodCallStatus call_status,bool result,const BaseReply & reply)252 void OnBaseReplyCallback(const Callback& callback,
253 chromeos::DBusMethodCallStatus call_status,
254 bool result,
255 const BaseReply& reply) {
256 if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
257 callback.Run(false, MOUNT_ERROR_FATAL);
258 return;
259 }
260 if (reply.has_error()) {
261 if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) {
262 callback.Run(false, MapError(reply.error()));
263 return;
264 }
265 }
266 callback.Run(true, MOUNT_ERROR_NONE);
267 }
268
269 base::WeakPtrFactory<HomedirMethodsImpl> weak_ptr_factory_;
270
271 DISALLOW_COPY_AND_ASSIGN(HomedirMethodsImpl);
272 };
273
274 } // namespace
275
276 // static
Initialize()277 void HomedirMethods::Initialize() {
278 if (g_homedir_methods) {
279 LOG(WARNING) << "HomedirMethods was already initialized";
280 return;
281 }
282 g_homedir_methods = new HomedirMethodsImpl();
283 VLOG(1) << "HomedirMethods initialized";
284 }
285
286 // static
InitializeForTesting(HomedirMethods * homedir_methods)287 void HomedirMethods::InitializeForTesting(HomedirMethods* homedir_methods) {
288 if (g_homedir_methods) {
289 LOG(WARNING) << "HomedirMethods was already initialized";
290 return;
291 }
292 g_homedir_methods = homedir_methods;
293 VLOG(1) << "HomedirMethods initialized";
294 }
295
296 // static
Shutdown()297 void HomedirMethods::Shutdown() {
298 if (!g_homedir_methods) {
299 LOG(WARNING) << "AsyncMethodCaller::Shutdown() called with NULL manager";
300 return;
301 }
302 delete g_homedir_methods;
303 g_homedir_methods = NULL;
304 VLOG(1) << "HomedirMethods Shutdown completed";
305 }
306
307 // static
GetInstance()308 HomedirMethods* HomedirMethods::GetInstance() { return g_homedir_methods; }
309
310 } // namespace cryptohome
311