]> git.saurik.com Git - apple/securityd.git/commitdiff
securityd-55199.0.1.tar.gz v55199.0.1
authorApple <opensource@apple.com>
Wed, 13 Nov 2013 21:06:20 +0000 (21:06 +0000)
committerApple <opensource@apple.com>
Wed, 13 Nov 2013 21:06:20 +0000 (21:06 +0000)
securityd_service/securityd_service/main.c
src/dbcrypto.cpp
src/dbcrypto.h
src/kcdatabase.cpp

index 18283a816595f7f2ea15d24e8d0b99ff6757112a..59674847e6825e85ad08684bb97f850736ecd20a 100644 (file)
@@ -28,7 +28,7 @@
 #include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
 
 #if DEBUG
 #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
 #else
 #define LOG(...)
 #endif
@@ -43,6 +43,8 @@ const char * kb_home_path = "Library/Keychains";
 const char * kb_user_bag = "user.kb";
 const char * kb_stash_bag = "stash.kb";
 
 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;
 typedef struct {
     uid_t uid;
     gid_t gid;
@@ -340,34 +342,6 @@ _kb_delete_bag_on_disk(service_user_record_t * ur, const char * bag_file)
     }
 }
 
     }
 }
 
-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)
 {
 static int
 _kb_get_session_handle(service_context_t * context, keybag_handle_t * handle_out)
 {
@@ -774,8 +748,91 @@ bool peer_has_entitlement(xpc_connection_t peer, const char * entitlement)
     return entitled;
 }
 
     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)
 {
 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) {
     xpc_type_t type = xpc_get_type(event);
     
     if (type == XPC_TYPE_ERROR) {
@@ -849,7 +906,13 @@ void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event)
         }
         
     done:
         }
         
     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);
         xpc_dictionary_set_int64(reply, SERVICE_XPC_RC, rc);
         xpc_connection_send_message(connection, reply);
         xpc_release(reply);
index 98b1caabc4ca3c672887fdd368a4cb279b748167..83d4469d00e3a925726cbd88e2297f89f97cf947 100644 (file)
@@ -135,6 +135,15 @@ void DatabaseCryptoCore::setup(const DbBlob *blob, CssmClient::Key master)
        mHaveMaster = true;
 }
 
        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
 
 //
 // Given a putative passphrase, determine whether that passphrase
index 5970f514f5ac25bfafe3f0b4b2e78e4cb8235625..dda04b4c13feb9e6dd59e21ddd56da28b72e164c 100644 (file)
@@ -68,6 +68,8 @@ public:
 
     static const uint32 managedAttributes = KeyBlob::managedAttributes;
        static const uint32 forcedAttributes = KeyBlob::forcedAttributes;
 
     static const uint32 managedAttributes = KeyBlob::managedAttributes;
        static const uint32 forcedAttributes = KeyBlob::forcedAttributes;
+
+    bool get_encryption_key(CssmOwnedData &data);
        
 public:
        bool validatePassphrase(const CssmData &passphrase);
        
 public:
        bool validatePassphrase(const CssmData &passphrase);
index 68271fa7d46d4e061163084f05368dbfa66b1f31..c9c1fe23c329d115f2a953a9db9380da27b4f789 100644 (file)
@@ -81,8 +81,30 @@ unlock_keybag(KeychainDbCommon & dbCommon, const void * secret, int secret_len)
         }
     }
 
         }
     }
 
+    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) {
     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;
     }
 
     return rc;
@@ -528,7 +550,8 @@ void KeychainDatabase::makeUnlocked(const AccessCredentials *cred)
 //
 void KeychainDatabase::stashDbCheck()
 {    
 //
 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;
 
     // Fetch the key
     int rc = 0;
@@ -538,7 +561,7 @@ void KeychainDatabase::stashDbCheck()
     rc = service_client_stash_get_key(&context, &stash_key, &stash_key_len);
     if (rc == 0) {
         if (stash_key) {
     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);
         }
             memset(stash_key, 0, stash_key_len);
             free(stash_key);
         }
@@ -550,7 +573,7 @@ void KeychainDatabase::stashDbCheck()
         StLock<Mutex> _(common());
 
         // Now establish it as the keychain master 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);
         CssmKey::Header &hdr = key.header();
         hdr.keyClass(CSSM_KEYCLASS_SESSION_KEY);
         hdr.algorithm(CSSM_ALGID_3DES_3KEY_EDE);
@@ -561,12 +584,14 @@ void KeychainDatabase::stashDbCheck()
 
         if (!decode())
             CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
 
         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) {
     // 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());
     }
 }
 
     }
 }
 
@@ -620,7 +645,7 @@ void KeychainDatabase::makeUnlocked(const CssmData &passphrase)
     if (common().isLoginKeychain()) {
         bool locked = false;
         service_context_t context = common().session().get_current_service_context();
     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());
         }
     }
             unlock_keybag(common(), passphrase.data(), (int)passphrase.length());
         }
     }
@@ -640,30 +665,8 @@ bool KeychainDatabase::decode(const CssmData &passphrase)
        assert(mBlob);
        common().setup(mBlob, passphrase);
        bool success = decode();
        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;
 }
     }
     return success;
 }