]> git.saurik.com Git - apple/security.git/blob - securityd/securityd_service/securityd_service/main.c
b3eb3c015463127360e4293e7fcc4e5ada9c4cbc
[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 <sys/codesign.h>
15 #include <os/log.h>
16 #include <stdio.h>
17 #include <errno.h>
18 #include <assert.h>
19 #include <unistd.h>
20 #include <pwd.h>
21 #include <uuid/uuid.h>
22 #include <bsm/libbsm.h>
23 #include <copyfile.h>
24 #include <AssertMacros.h>
25 #include <Security/Security.h>
26 #include <Security/SecTask.h>
27 #include <Security/SecTaskPriv.h>
28 #include <Security/SecKeychainPriv.h>
29 #include <MobileKeyBag/MobileKeyBag.h>
30 #include <corecrypto/ccsha2.h>
31 #include <corecrypto/cchmac.h>
32
33 #include <IOKit/IOKitLib.h>
34 #include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
35
36 #define LOG(...) os_log_debug(OS_LOG_DEFAULT, ##__VA_ARGS__);
37
38 static bool check_signature(xpc_connection_t connection);
39
40 static pid_t get_caller_pid(audit_token_t * token)
41 {
42 pid_t pid = 0;
43 if (token) {
44 audit_token_to_au32(*token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
45 }
46 return pid;
47 }
48
49 // exported from libaks.a
50 kern_return_t aks_register_for_notifications(mach_port_t server_port, uintptr_t message_id);
51 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);
52
53 const char * kb_home_path = "Library/Keychains";
54 const char * kb_user_bag = "user.kb";
55 const char * kb_stash_bag = "stash.kb";
56
57 #define HEXBUF_LEN 2048
58
59 typedef struct {
60 uid_t uid;
61 gid_t gid;
62 char * name;
63 char * home;
64 } service_user_record_t;
65
66 typedef enum {
67 kb_bag_type_user,
68 kb_bag_type_stash
69 } kb_bag_type_t;
70
71 static io_connect_t
72 openiodev(void)
73 {
74 io_registry_entry_t service;
75 io_connect_t conn;
76 kern_return_t kr;
77
78 service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kAppleFDEKeyStoreServiceName));
79 if (service == IO_OBJECT_NULL)
80 return IO_OBJECT_NULL;
81
82 kr = IOServiceOpen(service, mach_task_self(), 0, &conn);
83 if (kr != KERN_SUCCESS)
84 return IO_OBJECT_NULL;
85
86 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
87 if (kr != KERN_SUCCESS) {
88 IOServiceClose(conn);
89 return IO_OBJECT_NULL;
90 }
91
92 return conn;
93 }
94
95 static void
96 closeiodev(io_connect_t conn)
97 {
98 kern_return_t kr;
99 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
100 if (kr != KERN_SUCCESS)
101 return;
102 IOServiceClose(conn);
103 }
104
105 static dispatch_queue_t
106 _kb_service_get_dispatch_queue()
107 {
108 static dispatch_once_t onceToken = 0;
109 static dispatch_queue_t connection_queue = NULL;
110
111 dispatch_once(&onceToken, ^{
112 connection_queue = dispatch_queue_create("kb-service-queue", DISPATCH_QUEUE_SERIAL);
113 });
114
115 return connection_queue;
116 }
117
118 static service_user_record_t * get_user_record(uid_t uid)
119 {
120 service_user_record_t * ur = NULL;
121 long bufsize = 0;
122 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
123 bufsize = 4096;
124 }
125 char buf[bufsize];
126 struct passwd pwbuf, *pw = NULL;
127 int rc;
128 if (((rc = getpwuid_r(uid, &pwbuf, buf, bufsize, &pw)) == 0) && pw != NULL) {
129 ur = calloc(1u, sizeof(service_user_record_t));
130 require(ur, done);
131 ur->uid = pw->pw_uid;
132 ur->gid = pw->pw_gid;
133 ur->home = strdup(pw->pw_dir);
134 ur->name = strdup(pw->pw_name);
135 } else {
136 os_log(OS_LOG_DEFAULT, "failed (%d) to lookup user record for uid: %d", rc, uid);
137 }
138
139 done:
140 return ur;
141 }
142
143 static void free_user_record(service_user_record_t * ur)
144 {
145 if (ur != NULL) {
146 if (ur->home) {
147 free(ur->home);
148 }
149 if (ur->name) {
150 free(ur->name);
151 }
152 free(ur);
153 }
154 }
155
156 static const char * get_host_uuid()
157 {
158 static uuid_string_t hostuuid = {};
159 static dispatch_once_t onceToken;
160 dispatch_once(&onceToken, ^{
161 struct timespec timeout = {30, 0};
162 uuid_t uuid = {};
163 if (gethostuuid(uuid, &timeout) == 0) {
164 uuid_unparse(uuid, hostuuid);
165 } else {
166 os_log(OS_LOG_DEFAULT, "failed to get host uuid");
167 onceToken = 0;
168 }
169 });
170
171 return hostuuid;
172 }
173
174 static uint64_t
175 compute_kcv(uint8_t * key, size_t key_len)
176 {
177 uint8_t hmac[CCSHA256_OUTPUT_SIZE] = { 0 };
178 uint8_t kcv_data[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
179 cchmac(ccsha256_di(), key_len, key, sizeof(kcv_data), kcv_data, hmac);
180 return (uint64_t)(*(uint64_t *)hmac);
181 }
182
183 static char *
184 _kb_copy_bag_filename(service_user_record_t * ur, kb_bag_type_t type)
185 {
186 char * bag_file = NULL;
187 const char * name = NULL;
188
189 require(ur, done);
190 switch(type) {
191 case kb_bag_type_user:
192 name = kb_user_bag;
193 break;
194 case kb_bag_type_stash:
195 name = kb_stash_bag;
196 break;
197 default:
198 goto done;
199 }
200
201 bag_file = calloc(1u, PATH_MAX);
202 require(bag_file, done);
203
204 snprintf(bag_file, PATH_MAX, "%s/%s/%s/%s", ur->home, kb_home_path, get_host_uuid(), name);
205
206 done:
207 return bag_file;
208 }
209
210 static bool
211 _kb_verify_create_path(service_user_record_t * ur)
212 {
213 bool created = false;
214 struct stat st_info = {};
215 char new_path[PATH_MAX] = {};
216 char kb_path[PATH_MAX] = {};
217 snprintf(kb_path, sizeof(kb_path), "%s/%s/%s", ur->home, kb_home_path, get_host_uuid());
218 if (lstat(kb_path, &st_info) == 0) {
219 if (S_ISDIR(st_info.st_mode)) {
220 created = true;
221 } else {
222 os_log(OS_LOG_DEFAULT, "invalid directory at '%s' moving aside", kb_path);
223 snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path);
224 unlink(new_path);
225 if (rename(kb_path, new_path) != 0) {
226 os_log(OS_LOG_DEFAULT, "failed to rename file: %s (%s)", kb_path, strerror(errno));
227 goto done;
228 }
229 }
230 }
231 if (!created) {
232 require_action(mkpath_np(kb_path, 0700) == 0, done, os_log(OS_LOG_DEFAULT, "could not create path: %s (%s)", kb_path, strerror(errno)));
233 created = true;
234 }
235
236 done:
237 if (!created) {
238 os_log(OS_LOG_DEFAULT, "_kb_verify_create_path failed %s", kb_path);
239 }
240 return created;
241 }
242
243 static void
244 _set_thread_credentials(service_user_record_t * ur)
245 {
246 int rc = pthread_setugid_np(ur->uid, ur->gid);
247 if (rc) { os_log(OS_LOG_DEFAULT, "failed to set thread credential: %i (%s)", errno, strerror(errno)); }
248
249 rc = initgroups(ur->name, ur->gid);
250 if (rc) { os_log(OS_LOG_DEFAULT, "failed to initgroups: %i", rc); }
251 }
252
253 static void
254 _clear_thread_credentials()
255 {
256 int rc = pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE);
257 if (rc) { os_log(OS_LOG_DEFAULT, "failed to reset thread credential: %i (%s)", errno, strerror(errno)); }
258 }
259
260 static bool
261 _kb_bag_exists(service_user_record_t * ur, const char * bag_file)
262 {
263 bool exists = false;
264 struct stat st_info = {};
265 char new_file[PATH_MAX] = {};
266
267 require(ur, done);
268
269 _set_thread_credentials(ur);
270 if (lstat(bag_file, &st_info) == 0) {
271 if (S_ISREG(st_info.st_mode)) {
272 exists = true;
273 } else {
274 os_log(OS_LOG_DEFAULT, "invalid file at '%s' moving aside", bag_file);
275 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
276 unlink(new_file);
277 if (rename(bag_file, new_file) != 0) {
278 os_log(OS_LOG_DEFAULT, "failed to rename file: %s (%s)", bag_file, strerror(errno));
279 }
280 }
281 }
282
283 done:
284 _clear_thread_credentials();
285 return exists;
286 }
287
288 static bool
289 _kb_save_bag_to_disk(service_user_record_t * ur, const char * bag_file, void * data, size_t length, uint64_t * kcv)
290 {
291 bool result = false;
292 char tmp_bag[PATH_MAX];
293 int fd = -1;
294
295 require(bag_file, done);
296
297 _set_thread_credentials(ur);
298 require(_kb_verify_create_path(ur), done);
299
300 require_action(snprintf(tmp_bag, sizeof(tmp_bag), "%s.tmp", bag_file) < sizeof(tmp_bag), done, os_log(OS_LOG_DEFAULT, "path too large"));
301
302 fd = open(tmp_bag, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0600);
303 require_action(fd != -1, done, os_log(OS_LOG_DEFAULT, "could not create file: %s (%s)", tmp_bag, strerror(errno)));
304 require_action(write(fd, data, length) == length, done, os_log(OS_LOG_DEFAULT, "failed to write keybag to disk %s (%s)", tmp_bag, strerror(errno)));
305
306 /* try atomic swap (will fail if destination doesn't exist); if that fails, try regular rename */
307 if (renamex_np(tmp_bag, bag_file, RENAME_SWAP) != 0) {
308 os_log(OS_LOG_DEFAULT, "Warning: atomic swap failed, error=%i (%s)", errno, strerror(errno));
309 require_noerr_action(rename(tmp_bag, bag_file), done, os_log(OS_LOG_DEFAULT, "could not save keybag file, error=%i (%s)", errno, strerror(errno)));
310 } else {
311 (void)unlink(tmp_bag);
312 }
313 *kcv = compute_kcv(data, length);
314 result = true;
315
316 done:
317 if (fd != -1) { close(fd); }
318 _clear_thread_credentials();
319 return result;
320 }
321
322 static bool
323 _kb_load_bag_from_disk(service_user_record_t * ur, const char * bag_file, uint8_t ** data, size_t * length, uint64_t * kcv)
324 {
325 bool result = false;
326 int fd = -1;
327 uint8_t * buf = NULL;
328 size_t buf_size = 0;
329 struct stat st_info = {};
330
331 require(bag_file, done);
332
333 _set_thread_credentials(ur);
334 require(_kb_verify_create_path(ur), done);
335 require_action_quiet(lstat(bag_file, &st_info) == 0, done, os_log(OS_LOG_DEFAULT, "failed to stat file: %s (%s)", bag_file, strerror(errno)));
336 require_action(S_ISREG(st_info.st_mode), done, os_log(OS_LOG_DEFAULT, "failed to load, not a file: %s", bag_file));
337 buf_size = (size_t)st_info.st_size;
338
339 fd = open(bag_file, O_RDONLY | O_NOFOLLOW);
340 require_action(fd != -1, done, os_log(OS_LOG_DEFAULT, "could not open file: %s (%s)", bag_file, strerror(errno)));
341
342 buf = (uint8_t *)calloc(1u, buf_size);
343 require(buf != NULL, done);
344 require(read(fd, buf, buf_size) == buf_size, done);
345
346 *kcv = compute_kcv(buf, buf_size);
347 *data = buf;
348 *length = buf_size;
349 buf = NULL;
350 result = true;
351
352 done:
353 if (fd != -1) { close(fd); }
354 if (buf) { free(buf); }
355 _clear_thread_credentials();
356 return result;
357 }
358
359 static void
360 _kb_invalidate_bag(service_user_record_t *ur, const char * bag_file, uint64_t * kcv)
361 {
362 uint8_t *buf = NULL;
363 size_t buf_size = 0;
364
365 require(ur, out);
366
367 if (_kb_load_bag_from_disk(ur, bag_file, &buf, &buf_size, kcv)) {
368 require_action(buf && buf_size <= INT_MAX, out, os_log(OS_LOG_DEFAULT, "failed to read: %s", bag_file));
369 require_noerr_action(aks_invalidate_bag(buf, (int)buf_size), out, os_log(OS_LOG_DEFAULT, "failed to invalidate file: %s", bag_file));
370 } else {
371 os_log(OS_LOG_DEFAULT, "failed to read file: %s", bag_file);
372 }
373
374 out:
375 free(buf);
376 }
377
378 static void
379 _kb_rename_bag_on_disk(service_user_record_t * ur, const char * bag_file, uint64_t * kcv)
380 {
381 char new_file[PATH_MAX] = {};
382 if (bag_file) {
383 _set_thread_credentials(ur);
384 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
385 unlink(new_file);
386 rename(bag_file, new_file);
387 _kb_invalidate_bag(ur, new_file, kcv);
388 _clear_thread_credentials();
389 }
390 }
391
392 static void
393 _kb_delete_bag_on_disk(service_user_record_t * ur, const char * bag_file, uint64_t * kcv)
394 {
395 if (bag_file) {
396 _set_thread_credentials(ur);
397 _kb_invalidate_bag(ur, bag_file, kcv);
398 unlink(bag_file);
399 _clear_thread_credentials();
400 }
401 }
402
403 static int service_kb_load(service_context_t *context, uint64_t * kcv);
404 static int service_kb_load_uid(uid_t s_uid, uint64_t * kcv);
405
406 #ifndef AKS_MACOS_ROOT_HANDLE
407 #define AKS_MACOS_ROOT_HANDLE 4 //temporary define to avoid dependency on AKS change, filed rdar://problem/30542034
408 #endif /* AKS_MACOS_ROOT_HANDLE */
409
410 static int
411 _service_kb_set_system(keybag_handle_t handle, keybag_handle_t special_handle)
412 {
413 //Use reserved root handle for root sessions, since 0 clashes with device_keybag_handle in AKS
414 return aks_set_system(handle, (special_handle == 0) ? AKS_MACOS_ROOT_HANDLE : special_handle);
415 }
416
417 static int
418 _service_kb_get_system(keybag_handle_t special_handle, keybag_handle_t * handle_out)
419 {
420 //Use reserved root handle for root sessions, since 0 clashes with device_keybag_handle in AKS
421 return aks_get_system((special_handle == 0) ? AKS_MACOS_ROOT_HANDLE : special_handle, handle_out);
422 }
423
424 static int
425 _kb_get_session_handle(service_context_t * context, keybag_handle_t * handle_out, uint64_t * kcv)
426 {
427 int rc = KB_BagNotLoaded;
428 require_noerr_quiet(_service_kb_get_system(context->s_uid, handle_out), done);
429
430 rc = KB_Success;
431
432 done:
433 if (rc == KB_BagNotLoaded) {
434 if (service_kb_load(context, kcv) == KB_Success) {
435 if (_service_kb_get_system(context->s_uid, handle_out) == kIOReturnSuccess) {
436 rc = KB_Success;
437 }
438 }
439 }
440 return rc;
441 }
442
443 static void update_keybag_handle(keybag_handle_t handle)
444 {
445 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
446 uid_t uid = abs(handle);
447 uint8_t * buf = NULL;
448 size_t buf_size = 0;
449 service_user_record_t * ur = NULL;
450 char * bag_file = NULL;
451 uint64_t kcv = 0;
452
453 require_noerr(aks_save_bag(handle, (void**)&buf, (int*)&buf_size), done);
454 require(ur = get_user_record(uid), done);
455 require(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done);
456 require(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size, &kcv), done);
457
458 os_log(OS_LOG_DEFAULT, "successfully updated handle %d, save keybag kcv: 0x%0llx", handle, kcv);
459
460 done:
461 if (buf) free(buf);
462 if (ur) free_user_record(ur);
463 if (bag_file) free(bag_file);
464 });
465 }
466
467 static int
468 _kb_get_options_for_uid(uid_t uid, CFMutableDictionaryRef *options_out)
469 {
470 int result = KB_GeneralError;
471 CFMutableDictionaryRef options = NULL;
472 CFNumberRef cf_uid = NULL;
473
474 require(options_out, out);
475
476 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), out);
477 require(cf_uid = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &uid), out);
478 CFDictionaryAddValue(options, kKeyBagDeviceHandle, cf_uid);
479
480 *options_out = options;
481 options = NULL;
482
483 result = KB_Success;
484 out:
485 if (options) { CFRelease(options); }
486 if (cf_uid) { CFRelease(cf_uid); }
487
488 return result;
489 }
490
491 static int
492 _kb_set_properties(service_context_t * context, const void * secret, int secret_len)
493 {
494 int result = KB_GeneralError;
495 CFMutableDictionaryRef options = NULL;
496 CFDataRef passcode = NULL;
497
498 require_noerr(_kb_get_options_for_uid(context->s_uid, &options), done);
499
500 /* set user uuid, if not already set */
501 passcode = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, secret, secret_len, kCFAllocatorNull);
502 if (MKBKeyBagSetUserUUID(options, passcode)) {
503 os_log(OS_LOG_DEFAULT, "set user uuid failed");
504 }
505
506 #ifdef MKB_SUPPORTS_BIND_KEK
507 if (MKBKeyBagBindKEK(options, passcode)) {
508 os_log(OS_LOG_DEFAULT, "KEK bind failed");
509 }
510 #else
511 os_log(OS_LOG_DEFAULT, "Not bindinig KEK, update SDK");
512 #endif
513
514 result = KB_Success;
515 done:
516 if (options) { CFRelease(options); }
517 if (passcode) { CFRelease(passcode); }
518 return result;
519 }
520
521 static int
522 service_kb_create(service_context_t * context, const void * secret, int secret_len, uint64_t * kcv)
523 {
524 __block int rc = KB_GeneralError;
525
526 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
527 uint8_t * buf = NULL;
528 size_t buf_size = 0;
529 keybag_handle_t private_handle = bad_keybag_handle, session_handle = bad_keybag_handle;
530 service_user_record_t * ur = get_user_record(context->s_uid);
531 char * bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user);
532
533 require(bag_file, done);
534
535 // check for the existance of the bagfile
536 require_action(!_kb_bag_exists(ur, bag_file), done, rc = KB_BagExists);
537
538 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &private_handle), done);
539 require_noerr(rc = aks_save_bag(private_handle, (void**)&buf, (int*)&buf_size), done);
540 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size, kcv), done, rc = KB_BagError);
541 require_noerr(rc = _service_kb_set_system(private_handle, context->s_uid), done);
542 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
543
544 if (secret && rc == KB_Success) {
545 aks_unlock_bag(session_handle, secret, secret_len);
546 }
547
548 if (rc == KB_Success) {
549 _kb_set_properties(context, secret, secret_len);
550 }
551
552 done:
553 if (private_handle != bad_keybag_handle) {
554 aks_unload_bag(private_handle);
555 }
556 if (buf) free(buf);
557 if (bag_file) { free(bag_file); }
558 if (ur) free_user_record(ur);
559 });
560
561 return rc;
562 }
563
564 /* Load s_uid's keybag, unless already loaded */
565 static int
566 _service_kb_load_uid(uid_t s_uid, uint64_t * kcv)
567 {
568 __block int rc = KB_GeneralError;
569
570 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
571 uint8_t * buf = NULL;
572 size_t buf_size = 0;
573 keybag_handle_t private_handle = bad_keybag_handle, session_handle = bad_keybag_handle;
574 service_user_record_t * ur = NULL;
575 char * bag_file = NULL;
576 int _stage = 0;
577
578 rc = _service_kb_get_system(s_uid, &session_handle);
579 if (rc == kIOReturnNotFound) {
580 require_action(ur = get_user_record(s_uid), done, rc = KB_GeneralError; _stage = 1);
581 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError; _stage = 2);
582 require_action_quiet(_kb_load_bag_from_disk(ur, bag_file, &buf, &buf_size, kcv), done, rc = KB_BagNotFound; _stage = 3);
583 rc = aks_load_bag(buf, (int)buf_size, &private_handle);
584 switch (rc) {
585 case kAKSReturnBadDeviceKey:
586 case kAKSReturnBadSignature:
587 case kAKSReturnDecodeError:
588 case kAKSReturnPolicyInvalid:
589 os_log(OS_LOG_DEFAULT, "bag load failed 0x%x for uid (%i), discarding", rc, s_uid);
590 _kb_rename_bag_on_disk(ur, bag_file, kcv);
591 rc = KB_BagNotFound;
592 break;
593 case kAKSReturnSuccess:
594 /* nothing to do */
595 break;
596 default:
597 os_log(OS_LOG_DEFAULT, "bag load failed 0x%x for uid (%i)", rc, s_uid);
598 break;
599 }
600 require_noerr_action(rc, done, _stage = 4);
601 require_noerr_action(rc = _service_kb_set_system(private_handle, s_uid), done, _stage = 5);
602 }
603 require(rc == KB_Success, done);
604
605 done:
606 if (private_handle != bad_keybag_handle) {
607 aks_unload_bag(private_handle);
608 }
609 // this function should never fail unless bootstrapping the user for the first time, or rare conditions from aks_load_bag
610 if (rc != KB_Success) {
611 os_log(OS_LOG_DEFAULT, "%d: error %d loading keybag for uid (%i) at path: %s", _stage, rc, s_uid, bag_file);
612 }
613 if (buf) free(buf);
614 if (ur) free_user_record(ur);
615 if (bag_file) free(bag_file);
616 });
617
618 return rc;
619 }
620
621 static int
622 service_kb_load_uid(uid_t s_uid, uint64_t * kcv)
623 {
624 return _service_kb_load_uid(s_uid, kcv);
625 }
626
627 static int
628 service_kb_load(service_context_t * context, uint64_t * kcv)
629 {
630 return _service_kb_load_uid(context->s_uid, kcv);
631 }
632
633 static int
634 service_kb_unload(service_context_t *context)
635 {
636 __block int rc = KB_GeneralError;
637
638 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
639 keybag_handle_t session_handle = bad_keybag_handle;
640
641 rc = _service_kb_get_system(context->s_uid, &session_handle);
642 if (rc == kIOReturnNotFound) {
643 // No session bag, nothing to do
644 rc = KB_Success;
645 return;
646 } else if (rc != kIOReturnSuccess) {
647 os_log(OS_LOG_DEFAULT, "error locating session keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
648 rc = KB_BagError;
649 return;
650 }
651
652 rc = aks_unload_bag(session_handle);
653 if (rc != kAKSReturnSuccess) {
654 os_log(OS_LOG_DEFAULT, "error unloading keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
655 rc = KB_BagError;
656 } else {
657 os_log(OS_LOG_DEFAULT, "successfully unloaded keybag (%ld) for uid (%i) in session (%i)", (long)session_handle, context->s_uid, context->s_id);
658 }
659 });
660
661 return rc;
662 }
663
664 static int
665 service_kb_save(service_context_t * context, uint64_t * kcv)
666 {
667 __block int rc = KB_GeneralError;
668 keybag_handle_t session_handle;
669 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
670
671 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
672 uint8_t * buf = NULL;
673 size_t buf_size = 0;
674 service_user_record_t * ur = NULL;
675 char * bag_file = NULL;
676
677 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
678 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
679 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
680 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size, kcv), done, rc = KB_BagError);
681
682 rc = KB_Success;
683
684 done:
685 if (buf) free(buf);
686 if (ur) free_user_record(ur);
687 if (bag_file) free(bag_file);
688 return;
689 });
690
691 done:
692 return rc;
693 }
694
695 static int
696 service_kb_unlock(service_context_t * context, const void * secret, int secret_len, uint64_t * kcv)
697 {
698 int rc = KB_GeneralError;
699 keybag_handle_t session_handle;
700 CFDataRef passcode = NULL;
701 CFMutableDictionaryRef options = NULL;
702
703 require_noerr(_kb_get_options_for_uid(context->s_uid, &options), done);
704
705 /* technically, session_handle is not needed. Call this to handle lazy keybag loading */
706 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
707
708 require(passcode = CFDataCreateWithBytesNoCopy(NULL, secret, secret_len, kCFAllocatorNull), done);
709
710 rc = MKBUnlockDevice(passcode, options);
711 os_log_info(OS_LOG_DEFAULT, "MKBUnlockDevice result: (%ld), caller pid: %d", (long)rc, get_caller_pid(&context->procToken));
712
713 done:
714 if (options) { CFRelease(options); }
715 if (passcode) { CFRelease(passcode); }
716 return rc;
717 }
718
719 static int
720 service_kb_lock(service_context_t * context)
721 {
722 // this call has been disabled
723 return -1;
724 }
725
726 static int
727 service_kb_change_secret(service_context_t * context, const void * secret, int secret_len, const void * new_secret, int new_secret_len, uint64_t * kcv)
728 {
729 __block int rc = KB_GeneralError;
730 keybag_handle_t session_handle;
731 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
732
733 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
734 uint8_t * buf = NULL;
735 size_t buf_size = 0;
736 service_user_record_t * ur = NULL;
737 char * bag_file = NULL;
738
739 require_noerr(rc = aks_change_secret(session_handle, secret, secret_len, new_secret, new_secret_len, generation_noop, NULL), done);
740 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
741 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
742 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
743 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size, kcv), done, rc = KB_BagError);
744
745 rc = KB_Success;
746
747 done:
748 if (buf) free(buf);
749 if (ur) free_user_record(ur);
750 if (bag_file) free(bag_file);
751 return;
752 });
753
754 done:
755 return rc;
756 }
757
758 static int
759 service_kb_reset(service_context_t * context, const void * secret, int secret_len, uint64_t * kcv)
760 {
761 __block int rc = KB_GeneralError;
762 service_user_record_t * ur = NULL;
763 char * bag_file = NULL;
764
765 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
766 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
767
768 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
769 uint8_t * buf = NULL;
770 size_t buf_size = 0;
771 keybag_handle_t private_handle = bad_keybag_handle, session_handle = bad_keybag_handle;
772
773 os_log(OS_LOG_DEFAULT, "resetting keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
774 _kb_rename_bag_on_disk(ur, bag_file, kcv);
775
776 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &private_handle), done);
777 require_noerr(rc = aks_save_bag(private_handle, (void**)&buf, (int*)&buf_size), done);
778 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size, kcv), done, rc = KB_BagError);
779 require_noerr(rc = _service_kb_set_system(private_handle, context->s_uid), done);
780 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
781
782 if (secret && rc == KB_Success) {
783 aks_unlock_bag(session_handle, secret, secret_len);
784 }
785
786 if (rc == KB_Success) {
787 _kb_set_properties(context, secret, secret_len);
788 }
789
790 done:
791 if (private_handle != bad_keybag_handle) {
792 aks_unload_bag(private_handle);
793 }
794 if (buf) free(buf);
795 return;
796 });
797
798 done:
799 if (ur) free_user_record(ur);
800 if (bag_file) free(bag_file);
801 return rc;
802 }
803
804 static int
805 service_kb_is_locked(service_context_t * context, xpc_object_t reply, uint64_t * kcv)
806 {
807 int rc = KB_GeneralError;
808 keybag_state_t state;
809 keybag_handle_t session_handle;
810 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
811
812 require_noerr(rc = aks_get_lock_state(session_handle, &state), done);
813
814 xpc_dictionary_set_bool(reply, SERVICE_XPC_LOCKED, state & keybag_state_locked);
815 xpc_dictionary_set_bool(reply, SERVICE_XPC_NO_PIN, state & keybag_state_no_pin);
816
817 done:
818 return rc;
819 }
820
821 static int
822 service_kb_wrap_key(service_context_t *context, xpc_object_t event, xpc_object_t reply, uint64_t * kcv)
823 {
824 int rc = KB_GeneralError;
825 size_t sz;
826 const void *key;
827 int key_size;
828 keyclass_t key_class;
829 keybag_handle_t session_handle;
830 void *wrapped_key = NULL;
831 int wrapped_key_size;
832 keyclass_t wrapped_key_class;
833
834 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
835
836 key = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &sz);
837 require_action(key != NULL, done, rc = KB_GeneralError);
838 require_action(sz <= APPLE_KEYSTORE_MAX_KEY_LEN, done, rc = KB_GeneralError);
839 key_size = (int)sz;
840 key_class = (keyclass_t)xpc_dictionary_get_int64(event, SERVICE_XPC_KEYCLASS);
841
842 wrapped_key_size = APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN;
843 wrapped_key = calloc(1, wrapped_key_size);
844
845 rc = aks_wrap_key(key, key_size, key_class, session_handle, wrapped_key, &wrapped_key_size, &wrapped_key_class);
846 if (rc == KB_Success) {
847 xpc_dictionary_set_data(reply, SERVICE_XPC_WRAPPED_KEY, wrapped_key, wrapped_key_size);
848 xpc_dictionary_set_int64(reply, SERVICE_XPC_KEYCLASS, wrapped_key_class);
849 }
850
851 done:
852 free(wrapped_key);
853 return rc;
854 }
855
856 static int
857 service_kb_unwrap_key(service_context_t *context, xpc_object_t event, xpc_object_t reply, uint64_t * kcv)
858 {
859 int rc = KB_GeneralError;
860 size_t sz;
861 const void *wrapped_key;
862 int wrapped_key_size;
863 keyclass_t wrapped_key_class;
864 keybag_handle_t session_handle;
865 void *key = NULL;
866 int key_size;
867
868 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
869
870 wrapped_key = xpc_dictionary_get_data(event, SERVICE_XPC_WRAPPED_KEY, &sz);
871 require_action(wrapped_key != NULL, done, rc = KB_GeneralError);
872 require_action(sz <= APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN, done, rc = KB_GeneralError);
873 wrapped_key_size = (int)sz;
874 wrapped_key_class = (keyclass_t)xpc_dictionary_get_int64(event, SERVICE_XPC_KEYCLASS);
875
876 key_size = APPLE_KEYSTORE_MAX_KEY_LEN;
877 key = calloc(1, key_size);
878
879 rc = aks_unwrap_key(wrapped_key, wrapped_key_size, wrapped_key_class, session_handle, key, &key_size);
880 if (rc == KB_Success) {
881 xpc_dictionary_set_data(reply, SERVICE_XPC_KEY, key, key_size);
882 }
883
884 done:
885 free(key);
886 return rc;
887 }
888
889 static int
890 service_kb_stash_create(service_context_t * context, const void * key, unsigned key_size, uint64_t * kcv)
891 {
892 int rc = KB_GeneralError;
893 char * bag_file = NULL;
894 keybag_handle_t session_handle;
895 service_user_record_t * ur = NULL;
896 void * stashbag = NULL;
897 int stashbag_size = 0;
898 __block bool saved = false;
899
900 require(key, done);
901 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
902 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
903 require_noerr(rc = aks_stash_escrow(session_handle, true, key, key_size, NULL, 0, (void**)&stashbag, &stashbag_size), done);
904 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
905
906 // sync writing the bag to disk
907 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
908 saved = _kb_save_bag_to_disk(ur, bag_file, stashbag, stashbag_size, kcv);
909 });
910 require_action(saved, done, rc = KB_BagError);
911 rc = KB_Success;
912
913 done:
914 if (stashbag) { free(stashbag); }
915 if (bag_file) { free(bag_file); }
916 if (ur) free_user_record(ur);
917 return rc;
918 }
919
920 static int
921 service_kb_stash_load(service_context_t * context, const void * key, unsigned key_size, bool nondestructive, uint64_t * kcv)
922 {
923 __block int rc = KB_GeneralError;
924 char * bag_file = NULL;
925 keybag_handle_t session_handle;
926 service_user_record_t * ur = NULL;
927 __block uint8_t * stashbag = NULL;
928 __block size_t stashbag_size = 0;
929
930 require(key, done);
931 require_noerr(rc = _kb_get_session_handle(context, &session_handle, kcv), done);
932 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
933 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
934
935 // sync loading the bag from disk
936 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
937 if (!_kb_load_bag_from_disk(ur, bag_file, &stashbag, &stashbag_size, kcv)) {
938 rc = KB_BagError;
939 }
940 });
941 require_noerr(rc, done);
942
943 require_noerr(rc = aks_stash_escrow(session_handle, false, key, key_size, stashbag, (int)stashbag_size, NULL, NULL), done);
944 rc = KB_Success;
945
946 done:
947 if (stashbag) { free(stashbag); }
948 if ((bag_file) && (!nondestructive)) {
949 _kb_delete_bag_on_disk(ur, bag_file, kcv);
950 free(bag_file);
951 }
952 if (ur) free_user_record(ur);
953 return rc;
954 }
955
956 //
957 // Get the keychain master key from the AppleFDEKeyStore.
958 // Note that this is a one-time call - the master key is
959 // removed from the keystore after it is returned.
960 // Requires the entitlement: com.apple.private.securityd.keychain
961 //
962 OSStatus service_stash_get_key(service_context_t * context, xpc_object_t event, xpc_object_t reply, uint64_t * kcv)
963 {
964 getStashKey_InStruct_t inStruct;
965 getStashKey_OutStruct_t outStruct;
966 size_t outSize = sizeof(outStruct);
967 kern_return_t kr = KERN_INVALID_ARGUMENT;
968
969 io_connect_t conn = openiodev();
970 require(conn, done);
971 inStruct.type = kAppleFDEKeyStoreStash_master;
972
973 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_getStashKey,
974 NULL, 0,
975 &inStruct, sizeof(inStruct),
976 NULL, NULL,
977 &outStruct, &outSize);
978
979 if (kr == KERN_SUCCESS) {
980 xpc_dictionary_set_data(reply, SERVICE_XPC_KEY, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize);
981 service_kb_stash_load(context, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize, false, kcv);
982 } else {
983 os_log(OS_LOG_DEFAULT, "failed to get stash key: %d", (int)kr);
984 }
985
986 done:
987 if (conn)
988 closeiodev(conn);
989
990 return kr;
991 }
992
993 //
994 // Stash the keychain master key in the AppleFDEKeyStore and
995 // flag it as the keychain master key to be added to the
996 // reboot NVRAM blob.
997 // This requires two calls to the AKS: the first to store the
998 // key and get its uuid. The second uses the uuid to flag the
999 // key for blob inclusion.
1000 //
1001 OSStatus service_stash_set_key(service_context_t * context, xpc_object_t event, xpc_object_t reply, uint64_t * kcv)
1002 {
1003 kern_return_t kr = KERN_INVALID_ARGUMENT;
1004 io_connect_t conn = IO_OBJECT_NULL;
1005 size_t keydata_len = 0;
1006 size_t len;
1007
1008 keybag_state_t state;
1009 keybag_handle_t session_handle;
1010 require_noerr(_kb_get_session_handle(context, &session_handle, kcv), done);
1011 require_noerr(aks_get_lock_state(session_handle, &state), done);
1012 require_action(!(state & keybag_lock_locked), done, kr = CSSMERR_CSP_OS_ACCESS_DENIED; LOG("stash failed keybag locked"));
1013
1014 conn = openiodev();
1015 require(conn, done);
1016
1017 // Store the key in the keystore and get its uuid
1018 setKeyGetUUID_InStruct_t inStruct1;
1019 uuid_OutStruct_t outStruct1;
1020
1021
1022 const uint8_t *keydata = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &keydata_len);
1023 require(keydata, done);
1024
1025 memcpy(&inStruct1.inKey.key.key, keydata, keydata_len);
1026 inStruct1.inKey.key.keysize = (cryptosize_t) keydata_len;
1027 len = sizeof(outStruct1);
1028 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setKeyGetUUID,
1029 NULL, 0,
1030 &inStruct1, sizeof(inStruct1),
1031 NULL, NULL,
1032 &outStruct1, &len);
1033 require(kr == KERN_SUCCESS, done);
1034
1035 // Now using the uuid stash it as the master key
1036 setStashKey_InStruct_t inStruct2;
1037 memcpy(&inStruct2.uuid, &outStruct1.uuid, sizeof(outStruct1.uuid));
1038 inStruct2.type = kAppleFDEKeyStoreStash_master;
1039
1040 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setStashKey,
1041 NULL, 0,
1042 &inStruct2, sizeof(inStruct2),
1043 NULL, NULL,
1044 NULL, NULL);
1045
1046 if (kr == KERN_SUCCESS) {
1047 service_kb_stash_create(context, keydata, (unsigned)keydata_len, kcv);
1048 }
1049 done:
1050 os_log(OS_LOG_DEFAULT, "set stashkey %d", (int)kr);
1051
1052 if (conn)
1053 closeiodev(conn);
1054
1055 return kr;
1056 }
1057
1058 //
1059 // Load the master stash key
1060 //
1061 OSStatus service_stash_load_key(service_context_t * context, xpc_object_t event, xpc_object_t reply, uint64_t * kcv)
1062 {
1063 kern_return_t kr = KERN_SUCCESS;
1064 size_t keydata_len = 0;
1065
1066 const uint8_t *keydata = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &keydata_len);
1067 require(keydata, done);
1068
1069 kr = service_kb_stash_load(context, keydata, (cryptosize_t) keydata_len, true, kcv);
1070 done:
1071
1072 return kr;
1073 }
1074
1075 //
1076 // Signal the AppleFDEKeyStore to take the tagged FDE key
1077 // and keychain master key, stash them in an encrypted
1078 // blob structure and write the blob to NVRAM. The random
1079 // encryption key is written to the SMC.
1080 //
1081 #if DEBUG
1082 OSStatus service_stash_blob(xpc_object_t event, xpc_object_t reply)
1083 {
1084 kern_return_t kr = KERN_INVALID_ARGUMENT;
1085
1086 io_connect_t conn = openiodev();
1087 require(conn, done);
1088
1089 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_commitStash,
1090 NULL, 0,
1091 NULL, 0,
1092 NULL, NULL,
1093 NULL, NULL);
1094 done:
1095 if (conn)
1096 closeiodev(conn);
1097
1098 return kr;
1099 }
1100 #endif
1101
1102 bool peer_has_entitlement(xpc_connection_t peer, const char * entitlement)
1103 {
1104 bool entitled = false;
1105
1106 xpc_object_t value = xpc_connection_copy_entitlement_value(peer, entitlement);
1107 if (value && (xpc_get_type(value) == XPC_TYPE_BOOL)) {
1108 entitled = xpc_bool_get_value(value);
1109 }
1110
1111 if (value) xpc_release(value);
1112 return entitled;
1113 }
1114
1115 static char * sel_to_char(uint64_t sel)
1116 {
1117 switch (sel) {
1118 case SERVICE_STASH_SET_KEY:
1119 return "set_key";
1120 case SERVICE_STASH_GET_KEY:
1121 return "get_key";
1122 case SERVICE_STASH_BLOB:
1123 return "stash_blob";
1124 case SERVICE_KB_LOAD:
1125 return "kb_load";
1126 case SERVICE_KB_SAVE:
1127 return "kb_save";
1128 case SERVICE_KB_UNLOCK:
1129 return "kb_unlock";
1130 case SERVICE_KB_LOCK:
1131 return "kb_lock";
1132 case SERVICE_KB_CHANGE_SECRET:
1133 return "kb_change_secret";
1134 case SERVICE_KB_CREATE:
1135 return "kb_create";
1136 case SERVICE_KB_IS_LOCKED:
1137 return "kb_is_locked";
1138 case SERVICE_KB_RESET:
1139 return "kb_reset";
1140 case SERVICE_KB_UNLOAD:
1141 return "kb_unload";
1142 case SERVICE_KB_LOAD_UID:
1143 return "kb_load_uid";
1144 case SERVICE_KB_WRAP_KEY:
1145 return "kb_wrap_key";
1146 case SERVICE_KB_UNWRAP_KEY:
1147 return "kb_unwrap_key";
1148 default:
1149 return "unknown";
1150 }
1151 }
1152
1153 static char * err_to_char(int err)
1154 {
1155 switch (err) {
1156 case KB_Success:
1157 return "success";
1158 case KB_GeneralError:
1159 return "general error";
1160 case KB_BagNotFound:
1161 return "bag not found";
1162 case KB_BagError:
1163 return "bag error";
1164 case KB_BagNotLoaded:
1165 return "bag not loaded";
1166 case KB_BagExists:
1167 return "bag exists";
1168 case KB_InvalidSession:
1169 return "invalid session";
1170 default:
1171 return "";
1172 }
1173 }
1174
1175 static bool log_kcv(uint64_t request)
1176 {
1177 if ((request == SERVICE_KB_CREATE) ||
1178 (request == SERVICE_KB_LOAD) ||
1179 (request == SERVICE_KB_SAVE) ||
1180 (request == SERVICE_KB_UNLOCK) ||
1181 (request == SERVICE_KB_CHANGE_SECRET) ||
1182 (request == SERVICE_KB_RESET) ||
1183 (request == SERVICE_KB_IS_LOCKED) ||
1184 (request == SERVICE_STASH_GET_KEY) ||
1185 (request == SERVICE_STASH_SET_KEY) ||
1186 (request == SERVICE_STASH_LOAD_KEY) ||
1187 (request == SERVICE_KB_LOAD_UID) ||
1188 (request == SERVICE_KB_WRAP_KEY) ||
1189 (request == SERVICE_KB_UNWRAP_KEY)) {
1190
1191 return true;
1192 }
1193 return false;
1194 }
1195
1196 void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event)
1197 {
1198 xpc_type_t type = xpc_get_type(event);
1199 uid_t uid;
1200
1201 if (type == XPC_TYPE_ERROR) {
1202 if (event == XPC_ERROR_CONNECTION_INVALID) {
1203 }
1204 } else {
1205 assert(type == XPC_TYPE_DICTIONARY);
1206
1207 int rc = KB_GeneralError;
1208 uint64_t request = 0;
1209 const uint8_t * secret = NULL, * new_secret = NULL;
1210 size_t secret_len = 0, new_secret_len = 0, data_len = 0;
1211 service_context_t * context = NULL;
1212 bool free_context = false;
1213 const void * data;
1214 const char *entitlement;
1215 uint64_t kcv = 0;
1216
1217 xpc_object_t reply = xpc_dictionary_create_reply(event);
1218
1219 request = xpc_dictionary_get_uint64(event, SERVICE_XPC_REQUEST);
1220
1221
1222 // For SERVICE_KB_{UNLOAD,LOAD} only, allow non-securityd, non-root but
1223 // entitled callers.
1224 if (request == SERVICE_KB_UNLOAD || request == SERVICE_KB_LOAD_UID) {
1225 switch (request) {
1226 case SERVICE_KB_UNLOAD:
1227 entitlement = "com.apple.private.securityd.keybag-unload";
1228 break;
1229 case SERVICE_KB_LOAD_UID:
1230 entitlement = "com.apple.private.securityd.keybag-load";
1231 break;
1232 }
1233 if (!peer_has_entitlement(connection, entitlement) && !peer_has_entitlement(connection, "com.apple.keystore.device")) {
1234 xpc_connection_cancel(connection);
1235 return;
1236 }
1237 } else {
1238 if (xpc_connection_get_euid(connection) != 0) {
1239 xpc_connection_cancel(connection);
1240 return;
1241 }
1242 if (!check_signature(connection)) {
1243 xpc_connection_cancel(connection);
1244 return;
1245 }
1246 }
1247
1248 data = xpc_dictionary_get_data(event, SERVICE_XPC_CONTEXT, &data_len);
1249 require_action(data || request == SERVICE_KB_UNLOAD || request == SERVICE_KB_LOAD_UID, done, rc = KB_GeneralError);
1250 if (data) {
1251 require(data_len == sizeof(service_context_t), done);
1252 context = (service_context_t*)data;
1253 } else {
1254 audit_token_t audit_token = { 0 };
1255 xpc_connection_get_audit_token(connection, &audit_token);
1256 context = calloc(1, sizeof(service_context_t));
1257 context->s_id = xpc_connection_get_asid(connection);
1258 context->s_uid = xpc_connection_get_euid(connection);
1259 context->procToken = audit_token;
1260 free_context = true;
1261 }
1262
1263 require_action(context->s_id != AU_DEFAUDITSID, done, rc = KB_InvalidSession);
1264 require_action(context->s_uid != AU_DEFAUDITID, done, rc = KB_InvalidSession); // we only want to work in actual user sessions.
1265
1266 switch (request) {
1267 case SERVICE_KB_CREATE:
1268 // if (kb_service_has_entitlement(peer, "com.apple.keystore.device")) {
1269 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1270 rc = service_kb_create(context, secret, (int)secret_len, &kcv);
1271 // }
1272 break;
1273 case SERVICE_KB_LOAD:
1274 rc = service_kb_load(context, &kcv);
1275 break;
1276 case SERVICE_KB_UNLOAD:
1277 rc = service_kb_unload(context);
1278 break;
1279 case SERVICE_KB_SAVE:
1280 rc = service_kb_save(context, &kcv);
1281 break;
1282 case SERVICE_KB_UNLOCK:
1283 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1284 rc = service_kb_unlock(context, secret, (int)secret_len, &kcv);
1285 break;
1286 case SERVICE_KB_LOCK:
1287 rc = service_kb_lock(context);
1288 break;
1289 case SERVICE_KB_CHANGE_SECRET:
1290 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1291 new_secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET_NEW, &new_secret_len);
1292 rc = service_kb_change_secret(context, secret, (int)secret_len, new_secret, (int)new_secret_len, &kcv);
1293 break;
1294 case SERVICE_KB_RESET:
1295 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1296 rc = service_kb_reset(context, secret, (int)secret_len, &kcv);
1297 break;
1298 case SERVICE_KB_IS_LOCKED:
1299 rc = service_kb_is_locked(context, reply, &kcv);
1300 break;
1301 case SERVICE_STASH_GET_KEY:
1302 rc = service_stash_get_key(context, event, reply, &kcv);
1303 break;
1304 case SERVICE_STASH_SET_KEY:
1305 rc = service_stash_set_key(context, event, reply, &kcv);
1306 break;
1307 case SERVICE_STASH_LOAD_KEY:
1308 rc = service_stash_load_key(context, event, reply, &kcv);
1309 break;
1310 case SERVICE_KB_LOAD_UID:
1311 uid = (uid_t)xpc_dictionary_get_uint64(event, SERVICE_XPC_UID);
1312 rc = service_kb_load_uid(uid, &kcv);
1313 break;
1314 case SERVICE_KB_WRAP_KEY:
1315 rc = service_kb_wrap_key(context, event, reply, &kcv);
1316 break;
1317 case SERVICE_KB_UNWRAP_KEY:
1318 rc = service_kb_unwrap_key(context, event, reply, &kcv);
1319 break;
1320 #if DEBUG
1321 case SERVICE_STASH_BLOB:
1322 rc = service_stash_blob(event, reply);
1323 break;
1324 #endif
1325 default:
1326 LOG("unknown service type");
1327 break;
1328 }
1329
1330 done:
1331 {
1332 char log[200] = { 0 };
1333 int count = snprintf(log, sizeof(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);
1334 if (log_kcv(request) && (count < sizeof(log) - 1) && (count > 0) && (kcv > 0)) {
1335 count = snprintf(log + count, sizeof(log) - count, ", kcv: 0x%0llx", kcv);
1336 }
1337 if (count > 0) {
1338 #if DEBUG
1339 LOG("%s", log);
1340 #else
1341 if ((rc != 0) || log_kcv(request)) {
1342 os_log(OS_LOG_DEFAULT, "%s", log);
1343 }
1344 #endif
1345 }
1346 }
1347 xpc_dictionary_set_int64(reply, SERVICE_XPC_RC, rc);
1348 xpc_connection_send_message(connection, reply);
1349 xpc_release(reply);
1350 if (free_context) {
1351 free(context);
1352 }
1353 }
1354 }
1355
1356 bool check_signature(xpc_connection_t connection)
1357 {
1358 #if !(DEBUG || RC_BUILDIT_YES)
1359 audit_token_t token;
1360
1361 xpc_connection_get_audit_token(connection, &token);
1362
1363 SecTaskRef task = SecTaskCreateWithAuditToken(NULL, token);
1364 if (task == NULL) {
1365 os_log(OS_LOG_DEFAULT, "failed getting SecTaskRef of the client");
1366 return false;
1367 }
1368
1369 uint32_t flags = SecTaskGetCodeSignStatus(task);
1370 /* check if valid and platform binary, but not platform path */
1371 if ((flags & (CS_VALID | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_VALID | CS_PLATFORM_BINARY)) {
1372 os_log(OS_LOG_DEFAULT, "client is not a platform binary: %0x08x", flags);
1373 CFRelease(task);
1374 return false;
1375 }
1376
1377 CFStringRef signingIdentity = SecTaskCopySigningIdentifier(task, NULL);
1378 CFRelease(task);
1379 if (signingIdentity == NULL) {
1380 os_log(OS_LOG_DEFAULT, "client have no code sign identity");
1381 return false;
1382 }
1383
1384 bool res = CFEqual(signingIdentity, CFSTR("com.apple.securityd"));
1385 CFRelease(signingIdentity);
1386
1387 if (!res)
1388 os_log(OS_LOG_DEFAULT, "client is not not securityd");
1389
1390 return res;
1391 #else
1392 return true;
1393 #endif
1394 }
1395
1396 static void register_for_notifications()
1397 {
1398 __block kern_return_t kr;
1399 static mach_port_t mp = MACH_PORT_NULL;
1400
1401 static dispatch_once_t onceToken = 0;
1402 dispatch_once(&onceToken, ^{
1403 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
1404 if (kr == KERN_SUCCESS) {
1405 dispatch_source_t mach_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1406 dispatch_source_set_event_handler(mach_src, ^{
1407 mach_msg_return_t mr;
1408 uint8_t buf[sizeof(aks_notification_msg_t) + MAX_TRAILER_SIZE] = {};
1409 aks_notification_msg_t * msg = (aks_notification_msg_t*)buf;
1410 mr = mach_msg((mach_msg_header_t*)&buf, MACH_RCV_MSG, 0, sizeof(buf), mp, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
1411 if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_MSGID) {
1412 // ignored for now
1413 } else if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG) {
1414 os_log(OS_LOG_DEFAULT, "request to update handle %d", msg->handle);
1415 update_keybag_handle(msg->handle);
1416 } else {
1417 os_log(OS_LOG_DEFAULT, "mach_msg error: %x", mr);
1418 }
1419 });
1420 dispatch_resume(mach_src);
1421 } else {
1422 os_log(OS_LOG_DEFAULT, "failed to create notification port");
1423 }
1424
1425 });
1426
1427 kr = aks_register_for_notifications(mp, AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG);
1428 if (kr == KERN_SUCCESS) {
1429 os_log(OS_LOG_DEFAULT, "registered for notifications");
1430 } else {
1431 os_log(OS_LOG_DEFAULT, "failed to register for notifications %d", kr);
1432 }
1433 }
1434
1435 int main(int argc, const char * argv[])
1436 {
1437 char * errorbuf;
1438 if (sandbox_init(SECURITYD_SERVICE_NAME, SANDBOX_NAMED, &errorbuf) != 0) {
1439 os_log(OS_LOG_DEFAULT, "sandbox_init failed %s", errorbuf);
1440 sandbox_free_error(errorbuf);
1441 #ifndef DEBUG
1442 abort();
1443 #endif
1444 }
1445
1446 register_for_notifications();
1447
1448 xpc_connection_t listener = xpc_connection_create_mach_service(SECURITYD_SERVICE_NAME, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
1449 xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
1450 // It is safe to cast 'peer' to xpc_connection_t assuming
1451 // we have a correct configuration in our launchd.plist.
1452 xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
1453 vproc_transaction_t transaction = vproc_transaction_begin(NULL);
1454 service_peer_event_handler(peer, event);
1455 vproc_transaction_end(NULL, transaction);
1456 });
1457 xpc_connection_resume(peer);
1458 });
1459 xpc_connection_resume(listener);
1460
1461 dispatch_main();
1462 }
1463