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