1 /* Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. */
3 #include "securityd_service.h"
4 #include "securityd_service_client.h"
10 #include <xpc/private.h>
11 #include <dispatch/dispatch.h>
12 #include <sys/types.h>
14 #include <sys/codesign.h>
21 #include <uuid/uuid.h>
22 #include <bsm/libbsm.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>
30 #include <IOKit/IOKitLib.h>
31 #include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
34 #define LOG(...) syslog(LOG_ERR, ##__VA_ARGS__);
39 static bool check_signature(xpc_connection_t connection
);
41 static pid_t
get_caller_pid(audit_token_t
* token
)
45 audit_token_to_au32(*token
, NULL
, NULL
, NULL
, NULL
, NULL
, &pid
, NULL
, NULL
);
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
);
54 const char * kb_home_path
= "Library/Keychains";
55 const char * kb_user_bag
= "user.kb";
56 const char * kb_stash_bag
= "stash.kb";
58 #define HEXBUF_LEN 2048
65 } service_user_record_t
;
75 io_registry_entry_t service
;
79 service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOServiceMatching(kAppleFDEKeyStoreServiceName
));
80 if (service
== IO_OBJECT_NULL
)
81 return IO_OBJECT_NULL
;
83 kr
= IOServiceOpen(service
, mach_task_self(), 0, &conn
);
84 if (kr
!= KERN_SUCCESS
)
85 return IO_OBJECT_NULL
;
87 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStoreUserClientOpen
, NULL
, 0, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
88 if (kr
!= KERN_SUCCESS
) {
90 return IO_OBJECT_NULL
;
97 closeiodev(io_connect_t conn
)
100 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStoreUserClientClose
, NULL
, 0, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
101 if (kr
!= KERN_SUCCESS
)
103 IOServiceClose(conn
);
106 static dispatch_queue_t
107 _kb_service_get_dispatch_queue()
109 static dispatch_once_t onceToken
= 0;
110 static dispatch_queue_t connection_queue
= NULL
;
112 dispatch_once(&onceToken
, ^{
113 connection_queue
= dispatch_queue_create("kb-service-queue", DISPATCH_QUEUE_SERIAL
);
116 return connection_queue
;
119 static service_user_record_t
* get_user_record(uid_t uid
)
121 service_user_record_t
* ur
= NULL
;
123 if ((bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
)) == -1) {
127 struct passwd pwbuf
, *pw
= NULL
;
128 if ((getpwuid_r(uid
, &pwbuf
, buf
, bufsize
, &pw
) == 0) && pw
!= NULL
) {
129 ur
= calloc(1u, sizeof(service_user_record_t
));
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
);
136 syslog(LOG_ERR
, "failed to lookup user record for uid: %d", uid
);
143 static void free_user_record(service_user_record_t
* ur
)
156 static const char * get_host_uuid()
158 static uuid_string_t hostuuid
= {};
159 static dispatch_once_t onceToken
;
160 dispatch_once(&onceToken
, ^{
161 struct timespec timeout
= {30, 0};
163 if (gethostuuid(uuid
, &timeout
) == 0) {
164 uuid_unparse(uuid
, hostuuid
);
166 syslog(LOG_ERR
, "failed to get host uuid");
174 _kb_copy_bag_filename(service_user_record_t
* ur
, kb_bag_type_t type
)
176 char * bag_file
= NULL
;
177 const char * name
= NULL
;
181 case kb_bag_type_user
:
184 case kb_bag_type_stash
:
191 bag_file
= calloc(1u, PATH_MAX
);
192 require(bag_file
, done
);
194 snprintf(bag_file
, PATH_MAX
, "%s/%s/%s/%s", ur
->home
, kb_home_path
, get_host_uuid(), name
);
201 _kb_verify_create_path(service_user_record_t
* ur
)
203 bool created
= false;
204 struct stat st_info
= {};
205 char new_path
[PATH_MAX
] = {};
206 char kb_path
[PATH_MAX
] = {};
207 snprintf(kb_path
, sizeof(kb_path
), "%s/%s/%s", ur
->home
, kb_home_path
, get_host_uuid());
208 if (lstat(kb_path
, &st_info
) == 0) {
209 if (S_ISDIR(st_info
.st_mode
)) {
212 syslog(LOG_ERR
, "invalid directory at '%s' moving aside", kb_path
);
213 snprintf(new_path
, sizeof(new_path
), "%s-invalid", kb_path
);
215 if (rename(kb_path
, new_path
) != 0) {
216 syslog(LOG_ERR
, "failed to rename file: %s (%s)", kb_path
, strerror(errno
));
222 require_action(mkpath_np(kb_path
, 0700) == 0, done
, syslog(LOG_ERR
, "could not create path: %s (%s)", kb_path
, strerror(errno
)));
231 _set_thread_credentials(service_user_record_t
* ur
)
233 int rc
= pthread_setugid_np(ur
->uid
, ur
->gid
);
234 if (rc
) { syslog(LOG_ERR
, "failed to set thread credential: %i (%s)", errno
, strerror(errno
)); }
236 rc
= initgroups(ur
->name
, ur
->gid
);
237 if (rc
) { syslog(LOG_ERR
, "failed to initgroups: %i", rc
); }
241 _clear_thread_credentials()
243 int rc
= pthread_setugid_np(KAUTH_UID_NONE
, KAUTH_GID_NONE
);
244 if (rc
) { syslog(LOG_ERR
, "failed to reset thread credential: %i (%s)", errno
, strerror(errno
)); }
248 _kb_bag_exists(service_user_record_t
* ur
, const char * bag_file
)
251 struct stat st_info
= {};
252 char new_file
[PATH_MAX
] = {};
256 _set_thread_credentials(ur
);
257 if (lstat(bag_file
, &st_info
) == 0) {
258 if (S_ISREG(st_info
.st_mode
)) {
261 syslog(LOG_ERR
, "invalid file at '%s' moving aside", bag_file
);
262 snprintf(new_file
, sizeof(new_file
), "%s-invalid", bag_file
);
264 if (rename(bag_file
, new_file
) != 0) {
265 syslog(LOG_ERR
, "failed to rename file: %s (%s)", bag_file
, strerror(errno
));
271 _clear_thread_credentials();
276 _kb_save_bag_to_disk(service_user_record_t
* ur
, const char * bag_file
, void * data
, size_t length
)
281 require(bag_file
, done
);
283 _set_thread_credentials(ur
);
284 require(_kb_verify_create_path(ur
), done
);
286 fd
= open(bag_file
, O_CREAT
| O_TRUNC
| O_WRONLY
| O_NOFOLLOW
, 0600);
287 require_action(fd
!= -1, done
, syslog(LOG_ERR
, "could not create file: %s (%s)", bag_file
, strerror(errno
)));
288 require_action(write(fd
, data
, length
) != -1, done
, syslog(LOG_ERR
, "failed to write keybag to disk %s", strerror(errno
)));
293 if (fd
!= -1) { close(fd
); }
294 _clear_thread_credentials();
299 _kb_load_bag_from_disk(service_user_record_t
* ur
, const char * bag_file
, uint8_t ** data
, size_t * length
)
303 uint8_t * buf
= NULL
;
305 struct stat st_info
= {};
307 require(bag_file
, done
);
309 _set_thread_credentials(ur
);
310 require(_kb_verify_create_path(ur
), done
);
311 require_quiet(lstat(bag_file
, &st_info
) == 0, done
);
312 require_action(S_ISREG(st_info
.st_mode
), done
, syslog(LOG_ERR
, "failed to load, not a file: %s", bag_file
));
313 buf_size
= (size_t)st_info
.st_size
;
315 fd
= open(bag_file
, O_RDONLY
| O_NOFOLLOW
);
316 require_action(fd
!= -1, done
, syslog(LOG_ERR
, "could not open file: %s (%s)", bag_file
, strerror(errno
)));
318 buf
= (uint8_t *)calloc(1u, buf_size
);
319 require(buf
!= NULL
, done
);
320 require(read(fd
, buf
, buf_size
) == buf_size
, done
);
328 if (fd
!= -1) { close(fd
); }
329 if (buf
) { free(buf
); }
330 _clear_thread_credentials();
335 _kb_rename_bag_on_disk(service_user_record_t
* ur
, const char * bag_file
)
337 char new_file
[PATH_MAX
] = {};
339 _set_thread_credentials(ur
);
340 snprintf(new_file
, sizeof(new_file
), "%s-invalid", bag_file
);
342 rename(bag_file
, new_file
);
343 _clear_thread_credentials();
348 _kb_delete_bag_on_disk(service_user_record_t
* ur
, const char * bag_file
)
351 _set_thread_credentials(ur
);
353 _clear_thread_credentials();
357 static int service_kb_load(service_context_t
*context
);
358 static int service_kb_load_uid(uid_t s_uid
);
361 _kb_get_session_handle(service_context_t
* context
, keybag_handle_t
* handle_out
)
363 int rc
= KB_BagNotLoaded
;
364 require_noerr_quiet(aks_get_system(context
->s_uid
, handle_out
), done
);
369 if (rc
== KB_BagNotLoaded
) {
370 if (service_kb_load(context
) == KB_Success
) {
371 if (aks_get_system(context
->s_uid
, handle_out
) == kIOReturnSuccess
) {
379 static void update_keybag_handle(keybag_handle_t handle
)
381 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
382 uid_t uid
= abs(handle
);
383 uint8_t * buf
= NULL
;
385 service_user_record_t
* ur
= NULL
;
386 char * bag_file
= NULL
;
388 require_noerr(aks_save_bag(handle
, (void**)&buf
, (int*)&buf_size
), done
);
389 require(ur
= get_user_record(uid
), done
);
390 require(bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_user
), done
);
391 require(_kb_save_bag_to_disk(ur
, bag_file
, buf
, buf_size
), done
);
393 syslog(LOG_NOTICE
, "successfully updated handle %d", handle
);
397 if (ur
) free_user_record(ur
);
398 if (bag_file
) free(bag_file
);
403 service_kb_create(service_context_t
* context
, const void * secret
, int secret_len
)
405 __block
int rc
= KB_GeneralError
;
407 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
408 uint8_t * buf
= NULL
;
410 keybag_handle_t session_handle
= bad_keybag_handle
;
411 service_user_record_t
* ur
= get_user_record(context
->s_uid
);
412 char * bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_user
);
414 require(bag_file
, done
);
416 // check for the existance of the bagfile
417 require_action(!_kb_bag_exists(ur
, bag_file
), done
, rc
= KB_BagExists
);
419 require_noerr(rc
= aks_create_bag(secret
, secret_len
, kAppleKeyStoreDeviceBag
, &session_handle
), done
);
420 require_noerr(rc
= aks_save_bag(session_handle
, (void**)&buf
, (int*)&buf_size
), done
);
421 require_action(_kb_save_bag_to_disk(ur
, bag_file
, buf
, buf_size
), done
, rc
= KB_BagError
);
422 require_noerr(rc
= aks_set_system(session_handle
, context
->s_uid
), done
);
423 aks_unload_bag(session_handle
);
424 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
426 if (secret
&& rc
== KB_Success
) {
427 aks_unlock_bag(session_handle
, secret
, secret_len
);
432 if (bag_file
) { free(bag_file
); }
433 if (ur
) free_user_record(ur
);
439 /* Load s_uid's keybag, unless already loaded */
441 _service_kb_load_uid(uid_t s_uid
)
443 __block
int rc
= KB_GeneralError
;
445 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
446 uint8_t * buf
= NULL
;
448 keybag_handle_t session_handle
= bad_keybag_handle
;
449 service_user_record_t
* ur
= NULL
;
450 char * bag_file
= NULL
;
452 rc
= aks_get_system(s_uid
, &session_handle
);
453 if (rc
== kIOReturnNotFound
) {
454 require_action(ur
= get_user_record(s_uid
), done
, rc
= KB_GeneralError
);
455 require_action(bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_user
), done
, rc
= KB_GeneralError
);
456 require_action_quiet(_kb_load_bag_from_disk(ur
, bag_file
, &buf
, &buf_size
), done
, rc
= KB_BagNotFound
);
457 rc
= aks_load_bag(buf
, (int)buf_size
, &session_handle
);
458 if (rc
== kIOReturnNotPermitted
) {
459 syslog(LOG_ERR
, "error loading keybag for uid (%i)", s_uid
);
460 _kb_rename_bag_on_disk(ur
, bag_file
);
463 require_noerr(rc
, done
);
464 require_noerr(rc
= aks_set_system(session_handle
, s_uid
), done
);
465 aks_unload_bag(session_handle
);
467 require(rc
== KB_Success
, done
);
471 if (ur
) free_user_record(ur
);
472 if (bag_file
) free(bag_file
);
479 service_kb_load_uid(uid_t s_uid
)
481 return _service_kb_load_uid(s_uid
);
485 service_kb_load(service_context_t
* context
)
487 return _service_kb_load_uid(context
->s_uid
);
491 service_kb_unload(service_context_t
*context
)
493 __block
int rc
= KB_GeneralError
;
495 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
496 keybag_handle_t session_handle
= bad_keybag_handle
;
498 rc
= aks_get_system(context
->s_uid
, &session_handle
);
499 if (rc
== kIOReturnNotFound
) {
500 // No session bag, nothing to do
503 } else if (rc
!= kIOReturnSuccess
) {
504 syslog(LOG_ERR
, "error locating session keybag for uid (%i) in session (%i)", context
->s_uid
, context
->s_id
);
509 rc
= aks_unload_bag(session_handle
);
510 if (rc
!= kAKSReturnSuccess
) {
511 syslog(LOG_ERR
, "error unloading keybag for uid (%i) in session (%i)", context
->s_uid
, context
->s_id
);
514 syslog(LOG_ERR
, "successfully unloaded keybag (%ld) for uid (%i) in session (%i)", (long)session_handle
, context
->s_uid
, context
->s_id
);
522 service_kb_save(service_context_t
* context
)
524 __block
int rc
= KB_GeneralError
;
525 keybag_handle_t session_handle
;
526 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
528 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
529 uint8_t * buf
= NULL
;
531 service_user_record_t
* ur
= NULL
;
532 char * bag_file
= NULL
;
534 require_noerr(rc
= aks_save_bag(session_handle
, (void**)&buf
, (int*)&buf_size
), done
);
535 require_action(ur
= get_user_record(context
->s_uid
), done
, rc
= KB_GeneralError
);
536 require_action(bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_user
), done
, rc
= KB_GeneralError
);
537 require_action(_kb_save_bag_to_disk(ur
, bag_file
, buf
, buf_size
), done
, rc
= KB_BagError
);
543 if (ur
) free_user_record(ur
);
544 if (bag_file
) free(bag_file
);
553 service_kb_unlock(service_context_t
* context
, const void * secret
, int secret_len
)
555 int rc
= KB_GeneralError
;
556 keybag_handle_t session_handle
;
557 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
559 rc
= aks_unlock_bag(session_handle
, secret
, secret_len
);
562 syslog(LOG_NOTICE
, "aks_unlock_bag result: (%ld)", (long)rc
);
567 service_kb_lock(service_context_t
* context
)
569 // this call has been disabled
574 service_kb_change_secret(service_context_t
* context
, const void * secret
, int secret_len
, const void * new_secret
, int new_secret_len
)
576 __block
int rc
= KB_GeneralError
;
577 keybag_handle_t session_handle
;
578 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
580 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
581 uint8_t * buf
= NULL
;
583 service_user_record_t
* ur
= NULL
;
584 char * bag_file
= NULL
;
586 require_noerr(rc
= aks_change_secret(session_handle
, secret
, secret_len
, new_secret
, new_secret_len
, NULL
, NULL
), done
);
587 require_noerr(rc
= aks_save_bag(session_handle
, (void**)&buf
, (int*)&buf_size
), done
);
588 require_action(ur
= get_user_record(context
->s_uid
), done
, rc
= KB_GeneralError
);
589 require_action(bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_user
), done
, rc
= KB_GeneralError
);
590 require_action(_kb_save_bag_to_disk(ur
, bag_file
, buf
, buf_size
), done
, rc
= KB_BagError
);
596 if (ur
) free_user_record(ur
);
597 if (bag_file
) free(bag_file
);
606 service_kb_reset(service_context_t
* context
, const void * secret
, int secret_len
)
608 __block
int rc
= KB_GeneralError
;
609 service_user_record_t
* ur
= NULL
;
610 char * bag_file
= NULL
;
612 require_action(ur
= get_user_record(context
->s_uid
), done
, rc
= KB_GeneralError
);
613 require_action(bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_user
), done
, rc
= KB_GeneralError
);
615 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
616 uint8_t * buf
= NULL
;
618 keybag_handle_t session_handle
= bad_keybag_handle
;
620 syslog(LOG_ERR
, "resetting keybag for uid (%i) in session (%i)", context
->s_uid
, context
->s_id
);
621 _kb_rename_bag_on_disk(ur
, bag_file
);
623 require_noerr(rc
= aks_create_bag(secret
, secret_len
, kAppleKeyStoreDeviceBag
, &session_handle
), done
);
624 require_noerr(rc
= aks_save_bag(session_handle
, (void**)&buf
, (int*)&buf_size
), done
);
625 require_action(_kb_save_bag_to_disk(ur
, bag_file
, buf
, buf_size
), done
, rc
= KB_BagError
);
626 require_noerr(rc
= aks_set_system(session_handle
, context
->s_uid
), done
);
627 aks_unload_bag(session_handle
);
628 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
630 if (secret
&& rc
== KB_Success
) {
631 aks_unlock_bag(session_handle
, secret
, secret_len
);
640 if (ur
) free_user_record(ur
);
641 if (bag_file
) free(bag_file
);
646 service_kb_is_locked(service_context_t
* context
, xpc_object_t reply
)
648 int rc
= KB_GeneralError
;
649 keybag_state_t state
;
650 keybag_handle_t session_handle
;
651 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
653 require_noerr(rc
= aks_get_lock_state(session_handle
, &state
), done
);
655 xpc_dictionary_set_bool(reply
, SERVICE_XPC_LOCKED
, state
& keybag_state_locked
);
656 xpc_dictionary_set_bool(reply
, SERVICE_XPC_NO_PIN
, state
& keybag_state_no_pin
);
663 service_kb_stash_create(service_context_t
* context
, const void * key
, unsigned key_size
)
665 int rc
= KB_GeneralError
;
666 char * bag_file
= NULL
;
667 keybag_handle_t session_handle
;
668 service_user_record_t
* ur
= NULL
;
669 void * stashbag
= NULL
;
670 int stashbag_size
= 0;
671 __block
bool saved
= false;
674 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
675 require_action(ur
= get_user_record(context
->s_uid
), done
, rc
= KB_GeneralError
);
676 require_noerr(rc
= aks_stash_escrow(session_handle
, true, key
, key_size
, NULL
, 0, (void**)&stashbag
, &stashbag_size
), done
);
677 require_action(bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_stash
), done
, rc
= KB_GeneralError
);
679 // sync writing the bag to disk
680 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
681 saved
= _kb_save_bag_to_disk(ur
, bag_file
, stashbag
, stashbag_size
);
683 require_action(saved
, done
, rc
= KB_BagError
);
687 if (stashbag
) { free(stashbag
); }
688 if (bag_file
) { free(bag_file
); }
689 if (ur
) free_user_record(ur
);
694 service_kb_stash_load(service_context_t
* context
, const void * key
, unsigned key_size
, bool nondestructive
)
696 __block
int rc
= KB_GeneralError
;
697 char * bag_file
= NULL
;
698 keybag_handle_t session_handle
;
699 service_user_record_t
* ur
= NULL
;
700 __block
uint8_t * stashbag
= NULL
;
701 __block
size_t stashbag_size
= 0;
704 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
705 require_action(ur
= get_user_record(context
->s_uid
), done
, rc
= KB_GeneralError
);
706 require_action(bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_stash
), done
, rc
= KB_GeneralError
);
708 // sync loading the bag from disk
709 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
710 if (!_kb_load_bag_from_disk(ur
, bag_file
, &stashbag
, &stashbag_size
)) {
714 require_noerr(rc
, done
);
716 require_noerr(rc
= aks_stash_escrow(session_handle
, false, key
, key_size
, stashbag
, (int)stashbag_size
, NULL
, NULL
), done
);
720 if (stashbag
) { free(stashbag
); }
721 if ((bag_file
) && (!nondestructive
)) {
722 _kb_delete_bag_on_disk(ur
, bag_file
);
725 if (ur
) free_user_record(ur
);
730 // Get the keychain master key from the AppleFDEKeyStore.
731 // Note that this is a one-time call - the master key is
732 // removed from the keystore after it is returned.
733 // Requires the entitlement: com.apple.private.securityd.keychain
735 OSStatus
service_stash_get_key(service_context_t
* context
, xpc_object_t event
, xpc_object_t reply
)
737 getStashKey_InStruct_t inStruct
;
738 getStashKey_OutStruct_t outStruct
;
739 size_t outSize
= sizeof(outStruct
);
740 kern_return_t kr
= KERN_INVALID_ARGUMENT
;
742 io_connect_t conn
= openiodev();
744 inStruct
.type
= kAppleFDEKeyStoreStash_master
;
746 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStore_getStashKey
,
748 &inStruct
, sizeof(inStruct
),
750 &outStruct
, &outSize
);
752 if (kr
== KERN_SUCCESS
) {
753 xpc_dictionary_set_data(reply
, SERVICE_XPC_KEY
, outStruct
.outBuf
.key
.key
, outStruct
.outBuf
.key
.keysize
);
754 service_kb_stash_load(context
, outStruct
.outBuf
.key
.key
, outStruct
.outBuf
.key
.keysize
, false);
765 // Stash the keychain master key in the AppleFDEKeyStore and
766 // flag it as the keychain master key to be added to the
767 // reboot NVRAM blob.
768 // This requires two calls to the AKS: the first to store the
769 // key and get its uuid. The second uses the uuid to flag the
770 // key for blob inclusion.
772 OSStatus
service_stash_set_key(service_context_t
* context
, xpc_object_t event
, xpc_object_t reply
)
774 kern_return_t kr
= KERN_INVALID_ARGUMENT
;
775 io_connect_t conn
= IO_OBJECT_NULL
;
776 size_t keydata_len
= 0;
779 keybag_state_t state
;
780 keybag_handle_t session_handle
;
781 require_noerr(_kb_get_session_handle(context
, &session_handle
), done
);
782 require_noerr(aks_get_lock_state(session_handle
, &state
), done
);
783 require_action(!(state
& keybag_lock_locked
), done
, kr
= CSSMERR_CSP_OS_ACCESS_DENIED
; LOG("stash failed keybag locked"));
788 // Store the key in the keystore and get its uuid
789 setKeyGetUUID_InStruct_t inStruct1
;
790 uuid_OutStruct_t outStruct1
;
793 const uint8_t *keydata
= xpc_dictionary_get_data(event
, SERVICE_XPC_KEY
, &keydata_len
);
794 require(keydata
, done
);
796 memcpy(&inStruct1
.inKey
.key
.key
, keydata
, keydata_len
);
797 inStruct1
.inKey
.key
.keysize
= (cryptosize_t
) keydata_len
;
798 len
= sizeof(outStruct1
);
799 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStore_setKeyGetUUID
,
801 &inStruct1
, sizeof(inStruct1
),
804 require(kr
== KERN_SUCCESS
, done
);
806 // Now using the uuid stash it as the master key
807 setStashKey_InStruct_t inStruct2
;
808 memcpy(&inStruct2
.uuid
, &outStruct1
.uuid
, sizeof(outStruct1
.uuid
));
809 inStruct2
.type
= kAppleFDEKeyStoreStash_master
;
811 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStore_setStashKey
,
813 &inStruct2
, sizeof(inStruct2
),
817 if (kr
== KERN_SUCCESS
) {
818 service_kb_stash_create(context
, keydata
, (unsigned)keydata_len
);
828 // Load the master stash key
830 OSStatus
service_stash_load_key(service_context_t
* context
, xpc_object_t event
, xpc_object_t reply
)
832 kern_return_t kr
= KERN_SUCCESS
;
833 size_t keydata_len
= 0;
835 const uint8_t *keydata
= xpc_dictionary_get_data(event
, SERVICE_XPC_KEY
, &keydata_len
);
836 require(keydata
, done
);
838 kr
= service_kb_stash_load(context
, keydata
, (cryptosize_t
) keydata_len
, true);
845 // Signal the AppleFDEKeyStore to take the tagged FDE key
846 // and keychain master key, stash them in an encrypted
847 // blob structure and write the blob to NVRAM. The random
848 // encryption key is written to the SMC.
851 OSStatus
service_stash_blob(xpc_object_t event
, xpc_object_t reply
)
853 kern_return_t kr
= KERN_INVALID_ARGUMENT
;
855 io_connect_t conn
= openiodev();
858 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStore_commitStash
,
871 bool peer_has_entitlement(xpc_connection_t peer
, const char * entitlement
)
873 bool entitled
= false;
875 xpc_object_t value
= xpc_connection_copy_entitlement_value(peer
, entitlement
);
876 if (value
&& (xpc_get_type(value
) == XPC_TYPE_BOOL
)) {
877 entitled
= xpc_bool_get_value(value
);
880 if (value
) xpc_release(value
);
884 static char * sel_to_char(uint64_t sel
)
887 case SERVICE_STASH_SET_KEY
:
889 case SERVICE_STASH_GET_KEY
:
891 case SERVICE_STASH_BLOB
:
893 case SERVICE_KB_LOAD
:
895 case SERVICE_KB_SAVE
:
897 case SERVICE_KB_UNLOCK
:
899 case SERVICE_KB_LOCK
:
901 case SERVICE_KB_CHANGE_SECRET
:
902 return "kb_change_secret";
903 case SERVICE_KB_CREATE
:
905 case SERVICE_KB_IS_LOCKED
:
906 return "kb_is_locked";
907 case SERVICE_KB_RESET
:
909 case SERVICE_KB_UNLOAD
:
911 case SERVICE_KB_LOAD_UID
:
912 return "kb_load_uid";
918 static char * err_to_char(int err
)
923 case KB_GeneralError
:
924 return "general error";
926 return "bag not found";
929 case KB_BagNotLoaded
:
930 return "bag not loaded";
933 case KB_InvalidSession
:
934 return "invalid session";
940 void service_peer_event_handler(xpc_connection_t connection
, xpc_object_t event
)
942 xpc_type_t type
= xpc_get_type(event
);
945 if (type
== XPC_TYPE_ERROR
) {
946 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
949 assert(type
== XPC_TYPE_DICTIONARY
);
951 int rc
= KB_GeneralError
;
952 uint64_t request
= 0;
953 const uint8_t * secret
= NULL
, * new_secret
= NULL
;
954 size_t secret_len
= 0, new_secret_len
= 0, data_len
= 0;
955 service_context_t
* context
= NULL
;
956 bool free_context
= false;
958 const char *entitlement
;
960 xpc_object_t reply
= xpc_dictionary_create_reply(event
);
962 request
= xpc_dictionary_get_uint64(event
, SERVICE_XPC_REQUEST
);
965 // For SERVICE_KB_{UNLOAD,LOAD} only, allow non-securityd, non-root but
967 if (request
== SERVICE_KB_UNLOAD
|| request
== SERVICE_KB_LOAD_UID
) {
969 case SERVICE_KB_UNLOAD
:
970 entitlement
= "com.apple.private.securityd.keybag-unload";
972 case SERVICE_KB_LOAD_UID
:
973 entitlement
= "com.apple.private.securityd.keybag-load";
976 if (!peer_has_entitlement(connection
, entitlement
) && !peer_has_entitlement(connection
, "com.apple.keystore.device")) {
977 xpc_connection_cancel(connection
);
981 if (xpc_connection_get_euid(connection
) != 0) {
982 xpc_connection_cancel(connection
);
985 if (!check_signature(connection
)) {
986 xpc_connection_cancel(connection
);
991 data
= xpc_dictionary_get_data(event
, SERVICE_XPC_CONTEXT
, &data_len
);
992 require_action(data
|| request
== SERVICE_KB_UNLOAD
|| request
== SERVICE_KB_LOAD_UID
, done
, rc
= KB_GeneralError
);
994 require(data_len
== sizeof(service_context_t
), done
);
995 context
= (service_context_t
*)data
;
997 audit_token_t audit_token
= { 0 };
998 xpc_connection_get_audit_token(connection
, &audit_token
);
999 context
= calloc(1, sizeof(service_context_t
));
1000 context
->s_id
= xpc_connection_get_asid(connection
);
1001 context
->s_uid
= xpc_connection_get_euid(connection
);
1002 context
->procToken
= audit_token
;
1003 free_context
= true;
1006 require_action(context
->s_id
!= AU_DEFAUDITSID
, done
, rc
= KB_InvalidSession
);
1007 require_action(context
->s_uid
!= AU_DEFAUDITID
, done
, rc
= KB_InvalidSession
); // we only want to work in actual user sessions.
1010 case SERVICE_KB_CREATE
:
1011 // if (kb_service_has_entitlement(peer, "com.apple.keystore.device")) {
1012 secret
= xpc_dictionary_get_data(event
, SERVICE_XPC_SECRET
, &secret_len
);
1013 rc
= service_kb_create(context
, secret
, (int)secret_len
);
1016 case SERVICE_KB_LOAD
:
1017 rc
= service_kb_load(context
);
1019 case SERVICE_KB_UNLOAD
:
1020 rc
= service_kb_unload(context
);
1022 case SERVICE_KB_SAVE
:
1023 rc
= service_kb_save(context
);
1025 case SERVICE_KB_UNLOCK
:
1026 secret
= xpc_dictionary_get_data(event
, SERVICE_XPC_SECRET
, &secret_len
);
1027 rc
= service_kb_unlock(context
, secret
, (int)secret_len
);
1029 case SERVICE_KB_LOCK
:
1030 rc
= service_kb_lock(context
);
1032 case SERVICE_KB_CHANGE_SECRET
:
1033 secret
= xpc_dictionary_get_data(event
, SERVICE_XPC_SECRET
, &secret_len
);
1034 new_secret
= xpc_dictionary_get_data(event
, SERVICE_XPC_SECRET_NEW
, &new_secret_len
);
1035 rc
= service_kb_change_secret(context
, secret
, (int)secret_len
, new_secret
, (int)new_secret_len
);
1037 case SERVICE_KB_RESET
:
1038 secret
= xpc_dictionary_get_data(event
, SERVICE_XPC_SECRET
, &secret_len
);
1039 rc
= service_kb_reset(context
, secret
, (int)secret_len
);
1041 case SERVICE_KB_IS_LOCKED
:
1042 rc
= service_kb_is_locked(context
, reply
);
1044 case SERVICE_STASH_GET_KEY
:
1045 rc
= service_stash_get_key(context
, event
, reply
);
1047 case SERVICE_STASH_SET_KEY
:
1048 rc
= service_stash_set_key(context
, event
, reply
);
1050 case SERVICE_STASH_LOAD_KEY
:
1051 rc
= service_stash_load_key(context
, event
, reply
);
1053 case SERVICE_KB_LOAD_UID
:
1054 uid
= (uid_t
)xpc_dictionary_get_uint64(event
, SERVICE_XPC_UID
);
1055 rc
= service_kb_load_uid(uid
);
1058 case SERVICE_STASH_BLOB
:
1059 rc
= service_stash_blob(event
, reply
);
1063 LOG("unknown service type");
1069 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);
1072 syslog(LOG_NOTICE
, "selector: %s (%llu), error: %s (%x), sid: %d, suid: %d, pid: %d", sel_to_char(request
), request
, err_to_char(rc
), rc
, context
? context
->s_id
: 0, context
? context
->s_uid
: 0, context
? get_caller_pid(&context
->procToken
) : 0);
1075 xpc_dictionary_set_int64(reply
, SERVICE_XPC_RC
, rc
);
1076 xpc_connection_send_message(connection
, reply
);
1084 bool check_signature(xpc_connection_t connection
)
1086 #if !(DEBUG || RC_BUILDIT_YES)
1087 audit_token_t token
;
1089 xpc_connection_get_audit_token(connection
, &token
);
1091 SecTaskRef task
= SecTaskCreateWithAuditToken(NULL
, token
);
1093 syslog(LOG_NOTICE
, "failed getting SecTaskRef of the client");
1097 uint32_t flags
= SecTaskGetCodeSignStatus(task
);
1098 /* check if valid and platform binary, but not platform path */
1099 if ((flags
& (CS_VALID
| CS_PLATFORM_BINARY
| CS_PLATFORM_PATH
)) != (CS_VALID
| CS_PLATFORM_BINARY
)) {
1100 syslog(LOG_NOTICE
, "client is not a platform binary: %0x08x", flags
);
1105 CFStringRef signingIdentity
= SecTaskCopySigningIdentifier(task
, NULL
);
1107 if (signingIdentity
== NULL
) {
1108 syslog(LOG_NOTICE
, "client have no code sign identity");
1112 bool res
= CFEqual(signingIdentity
, CFSTR("com.apple.securityd"));
1113 CFRelease(signingIdentity
);
1116 syslog(LOG_NOTICE
, "client is not not securityd");
1124 static void register_for_notifications()
1126 __block kern_return_t kr
;
1127 static mach_port_t mp
= MACH_PORT_NULL
;
1129 static dispatch_once_t onceToken
= 0;
1130 dispatch_once(&onceToken
, ^{
1131 kr
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &mp
);
1132 if (kr
== KERN_SUCCESS
) {
1133 dispatch_source_t mach_src
= dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV
, mp
, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0));
1134 dispatch_source_set_event_handler(mach_src
, ^{
1135 mach_msg_return_t mr
;
1136 uint8_t buf
[sizeof(aks_notification_msg_t
) + MAX_TRAILER_SIZE
] = {};
1137 aks_notification_msg_t
* msg
= (aks_notification_msg_t
*)buf
;
1138 mr
= mach_msg((mach_msg_header_t
*)&buf
, MACH_RCV_MSG
, 0, sizeof(buf
), mp
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
1139 if (mr
== MACH_MSG_SUCCESS
&& msg
->hdr
.msgh_id
== AKS_NOTIFICATION_MSGID
) {
1141 } else if (mr
== MACH_MSG_SUCCESS
&& msg
->hdr
.msgh_id
== AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG
) {
1142 syslog(LOG_NOTICE
, "request to update handle %d", msg
->handle
);
1143 update_keybag_handle(msg
->handle
);
1145 syslog(LOG_ERR
, "mach_msg error: %x", mr
);
1148 dispatch_resume(mach_src
);
1150 syslog(LOG_NOTICE
, "failed to create notification port");
1155 kr
= aks_register_for_notifications(mp
, AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG
);
1156 if (kr
== KERN_SUCCESS
) {
1157 syslog(LOG_NOTICE
, "registered for notifications");
1159 syslog(LOG_NOTICE
, "failed to register for notifications %d", kr
);
1163 int main(int argc
, const char * argv
[])
1166 if (sandbox_init(SECURITYD_SERVICE_NAME
, SANDBOX_NAMED
, &errorbuf
) != 0) {
1167 syslog(LOG_ERR
, "sandbox_init failed %s", errorbuf
);
1168 sandbox_free_error(errorbuf
);
1174 register_for_notifications();
1176 xpc_connection_t listener
= xpc_connection_create_mach_service(SECURITYD_SERVICE_NAME
, NULL
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
1177 xpc_connection_set_event_handler(listener
, ^(xpc_object_t peer
) {
1178 // It is safe to cast 'peer' to xpc_connection_t assuming
1179 // we have a correct configuration in our launchd.plist.
1180 xpc_connection_set_event_handler(peer
, ^(xpc_object_t event
) {
1181 vproc_transaction_t transaction
= vproc_transaction_begin(NULL
);
1182 service_peer_event_handler(peer
, event
);
1183 vproc_transaction_end(NULL
, transaction
);
1185 xpc_connection_resume(peer
);
1187 xpc_connection_resume(listener
);