]> git.saurik.com Git - apple/security.git/blob - securityd/securityd_service/securityd_service/main.c
0f848dc0abdcc27d57ba252410271e1d7a86f80e
[apple/security.git] / securityd / securityd_service / securityd_service / main.c
1 /* Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. */
2
3 #include "securityd_service.h"
4 #include "securityd_service_client.h"
5 #include <libaks.h>
6
7 #include <sandbox.h>
8 #include <vproc.h>
9 #include <xpc/xpc.h>
10 #include <xpc/private.h>
11 #include <dispatch/dispatch.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <stdio.h>
15 #include <errno.h>
16 #include <assert.h>
17 #include <syslog.h>
18 #include <unistd.h>
19 #include <pwd.h>
20 #include <uuid/uuid.h>
21 #include <bsm/libbsm.h>
22 #include <copyfile.h>
23 #include <AssertMacros.h>
24 #include <Security/Security.h>
25 #include <Security/SecKeychainPriv.h>
26
27 #include <IOKit/IOKitLib.h>
28 #include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
29
30 #if DEBUG
31 #define LOG(...) syslog(LOG_ERR, ##__VA_ARGS__);
32 #else
33 #define LOG(...)
34 #endif
35
36 static bool check_signature(xpc_connection_t connection);
37
38 static pid_t get_caller_pid(audit_token_t * token)
39 {
40 pid_t pid = 0;
41 if (token) {
42 audit_token_to_au32(*token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
43 }
44 return pid;
45 }
46
47 // exported from libaks.a
48 kern_return_t aks_register_for_notifications(mach_port_t server_port, uintptr_t message_id);
49 kern_return_t aks_stash_escrow(keybag_handle_t handle, bool create, const void * secret, int secret_len, const void * in_data, int in_data_len, void ** out_data, int * out_data_len);
50
51 const char * kb_home_path = "Library/Keychains";
52 const char * kb_user_bag = "user.kb";
53 const char * kb_stash_bag = "stash.kb";
54
55 #define HEXBUF_LEN 2048
56
57 typedef struct {
58 uid_t uid;
59 gid_t gid;
60 char * name;
61 char * home;
62 } service_user_record_t;
63
64 typedef enum {
65 kb_bag_type_user,
66 kb_bag_type_stash
67 } kb_bag_type_t;
68
69 static io_connect_t
70 openiodev(void)
71 {
72 io_registry_entry_t service;
73 io_connect_t conn;
74 kern_return_t kr;
75
76 service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kAppleFDEKeyStoreServiceName));
77 if (service == IO_OBJECT_NULL)
78 return IO_OBJECT_NULL;
79
80 kr = IOServiceOpen(service, mach_task_self(), 0, &conn);
81 if (kr != KERN_SUCCESS)
82 return IO_OBJECT_NULL;
83
84 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
85 if (kr != KERN_SUCCESS) {
86 IOServiceClose(conn);
87 return IO_OBJECT_NULL;
88 }
89
90 return conn;
91 }
92
93 static void
94 closeiodev(io_connect_t conn)
95 {
96 kern_return_t kr;
97 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
98 if (kr != KERN_SUCCESS)
99 return;
100 IOServiceClose(conn);
101 }
102
103 static dispatch_queue_t
104 _kb_service_get_dispatch_queue()
105 {
106 static dispatch_once_t onceToken = 0;
107 static dispatch_queue_t connection_queue = NULL;
108
109 dispatch_once(&onceToken, ^{
110 connection_queue = dispatch_queue_create("kb-service-queue", DISPATCH_QUEUE_SERIAL);
111 });
112
113 return connection_queue;
114 }
115
116 static service_user_record_t * get_user_record(uid_t uid)
117 {
118 service_user_record_t * ur = NULL;
119 long bufsize = 0;
120 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
121 bufsize = 4096;
122 }
123 char buf[bufsize];
124 struct passwd pwbuf, *pw = NULL;
125 if ((getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0) && pw != NULL) {
126 ur = calloc(1u, sizeof(service_user_record_t));
127 require(ur, done);
128 ur->uid = pw->pw_uid;
129 ur->gid = pw->pw_gid;
130 ur->home = strdup(pw->pw_dir);
131 ur->name = strdup(pw->pw_name);
132 } else {
133 syslog(LOG_ERR, "failed to lookup user record for uid: %d", uid);
134 }
135
136 done:
137 return ur;
138 }
139
140 static void free_user_record(service_user_record_t * ur)
141 {
142 if (ur != NULL) {
143 if (ur->home) {
144 free(ur->home);
145 }
146 if (ur->name) {
147 free(ur->name);
148 }
149 free(ur);
150 }
151 }
152
153 static const char * get_host_uuid()
154 {
155 static uuid_string_t hostuuid = {};
156 static dispatch_once_t onceToken;
157 dispatch_once(&onceToken, ^{
158 struct timespec timeout = {30, 0};
159 uuid_t uuid = {};
160 if (gethostuuid(uuid, &timeout) == 0) {
161 uuid_unparse(uuid, hostuuid);
162 } else {
163 syslog(LOG_ERR, "failed to get host uuid");
164 }
165 });
166
167 return hostuuid;
168 }
169
170 static char *
171 _kb_copy_bag_filename(service_user_record_t * ur, kb_bag_type_t type)
172 {
173 char * bag_file = NULL;
174 const char * name = NULL;
175
176 require(ur, done);
177 switch(type) {
178 case kb_bag_type_user:
179 name = kb_user_bag;
180 break;
181 case kb_bag_type_stash:
182 name = kb_stash_bag;
183 break;
184 default:
185 goto done;
186 }
187
188 bag_file = calloc(1u, PATH_MAX);
189 require(bag_file, done);
190
191 snprintf(bag_file, PATH_MAX, "%s/%s/%s/%s", ur->home, kb_home_path, get_host_uuid(), name);
192
193 done:
194 return bag_file;
195 }
196
197 static bool
198 _kb_verify_create_path(service_user_record_t * ur)
199 {
200 bool created = false;
201 struct stat st_info = {};
202 char new_path[PATH_MAX] = {};
203 char kb_path[PATH_MAX] = {};
204 snprintf(kb_path, sizeof(kb_path), "%s/%s/%s", ur->home, kb_home_path, get_host_uuid());
205 if (lstat(kb_path, &st_info) == 0) {
206 if (S_ISDIR(st_info.st_mode)) {
207 created = true;
208 } else {
209 syslog(LOG_ERR, "invalid directory at '%s' moving aside", kb_path);
210 snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path);
211 unlink(new_path);
212 if (rename(kb_path, new_path) != 0) {
213 syslog(LOG_ERR, "failed to rename file: %s (%s)", kb_path, strerror(errno));
214 goto done;
215 }
216 }
217 }
218 if (!created) {
219 require_action(mkpath_np(kb_path, 0700) == 0, done, syslog(LOG_ERR, "could not create path: %s (%s)", kb_path, strerror(errno)));
220 created = true;
221 }
222
223 done:
224 return created;
225 }
226
227 static void
228 _set_thread_credentials(service_user_record_t * ur)
229 {
230 int rc = pthread_setugid_np(ur->uid, ur->gid);
231 if (rc) { syslog(LOG_ERR, "failed to set thread credential: %i (%s)", errno, strerror(errno)); }
232
233 rc = initgroups(ur->name, ur->gid);
234 if (rc) { syslog(LOG_ERR, "failed to initgroups: %i", rc); }
235 }
236
237 static void
238 _clear_thread_credentials()
239 {
240 int rc = pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE);
241 if (rc) { syslog(LOG_ERR, "failed to reset thread credential: %i (%s)", errno, strerror(errno)); }
242 }
243
244 static bool
245 _kb_bag_exists(service_user_record_t * ur, const char * bag_file)
246 {
247 bool exists = false;
248 struct stat st_info = {};
249 char new_file[PATH_MAX] = {};
250
251 require(ur, done);
252
253 _set_thread_credentials(ur);
254 if (lstat(bag_file, &st_info) == 0) {
255 if (S_ISREG(st_info.st_mode)) {
256 exists = true;
257 } else {
258 syslog(LOG_ERR, "invalid file at '%s' moving aside", bag_file);
259 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
260 unlink(new_file);
261 if (rename(bag_file, new_file) != 0) {
262 syslog(LOG_ERR, "failed to rename file: %s (%s)", bag_file, strerror(errno));
263 }
264 }
265 }
266
267 done:
268 _clear_thread_credentials();
269 return exists;
270 }
271
272 static bool
273 _kb_save_bag_to_disk(service_user_record_t * ur, const char * bag_file, void * data, size_t length)
274 {
275 bool result = false;
276 int fd = -1;
277
278 require(bag_file, done);
279
280 _set_thread_credentials(ur);
281 require(_kb_verify_create_path(ur), done);
282
283 fd = open(bag_file, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0600);
284 require_action(fd != -1, done, syslog(LOG_ERR, "could not create file: %s (%s)", bag_file, strerror(errno)));
285 require_action(write(fd, data, length) != -1, done, syslog(LOG_ERR, "failed to write keybag to disk %s", strerror(errno)));
286
287 result = true;
288
289 done:
290 if (fd != -1) { close(fd); }
291 _clear_thread_credentials();
292 return result;
293 }
294
295 static bool
296 _kb_load_bag_from_disk(service_user_record_t * ur, const char * bag_file, uint8_t ** data, size_t * length)
297 {
298 bool result = false;
299 int fd = -1;
300 uint8_t * buf = NULL;
301 size_t buf_size = 0;
302 struct stat st_info = {};
303
304 require(bag_file, done);
305
306 _set_thread_credentials(ur);
307 require(_kb_verify_create_path(ur), done);
308 require_quiet(lstat(bag_file, &st_info) == 0, done);
309 require_action(S_ISREG(st_info.st_mode), done, syslog(LOG_ERR, "failed to load, not a file: %s", bag_file));
310 buf_size = (size_t)st_info.st_size;
311
312 fd = open(bag_file, O_RDONLY | O_NOFOLLOW);
313 require_action(fd != -1, done, syslog(LOG_ERR, "could not open file: %s (%s)", bag_file, strerror(errno)));
314
315 buf = (uint8_t *)calloc(1u, buf_size);
316 require(buf != NULL, done);
317 require(read(fd, buf, buf_size) == buf_size, done);
318
319 *data = buf;
320 *length = buf_size;
321 buf = NULL;
322 result = true;
323
324 done:
325 if (fd != -1) { close(fd); }
326 if (buf) { free(buf); }
327 _clear_thread_credentials();
328 return result;
329 }
330
331 static void
332 _kb_rename_bag_on_disk(service_user_record_t * ur, const char * bag_file)
333 {
334 char new_file[PATH_MAX] = {};
335 if (bag_file) {
336 _set_thread_credentials(ur);
337 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
338 unlink(new_file);
339 rename(bag_file, new_file);
340 _clear_thread_credentials();
341 }
342 }
343
344 static void
345 _kb_delete_bag_on_disk(service_user_record_t * ur, const char * bag_file)
346 {
347 if (bag_file) {
348 _set_thread_credentials(ur);
349 unlink(bag_file);
350 _clear_thread_credentials();
351 }
352 }
353
354 static int
355 _kb_get_session_handle(service_context_t * context, keybag_handle_t * handle_out)
356 {
357 int rc = KB_BagNotLoaded;
358 keybag_handle_t session_handle = bad_keybag_handle;
359 require_noerr_quiet(aks_get_system(context->s_uid, &session_handle), done);
360
361 *handle_out = session_handle;
362 rc = KB_Success;
363
364 done:
365 return rc;
366 }
367
368 static void update_keybag_handle(keybag_handle_t handle)
369 {
370 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
371 uid_t uid = abs(handle);
372 uint8_t * buf = NULL;
373 size_t buf_size = 0;
374 service_user_record_t * ur = NULL;
375 char * bag_file = NULL;
376
377 require_noerr(aks_save_bag(handle, (void**)&buf, (int*)&buf_size), done);
378 require(ur = get_user_record(uid), done);
379 require(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done);
380 require(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done);
381
382 syslog(LOG_NOTICE, "successfully updated handle %d", handle);
383
384 done:
385 if (buf) free(buf);
386 if (ur) free_user_record(ur);
387 if (bag_file) free(bag_file);
388 });
389 }
390
391 static int
392 service_kb_create(service_context_t * context, const void * secret, int secret_len)
393 {
394 __block int rc = KB_GeneralError;
395
396 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
397 uint8_t * buf = NULL;
398 size_t buf_size = 0;
399 keybag_handle_t session_handle = bad_keybag_handle;
400 service_user_record_t * ur = get_user_record(context->s_uid);
401 char * bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user);
402
403 require(bag_file, done);
404
405 // check for the existance of the bagfile
406 require_action(!_kb_bag_exists(ur, bag_file), done, rc = KB_BagExists);
407
408 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &session_handle), done);
409 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
410 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
411 require_noerr(rc = aks_set_system(session_handle, context->s_uid), done);
412 aks_unload_bag(session_handle);
413 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
414
415 if (secret && rc == KB_Success) {
416 aks_unlock_bag(session_handle, secret, secret_len);
417 }
418
419 done:
420 if (buf) free(buf);
421 if (bag_file) { free(bag_file); }
422 if (ur) free_user_record(ur);
423 });
424
425 return rc;
426 }
427
428 static int
429 service_kb_load(service_context_t * context)
430 {
431 __block int rc = KB_GeneralError;
432
433 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
434 uint8_t * buf = NULL;
435 size_t buf_size = 0;
436 keybag_handle_t session_handle = bad_keybag_handle;
437 service_user_record_t * ur = NULL;
438 char * bag_file = NULL;
439
440 rc = aks_get_system(context->s_uid, &session_handle);
441 if (rc == kIOReturnNotFound) {
442 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
443 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
444 require_action_quiet(_kb_load_bag_from_disk(ur, bag_file, &buf, &buf_size), done, rc = KB_BagNotFound);
445 rc = aks_load_bag(buf, (int)buf_size, &session_handle);
446 if (rc == kIOReturnNotPermitted) {
447 syslog(LOG_ERR, "error loading keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
448 _kb_rename_bag_on_disk(ur, bag_file);
449 rc = KB_BagNotFound;
450 }
451 require_noerr(rc, done);
452 require_noerr(rc = aks_set_system(session_handle, context->s_uid), done);
453 aks_unload_bag(session_handle);
454 }
455 require(rc == KB_Success, done);
456
457 done:
458 if (buf) free(buf);
459 if (ur) free_user_record(ur);
460 if (bag_file) free(bag_file);
461 });
462
463 return rc;
464 }
465
466 static int
467 service_kb_unload(service_context_t *context)
468 {
469 __block int rc = KB_GeneralError;
470
471 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
472 keybag_handle_t session_handle = bad_keybag_handle;
473
474 rc = aks_get_system(context->s_uid, &session_handle);
475 if (rc == kIOReturnNotFound) {
476 // No session bag, nothing to do
477 rc = KB_Success;
478 return;
479 } else if (rc != kIOReturnSuccess) {
480 syslog(LOG_ERR, "error locating session keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
481 rc = KB_BagError;
482 return;
483 }
484
485 rc = aks_unload_bag(session_handle);
486 if (rc != kAKSReturnSuccess) {
487 syslog(LOG_ERR, "error unloading keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
488 rc = KB_BagError;
489 } else {
490 syslog(LOG_ERR, "successfully unloaded keybag (%ld) for uid (%i) in session (%i)", (long)session_handle, context->s_uid, context->s_id);
491 }
492 });
493
494 return rc;
495 }
496
497 static int
498 service_kb_save(service_context_t * context)
499 {
500 __block int rc = KB_GeneralError;
501 keybag_handle_t session_handle;
502 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
503
504 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
505 uint8_t * buf = NULL;
506 size_t buf_size = 0;
507 service_user_record_t * ur = NULL;
508 char * bag_file = NULL;
509
510 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
511 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
512 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
513 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
514
515 rc = KB_Success;
516
517 done:
518 if (buf) free(buf);
519 if (ur) free_user_record(ur);
520 if (bag_file) free(bag_file);
521 return;
522 });
523
524 done:
525 return rc;
526 }
527
528 static int
529 service_kb_unlock(service_context_t * context, const void * secret, int secret_len)
530 {
531 int rc = KB_GeneralError;
532 keybag_handle_t session_handle;
533 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
534
535 rc = aks_unlock_bag(session_handle, secret, secret_len);
536
537 done:
538 return rc;
539 }
540
541 static int
542 service_kb_lock(service_context_t * context)
543 {
544 int rc = KB_GeneralError;
545 keybag_handle_t session_handle;
546 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
547
548 rc = aks_lock_bag(session_handle);
549
550 done:
551 return rc;
552 }
553
554 static int
555 service_kb_change_secret(service_context_t * context, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
556 {
557 __block int rc = KB_GeneralError;
558 keybag_handle_t session_handle;
559 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
560
561 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
562 uint8_t * buf = NULL;
563 size_t buf_size = 0;
564 service_user_record_t * ur = NULL;
565 char * bag_file = NULL;
566
567 require_noerr(rc = aks_change_secret(session_handle, secret, secret_len, new_secret, new_secret_len, NULL, NULL), done);
568 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
569 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
570 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
571 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
572
573 rc = KB_Success;
574
575 done:
576 if (buf) free(buf);
577 if (ur) free_user_record(ur);
578 if (bag_file) free(bag_file);
579 return;
580 });
581
582 done:
583 return rc;
584 }
585
586 static int
587 service_kb_reset(service_context_t * context, const void * secret, int secret_len)
588 {
589 __block int rc = KB_GeneralError;
590 service_user_record_t * ur = NULL;
591 char * bag_file = NULL;
592
593 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
594 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
595
596 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
597 uint8_t * buf = NULL;
598 size_t buf_size = 0;
599 keybag_handle_t session_handle = bad_keybag_handle;
600
601 syslog(LOG_ERR, "resetting keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
602 _kb_rename_bag_on_disk(ur, bag_file);
603
604 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &session_handle), done);
605 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
606 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
607 require_noerr(rc = aks_set_system(session_handle, context->s_uid), done);
608 aks_unload_bag(session_handle);
609 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
610
611 if (secret && rc == KB_Success) {
612 aks_unlock_bag(session_handle, secret, secret_len);
613 }
614
615 done:
616 if (buf) free(buf);
617 return;
618 });
619
620 done:
621 if (ur) free_user_record(ur);
622 if (bag_file) free(bag_file);
623 return rc;
624 }
625
626 static int
627 service_kb_is_locked(service_context_t * context, xpc_object_t reply)
628 {
629 int rc = KB_GeneralError;
630 keybag_state_t state;
631 keybag_handle_t session_handle;
632 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
633
634 require_noerr(rc = aks_get_lock_state(session_handle, &state), done);
635
636 xpc_dictionary_set_bool(reply, SERVICE_XPC_LOCKED, state & keybag_state_locked);
637 xpc_dictionary_set_bool(reply, SERVICE_XPC_NO_PIN, state & keybag_state_no_pin);
638
639 done:
640 return rc;
641 }
642
643 static int
644 service_kb_stash_create(service_context_t * context, const void * key, unsigned key_size)
645 {
646 int rc = KB_GeneralError;
647 char * bag_file = NULL;
648 keybag_handle_t session_handle;
649 service_user_record_t * ur = NULL;
650 void * stashbag = NULL;
651 int stashbag_size = 0;
652 __block bool saved = false;
653
654 require(key, done);
655 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
656 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
657 require_noerr(rc = aks_stash_escrow(session_handle, true, key, key_size, NULL, 0, (void**)&stashbag, &stashbag_size), done);
658 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
659
660 // sync writing the bag to disk
661 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
662 saved = _kb_save_bag_to_disk(ur, bag_file, stashbag, stashbag_size);
663 });
664 require_action(saved, done, rc = KB_BagError);
665 rc = KB_Success;
666
667 done:
668 if (stashbag) { free(stashbag); }
669 if (bag_file) { free(bag_file); }
670 if (ur) free_user_record(ur);
671 return rc;
672 }
673
674 static int
675 service_kb_stash_load(service_context_t * context, const void * key, unsigned key_size, bool nondestructive)
676 {
677 __block int rc = KB_GeneralError;
678 char * bag_file = NULL;
679 keybag_handle_t session_handle;
680 service_user_record_t * ur = NULL;
681 __block uint8_t * stashbag = NULL;
682 __block size_t stashbag_size = 0;
683
684 require(key, done);
685 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
686 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
687 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
688
689 // sync loading the bag from disk
690 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
691 if (!_kb_load_bag_from_disk(ur, bag_file, &stashbag, &stashbag_size)) {
692 rc = KB_BagError;
693 }
694 });
695 require_noerr(rc, done);
696
697 require_noerr(rc = aks_stash_escrow(session_handle, false, key, key_size, stashbag, (int)stashbag_size, NULL, NULL), done);
698 rc = KB_Success;
699
700 done:
701 if (stashbag) { free(stashbag); }
702 if ((bag_file) && (!nondestructive)) {
703 _kb_delete_bag_on_disk(ur, bag_file);
704 free(bag_file);
705 }
706 if (ur) free_user_record(ur);
707 return rc;
708 }
709
710 //
711 // Get the keychain master key from the AppleFDEKeyStore.
712 // Note that this is a one-time call - the master key is
713 // removed from the keystore after it is returned.
714 // Requires the entitlement: com.apple.private.securityd.keychain
715 //
716 OSStatus service_stash_get_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
717 {
718 getStashKey_InStruct_t inStruct;
719 getStashKey_OutStruct_t outStruct;
720 size_t outSize = sizeof(outStruct);
721 kern_return_t kr = KERN_INVALID_ARGUMENT;
722
723 io_connect_t conn = openiodev();
724 require(conn, done);
725 inStruct.type = kAppleFDEKeyStoreStash_master;
726
727 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_getStashKey,
728 NULL, 0,
729 &inStruct, sizeof(inStruct),
730 NULL, NULL,
731 &outStruct, &outSize);
732
733 if (kr == KERN_SUCCESS) {
734 xpc_dictionary_set_data(reply, SERVICE_XPC_KEY, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize);
735 service_kb_stash_load(context, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize, false);
736 }
737
738 done:
739 if (conn)
740 closeiodev(conn);
741
742 return kr;
743 }
744
745 //
746 // Stash the keychain master key in the AppleFDEKeyStore and
747 // flag it as the keychain master key to be added to the
748 // reboot NVRAM blob.
749 // This requires two calls to the AKS: the first to store the
750 // key and get its uuid. The second uses the uuid to flag the
751 // key for blob inclusion.
752 //
753 OSStatus service_stash_set_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
754 {
755 kern_return_t kr = KERN_INVALID_ARGUMENT;
756 size_t keydata_len = 0;
757 size_t len;
758
759 io_connect_t conn = openiodev();
760 require(conn, done);
761
762 // Store the key in the keystore and get its uuid
763 setKeyGetUUID_InStruct_t inStruct1;
764 uuid_OutStruct_t outStruct1;
765
766
767 const uint8_t *keydata = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &keydata_len);
768 require(keydata, done);
769
770 memcpy(&inStruct1.inKey.key.key, keydata, keydata_len);
771 inStruct1.inKey.key.keysize = (cryptosize_t) keydata_len;
772 len = sizeof(outStruct1);
773 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setKeyGetUUID,
774 NULL, 0,
775 &inStruct1, sizeof(inStruct1),
776 NULL, NULL,
777 &outStruct1, &len);
778 require(kr == KERN_SUCCESS, done);
779
780 // Now using the uuid stash it as the master key
781 setStashKey_InStruct_t inStruct2;
782 memcpy(&inStruct2.uuid, &outStruct1.uuid, sizeof(outStruct1.uuid));
783 inStruct2.type = kAppleFDEKeyStoreStash_master;
784
785 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setStashKey,
786 NULL, 0,
787 &inStruct2, sizeof(inStruct2),
788 NULL, NULL,
789 NULL, NULL);
790
791 if (kr == KERN_SUCCESS) {
792 service_kb_stash_create(context, keydata, (unsigned)keydata_len);
793 }
794 done:
795 if (conn)
796 closeiodev(conn);
797
798 return kr;
799 }
800
801 //
802 // Load the master stash key
803 //
804 OSStatus service_stash_load_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
805 {
806 kern_return_t kr = KERN_SUCCESS;
807 size_t keydata_len = 0;
808
809 const uint8_t *keydata = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &keydata_len);
810 require(keydata, done);
811
812 kr = service_kb_stash_load(context, keydata, (cryptosize_t) keydata_len, true);
813 done:
814
815 return kr;
816 }
817
818 //
819 // Signal the AppleFDEKeyStore to take the tagged FDE key
820 // and keychain master key, stash them in an encrypted
821 // blob structure and write the blob to NVRAM. The random
822 // encryption key is written to the SMC.
823 //
824 #if DEBUG
825 OSStatus service_stash_blob(xpc_object_t event, xpc_object_t reply)
826 {
827 kern_return_t kr = KERN_INVALID_ARGUMENT;
828
829 io_connect_t conn = openiodev();
830 require(conn, done);
831
832 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_commitStash,
833 NULL, 0,
834 NULL, 0,
835 NULL, NULL,
836 NULL, NULL);
837 done:
838 if (conn)
839 closeiodev(conn);
840
841 return kr;
842 }
843 #endif
844
845 bool peer_has_entitlement(xpc_connection_t peer, const char * entitlement)
846 {
847 bool entitled = false;
848
849 xpc_object_t value = xpc_connection_copy_entitlement_value(peer, entitlement);
850 if (value && (xpc_get_type(value) == XPC_TYPE_BOOL)) {
851 entitled = xpc_bool_get_value(value);
852 }
853
854 if (value) xpc_release(value);
855 return entitled;
856 }
857
858 static char * sel_to_char(uint64_t sel)
859 {
860 switch (sel) {
861 case SERVICE_STASH_SET_KEY:
862 return "set_key";
863 case SERVICE_STASH_GET_KEY:
864 return "get_key";
865 case SERVICE_STASH_BLOB:
866 return "stash_blob";
867 case SERVICE_KB_LOAD:
868 return "kb_load";
869 case SERVICE_KB_SAVE:
870 return "kb_save";
871 case SERVICE_KB_UNLOCK:
872 return "kb_unlock";
873 case SERVICE_KB_LOCK:
874 return "kb_lock";
875 case SERVICE_KB_CHANGE_SECRET:
876 return "kb_change_secret";
877 case SERVICE_KB_CREATE:
878 return "kb_create";
879 case SERVICE_KB_IS_LOCKED:
880 return "kb_is_locked";
881 case SERVICE_KB_RESET:
882 return "kb_reset";
883 case SERVICE_KB_UNLOAD:
884 return "kb_unload";
885 default:
886 return "unknown";
887 }
888 }
889
890 static char * err_to_char(int err)
891 {
892 switch (err) {
893 case KB_Success:
894 return "success";
895 case KB_GeneralError:
896 return "general error";
897 case KB_BagNotFound:
898 return "bag not found";
899 case KB_BagError:
900 return "bag error";
901 case KB_BagNotLoaded:
902 return "bag not loaded";
903 case KB_BagExists:
904 return "bag exists";
905 case KB_InvalidSession:
906 return "invalid session";
907 default:
908 return "";
909 }
910 }
911
912 void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event)
913 {
914 xpc_type_t type = xpc_get_type(event);
915
916 if (type == XPC_TYPE_ERROR) {
917 if (event == XPC_ERROR_CONNECTION_INVALID) {
918 }
919 } else {
920 assert(type == XPC_TYPE_DICTIONARY);
921
922 int rc = KB_GeneralError;
923 uint64_t request = 0;
924 const uint8_t * secret = NULL, * new_secret = NULL;
925 size_t secret_len = 0, new_secret_len = 0, data_len = 0;
926 service_context_t * context = NULL;
927 bool free_context = false;
928 const void * data;
929
930 xpc_object_t reply = xpc_dictionary_create_reply(event);
931
932 request = xpc_dictionary_get_uint64(event, SERVICE_XPC_REQUEST);
933
934 // For SERVICE_KB_UNLOAD only, allow non-securityd, non-root but
935 // entitled callers.
936 if (request == SERVICE_KB_UNLOAD) {
937 if (!peer_has_entitlement(connection, "com.apple.private.securityd.keybag-unload")) {
938 xpc_connection_cancel(connection);
939 return;
940 }
941 } else {
942 if (xpc_connection_get_euid(connection) != 0) {
943 xpc_connection_cancel(connection);
944 return;
945 }
946
947 if (!check_signature(connection)) {
948 xpc_connection_cancel(connection);
949 return;
950 }
951 }
952
953 data = xpc_dictionary_get_data(event, SERVICE_XPC_CONTEXT, &data_len);
954 require_action(data || request == SERVICE_KB_UNLOAD, done, rc = KB_GeneralError);
955 if (data) {
956 require(data_len == sizeof(service_context_t), done);
957 context = (service_context_t*)data;
958 } else {
959 audit_token_t audit_token = { 0 };
960 xpc_connection_get_audit_token(connection, &audit_token);
961 context = calloc(1, sizeof(service_context_t));
962 context->s_id = xpc_connection_get_asid(connection);
963 context->s_uid = xpc_connection_get_euid(connection);
964 context->procToken = audit_token;
965 free_context = true;
966 }
967
968 require_action(context->s_id != AU_DEFAUDITSID, done, rc = KB_InvalidSession);
969 require_action(context->s_uid != AU_DEFAUDITID, done, rc = KB_InvalidSession); // we only want to work in actual user sessions.
970
971 switch (request) {
972 case SERVICE_KB_CREATE:
973 // if (kb_service_has_entitlement(peer, "com.apple.keystore.device")) {
974 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
975 rc = service_kb_create(context, secret, (int)secret_len);
976 // }
977 break;
978 case SERVICE_KB_LOAD:
979 rc = service_kb_load(context);
980 break;
981 case SERVICE_KB_UNLOAD:
982 rc = service_kb_unload(context);
983 break;
984 case SERVICE_KB_SAVE:
985 rc = service_kb_save(context);
986 break;
987 case SERVICE_KB_UNLOCK:
988 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
989 rc = service_kb_unlock(context, secret, (int)secret_len);
990 break;
991 case SERVICE_KB_LOCK:
992 rc = service_kb_lock(context);
993 break;
994 case SERVICE_KB_CHANGE_SECRET:
995 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
996 new_secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET_NEW, &new_secret_len);
997 rc = service_kb_change_secret(context, secret, (int)secret_len, new_secret, (int)new_secret_len);
998 break;
999 case SERVICE_KB_RESET:
1000 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1001 rc = service_kb_reset(context, secret, (int)secret_len);
1002 break;
1003 case SERVICE_KB_IS_LOCKED:
1004 rc = service_kb_is_locked(context, reply);
1005 break;
1006 case SERVICE_STASH_GET_KEY:
1007 rc = service_stash_get_key(context, event, reply);
1008 break;
1009 case SERVICE_STASH_SET_KEY:
1010 rc = service_stash_set_key(context, event, reply);
1011 break;
1012 case SERVICE_STASH_LOAD_KEY:
1013 rc = service_stash_load_key(context, event, reply);
1014 break;
1015 #if DEBUG
1016 case SERVICE_STASH_BLOB:
1017 rc = service_stash_blob(event, reply);
1018 break;
1019 #endif
1020 default:
1021 LOG("unknown service type");
1022 break;
1023 }
1024
1025 done:
1026 #if DEBUG
1027 LOG("selector: %s (%llu), error: %s (%x), sid: %d, suid: %d, pid: %d", sel_to_char(request), request, err_to_char(rc), rc, context ? context->s_id : 0, context ? context->s_uid : 0, context ? get_caller_pid(&context->procToken) : 0);
1028 #else
1029 if (rc != 0) {
1030 syslog(LOG_NOTICE, "selector: %s (%llu), error: %s (%x), sid: %d, suid: %d, pid: %d", sel_to_char(request), request, err_to_char(rc), rc, context ? context->s_id : 0, context ? context->s_uid : 0, context ? get_caller_pid(&context->procToken) : 0);
1031 }
1032 #endif
1033 xpc_dictionary_set_int64(reply, SERVICE_XPC_RC, rc);
1034 xpc_connection_send_message(connection, reply);
1035 xpc_release(reply);
1036 if (free_context) {
1037 free(context);
1038 }
1039 }
1040 }
1041
1042 bool check_signature(xpc_connection_t connection)
1043 {
1044 CFStringRef reqStr = CFSTR("identifier com.apple.securityd and anchor apple");
1045 SecRequirementRef requirement = NULL;
1046 SecCodeRef codeRef = NULL;
1047 CFMutableDictionaryRef codeDict = NULL;
1048 CFNumberRef codePid = NULL;
1049 pid_t pid = xpc_connection_get_pid(connection);
1050
1051 OSStatus status = SecRequirementCreateWithString(reqStr, kSecCSDefaultFlags, &requirement);
1052 require_action(status == errSecSuccess, done, LOG("failed to create requirement"));
1053
1054 codeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1055 codePid = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid);
1056 CFDictionarySetValue(codeDict, kSecGuestAttributePid, codePid);
1057 status = SecCodeCopyGuestWithAttributes(NULL, codeDict, kSecCSDefaultFlags, &codeRef);
1058 require_action(status == errSecSuccess, done, LOG("failed to get code ref"));
1059
1060 status = SecCodeCheckValidity(codeRef, kSecCSDefaultFlags,
1061 #if DEBUG || RC_BUILDIT_YES
1062 NULL);
1063 #else
1064 requirement);
1065 #endif
1066 require_action(status == errSecSuccess, done, syslog(LOG_ERR, "pid %d, does not satisfy code requirment (%d)", pid, status));
1067
1068 done:
1069 if (codeRef) CFRelease(codeRef);
1070 if (requirement) CFRelease(requirement);
1071 if (codeDict) CFRelease(codeDict);
1072 if (codePid) CFRelease(codePid);
1073
1074 return (status == errSecSuccess);
1075 }
1076
1077 static void register_for_notifications()
1078 {
1079 __block kern_return_t kr;
1080 static mach_port_t mp = MACH_PORT_NULL;
1081
1082 static dispatch_once_t onceToken = 0;
1083 dispatch_once(&onceToken, ^{
1084 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
1085 if (kr == KERN_SUCCESS) {
1086 dispatch_source_t mach_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1087 dispatch_source_set_event_handler(mach_src, ^{
1088 mach_msg_return_t mr;
1089 uint8_t buf[sizeof(aks_notification_msg_t) + MAX_TRAILER_SIZE] = {};
1090 aks_notification_msg_t * msg = (aks_notification_msg_t*)buf;
1091 mr = mach_msg((mach_msg_header_t*)&buf, MACH_RCV_MSG, 0, sizeof(buf), mp, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
1092 if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_MSGID) {
1093 // ignored for now
1094 } else if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG) {
1095 syslog(LOG_NOTICE, "request to update handle %d", msg->handle);
1096 update_keybag_handle(msg->handle);
1097 } else {
1098 syslog(LOG_ERR, "mach_msg error: %x", mr);
1099 }
1100 });
1101 dispatch_resume(mach_src);
1102 } else {
1103 syslog(LOG_NOTICE, "failed to create notification port");
1104 }
1105
1106 });
1107
1108 kr = aks_register_for_notifications(mp, AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG);
1109 if (kr == KERN_SUCCESS) {
1110 syslog(LOG_NOTICE, "registered for notifications");
1111 } else {
1112 syslog(LOG_NOTICE, "failed to register for notifications %d", kr);
1113 }
1114 }
1115
1116 int main(int argc, const char * argv[])
1117 {
1118 char * errorbuf;
1119 if (sandbox_init(SECURITYD_SERVICE_NAME, SANDBOX_NAMED, &errorbuf) != 0) {
1120 syslog(LOG_ERR, "sandbox_init failed %s", errorbuf);
1121 sandbox_free_error(errorbuf);
1122 #ifndef DEBUG
1123 abort();
1124 #endif
1125 }
1126
1127 register_for_notifications();
1128
1129 xpc_connection_t listener = xpc_connection_create_mach_service(SECURITYD_SERVICE_NAME, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
1130 xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
1131 // It is safe to cast 'peer' to xpc_connection_t assuming
1132 // we have a correct configuration in our launchd.plist.
1133 xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
1134 vproc_transaction_t transaction = vproc_transaction_begin(NULL);
1135 service_peer_event_handler(peer, event);
1136 vproc_transaction_end(NULL, transaction);
1137 });
1138 xpc_connection_resume(peer);
1139 });
1140 xpc_connection_resume(listener);
1141
1142 dispatch_main();
1143 exit(EXIT_FAILURE);
1144 }
1145