#include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
#if DEBUG
-#define LOG(...) syslog(LOG_NOTICE, ##__VA_ARGS__);
+#define LOG(...) syslog(LOG_ERR, ##__VA_ARGS__);
#else
#define LOG(...)
#endif
const char * kb_user_bag = "user.kb";
const char * kb_stash_bag = "stash.kb";
+#define HEXBUF_LEN 2048
+
typedef struct {
uid_t uid;
gid_t gid;
}
}
-static void
-_kb_migrate_old_bag_if_exists(service_user_record_t * ur)
-{
- char session_file[PATH_MAX] = {};
- struct stat st_info = {};
- char * bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user);
-
- if (bag_file) {
- snprintf(session_file, sizeof(session_file), "/var/keybags/%i.kb", ur->uid);
-
- // if the bag_file does not exist
- // check for the session_file and copy it into place
- if (!_kb_bag_exists(ur, bag_file)) {
- if (lstat(session_file, &st_info) == 0 && (S_ISREG(st_info.st_mode))) {
- lchmod("/var/keybags", 0777);
- lchmod(session_file, 0666);
- _set_thread_credentials(ur);
- _kb_verify_create_path(ur);
- syslog(LOG_ERR, "migrating %s to %s", session_file, bag_file);
- copyfile(session_file, bag_file, NULL, COPYFILE_ALL | COPYFILE_MOVE | COPYFILE_NOFOLLOW | COPYFILE_EXCL);
- lchmod(bag_file, 0600);
- _clear_thread_credentials();
- }
- }
- free(bag_file);
- }
-}
-
static int
_kb_get_session_handle(service_context_t * context, keybag_handle_t * handle_out)
{
return entitled;
}
+#if DEBUG
+static char *
+to_hex(char * dst, const void * src, size_t size)
+{
+ int notleading = 0;
+
+ if ((size * 2) > HEXBUF_LEN) return NULL;
+
+ uint8_t * buf = (uint8_t *)src;
+ register char *chp = dst;
+ *dst = '\0';
+ if (size != 0) do {
+ if(notleading || *buf != '\0') {
+ if(!notleading && (*buf & 0xf0) == 0) {
+ sprintf(chp, "%.1x", * (unsigned char *) src);
+ chp += 1;
+ }
+ else {
+ sprintf(chp, "%.2x", * (unsigned char *) src);
+ chp += 2;
+ }
+ notleading = 1;
+ }
+ ++src;
+ } while (--size != 0);
+ return dst;
+}
+#endif // DEBUG
+
+static char * sel_to_char(uint64_t sel)
+{
+ switch (sel) {
+ case SERVICE_STASH_SET_KEY:
+ return "set_key";
+ case SERVICE_STASH_GET_KEY:
+ return "get_key";
+ case SERVICE_STASH_BLOB:
+ return "stash_blob";
+ case SERVICE_KB_LOAD:
+ return "kb_load";
+ case SERVICE_KB_UNLOCK:
+ return "kb_unlock";
+ case SERVICE_KB_LOCK:
+ return "kb_lock";
+ case SERVICE_KB_CHANGE_SECRET:
+ return "kb_change_secret";
+ case SERVICE_KB_CREATE:
+ return "kb_create";
+ case SERVICE_KB_IS_LOCKED:
+ return "kb_is_locked";
+ case SERVICE_KB_RESET:
+ return "kb_reset";
+ default:
+ return "unknown";
+ }
+}
+
+static char * err_to_char(int err)
+{
+ switch (err) {
+ case KB_Success:
+ return "success";
+ case KB_GeneralError:
+ return "general error";
+ case KB_BagNotFound:
+ return "bag not found";
+ case KB_BagError:
+ return "bag error";
+ case KB_BagNotLoaded:
+ return "bag not loaded";
+ case KB_BagExists:
+ return "bag exists";
+ case KB_InvalidSession:
+ return "invalid session";
+ default:
+ return "";
+ }
+}
+
void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event)
{
+#if DEBUG
+ char hexbuf1[HEXBUF_LEN];
+ char hexbuf2[HEXBUF_LEN];
+#endif // DEBUG
xpc_type_t type = xpc_get_type(event);
if (type == XPC_TYPE_ERROR) {
}
done:
- LOG("selector: %llu, error: %x, secret_len: %zu, new_secret_len: %zu, sid: %d, suid: %d)", request, rc, secret_len, new_secret_len, context ? context->s_id : 0, context ? context->s_uid : 0);
+#if DEBUG
+ LOG("selector: %s (%llu), error: %s (%x), '%s' secret_len: %zu, '%s' new_secret_len: %zu, sid: %d, suid: %d", sel_to_char(request), request, err_to_char(rc), rc, to_hex(hexbuf1, secret, secret_len), secret_len, to_hex(hexbuf2, new_secret, new_secret_len), new_secret_len, context ? context->s_id : 0, context ? context->s_uid : 0);
+#else
+ if (rc != 0) {
+ syslog(LOG_NOTICE, "selector: %s (%llu), error: %s (%x), sid: %d, suid: %d", sel_to_char(request), request, err_to_char(rc), rc, context ? context->s_id : 0, context ? context->s_uid : 0);
+ }
+#endif
xpc_dictionary_set_int64(reply, SERVICE_XPC_RC, rc);
xpc_connection_send_message(connection, reply);
xpc_release(reply);
mHaveMaster = true;
}
+bool DatabaseCryptoCore::get_encryption_key(CssmOwnedData &data)
+{
+ bool result = false;
+ if (isValid()) {
+ data = mEncryptionKey->keyData();
+ result = true;
+ }
+ return result;
+}
//
// Given a putative passphrase, determine whether that passphrase
static const uint32 managedAttributes = KeyBlob::managedAttributes;
static const uint32 forcedAttributes = KeyBlob::forcedAttributes;
+
+ bool get_encryption_key(CssmOwnedData &data);
public:
bool validatePassphrase(const CssmData &passphrase);
}
}
+ if (rc != 0) { // if we just upgraded make sure we swap the encryption key to the password
+ if (!dbCommon.session().keybagGetState(session_keybag_check_master_key)) {
+ CssmAutoData encKey(Allocator::standard(Allocator::sensitive));
+ dbCommon.get_encryption_key(encKey);
+ if ((rc = service_client_kb_unlock(&context, encKey.data(), (int)encKey.length())) == 0) {
+ rc = service_client_kb_change_secret(&context, encKey.data(), (int)encKey.length(), secret, secret_len);
+ }
+
+ if (rc != 0) { // if a login.keychain password exists but doesnt on the keybag update it
+ bool no_pin = false;
+ if ((secret_len > 0) && service_client_kb_is_locked(&context, NULL, &no_pin) == 0) {
+ if (no_pin) {
+ syslog(LOG_ERR, "Updating iCloud keychain passphrase for uid %d", dbCommon.session().originatorUid());
+ service_client_kb_change_secret(&context, NULL, 0, secret, secret_len);
+ }
+ }
+ }
+ } // session_keybag_check_master_key
+ }
+
if (rc == 0) {
- dbCommon.session().keybagSetState(session_keybag_unlocked|session_keybag_loaded);
+ dbCommon.session().keybagSetState(session_keybag_unlocked|session_keybag_loaded|session_keybag_check_master_key);
+ } else {
+ syslog(LOG_ERR, "Failed to unlock iCloud keychain for uid %d", dbCommon.session().originatorUid());
}
return rc;
//
void KeychainDatabase::stashDbCheck()
{
- CssmAutoData data(Allocator::standard(Allocator::sensitive));
+ CssmAutoData masterKey(Allocator::standard(Allocator::sensitive));
+ CssmAutoData encKey(Allocator::standard(Allocator::sensitive));
// Fetch the key
int rc = 0;
rc = service_client_stash_get_key(&context, &stash_key, &stash_key_len);
if (rc == 0) {
if (stash_key) {
- data.copy(CssmData((void *)stash_key,stash_key_len));
+ masterKey.copy(CssmData((void *)stash_key,stash_key_len));
memset(stash_key, 0, stash_key_len);
free(stash_key);
}
StLock<Mutex> _(common());
// Now establish it as the keychain master key
- CssmClient::Key key(Server::csp(), data.get());
+ CssmClient::Key key(Server::csp(), masterKey.get());
CssmKey::Header &hdr = key.header();
hdr.keyClass(CSSM_KEYCLASS_SESSION_KEY);
hdr.algorithm(CSSM_ALGID_3DES_3KEY_EDE);
if (!decode())
CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
+
+ common().get_encryption_key(encKey);
}
- // when upgrading from pre-10.9 create a keybag if it doesn't exist with the master secret
+ // when upgrading from pre-10.9 create a keybag if it doesn't exist with the encryption key
// only do this after we have verified the master key unlocks the login.keychain
if (service_client_kb_load(&context) == KB_BagNotFound) {
- service_client_kb_create(&context, data.data(), (int)data.length());
+ service_client_kb_create(&context, encKey.data(), (int)encKey.length());
}
}
if (common().isLoginKeychain()) {
bool locked = false;
service_context_t context = common().session().get_current_service_context();
- if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked) {
+ if (!common().session().keybagGetState(session_keybag_check_master_key) || ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked)) {
unlock_keybag(common(), passphrase.data(), (int)passphrase.length());
}
}
assert(mBlob);
common().setup(mBlob, passphrase);
bool success = decode();
- if (success) {
- if (common().isLoginKeychain() && (unlock_keybag(common(), passphrase.data(), (int)passphrase.length()) != 0)) {
- service_context_t context = common().session().get_current_service_context();
- // check to see if it was locked with the master key if so change the secret to the passphrase
- if (!common().session().keybagGetState(session_keybag_check_master_key)) {
-
- CssmAutoData key(Allocator::standard(Allocator::sensitive));
- key = common().masterKey()->keyData();
- if (service_client_kb_unlock(&context, key.data(), (int)key.length()) == 0) {
- service_client_kb_change_secret(&context, key.data(), (int)key.length(), passphrase.data(), (int)passphrase.length());
- }
- common().session().keybagSetState(session_keybag_check_master_key);
- }
-
- bool no_pin = false;
- if (service_client_kb_is_locked(&context, NULL, &no_pin) == 0) {
- if ((passphrase.length() > 0) && no_pin) {
- syslog(LOG_ERR, "Updating passphrase for your iCloud keychain");
- service_client_kb_change_secret(&context, NULL, 0, passphrase.data(), (int)passphrase.length());
- } else {
- syslog(LOG_ERR, "The passphrase for your login.keychain and your iCloud keychain are out of sync");
- }
- }
- }
+ if (success && common().isLoginKeychain()) {
+ unlock_keybag(common(), passphrase.data(), (int)passphrase.length());
}
return success;
}