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