]> git.saurik.com Git - apple/security.git/blobdiff - sec/securityd/SecItemServer.c
Security-57031.1.35.tar.gz
[apple/security.git] / sec / securityd / SecItemServer.c
diff --git a/sec/securityd/SecItemServer.c b/sec/securityd/SecItemServer.c
deleted file mode 100644 (file)
index c6dec55..0000000
+++ /dev/null
@@ -1,4446 +0,0 @@
-/*
- * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * SecItemServer.c - CoreFoundation-based constants and functions for
-    access to Security items (certificates, keys, identities, and
-    passwords.)
- */
-
-#include <securityd/SecItemServer.h>
-#include <securityd/SecDbItem.h>
-
-#include <Security/SecItem.h>
-#include <Security/SecItemPriv.h>
-#include <Security/SecItemInternal.h>
-#include <Security/SecKey.h>
-#include <Security/SecKeyPriv.h>
-#include <Security/SecCertificateInternal.h>
-#include <Security/SecIdentity.h>
-#include <Security/SecIdentityPriv.h>
-#include <Security/SecFramework.h>
-#include <Security/SecRandom.h>
-#include <Security/SecBasePriv.h>
-#include <utilities/SecIOFormat.h>
-#include <utilities/SecCFWrappers.h>
-#include <utilities/SecCFError.h>
-#include <utilities/der_plist.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <Security/SecBase.h>
-#include <CoreFoundation/CFData.h>
-#include <CoreFoundation/CFDate.h>
-#include <CoreFoundation/CFArray.h>
-#include <CoreFoundation/CFDictionary.h>
-#include <CoreFoundation/CFNumber.h>
-#include <CoreFoundation/CFString.h>
-#include <CoreFoundation/CFURL.h>
-#include <CommonCrypto/CommonDigest.h>
-#include <CommonCrypto/CommonDigestSPI.h>
-#include <CommonCrypto/CommonCryptor.h>
-#include <CommonCrypto/CommonCryptorSPI.h>
-#include <libkern/OSByteOrder.h>
-#include <utilities/debugging.h>
-#include <assert.h>
-#include <Security/SecInternal.h>
-#include "securityd_client.h"
-#include "utilities/sqlutils.h"
-#include "utilities/SecIOFormat.h"
-#include "utilities/SecFileLocations.h"
-#include <utilities/iCloudKeychainTrace.h>
-#include <AssertMacros.h>
-#include <asl.h>
-#include <inttypes.h>
-#include <utilities/array_size.h>
-#include <utilities/SecDb.h>
-#include <securityd/SOSCloudCircleServer.h>
-#include <notify.h>
-#include "OTATrustUtilities.h"
-
-#if USE_KEYSTORE
-#include <IOKit/IOKitLib.h>
-#include <libaks.h>
-#if TARGET_OS_EMBEDDED
-#include <MobileKeyBag/MobileKeyBag.h>
-#endif
-#endif /* USE_KEYSTORE */
-
-
-/* g_keychain_handle is the keybag handle used for encrypting item in the keychain.
-   For testing purposes, it can be set to something other than the default, with SecItemServerSetKeychainKeybag */
-#if USE_KEYSTORE
-#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
-static keybag_handle_t g_keychain_keybag = session_keybag_handle;
-#else
-static keybag_handle_t g_keychain_keybag = device_keybag_handle;
-#endif
-#else /* !USE_KEYSTORE */
-static int32_t g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
-#endif /* USE_KEYSTORE */
-
-void SecItemServerSetKeychainKeybag(int32_t keybag)
-{
-    g_keychain_keybag=keybag;
-}
-
-void SecItemServerResetKeychainKeybag(void)
-{
-#if USE_KEYSTORE
-#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
-    g_keychain_keybag = session_keybag_handle;
-#else
-    g_keychain_keybag = device_keybag_handle;
-#endif
-#else /* !USE_KEYSTORE */
-    g_keychain_keybag = 0; /* 0 == device_keybag_handle, constant dictated by AKS */
-#endif /* USE_KEYSTORE */
-}
-
-/* KEYBAG_NONE is private to security and have special meaning.
-   They should not collide with AppleKeyStore constants, but are only referenced
-   in here.
- */
-#define KEYBAG_NONE (-1)   /* Set q_keybag to KEYBAG_NONE to obtain cleartext data. */
-#define KEYBAG_DEVICE (g_keychain_keybag) /* actual keybag used to encrypt items */
-
-/* Changed the name of the keychain changed notification, for testing */
-static const char *g_keychain_changed_notification = kSecServerKeychainChangedNotification;
-
-void SecItemServerSetKeychainChangedNotification(const char *notification_name)
-{
-    g_keychain_changed_notification = notification_name;
-}
-
-/* label when certificate data is joined with key data */
-#define CERTIFICATE_DATA_COLUMN_LABEL "certdata"
-
-#define CURRENT_DB_VERSION 6
-
-#define CLOSE_DB  0
-
-/* Forward declaration of import export SPIs. */
-enum SecItemFilter {
-    kSecNoItemFilter,
-    kSecSysBoundItemFilter,
-    kSecBackupableItemFilter,
-};
-
-static CF_RETURNS_RETAINED CFDictionaryRef SecServerExportKeychainPlist(SecDbConnectionRef dbt,
-    keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
-    enum SecItemFilter filter, CFErrorRef *error);
-static bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt,
-    keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
-    CFDictionaryRef keychain, enum SecItemFilter filter, CFErrorRef *error);
-
-#if USE_KEYSTORE
-
-static bool hwaes_key_available(void)
-{
-    keybag_handle_t handle = bad_keybag_handle;
-    keybag_handle_t special_handle = bad_keybag_handle;
-#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
-    special_handle = session_keybag_handle;
-#elif TARGET_OS_EMBEDDED
-    special_handle = device_keybag_handle;
-#endif
-    kern_return_t kr = aks_get_system(special_handle, &handle);
-    if (kr != kIOReturnSuccess) {
-#if TARGET_OS_EMBEDDED
-        /* TODO: Remove this once the kext runs the daemon on demand if
-         there is no system keybag. */
-        int kb_state = MKBGetDeviceLockState(NULL);
-        asl_log(NULL, NULL, ASL_LEVEL_INFO, "AppleKeyStore lock state: %d", kb_state);
-#endif
-    }
-    return true;
-}
-
-#else /* !USE_KEYSTORE */
-
-static bool hwaes_key_available(void)
-{
-       return false;
-}
-
-#endif /* USE_KEYSTORE */
-
-// MARK -
-// MARK Keychain version 6 schema
-
-#define __FLAGS(ARG, ...) SECDBFLAGS(__VA_ARGS__)
-#define SECDBFLAGS(ARG, ...) __FLAGS_##ARG | __FLAGS(__VA_ARGS__)
-
-#define SecDbFlags(P,L,I,S,A,D,R,C,H,B,Z,E,N) (__FLAGS_##P|__FLAGS_##L|__FLAGS_##I|__FLAGS_##S|__FLAGS_##A|__FLAGS_##D|__FLAGS_##R|__FLAGS_##C|__FLAGS_##H|__FLAGS_##B|__FLAGS_##Z|__FLAGS_##E|__FLAGS_##N)
-
-#define __FLAGS_   0
-#define __FLAGS_P  kSecDbPrimaryKeyFlag
-#define __FLAGS_L  kSecDbInFlag
-#define __FLAGS_I  kSecDbIndexFlag
-#define __FLAGS_S  kSecDbSHA1ValueInFlag
-#define __FLAGS_A  kSecDbReturnAttrFlag
-#define __FLAGS_D  kSecDbReturnDataFlag
-#define __FLAGS_R  kSecDbReturnRefFlag
-#define __FLAGS_C  kSecDbInCryptoDataFlag
-#define __FLAGS_H  kSecDbInHashFlag
-#define __FLAGS_B  kSecDbInBackupFlag
-#define __FLAGS_Z  kSecDbDefault0Flag
-#define __FLAGS_E  kSecDbDefaultEmptyFlag
-#define __FLAGS_N  kSecDbNotNullFlag
-
-//                                                                   ,------------- P : Part of primary key
-//                                                                  / ,------------ L : Stored in local database
-//                                                                 / / ,----------- I : Attribute wants an index in the database
-//                                                                / / / ,---------- S : SHA1 hashed attribute value in database (implies L)
-//                                                               / / / / ,--------- A : Returned to client as attribute in queries
-//                                                              / / / / / ,-------- D : Returned to client as data in queries
-//                                                             / / / / / / ,------- R : Returned to client as ref/persistant ref in queries
-//                                                            / / / / / / / ,------ C : Part of encrypted blob
-//                                                           / / / / / / / / ,----- H : Attribute is part of item SHA1 hash (Implied by C)
-//                                                          / / / / / / / / / ,---- B : Attribute is part of iTunes/iCloud backup bag
-//                                                         / / / / / / / / / / ,--- Z : Attribute has a default value of 0
-//                                                        / / / / / / / / / / / ,-- E : Attribute has a default value of "" or empty data
-//                                                       / / / / / / / / / / / / ,- N : Attribute must have a value
-//                                                      / / / / / / / / / / / / /
-//                                                     / / / / / / / / / / / / /
-//                                                    | | | | | | | | | | | | |
-// common to all                                      | | | | | | | | | | | | |
-SECDB_ATTR(v6rowid, "rowid", RowId,        SecDbFlags( ,L, , , , ,R, , ,B, , , ));
-SECDB_ATTR(v6cdat, "cdat", CreationDate,   SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6mdat, "mdat",ModificationDate,SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6labl, "labl", Blob,           SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
-SECDB_ATTR(v6data, "data", EncryptedData,  SecDbFlags( ,L, , , , , , , ,B, , , ));
-SECDB_ATTR(v6agrp, "agrp", String,         SecDbFlags(P,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6pdmn, "pdmn", Access,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6sync, "sync", Sync,           SecDbFlags(P,L,I, ,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6tomb, "tomb", Tomb,           SecDbFlags( ,L, , , , , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6sha1, "sha1", SHA1,           SecDbFlags( ,L,I, ,A, ,R, , , , , , ));
-SECDB_ATTR(v6v_Data, "v_Data", Data,       SecDbFlags( , , , , ,D, ,C,H, , , , ));
-SECDB_ATTR(v6v_pk, "v_pk", PrimaryKey,     SecDbFlags( , , , , , , , , , , , , ));
-// genp and inet and keys                             | | | | | | | | | | | | |
-SECDB_ATTR(v6crtr, "crtr", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6alis, "alis", Blob,           SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
-// genp and inet                                      | | | | | | | | | | | | |
-SECDB_ATTR(v6desc, "desc", Blob,           SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
-SECDB_ATTR(v6icmt, "icmt", Blob,           SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
-SECDB_ATTR(v6type, "type", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6invi, "invi", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6nega, "nega", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6cusi, "cusi", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6prot, "prot", Blob,           SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
-SECDB_ATTR(v6scrp, "scrp", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6acct, "acct", Blob,           SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
-// genp only                                          | | | | | | | | | | | | |
-SECDB_ATTR(v6svce, "svce", Blob,           SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
-SECDB_ATTR(v6gena, "gena", Blob,           SecDbFlags( ,L, ,S,A, , ,C,H, , , , ));
-// inet only                                          | | | | | | | | | | | | |
-SECDB_ATTR(v6sdmn, "sdmn", Blob,           SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
-SECDB_ATTR(v6srvr, "srvr", Blob,           SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
-SECDB_ATTR(v6ptcl, "ptcl", Number,         SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6atyp, "atyp", Blob,           SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
-SECDB_ATTR(v6port, "port", Number,         SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6path, "path", Blob,           SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
-// cert only                                          | | | | | | | | | | | | |
-SECDB_ATTR(v6ctyp, "ctyp", Number,         SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6cenc, "cenc", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6subj, "subj", Data,           SecDbFlags( ,L,I,S,A, , ,C,H, , , , ));
-SECDB_ATTR(v6issr, "issr", Data,           SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
-SECDB_ATTR(v6slnr, "slnr", Data,           SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
-SECDB_ATTR(v6skid, "skid", Data,           SecDbFlags( ,L,I,S,A, , ,C,H, , , , ));
-SECDB_ATTR(v6pkhh, "pkhh", Data,           SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
-// cert attributes that share names with common ones but have different flags
-SECDB_ATTR(v6certalis, "alis", Blob,       SecDbFlags( ,L,I,S,A, , ,C,H, , , , ));
-// keys only                                          | | | | | | | | | | | | |
-SECDB_ATTR(v6kcls, "kcls", Number,         SecDbFlags(P,L,I,S,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6perm, "perm", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6priv, "priv", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6modi, "modi", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6klbl, "klbl", Data,           SecDbFlags(P,L,I, ,A, , ,C,H, , ,E,N));
-SECDB_ATTR(v6atag, "atag", Blob,           SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N));
-SECDB_ATTR(v6bsiz, "bsiz", Number,         SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6esiz, "esiz", Number,         SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6sdat, "sdat", Date,           SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6edat, "edat", Date,           SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6sens, "sens", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6asen, "asen", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6extr, "extr", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6next, "next", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6encr, "encr", Number,         SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6decr, "decr", Number,         SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6drve, "drve", Number,         SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6sign, "sign", Number,         SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6vrfy, "vrfy", Number,         SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6snrc, "snrc", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6vyrc, "vyrc", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6wrap, "wrap", Number,         SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
-SECDB_ATTR(v6unwp, "unwp", Number,         SecDbFlags( ,L,I, ,A, , ,C,H, , , , ));
-// keys attributes that share names with common ones but have different flags
-SECDB_ATTR(v6keytype, "type", Number,      SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
-SECDB_ATTR(v6keycrtr, "crtr", Number,      SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N));
-
-static const SecDbClass genp_class = {
-    .name = CFSTR("genp"),
-    .attrs = {
-        &v6rowid,
-        &v6cdat,
-        &v6mdat,
-        &v6desc,
-        &v6icmt,
-        &v6crtr,
-        &v6type,
-        &v6scrp,
-        &v6labl,
-        &v6alis,
-        &v6invi,
-        &v6nega,
-        &v6cusi,
-        &v6prot,
-        &v6acct,
-        &v6svce,
-        &v6gena,
-        &v6data,
-        &v6agrp,
-        &v6pdmn,
-        &v6sync,
-        &v6tomb,
-        &v6sha1,
-        &v6v_Data,
-        &v6v_pk,
-        NULL
-    },
-};
-
-static const SecDbClass inet_class = {
-    .name = CFSTR("inet"),
-    .attrs = {
-        &v6rowid,
-        &v6cdat,
-        &v6mdat,
-        &v6desc,
-        &v6icmt,
-        &v6crtr,
-        &v6type,
-        &v6scrp,
-        &v6labl,
-        &v6alis,
-        &v6invi,
-        &v6nega,
-        &v6cusi,
-        &v6prot,
-        &v6acct,
-        &v6sdmn,
-        &v6srvr,
-        &v6ptcl,
-        &v6atyp,
-        &v6port,
-        &v6path,
-        &v6data,
-        &v6agrp,
-        &v6pdmn,
-        &v6sync,
-        &v6tomb,
-        &v6sha1,
-        &v6v_Data,
-        &v6v_pk,
-        0
-    },
-};
-
-static const SecDbClass cert_class = {
-    .name = CFSTR("cert"),
-    .attrs = {
-        &v6rowid,
-        &v6cdat,
-        &v6mdat,
-        &v6ctyp,
-        &v6cenc,
-        &v6labl,
-        &v6certalis,
-        &v6subj,
-        &v6issr,
-        &v6slnr,
-        &v6skid,
-        &v6pkhh,
-        &v6data,
-        &v6agrp,
-        &v6pdmn,
-        &v6sync,
-        &v6tomb,
-        &v6sha1,
-        &v6v_Data,
-        &v6v_pk,
-        0
-    },
-};
-
-static const SecDbClass keys_class = {
-    .name = CFSTR("keys"),
-    .attrs = {
-        &v6rowid,
-        &v6cdat,
-        &v6mdat,
-        &v6kcls,
-        &v6labl,
-        &v6alis,
-        &v6perm,
-        &v6priv,
-        &v6modi,
-        &v6klbl,
-        &v6atag,
-        &v6keycrtr,
-        &v6keytype,
-        &v6bsiz,
-        &v6esiz,
-        &v6sdat,
-        &v6edat,
-        &v6sens,
-        &v6asen,
-        &v6extr,
-        &v6next,
-        &v6encr,
-        &v6decr,
-        &v6drve,
-        &v6sign,
-        &v6vrfy,
-        &v6snrc,
-        &v6vyrc,
-        &v6wrap,
-        &v6unwp,
-        &v6data,
-        &v6agrp,
-        &v6pdmn,
-        &v6sync,
-        &v6tomb,
-        &v6sha1,
-        &v6v_Data,
-        &v6v_pk,
-        0
-    }
-};
-
-/* An identity which is really a cert + a key, so all cert and keys attrs are
- allowed. */
-static const SecDbClass identity_class = {
-    .name = CFSTR("idnt"),
-    .attrs = {
-        0
-    },
-};
-
-static const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c,
-                                         CFTypeRef key,
-                                         CFErrorRef *error) {
-    /* Special case: identites can have all attributes of either cert
-       or keys. */
-    if (c == &identity_class) {
-        const SecDbAttr *desc;
-        if (!(desc = SecDbAttrWithKey(&cert_class, key, 0)))
-            desc = SecDbAttrWithKey(&keys_class, key, error);
-        return desc;
-    }
-
-    if (isString(key)) {
-        SecDbForEachAttr(c, a) {
-            if (CFEqual(a->name, key))
-                return a;
-        }
-    }
-
-    SecError(errSecNoSuchAttr, error, CFSTR("attribute %@ not found in class %@"), key, c->name);
-
-    return NULL;
-}
-
-static bool kc_transaction(SecDbConnectionRef dbt, CFErrorRef *error, bool(^perform)()) {
-    __block bool ok = true;
-    return ok && SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) {
-        ok = *commit = perform();
-    });
-}
-
-static CFStringRef SecDbGetKindSQL(SecDbAttrKind kind) {
-    switch (kind) {
-        case kSecDbBlobAttr:
-        case kSecDbDataAttr:
-        case kSecDbSHA1Attr:
-        case kSecDbPrimaryKeyAttr:
-        case kSecDbEncryptedDataAttr:
-            return CFSTR("BLOB");
-        case kSecDbAccessAttr:
-        case kSecDbStringAttr:
-            return CFSTR("TEXT");
-        case kSecDbNumberAttr:
-        case kSecDbSyncAttr:
-        case kSecDbTombAttr:
-            return CFSTR("INTEGER");
-        case kSecDbDateAttr:
-        case kSecDbCreationDateAttr:
-        case kSecDbModificationDateAttr:
-            return CFSTR("REAL");
-        case kSecDbRowIdAttr:
-            return CFSTR("INTEGER PRIMARY KEY AUTOINCREMENT");
-    }
-}
-
-static void SecDbAppendUnqiue(CFMutableStringRef sql, CFStringRef value, bool *haveUnique) {
-    assert(haveUnique);
-    if (!*haveUnique)
-        CFStringAppend(sql, CFSTR("UNIQUE("));
-
-    SecDbAppendElement(sql, value, haveUnique);
-}
-
-static void SecDbAppendCreateTableWithClass(CFMutableStringRef sql, const SecDbClass *c) {
-    CFStringAppendFormat(sql, 0, CFSTR("CREATE TABLE %@("), c->name);
-    SecDbForEachAttrWithMask(c,desc,kSecDbInFlag) {
-        CFStringAppendFormat(sql, 0, CFSTR("%@ %@"), desc->name, SecDbGetKindSQL(desc->kind));
-        if (desc->flags & kSecDbNotNullFlag)
-            CFStringAppend(sql, CFSTR(" NOT NULL"));
-        if (desc->flags & kSecDbDefault0Flag)
-            CFStringAppend(sql, CFSTR(" DEFAULT 0"));
-        if (desc->flags & kSecDbDefaultEmptyFlag)
-            CFStringAppend(sql, CFSTR(" DEFAULT ''"));
-        CFStringAppend(sql, CFSTR(","));
-    }
-
-    bool haveUnique = false;
-    SecDbForEachAttrWithMask(c,desc,kSecDbPrimaryKeyFlag | kSecDbInFlag) {
-        SecDbAppendUnqiue(sql, desc->name, &haveUnique);
-    }
-    if (haveUnique)
-        CFStringAppend(sql, CFSTR(")"));
-
-    CFStringAppend(sql, CFSTR(");"));
-}
-
-static const char * const s3dl_upgrade_sql[] = {
-    /* 0 */
-    "",
-
-    /* 1 */
-    /* Create indices. */
-    "CREATE INDEX igsha ON genp(sha1);"
-    "CREATE INDEX iisha ON inet(sha1);"
-    "CREATE INDEX icsha ON cert(sha1);"
-    "CREATE INDEX iksha ON keys(sha1);"
-    "CREATE INDEX ialis ON cert(alis);"
-    "CREATE INDEX isubj ON cert(subj);"
-    "CREATE INDEX iskid ON cert(skid);"
-    "CREATE INDEX ipkhh ON cert(pkhh);"
-    "CREATE INDEX ikcls ON keys(kcls);"
-    "CREATE INDEX iklbl ON keys(klbl);"
-    "CREATE INDEX iencr ON keys(encr);"
-    "CREATE INDEX idecr ON keys(decr);"
-    "CREATE INDEX idrve ON keys(drve);"
-    "CREATE INDEX isign ON keys(sign);"
-    "CREATE INDEX ivrfy ON keys(vrfy);"
-    "CREATE INDEX iwrap ON keys(wrap);"
-    "CREATE INDEX iunwp ON keys(unwp);",
-
-    /* 2 */
-    "",
-
-    /* 3 */
-    /* Rename version 2 or version 3 tables and drop version table since
-       step 0 creates it. */
-    "ALTER TABLE genp RENAME TO ogenp;"
-    "ALTER TABLE inet RENAME TO oinet;"
-    "ALTER TABLE cert RENAME TO ocert;"
-    "ALTER TABLE keys RENAME TO okeys;"
-    "DROP TABLE tversion;",
-
-    /* 4 */
-    "",
-
-    /* 5 */
-    "",
-
-    /* 6 */
-    "",
-
-    /* 7 */
-    /* Move data from version 5 tables to new ones and drop old ones. */
-    "INSERT INTO genp (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data,agrp,pdmn) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data,agrp,pdmn from ogenp;"
-    "INSERT INTO inet (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data,agrp,pdmn) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data,agrp,pdmn from oinet;"
-    "INSERT INTO cert (rowid,cdat,mdat,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp,pdmn) SELECT rowid,cdat,mdat,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp,pdmn from ocert;"
-    "INSERT INTO keys (rowid,cdat,mdat,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data,agrp,pdmn) SELECT rowid,cdat,mdat,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data,agrp,pdmn from okeys;"
-    "DROP TABLE ogenp;"
-    "DROP TABLE oinet;"
-    "DROP TABLE ocert;"
-    "DROP TABLE okeys;"
-    "CREATE INDEX igsha ON genp(sha1);"
-    "CREATE INDEX iisha ON inet(sha1);"
-    "CREATE INDEX icsha ON cert(sha1);"
-    "CREATE INDEX iksha ON keys(sha1);",
-};
-
-struct sql_stages {
-    int pre;
-    int main;
-    int post;
-    bool init_pdmn; // If true do a full export followed by an import of the entire database so all items are re-encoded.
-};
-
-/* On disk database format version upgrade scripts.
-   If pre is 0, version is unsupported and db is considered corrupt for having that version.
-   First entry creates the current db, each susequent entry upgrade to current from the version
-   represented by the index of the slot.  Each script is either -1 (disabled) of the number of
-   the script in the main table.
-    {pre,main,post, reencode} */
-static struct sql_stages s3dl_upgrade_script[] = {
-    { -1, 0, 1, false },/* 0->current: Create version 6 database. */
-    {},                 /* 1->current: Upgrade to version 6 from version 1 (LittleBear) -- Unsupported. */
-    {},                 /* 2->current: Upgrade to version 6 from version 2 (BigBearBeta) -- Unsupported */
-    {},                 /* 3->current: Upgrade to version 6 from version 3 (Apex) -- Unsupported */
-    {},                 /* 4->current: Upgrade to version 6 from version 4 (Telluride) -- Unsupported */
-    { 3, 0, 7, true },  /* 5->current: Upgrade to version 6 from version 5 (TellurideGM). */
-};
-
-static bool sql_run_script(SecDbConnectionRef dbt, int number, CFErrorRef *error)
-{
-    /* Script -1 == skip this step. */
-    if (number < 0)
-        return true;
-
-    /* If we are attempting to run a script we don't have, fail. */
-    if ((size_t)number >= array_size(s3dl_upgrade_sql))
-        return SecDbError(SQLITE_CORRUPT, error, CFSTR("script %d exceeds maximum %d"),
-                                number, (int)(array_size(s3dl_upgrade_sql)));
-    __block bool ok = true;
-    if (number == 0) {
-        CFMutableStringRef sql = CFStringCreateMutable(0, 0);
-        SecDbAppendCreateTableWithClass(sql, &genp_class);
-        SecDbAppendCreateTableWithClass(sql, &inet_class);
-        SecDbAppendCreateTableWithClass(sql, &cert_class);
-        SecDbAppendCreateTableWithClass(sql, &keys_class);
-        CFStringAppend(sql, CFSTR("CREATE TABLE tversion(version INTEGER);INSERT INTO tversion(version) VALUES(6);"));
-        CFStringPerformWithCString(sql, ^(const char *sql_string) {
-            ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), sql_string, NULL, NULL, NULL),
-                                     SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), sql_string);
-        });
-        CFReleaseSafe(sql);
-    } else {
-        ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), s3dl_upgrade_sql[number], NULL, NULL, NULL),
-                                 SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), s3dl_upgrade_sql[number]);
-    }
-    return ok;
-}
-
-/* Return the current database version in *version.  Returns a
- SQLITE error. */
-static bool s3dl_dbt_get_version(SecDbConnectionRef dbt, int *version, CFErrorRef *error)
-{
-    CFStringRef sql = CFSTR("SELECT version FROM tversion LIMIT 1");
-    return SecDbWithSQL(dbt, sql, error, ^(sqlite3_stmt *stmt) {
-        __block bool found_version = false;
-        bool step_ok = SecDbForEach(stmt, error, ^(int row_index __unused) {
-            if (!found_version) {
-                *version = sqlite3_column_int(stmt, 0);
-                found_version = true;
-            }
-            return found_version;
-        });
-        if (!found_version) {
-            /* We have a tversion table but we didn't find a single version
-             value, now what? I suppose we pretend the db is corrupted
-             since this isn't supposed to ever happen. */
-            step_ok = SecDbError(SQLITE_CORRUPT, error, CFSTR("Failed to read version: database corrupt"));
-            secwarning("SELECT version step: %@", error ? *error : NULL);
-        }
-        return step_ok;
-    });
-}
-
-static bool s3dl_dbt_upgrade_from_version(SecDbConnectionRef dbt, int version, CFErrorRef *error)
-{
-    /* We need to go from db version to CURRENT_DB_VERSION, let's do so. */
-    __block bool ok = true;
-    /* O, guess we're done already. */
-    if (version == CURRENT_DB_VERSION)
-        return ok;
-
-    if (ok && version < 6) {
-        // Pre v6 keychains need to have WAL enabled, since SecDb only
-        // does this at db creation time.
-        // NOTE: This has to be run outside of a transaction.
-        ok = (SecDbExec(dbt, CFSTR("PRAGMA auto_vacuum = FULL"), error) &&
-              SecDbExec(dbt, CFSTR("PRAGMA journal_mode = WAL"), error));
-    }
-
-    // Start a transaction to do the upgrade within
-    if (ok) { ok = SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) {
-        // Be conservative and get the version again once we start a transaction.
-        int cur_version = version;
-        s3dl_dbt_get_version(dbt, &cur_version, NULL);
-
-        /* If we are attempting to upgrade to a version greater than what we have
-         an upgrade script for, fail. */
-        if (ok && (cur_version < 0 ||
-            (size_t)cur_version >= array_size(s3dl_upgrade_script))) {
-            ok = SecDbError(SQLITE_CORRUPT, error, CFSTR("no upgrade script for version: %d"), cur_version);
-            secerror("no upgrade script for version %d", cur_version);
-        }
-
-        struct sql_stages *script;
-        if (ok) {
-            script = &s3dl_upgrade_script[cur_version];
-            if (script->pre == 0)
-                ok = SecDbError(SQLITE_CORRUPT, error, CFSTR("unsupported db version %d"), cur_version);
-        }
-        if (ok)
-            ok = sql_run_script(dbt, script->pre, error);
-        if (ok)
-            ok = sql_run_script(dbt, script->main, error);
-        if (ok)
-            ok = sql_run_script(dbt, script->post, error);
-        if (ok && script->init_pdmn) {
-            CFErrorRef localError = NULL;
-            CFDictionaryRef backup = SecServerExportKeychainPlist(dbt,
-                                                                  KEYBAG_DEVICE, KEYBAG_NONE, kSecNoItemFilter, &localError);
-            if (backup) {
-                if (localError) {
-                    secerror("Ignoring export error: %@ during upgrade export", localError);
-                    CFReleaseNull(localError);
-                }
-                ok = SecServerImportKeychainInPlist(dbt, KEYBAG_NONE,
-                                                    KEYBAG_DEVICE, backup, kSecNoItemFilter, &localError);
-                CFRelease(backup);
-            } else {
-                ok = false;
-
-                if (localError && CFErrorGetCode(localError) == errSecInteractionNotAllowed) {
-                    SecError(errSecUpgradePending, error,
-                         CFSTR("unable to complete upgrade due to device lock state"));
-                    secerror("unable to complete upgrade due to device lock state");
-                } else {
-                    secerror("unable to complete upgrade for unknown reason, marking DB as corrupt: %@", localError);
-                    SecDbCorrupt(dbt);
-                }
-            }
-
-            if (localError) {
-                if (error && !*error)
-                    *error = localError;
-                else
-                    CFRelease(localError);
-            }
-        } else if (!ok) {
-            secerror("unable to complete upgrade scripts, marking DB as corrupt: %@", error ? *error : NULL);
-            SecDbCorrupt(dbt);
-        }
-        *commit = ok;
-    }); } else {
-        secerror("unable to complete upgrade scripts, marking DB as corrupt: %@", error ? *error : NULL);
-        SecDbCorrupt(dbt);
-    }
-
-    return ok;
-}
-
-
-/* This function is called if the db doesn't have the proper version.  We
-   start an exclusive transaction and recheck the version, and then perform
-   the upgrade within that transaction. */
-static bool s3dl_dbt_upgrade(SecDbConnectionRef dbt, CFErrorRef *error)
-{
-    // Already in a transaction
-    //return kc_transaction(dbt, error, ^{
-        int version = 0; // Upgrade from version 0 == create new db
-        s3dl_dbt_get_version(dbt, &version, NULL);
-        return s3dl_dbt_upgrade_from_version(dbt, version, error);
-    //});
-}
-
-const uint32_t v0KeyWrapOverHead = 8;
-
-/* Wrap takes a 128 - 256 bit key as input and returns output of
-   inputsize + 64 bits.
-   In bytes this means that a
-   16 byte (128 bit) key returns a 24 byte wrapped key
-   24 byte (192 bit) key returns a 32 byte wrapped key
-   32 byte (256 bit) key returns a 40 byte wrapped key  */
-static bool ks_crypt(uint32_t selector, keybag_handle_t keybag,
-    keyclass_t keyclass, uint32_t textLength, const uint8_t *source, uint8_t *dest, size_t *dest_len, CFErrorRef *error) {
-#if USE_KEYSTORE
-       kern_return_t kernResult = kIOReturnBadArgument;
-
-    if (selector == kAppleKeyStoreKeyWrap) {
-        kernResult = aks_wrap_key(source, textLength, keyclass, keybag, dest, (int*)dest_len);
-    } else if (selector == kAppleKeyStoreKeyUnwrap) {
-        kernResult = aks_unwrap_key(source, textLength, keyclass, keybag, dest, (int*)dest_len);
-    }
-
-       if (kernResult != KERN_SUCCESS) {
-        if ((kernResult == kIOReturnNotPermitted) || (kernResult == kIOReturnNotPrivileged)) {
-            /* Access to item attempted while keychain is locked. */
-            return SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt: %x failed to %s item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked."),
-                     kernResult, (selector == kAppleKeyStoreKeyWrap ? "wrap" : "unwrap"), keyclass, keybag);
-        } else if (kernResult == kIOReturnError) {
-            /* Item can't be decrypted on this device, ever, so drop the item. */
-            return SecError(errSecDecode, error, CFSTR("ks_crypt: %x failed to %s item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."),
-                     kernResult, (selector == kAppleKeyStoreKeyWrap ? "wrap" : "unwrap"), keyclass, keybag);
-        } else {
-            return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to %s item (class %"PRId32", bag: %"PRId32")"),
-                     kernResult, (selector == kAppleKeyStoreKeyWrap ? "wrap" : "unwrap"), keyclass, keybag);
-        }
-       }
-       return true;
-#else /* !USE_KEYSTORE */
-    if (selector == kAppleKeyStoreKeyWrap) {
-        /* The no encryption case. */
-        if (*dest_len >= textLength + 8) {
-            memcpy(dest, source, textLength);
-            memset(dest + textLength, 8, 8);
-            *dest_len = textLength + 8;
-        } else
-            return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to wrap item (class %"PRId32")"), keyclass);
-    } else if (selector == kAppleKeyStoreKeyUnwrap) {
-        if (*dest_len + 8 >= textLength) {
-            memcpy(dest, source, textLength - 8);
-            *dest_len = textLength - 8;
-        } else
-            return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: failed to unwrap item (class %"PRId32")"), keyclass);
-    }
-    return true;
-#endif /* USE_KEYSTORE */
-}
-
-
-CFDataRef kc_plist_copy_der(CFPropertyListRef plist, CFErrorRef *error) {
-    size_t len = der_sizeof_plist(plist, error);
-    CFMutableDataRef encoded = CFDataCreateMutable(0, len);
-    CFDataSetLength(encoded, len);
-    uint8_t *der_end = CFDataGetMutableBytePtr(encoded);
-    const uint8_t *der = der_end;
-    der_end += len;
-    der_end = der_encode_plist(plist, error, der, der_end);
-    if (!der_end) {
-        CFReleaseNull(encoded);
-    } else {
-        assert(!der_end || der_end == der);
-    }
-    return encoded;
-}
-
-static CFDataRef kc_copy_digest(const struct ccdigest_info *di, size_t len,
-                                const void *data, CFErrorRef *error) {
-    CFMutableDataRef digest = CFDataCreateMutable(0, di->output_size);
-    CFDataSetLength(digest, di->output_size);
-    ccdigest(di, len, data, CFDataGetMutableBytePtr(digest));
-    return digest;
-}
-
-CFDataRef kc_copy_sha1(size_t len, const void *data, CFErrorRef *error) {
-    return kc_copy_digest(ccsha1_di(), len, data, error);
-}
-
-CFDataRef kc_copy_plist_sha1(CFPropertyListRef plist, CFErrorRef *error) {
-    CFDataRef der = kc_plist_copy_der(plist, error);
-    CFDataRef digest = NULL;
-    if (der) {
-        digest = kc_copy_sha1(CFDataGetLength(der), CFDataGetBytePtr(der), error);
-        CFRelease(der);
-    }
-    return digest;
-}
-
-/* Given plainText create and return a CFDataRef containing:
-   BULK_KEY = RandomKey()
-   version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
-    AES(BULK_KEY, NULL_IV, plainText || padding)
- */
-bool ks_encrypt_data(keybag_handle_t keybag,
-    keyclass_t keyclass, CFDataRef plainText, CFDataRef *pBlob, CFErrorRef *error) {
-    CFMutableDataRef blob = NULL;
-    bool ok = true;
-    //check(keybag >= 0);
-
-    /* Precalculate output blob length. */
-    const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */
-    const uint32_t maxKeyWrapOverHead = 8 + 32;
-    uint8_t bulkKey[bulkKeySize];
-    uint8_t bulkKeyWrapped[bulkKeySize + maxKeyWrapOverHead];
-    size_t bulkKeyWrappedSize = sizeof(bulkKeyWrapped);
-    uint32_t key_wrapped_size;
-
-    if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID()
-        || keyclass == 0) {
-        ok = SecError(errSecParam, error, CFSTR("ks_encrypt_data: invalid plain text"));
-        goto out;
-    }
-
-    size_t ptLen = CFDataGetLength(plainText);
-    size_t ctLen = ptLen;
-    size_t tagLen = 16;
-    uint32_t version = 3;
-
-    if (SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey)) {
-        ok = SecError(errSecAllocate, error, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed"));
-        goto out;
-    }
-
-    /* Now that we're done using the bulkKey, in place encrypt it. */
-    require_quiet(ok = ks_crypt(kAppleKeyStoreKeyWrap, keybag, keyclass,
-                                       bulkKeySize, bulkKey, bulkKeyWrapped,
-                                       &bulkKeyWrappedSize, error), out);
-    key_wrapped_size = (uint32_t)bulkKeyWrappedSize;
-
-    size_t blobLen = sizeof(version) + sizeof(keyclass) +
-        sizeof(key_wrapped_size) + key_wrapped_size + ctLen + tagLen;
-
-       require_quiet(blob = CFDataCreateMutable(NULL, blobLen), out);
-    CFDataSetLength(blob, blobLen);
-       UInt8 *cursor = CFDataGetMutableBytePtr(blob);
-
-    *((uint32_t *)cursor) = version;
-    cursor += sizeof(version);
-
-    *((keyclass_t *)cursor) = keyclass;
-    cursor += sizeof(keyclass);
-
-    *((uint32_t *)cursor) = key_wrapped_size;
-    cursor += sizeof(key_wrapped_size);
-
-    memcpy(cursor, bulkKeyWrapped, key_wrapped_size);
-    cursor += key_wrapped_size;
-
-    /* Encrypt the plainText with the bulkKey. */
-    CCCryptorStatus ccerr = CCCryptorGCM(kCCEncrypt, kCCAlgorithmAES128,
-                                         bulkKey, bulkKeySize,
-                                         NULL, 0,  /* iv */
-                                         NULL, 0,  /* auth data */
-                                         CFDataGetBytePtr(plainText), ptLen,
-                                         cursor,
-                                         cursor + ctLen, &tagLen);
-    if (ccerr) {
-        ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr);
-        goto out;
-    }
-    if (tagLen != 16) {
-        ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
-        goto out;
-    }
-
-out:
-    memset(bulkKey, 0, sizeof(bulkKey));
-       if (!ok) {
-               CFReleaseSafe(blob);
-       } else {
-               *pBlob = blob;
-       }
-    return ok;
-}
-
-/* Given cipherText containing:
-   version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
-    AES(BULK_KEY, NULL_IV, plainText || padding)
-   return the plainText. */
-bool ks_decrypt_data(keybag_handle_t keybag,
-    keyclass_t *pkeyclass, CFDataRef blob, CFDataRef *pPlainText,
-    uint32_t *version_p, CFErrorRef *error) {
-    const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */
-    uint8_t bulkKey[bulkKeySize];
-    size_t bulkKeyCapacity = sizeof(bulkKey);
-    bool ok = true;
-
-    CFMutableDataRef plainText = NULL;
-#if USE_KEYSTORE
-#if TARGET_OS_IPHONE
-    check(keybag >= 0);
-#else
-    check((keybag >= 0) || (keybag == session_keybag_handle));
-#endif
-#endif
-
-    if (!blob) {
-        ok = SecError(errSecParam, error, CFSTR("ks_decrypt_data: invalid blob"));
-        goto out;
-    }
-
-    size_t blobLen = CFDataGetLength(blob);
-    const uint8_t *cursor = CFDataGetBytePtr(blob);
-    uint32_t version;
-    keyclass_t keyclass;
-    uint32_t wrapped_key_size;
-
-    /* Check for underflow, ensuring we have at least one full AES block left. */
-    if (blobLen < sizeof(version) + sizeof(keyclass) +
-        bulkKeySize + v0KeyWrapOverHead + 16) {
-        ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow"));
-        goto out;
-    }
-
-    version = *((uint32_t *)cursor);
-    cursor += sizeof(version);
-
-    keyclass = *((keyclass_t *)cursor);
-    if (pkeyclass)
-        *pkeyclass = keyclass;
-    cursor += sizeof(keyclass);
-
-    size_t minimum_blob_len = sizeof(version) + sizeof(keyclass) + 16;
-    size_t ctLen = blobLen - sizeof(version) - sizeof(keyclass);
-    size_t tagLen = 0;
-    switch (version) {
-        case 0:
-            wrapped_key_size = bulkKeySize + v0KeyWrapOverHead;
-            break;
-        case 2:
-            /* DROPTHROUGH */
-            /* v2 and v3 have the same crypto, just different dictionary encodings. */
-        case 3:
-            tagLen = 16;
-            minimum_blob_len -= 16; // Remove PKCS7 padding block requirement
-            ctLen -= tagLen;        // Remove tagLen from ctLen
-            /* DROPTHROUGH */
-        case 1:
-            wrapped_key_size = *((uint32_t *)cursor);
-            cursor += sizeof(wrapped_key_size);
-            minimum_blob_len += sizeof(wrapped_key_size);
-            ctLen -= sizeof(wrapped_key_size);
-            break;
-        default:
-            ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version %d"), version);
-            goto out;
-    }
-
-    /* Validate key wrap length against total length */
-    require(blobLen - minimum_blob_len - tagLen >= wrapped_key_size, out);
-    ctLen -= wrapped_key_size;
-    if (version < 2 && (ctLen & 0xF) != 0) {
-        ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version"));
-        goto out;
-    }
-
-    /* Now unwrap the bulk key using a key in the keybag. */
-    require_quiet(ok = ks_crypt(kAppleKeyStoreKeyUnwrap, keybag,
-        keyclass, wrapped_key_size, cursor, bulkKey, &bulkKeyCapacity, error), out);
-    cursor += wrapped_key_size;
-
-    plainText = CFDataCreateMutable(NULL, ctLen);
-    if (!plainText) {
-        ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: failed to allocate data for plain text"));
-        goto out;
-    }
-    CFDataSetLength(plainText, ctLen);
-
-    /* Decrypt the cipherText with the bulkKey. */
-    CCCryptorStatus ccerr;
-    if (tagLen) {
-        uint8_t tag[tagLen];
-        ccerr = CCCryptorGCM(kCCDecrypt, kCCAlgorithmAES128,
-                             bulkKey, bulkKeySize,
-                             NULL, 0,  /* iv */
-                             NULL, 0,  /* auth data */
-                             cursor, ctLen,
-                             CFDataGetMutableBytePtr(plainText),
-                             tag, &tagLen);
-        if (ccerr) {
-            /* TODO: Should this be errSecDecode once AppleKeyStore correctly
-             identifies uuid unwrap failures? */
-            /* errSecInteractionNotAllowed; */
-            ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr);
-            goto out;
-        }
-        if (tagLen != 16) {
-            ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
-            goto out;
-        }
-        cursor += ctLen;
-        if (memcmp(tag, cursor, tagLen)) {
-            ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob"));
-            goto out;
-        }
-    } else {
-        size_t ptLen;
-        ccerr = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
-                        bulkKey, bulkKeySize, NULL, cursor, ctLen,
-                        CFDataGetMutableBytePtr(plainText), ctLen, &ptLen);
-        if (ccerr) {
-            /* TODO: Should this be errSecDecode once AppleKeyStore correctly
-               identifies uuid unwrap failures? */
-            /* errSecInteractionNotAllowed; */
-            ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr);
-            goto out;
-        }
-        CFDataSetLength(plainText, ptLen);
-    }
-    if (version_p) *version_p = version;
-out:
-    memset(bulkKey, 0, bulkKeySize);
-       if (!ok) {
-               CFReleaseSafe(plainText);
-       } else {
-               *pPlainText = plainText;
-       }
-    return ok;
-}
-
-static bool use_hwaes() {
-    static bool use_hwaes;
-    static dispatch_once_t check_once;
-    dispatch_once(&check_once, ^{
-        use_hwaes = hwaes_key_available();
-        if (use_hwaes) {
-            asl_log(NULL, NULL, ASL_LEVEL_INFO, "using hwaes key");
-        } else {
-            asl_log(NULL, NULL, ASL_LEVEL_ERR, "unable to access hwaes key");
-        }
-    });
-    return use_hwaes;
-}
-
-/* Upper limit for number of keys in a QUERY dictionary. */
-#define QUERY_KEY_LIMIT_BASE    (128)
-#ifdef NO_SERVER
-#define QUERY_KEY_LIMIT  (31 + QUERY_KEY_LIMIT_BASE)
-#else
-#define QUERY_KEY_LIMIT  QUERY_KEY_LIMIT_BASE
-#endif
-
-/* Inline accessors to attr and match values in a query. */
-static inline CFIndex query_attr_count(const Query *q)
-{
-    return q->q_attr_end;
-}
-
-static inline Pair query_attr_at(const Query *q, CFIndex ix)
-{
-    return q->q_pairs[ix];
-}
-
-static inline CFIndex query_match_count(const Query *q)
-{
-    return q->q_match_end - q->q_match_begin;
-}
-
-static inline Pair query_match_at(const Query *q, CFIndex ix)
-{
-    return q->q_pairs[q->q_match_begin + ix];
-}
-
-/* Private routines used to parse a query. */
-
-/* Sets q_keyclass based on value. */
-static void query_parse_keyclass(const void *value, Query *q) {
-    if (!isString(value)) {
-        SecError(errSecParam, &q->q_error, CFSTR("accessible attribute %@ not a string"), value);
-        return;
-    } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) {
-        q->q_keyclass = key_class_ak;
-    } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) {
-        q->q_keyclass = key_class_ck;
-    } else if (CFEqual(value, kSecAttrAccessibleAlways)) {
-        q->q_keyclass = key_class_dk;
-    } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) {
-        q->q_keyclass = key_class_aku;
-    } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) {
-        q->q_keyclass = key_class_cku;
-    } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnly)) {
-        q->q_keyclass = key_class_dku;
-    } else {
-        SecError(errSecParam, &q->q_error, CFSTR("accessible attribute %@ unknown"), value);
-        return;
-    }
-    //q->q_keyclass_s = value;
-}
-
-static const SecDbClass *kc_class_with_name(CFStringRef name) {
-    if (isString(name)) {
-#if 0
-        // TODO Iterate kc_db_classes and look for name == class->name.
-        // Or get clever and switch on first letter of class name and compare to verify
-        static const void *kc_db_classes[] = {
-            &genp_class,
-            &inet_class,
-            &cert_class,
-            &keys_class,
-            &identity_class
-        };
-#endif
-        if (CFEqual(name, kSecClassGenericPassword))
-            return &genp_class;
-        else if (CFEqual(name, kSecClassInternetPassword))
-            return &inet_class;
-        else if (CFEqual(name, kSecClassCertificate))
-            return &cert_class;
-        else if (CFEqual(name, kSecClassKey))
-            return &keys_class;
-        else if (CFEqual(name, kSecClassIdentity))
-            return &identity_class;
-    }
-    return NULL;
-}
-
-/* AUDIT[securityd](done):
-   key (ok) is a caller provided, string or number of length 4.
-   value (ok) is a caller provided, non NULL CFTypeRef.
- */
-static void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q)
-{
-    if (CFEqual(desc->name, kSecAttrSynchronizable)) {
-        q->q_sync = true;
-        if (CFEqual(value, kSecAttrSynchronizableAny))
-            return; /* skip the attribute so it isn't part of the search */
-    }
-
-    CFTypeRef attr = NULL;
-    switch (desc->kind) {
-        case kSecDbDataAttr:
-            attr = copyData(value);
-            break;
-        case kSecDbBlobAttr:
-            attr = copyBlob(value);
-            break;
-        case kSecDbDateAttr:
-        case kSecDbCreationDateAttr:
-        case kSecDbModificationDateAttr:
-            attr = copyDate(value);
-            break;
-        case kSecDbNumberAttr:
-        case kSecDbSyncAttr:
-        case kSecDbTombAttr:
-            attr = copyNumber(value);
-            break;
-        case kSecDbAccessAttr:
-        case kSecDbStringAttr:
-            attr = copyString(value);
-            break;
-        case kSecDbSHA1Attr:
-            attr = copySHA1(value);
-            break;
-        case kSecDbRowIdAttr:
-        case kSecDbPrimaryKeyAttr:
-        case kSecDbEncryptedDataAttr:
-            break;
-    }
-
-    if (!attr) {
-        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value);
-        return;
-    }
-
-    /* Store plaintext attr data in q_item unless it's a kSecDbSHA1Attr. */
-    if (q->q_item && desc->kind != kSecDbSHA1Attr) {
-        CFDictionarySetValue(q->q_item, desc->name, attr);
-    }
-
-    if (CFEqual(desc->name, kSecAttrAccessible)) {
-        query_parse_keyclass(attr, q);
-    }
-
-    /* Convert attr to (sha1) digest if requested. */
-    if (desc->flags & kSecDbSHA1ValueInFlag) {
-        CFDataRef data = copyData(attr);
-        CFRelease(attr);
-        if (!data) {
-            SecError(errSecInternal, &q->q_error, CFSTR("failed to get attribute %@ data"), desc->name);
-            return;
-        }
-
-        CFMutableDataRef digest = CFDataCreateMutable(0, CC_SHA1_DIGEST_LENGTH);
-        CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH);
-        /* 64 bits cast: worst case is we generate the wrong hash */
-        assert((unsigned long)CFDataGetLength(data)<UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
-        CCDigest(kCCDigestSHA1, CFDataGetBytePtr(data), (CC_LONG)CFDataGetLength(data),
-                CFDataGetMutableBytePtr(digest));
-        CFRelease(data);
-        attr = digest;
-    }
-
-    /* Record the new attr key, value in q_pairs. */
-    q->q_pairs[q->q_attr_end].key = desc->name;
-    q->q_pairs[q->q_attr_end++].value = attr;
-}
-
-static void query_add_attribute(const void *key, const void *value, Query *q)
-{
-    const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
-    if (desc)
-        query_add_attribute_with_desc(desc, value, q);
-}
-
-/* First remove key from q->q_pairs if it's present, then add the attribute again. */
-static void query_set_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q) {
-    if (CFDictionaryContainsKey(q->q_item, desc->name)) {
-        CFIndex ix;
-        for (ix = 0; ix < q->q_attr_end; ++ix) {
-            if (CFEqual(desc->name, q->q_pairs[ix].key)) {
-                CFReleaseSafe(q->q_pairs[ix].value);
-                --q->q_attr_end;
-                for (; ix < q->q_attr_end; ++ix) {
-                    q->q_pairs[ix] = q->q_pairs[ix + 1];
-                }
-                CFDictionaryRemoveValue(q->q_item, desc->name);
-                break;
-            }
-        }
-    }
-    query_add_attribute_with_desc(desc, value, q);
-}
-
-/* AUDIT[securityd](done):
-   key (ok) is a caller provided, string starting with 'm'.
-   value (ok) is a caller provided, non NULL CFTypeRef.
- */
-static void query_add_match(const void *key, const void *value, Query *q)
-{
-    /* Record the match key, value in q_pairs. */
-    --(q->q_match_begin);
-    q->q_pairs[q->q_match_begin].key = key;
-    q->q_pairs[q->q_match_begin].value = value;
-
-    if (CFEqual(kSecMatchLimit, key)) {
-        /* Figure out what the value for kSecMatchLimit is if specified. */
-        if (CFGetTypeID(value) == CFNumberGetTypeID()) {
-            if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit))
-                SecError(errSecItemInvalidValue, &q->q_error, CFSTR("failed to convert match limit %@ to CFIndex"), value);
-        } else if (CFEqual(kSecMatchLimitAll, value)) {
-            q->q_limit = kSecMatchUnlimited;
-        } else if (CFEqual(kSecMatchLimitOne, value)) {
-            q->q_limit = 1;
-        } else {
-            SecError(errSecItemInvalidValue, &q->q_error, CFSTR("unsupported match limit %@"), value);
-        }
-    } else if (CFEqual(kSecMatchIssuers, key) &&
-               (CFGetTypeID(value) == CFArrayGetTypeID()))
-    {
-        CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-        if (canonical_issuers) {
-            CFIndex i, count = CFArrayGetCount(value);
-            for (i = 0; i < count; i++) {
-                CFTypeRef issuer_data = CFArrayGetValueAtIndex(value, i);
-                CFDataRef issuer_canonical = NULL;
-                if (CFDataGetTypeID() == CFGetTypeID(issuer_data))
-                    issuer_canonical = SecDistinguishedNameCopyNormalizedContent((CFDataRef)issuer_data);
-                if (issuer_canonical) {
-                    CFArrayAppendValue(canonical_issuers, issuer_canonical);
-                    CFRelease(issuer_canonical);
-                }
-            }
-
-            if (CFArrayGetCount(canonical_issuers) > 0) {
-                q->q_match_issuer = canonical_issuers;
-            } else
-                CFRelease(canonical_issuers);
-        }
-    }
-}
-
-static bool query_set_class(Query *q, CFStringRef c_name, CFErrorRef *error) {
-    const SecDbClass *value;
-    if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() &&
-        (value = kc_class_with_name(c_name)) &&
-        (q->q_class == 0 || q->q_class == value)) {
-        q->q_class = value;
-        return true;
-    }
-
-    if (error && !*error)
-        SecError((c_name ? errSecNoSuchClass : errSecItemClassMissing), error, CFSTR("can find class named: %@"), c_name);
-
-
-    return false;
-}
-
-static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *error) {
-    CFStringRef c_name = NULL;
-    const void *value = CFDictionaryGetValue(query, kSecClass);
-    if (isString(value)) {
-        c_name = value;
-    } else {
-        value = CFDictionaryGetValue(query, kSecValuePersistentRef);
-        if (isData(value)) {
-            CFDataRef pref = value;
-            _SecItemParsePersistentRef(pref, &c_name, 0);
-        }
-    }
-
-    if (c_name && (value = kc_class_with_name(c_name))) {
-        return value;
-    } else {
-        if (c_name)
-            SecError(errSecNoSuchClass, error, CFSTR("can't find class named: %@"), c_name);
-        else
-            SecError(errSecItemClassMissing, error, CFSTR("query missing class name"));
-        return NULL;
-    }
-}
-
-/* AUDIT[securityd](done):
-   key (ok) is a caller provided, string starting with 'c'.
-   value (ok) is a caller provided, non NULL CFTypeRef.
- */
-static void query_add_class(const void *key, const void *value, Query *q)
-{
-    if (CFEqual(key, kSecClass)) {
-        query_set_class(q, value, &q->q_error);
-    } else {
-        SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_class: key %@ is not %@"), key, kSecClass);
-    }
-}
-
-/* AUDIT[securityd](done):
-   key (ok) is a caller provided, string starting with 'r'.
-   value (ok) is a caller provided, non NULL CFTypeRef.
- */
-static void query_add_return(const void *key, const void *value, Query *q)
-{
-    ReturnTypeMask mask;
-    if (CFGetTypeID(value) != CFBooleanGetTypeID()) {
-        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_return: value %@ is not CFBoolean"), value);
-        return;
-    }
-
-    int set_it = CFEqual(value, kCFBooleanTrue);
-
-    if (CFEqual(key, kSecReturnData))
-        mask = kSecReturnDataMask;
-    else if (CFEqual(key, kSecReturnAttributes))
-        mask = kSecReturnAttributesMask;
-    else if (CFEqual(key, kSecReturnRef))
-        mask = kSecReturnRefMask;
-    else if (CFEqual(key, kSecReturnPersistentRef))
-        mask = kSecReturnPersistentRefMask;
-    else {
-        SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_return: unknown key %@"), key);
-        return;
-    }
-
-    if ((q->q_return_type & mask) && !set_it) {
-        /* Clear out this bit (it's set so xor with the mask will clear it). */
-        q->q_return_type ^= mask;
-    } else if (!(q->q_return_type & mask) && set_it) {
-        /* Set this bit. */
-        q->q_return_type |= mask;
-    }
-}
-
-/* AUDIT[securityd](done):
-   key (ok) is a caller provided, string starting with 'u'.
-   value (ok since q_use_item_list is unused) is a caller provided, non
-       NULL CFTypeRef.
- */
-static void query_add_use(const void *key, const void *value, Query *q)
-{
-    if (CFEqual(key, kSecUseItemList)) {
-        /* TODO: Add sanity checking when we start using this. */
-        q->q_use_item_list = value;
-    } else if (CFEqual(key, kSecUseTombstones)) {
-        if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
-            q->q_use_tomb = value;
-        } else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
-            q->q_use_tomb = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
-        } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
-            q->q_use_tomb = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
-        } else {
-            SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key);
-            return;
-        }
-#if defined(MULTIPLE_KEYCHAINS)
-    } else if (CFEqual(key, kSecUseKeychain)) {
-        q->q_use_keychain = value;
-    } else if (CFEqual(key, kSecUseKeychainList)) {
-        q->q_use_keychain_list = value;
-#endif /* !defined(MULTIPLE_KEYCHAINS) */
-    } else {
-        SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_use: unknown key %@"), key);
-        return;
-    }
-}
-
-static void query_set_data(const void *value, Query *q) {
-    if (!isData(value)) {
-        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("set_data: value %@ is not type data"), value);
-    } else {
-        q->q_data = value;
-        if (q->q_item)
-            CFDictionarySetValue(q->q_item, kSecValueData, value);
-    }
-}
-
-/* AUDIT[securityd](done):
-   key (ok) is a caller provided, string starting with 'u'.
-   value (ok) is a caller provided, non NULL CFTypeRef.
- */
-static void query_add_value(const void *key, const void *value, Query *q)
-{
-    if (CFEqual(key, kSecValueData)) {
-        query_set_data(value, q);
-#ifdef NO_SERVER
-    } else if (CFEqual(key, kSecValueRef)) {
-        q->q_ref = value;
-        /* TODO: Add value type sanity checking. */
-#endif
-    } else if (CFEqual(key, kSecValuePersistentRef)) {
-        CFStringRef c_name;
-        if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id))
-            query_set_class(q, c_name, &q->q_error);
-        else
-            SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_value: value %@ is not a valid persitent ref"), value);
-    } else {
-        SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_value: unknown key %@"), key);
-        return;
-    }
-}
-
-/* AUDIT[securityd](done):
-   key (ok) is a caller provided, unchecked.
-   value (ok) is a caller provided, unchecked.
- */
-static void query_update_applier(const void *key, const void *value,
-    void *context)
-{
-    Query *q = (Query *)context;
-    /* If something went wrong there is no point processing any more args. */
-    if (q->q_error)
-        return;
-
-    /* Make sure we have a string key. */
-    if (!isString(key)) {
-        SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("update_applier: unknown key type %@"), key);
-        return;
-    }
-
-    if (!value) {
-        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("update_applier: key %@ has NULL value"), key);
-        return;
-    }
-
-    if (CFEqual(key, kSecValueData)) {
-        query_set_data(value, q);
-    } else {
-        query_add_attribute(key, value, q);
-    }
-}
-
-/* AUDIT[securityd](done):
-   key (ok) is a caller provided, unchecked.
-   value (ok) is a caller provided, unchecked.
- */
-static void query_applier(const void *key, const void *value, void *context)
-{
-    Query *q = (Query *)context;
-    /* If something went wrong there is no point processing any more args. */
-    if (q->q_error)
-        return;
-
-    /* Make sure we have a key. */
-    if (!key) {
-        SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: NULL key"));
-        return;
-    }
-
-    /* Make sure we have a value. */
-    if (!value) {
-        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("applier: key %@ has NULL value"), key);
-        return;
-    }
-
-    /* Figure out what type of key we are dealing with. */
-    CFTypeID key_id = CFGetTypeID(key);
-    if (key_id == CFStringGetTypeID()) {
-        CFIndex key_len = CFStringGetLength(key);
-        /* String keys can be different things.  The subtype is determined by:
-           length 4 strings are all attributes.  Otherwise the first char
-           determines the type:
-           c: class must be kSecClass
-           m: match like kSecMatchPolicy
-           r: return like kSecReturnData
-           u: use keys
-           v: value
-         */
-        if (key_len == 4) {
-            /* attributes */
-            query_add_attribute(key, value, q);
-        } else if (key_len > 1) {
-            UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0);
-            switch (k_first_char)
-            {
-            case 'c': /* class */
-                query_add_class(key, value, q);
-                break;
-            case 'm': /* match */
-                query_add_match(key, value, q);
-                break;
-            case 'r': /* return */
-                query_add_return(key, value, q);
-                break;
-            case 'u': /* use */
-                query_add_use(key, value, q);
-                break;
-            case 'v': /* value */
-                query_add_value(key, value, q);
-                break;
-            default:
-                SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key);
-                break;
-            }
-        } else {
-            SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid length"), key);
-        }
-    } else if (key_id == CFNumberGetTypeID()) {
-        /* Numeric keys are always (extended) attributes. */
-        /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */
-        query_add_attribute(key, value, q);
-    } else {
-        /* We only support string and number type keys. */
-        SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: key %@ neither string nor number"), key);
-    }
-}
-
-static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) {
-    /* apsd and lockdown are always dku. */
-    if (CFEqual(agrp, CFSTR("com.apple.apsd"))
-        || CFEqual(agrp, CFSTR("lockdown-identities"))) {
-        return kSecAttrAccessibleAlwaysThisDeviceOnly;
-    }
-    /* All other certs or in the apple agrp is dk. */
-    if (q->q_class == &cert_class) {
-        /* third party certs are always dk. */
-        return kSecAttrAccessibleAlways;
-    }
-    /* The rest defaults to ak. */
-    return kSecAttrAccessibleWhenUnlocked;
-}
-
-static void query_ensure_keyclass(Query *q, CFStringRef agrp) {
-    if (q->q_keyclass == 0) {
-        CFStringRef accessible = query_infer_keyclass(q, agrp);
-        query_add_attribute(kSecAttrAccessible, accessible, q);
-    }
-}
-
-static bool query_error(Query *q, CFErrorRef *error) {
-    if (q->q_error) {
-        CFErrorRef tmp = q->q_error;
-        q->q_error = NULL;
-        if (error && !*error) {
-            *error = tmp;
-        } else {
-            CFRelease(tmp);
-        }
-        return false;
-    }
-    return true;
-}
-
-bool query_destroy(Query *q, CFErrorRef *error) {
-    bool ok = query_error(q, error);
-    CFIndex ix, attr_count = query_attr_count(q);
-    for (ix = 0; ix < attr_count; ++ix) {
-        CFReleaseSafe(query_attr_at(q, ix).value);
-    }
-    CFReleaseSafe(q->q_item);
-    CFReleaseSafe(q->q_primary_key_digest);
-    CFReleaseSafe(q->q_match_issuer);
-
-    free(q);
-    return ok;
-}
-
-static void SecKeychainChanged(bool syncWithPeers) {
-    uint32_t result = notify_post(g_keychain_changed_notification);
-    if (syncWithPeers)
-        SOSCCSyncWithAllPeers();
-    if (result == NOTIFY_STATUS_OK)
-        secnotice("item", "Sent %s%s", syncWithPeers ? "SyncWithAllPeers and " : "", g_keychain_changed_notification);
-    else
-        secerror("%snotify_post %s returned: %" PRIu32, syncWithPeers ? "Sent SyncWithAllPeers, " : "", g_keychain_changed_notification, result);
-}
-
-static bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) {
-    if (ok && !q->q_error && q->q_sync_changed) {
-        SecKeychainChanged(true);
-    }
-    return query_destroy(q, error) && ok;
-}
-
-/* Allocate and initialize a Query object for query. */
-Query *query_create(const SecDbClass *qclass, CFDictionaryRef query,
-                    CFErrorRef *error)
-{
-    if (!qclass) {
-        if (error && !*error)
-            SecError(errSecItemClassMissing, error, CFSTR("Missing class"));
-        return NULL;
-    }
-
-    /* Number of pairs we need is the number of attributes in this class
-       plus the number of keys in the dictionary, minus one for each key in
-       the dictionary that is a regular attribute. */
-    CFIndex key_count = SecDbClassAttrCount(qclass);
-    if (key_count == 0) {
-        // Identities claim to have 0 attributes, but they really support any keys or cert attribute.
-        key_count = SecDbClassAttrCount(&cert_class) + SecDbClassAttrCount(&keys_class);
-    }
-
-    if (query) {
-        key_count += CFDictionaryGetCount(query);
-        SecDbForEachAttr(qclass, attr) {
-            if (CFDictionaryContainsKey(query, attr->name))
-                --key_count;
-        }
-    }
-
-    if (key_count > QUERY_KEY_LIMIT) {
-        if (error && !*error)
-        {
-            secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count, QUERY_KEY_LIMIT);
-            SecError(errSecItemIllegalQuery, error, CFSTR("Past query key limit"));
-        }
-        return NULL;
-    }
-
-    Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count);
-    if (q == NULL) {
-        if (error && !*error)
-            SecError(errSecAllocate, error, CFSTR("Out of memory"));
-        return NULL;
-    }
-
-    q->q_keybag = KEYBAG_DEVICE;
-    q->q_class = qclass;
-    q->q_match_begin = q->q_match_end = key_count;
-    q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-
-    return q;
-}
-
-/* Parse query for a Query object q. */
-static bool query_parse_with_applier(Query *q, CFDictionaryRef query,
-                                     CFDictionaryApplierFunction applier,
-                                     CFErrorRef *error) {
-    CFDictionaryApplyFunction(query, applier, q);
-    return query_error(q, error);
-}
-
-/* Parse query for a Query object q. */
-static bool query_parse(Query *q, CFDictionaryRef query,
-                        CFErrorRef *error) {
-    return query_parse_with_applier(q, query, query_applier, error);
-}
-
-/* Parse query for a Query object q. */
-static bool query_update_parse(Query *q, CFDictionaryRef update,
-                               CFErrorRef *error) {
-    return query_parse_with_applier(q, update, query_update_applier, error);
-}
-
-static Query *query_create_with_limit(CFDictionaryRef query, CFIndex limit,
-                                      CFErrorRef *error) {
-    Query *q;
-    q = query_create(query_get_class(query, error), query, error);
-    if (q) {
-        q->q_limit = limit;
-        if (!query_parse(q, query, error)) {
-            query_destroy(q, error);
-            return NULL;
-        }
-        if (!q->q_sync && !q->q_row_id) {
-            /* query did not specify a kSecAttrSynchronizable attribute,
-             * and did not contain a persistent reference. */
-            query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q);
-        }
-    }
-    return q;
-}
-
-
-//TODO: Move this to SecDbItemRef
-
-/* Make sure all attributes that are marked as not_null have a value.  If
-   force_date is false, only set mdat and cdat if they aren't already set. */
-static void
-query_pre_add(Query *q, bool force_date) {
-    CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
-    SecDbForEachAttrWithMask(q->q_class, desc, kSecDbInFlag) {
-        if (desc->kind == kSecDbCreationDateAttr ||
-            desc->kind == kSecDbModificationDateAttr) {
-            if (force_date) {
-                query_set_attribute_with_desc(desc, now, q);
-            } else if (!CFDictionaryContainsKey(q->q_item, desc->name)) {
-                query_add_attribute_with_desc(desc, now, q);
-            }
-        } else if ((desc->flags & kSecDbNotNullFlag) &&
-                   !CFDictionaryContainsKey(q->q_item, desc->name)) {
-            CFTypeRef value = NULL;
-            if (desc->flags & kSecDbDefault0Flag) {
-                if (desc->kind == kSecDbDateAttr)
-                    value = CFDateCreate(kCFAllocatorDefault, 0.0);
-                else {
-                    SInt32 vzero = 0;
-                    value = CFNumberCreate(0, kCFNumberSInt32Type, &vzero);
-                }
-            } else if (desc->flags & kSecDbDefaultEmptyFlag) {
-                if (desc->kind == kSecDbDataAttr)
-                    value = CFDataCreate(kCFAllocatorDefault, NULL, 0);
-                else {
-                    value = CFSTR("");
-                    CFRetain(value);
-                }
-            }
-            if (value) {
-                /* Safe to use query_add_attribute here since the attr wasn't
-                 set yet. */
-                query_add_attribute_with_desc(desc, value, q);
-                CFRelease(value);
-            }
-        }
-    }
-    CFReleaseSafe(now);
-}
-
-//TODO: Move this to SecDbItemRef
-
-/* Update modification_date if needed. */
-static void
-query_pre_update(Query *q) {
-    SecDbForEachAttr(q->q_class, desc) {
-        if (desc->kind == kSecDbModificationDateAttr) {
-            CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
-            query_set_attribute_with_desc(desc, now, q);
-            CFReleaseSafe(now);
-        }
-    }
-}
-
-/* AUDIT[securityd](done):
-   accessGroup (ok) is a caller provided, non NULL CFTypeRef.
-
-   Return true iff accessGroup is allowable according to accessGroups.
- */
-static bool accessGroupsAllows(CFArrayRef accessGroups,
-    CFStringRef accessGroup) {
-    /* NULL accessGroups is wildcard. */
-    if (!accessGroups)
-        return true;
-    /* Make sure we have a string. */
-    if (!isString(accessGroup))
-        return false;
-
-    /* Having the special accessGroup "*" allows access to all accessGroups. */
-    CFRange range = { 0, CFArrayGetCount(accessGroups) };
-    if (range.length &&
-        (CFArrayContainsValue(accessGroups, range, accessGroup) ||
-         CFArrayContainsValue(accessGroups, range, CFSTR("*"))))
-        return true;
-
-    return false;
-}
-
-static bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups) {
-    return accessGroupsAllows(accessGroups,
-                              CFDictionaryGetValue(item, kSecAttrAccessGroup));
-}
-
-static void s3dl_merge_into_dict(const void *key, const void *value, void *context) {
-    CFDictionarySetValue(context, key, value);
-}
-
-/* Return whatever the caller requested based on the value of q->q_return_type.
-   keys and values must be 3 larger than attr_count in size to accomadate the
-   optional data, class and persistent ref results.  This is so we can use
-   the CFDictionaryCreate() api here rather than appending to a
-   mutable dictionary. */
-static CFTypeRef handle_result(Query *q, CFMutableDictionaryRef item,
-                               sqlite_int64 rowid) {
-    CFTypeRef a_result;
-    CFDataRef data;
-    data = CFDictionaryGetValue(item, kSecValueData);
-       if (q->q_return_type == 0) {
-               /* Caller isn't interested in any results at all. */
-               a_result = kCFNull;
-       } else if (q->q_return_type == kSecReturnDataMask) {
-        if (data) {
-            a_result = data;
-            CFRetain(a_result);
-        } else {
-            a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0);
-        }
-       } else if (q->q_return_type == kSecReturnPersistentRefMask) {
-               a_result = _SecItemMakePersistentRef(q->q_class->name, rowid);
-       } else {
-               /* We need to return more than one value. */
-        if (q->q_return_type & kSecReturnRefMask) {
-            CFDictionarySetValue(item, kSecClass, q->q_class->name);
-        } else if ((q->q_return_type & kSecReturnAttributesMask)) {
-            if (!(q->q_return_type & kSecReturnDataMask)) {
-                CFDictionaryRemoveValue(item, kSecValueData);
-            }
-        } else {
-            if (data)
-                CFRetain(data);
-            CFDictionaryRemoveAllValues(item);
-            if ((q->q_return_type & kSecReturnDataMask) && data) {
-                CFDictionarySetValue(item, kSecValueData, data);
-                CFRelease(data);
-            }
-        }
-               if (q->q_return_type & kSecReturnPersistentRefMask) {
-            CFDataRef pref = _SecItemMakePersistentRef(q->q_class->name, rowid);
-                       CFDictionarySetValue(item, kSecValuePersistentRef, pref);
-            CFRelease(pref);
-               }
-
-               a_result = item;
-        CFRetain(item);
-       }
-
-       return a_result;
-}
-
-static CFDataRef SecDbItemMakePersistentRef(SecDbItemRef item, CFErrorRef *error) {
-    sqlite3_int64 row_id = SecDbItemGetRowId(item, error);
-    if (row_id)
-        return _SecItemMakePersistentRef(SecDbItemGetClass(item)->name, row_id);
-    return NULL;
-}
-
-static CFTypeRef SecDbItemCopyResult(SecDbItemRef item, ReturnTypeMask return_type, CFErrorRef *error) {
-    CFTypeRef a_result;
-
-       if (return_type == 0) {
-               /* Caller isn't interested in any results at all. */
-               a_result = kCFNull;
-       } else if (return_type == kSecReturnDataMask) {
-        a_result = SecDbItemGetCachedValueWithName(item, kSecValueData);
-        if (a_result) {
-            CFRetainSafe(a_result);
-        } else {
-            a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0);
-        }
-       } else if (return_type == kSecReturnPersistentRefMask) {
-               a_result = SecDbItemMakePersistentRef(item, error);
-       } else {
-        CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(CFGetAllocator(item));
-               /* We need to return more than one value. */
-        if (return_type & kSecReturnRefMask) {
-            CFDictionarySetValue(dict, kSecClass, SecDbItemGetClass(item)->name);
-        }
-        CFOptionFlags mask = (((return_type & kSecReturnDataMask || return_type & kSecReturnRefMask) ? kSecDbReturnDataFlag : 0) |
-                              ((return_type & kSecReturnAttributesMask || return_type & kSecReturnRefMask) ? kSecDbReturnAttrFlag : 0));
-        SecDbForEachAttr(SecDbItemGetClass(item), desc) {
-            if ((desc->flags & mask) != 0) {
-                CFTypeRef value = SecDbItemGetValue(item, desc, error);
-                if (value && !CFEqual(kCFNull, value)) {
-                    CFDictionarySetValue(dict, desc->name, value);
-                } else if (value == NULL) {
-                    CFReleaseNull(dict);
-                    break;
-                }
-            }
-        }
-               if (return_type & kSecReturnPersistentRefMask) {
-            CFDataRef pref = SecDbItemMakePersistentRef(item, error);
-                       CFDictionarySetValue(dict, kSecValuePersistentRef, pref);
-            CFRelease(pref);
-               }
-
-               a_result = dict;
-       }
-
-       return a_result;
-}
-
-
-// MARK: -
-// MARK: Forward declarations
-
-static CFMutableDictionaryRef
-s3dl_item_from_col(sqlite3_stmt *stmt, Query *q, int col,
-                   CFArrayRef accessGroups, keyclass_t *keyclass, CFErrorRef *error);
-
-/* AUDIT[securityd](done):
-   attributes (ok) is a caller provided dictionary, only its cf type has
-       been checked.
- */
-static bool
-s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef *error)
-{
-    if (query_match_count(q) != 0)
-        return errSecItemMatchUnsupported;
-
-    /* Add requires a class to be specified unless we are adding a ref. */
-    if (q->q_use_item_list)
-        return errSecUseItemListUnsupported;
-
-    /* Actual work here. */
-    SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, q->q_class, q->q_item, KEYBAG_DEVICE, error);
-    if (!item)
-        return false;
-
-    bool ok = true;
-    if (q->q_data)
-        ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), q->q_data, error);
-    if (q->q_row_id)
-        ok = SecDbItemSetRowId(item, q->q_row_id, error);
-
-    if (ok)
-        ok = SecDbItemInsert(item, dbt, error);
-    if (ok) {
-        if (result && q->q_return_type) {
-            *result = SecDbItemCopyResult(item, q->q_return_type, error);
-        }
-    }
-    if (!ok && error && *error) {
-        if (CFEqual(CFErrorGetDomain(*error), kSecDbErrorDomain) && CFErrorGetCode(*error) == SQLITE_CONSTRAINT) {
-            CFReleaseNull(*error);
-            SecError(errSecDuplicateItem, error, CFSTR("duplicate item %@"), item);
-        }
-    }
-
-    if (ok) {
-        q->q_changed = true;
-        if (SecDbItemIsSyncable(item))
-            q->q_sync_changed = true;
-    }
-
-    secdebug("dbitem", "inserting item %@%s%@", item, ok ? "" : "failed: ", ok || error == NULL ? (CFErrorRef)CFSTR("") : *error);
-
-    CFRelease(item);
-
-       return ok;
-}
-
-typedef void (*s3dl_handle_row)(sqlite3_stmt *stmt, void *context);
-
-/* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise.  Does nothing if plist is already NULL. */
-static CFMutableDictionaryRef dictionaryFromPlist(CFPropertyListRef plist, CFErrorRef *error) {
-    if (plist && !isDictionary(plist)) {
-        CFStringRef typeName = CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef)plist));
-        SecError(errSecDecode, error, CFSTR("plist is a %@, expecting a dictionary"), typeName);
-        CFReleaseSafe(typeName);
-        CFReleaseNull(plist);
-    }
-    return (CFMutableDictionaryRef)plist;
-}
-
-static CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error) {
-    CFPropertyListRef item;
-    item = CFPropertyListCreateWithData(0, plain, kCFPropertyListMutableContainers, NULL, error);
-    return dictionaryFromPlist(item, error);
-}
-
-static CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error) {
-    CFPropertyListRef item = NULL;
-    const uint8_t *der = CFDataGetBytePtr(plain);
-    const uint8_t *der_end = der + CFDataGetLength(plain);
-    der = der_decode_plist(0, kCFPropertyListMutableContainers, &item, error, der, der_end);
-    if (der && der != der_end) {
-        SecCFCreateError(errSecDecode, kSecErrorDomain, CFSTR("trailing garbage at end of decrypted item"), NULL, error);
-        CFReleaseNull(item);
-    }
-    return dictionaryFromPlist(item, error);
-}
-
-static CFMutableDictionaryRef
-s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups, keyclass_t *keyclass, CFErrorRef *error) {
-    CFMutableDictionaryRef item = NULL;
-    CFDataRef plain =  NULL;
-
-    /* Decrypt and decode the item and check the decoded attributes against the query. */
-    uint32_t version;
-    require_quiet((ks_decrypt_data(q->q_keybag, keyclass, edata, &plain, &version, error)), out);
-    if (version < 2) {
-        goto out;
-    }
-
-    if (version < 3) {
-        item = s3dl_item_v2_decode(plain, error);
-    } else {
-        item = s3dl_item_v3_decode(plain, error);
-    }
-
-    if (!item && plain) {
-        secerror("decode v%d failed: %@ [item: %@]", version, error ? *error : NULL, plain);
-    }
-    if (item && !itemInAccessGroup(item, accessGroups)) {
-        secerror("items accessGroup %@ not in %@",
-                 CFDictionaryGetValue(item, kSecAttrAccessGroup),
-                 accessGroups);
-        CFReleaseNull(item);
-    }
-    /* TODO: Validate keyclass attribute. */
-
-out:
-    CFReleaseSafe(plain);
-    return item;
-}
-
-static CFDataRef
-s3dl_copy_data_from_col(sqlite3_stmt *stmt, int col, CFErrorRef *error) {
-    return CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col),
-                                        sqlite3_column_bytes(stmt, col),
-                                        kCFAllocatorNull);
-}
-
-static CFMutableDictionaryRef
-s3dl_item_from_col(sqlite3_stmt *stmt, Query *q, int col,
-                   CFArrayRef accessGroups, keyclass_t *keyclass, CFErrorRef *error) {
-    CFMutableDictionaryRef item = NULL;
-    CFDataRef edata = NULL;
-    require(edata = s3dl_copy_data_from_col(stmt, col, error), out);
-    item = s3dl_item_from_data(edata, q, accessGroups, keyclass, error);
-
-out:
-    CFReleaseSafe(edata);
-    return item;
-}
-
-struct s3dl_query_ctx {
-    Query *q;
-    CFArrayRef accessGroups;
-    CFTypeRef result;
-    int found;
-};
-
-static bool match_item(Query *q, CFArrayRef accessGroups, CFDictionaryRef item);
-
-static void s3dl_query_row(sqlite3_stmt *stmt, void *context) {
-    struct s3dl_query_ctx *c = context;
-    Query *q = c->q;
-
-    CFMutableDictionaryRef item = s3dl_item_from_col(stmt, q, 1,
-                                                     c->accessGroups, NULL, &q->q_error);
-    sqlite_int64 rowid = sqlite3_column_int64(stmt, 0);
-    if (!item) {
-        secerror("decode %@,rowid=%" PRId64 " failed (%ld): %@", q->q_class->name, rowid, CFErrorGetCode(q->q_error), q->q_error);
-        // errSecDecode means the tiem is corrupted, stash it for delete.
-        if(CFErrorGetCode(q->q_error)==errSecDecode)
-        {
-            secerror("We should attempt to delete this row (%lld)", rowid);
-
-            {
-                CFDataRef edata = s3dl_copy_data_from_col(stmt, 1, NULL);
-                CFMutableStringRef edatastring =  CFStringCreateMutable(kCFAllocatorDefault, 0);
-                if(edatastring) {
-                    CFStringAppendEncryptedData(edatastring, edata);
-                    secnotice("item", "corrupted edata=%@", edatastring);
-                }
-                CFReleaseSafe(edata);
-                CFReleaseSafe(edatastring);
-            }
-
-            if(q->corrupted_rows==NULL) {
-                q->corrupted_rows=CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-            }
-
-            if(q->corrupted_rows==NULL) {
-                secerror("Could not create a mutable array to store corrupted row! No memory ?");
-            } else {
-                long long row=rowid;
-                CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &row);
-                if(number==NULL) {
-                    secerror("Could not create a CFNumber to store corrupted row! No memory ?");
-                } else {
-                    CFArrayAppendValue(q->corrupted_rows, number);
-                    CFReleaseNull(number);
-                    /* Hide this error, this will just pretend the item didnt exist at all */
-                    CFReleaseNull(q->q_error);
-                }
-            }
-        }
-        // q->q_error will be released appropriately by a call to query_error
-        return;
-    }
-
-    if (q->q_class == &identity_class) {
-        // TODO: Use col 2 for key rowid and use both rowids in persistent ref.
-        CFMutableDictionaryRef key = s3dl_item_from_col(stmt, q, 3,
-                                                        c->accessGroups, NULL, &q->q_error);
-
-        /* TODO : if there is a errSecDecode error here, we should cleanup */
-        if (!key)
-            goto out;
-
-        CFDataRef certData = CFDictionaryGetValue(item, kSecValueData);
-        if (certData) {
-            CFDictionarySetValue(key, CFSTR(CERTIFICATE_DATA_COLUMN_LABEL),
-                                 certData);
-            CFDictionaryRemoveValue(item, kSecValueData);
-        }
-        CFDictionaryApplyFunction(item, s3dl_merge_into_dict, key);
-        CFRelease(item);
-        item = key;
-    }
-
-    if (!match_item(q, c->accessGroups, item))
-        goto out;
-
-    CFTypeRef a_result = handle_result(q, item, rowid);
-    if (a_result) {
-        if (a_result == kCFNull) {
-            /* Caller wasn't interested in a result, but we still
-             count this row as found. */
-        } else if (q->q_limit == 1) {
-            c->result = a_result;
-        } else {
-            CFArrayAppendValue((CFMutableArrayRef)c->result, a_result);
-            CFRelease(a_result);
-        }
-        c->found++;
-    }
-
-out:
-    CFRelease(item);
-}
-
-static void
-SecDbAppendWhereROWID(CFMutableStringRef sql,
-                    CFStringRef col, sqlite_int64 row_id,
-                    bool *needWhere) {
-    if (row_id > 0) {
-        SecDbAppendWhereOrAnd(sql, needWhere);
-        CFStringAppendFormat(sql, NULL, CFSTR("%@=%lld"), col, row_id);
-    }
-}
-
-static void
-SecDbAppendWhereAttrs(CFMutableStringRef sql, const Query *q, bool *needWhere) {
-    CFIndex ix, attr_count = query_attr_count(q);
-    for (ix = 0; ix < attr_count; ++ix) {
-        SecDbAppendWhereOrAndEquals(sql, query_attr_at(q, ix).key, needWhere);
-    }
-}
-
-static void
-SecDbAppendWhereAccessGroups(CFMutableStringRef sql,
-                           CFStringRef col,
-                           CFArrayRef accessGroups,
-                           bool *needWhere) {
-    CFIndex ix, ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
-        return;
-    }
-
-    SecDbAppendWhereOrAnd(sql, needWhere);
-    CFStringAppend(sql, col);
-    CFStringAppend(sql, CFSTR(" IN (?"));
-    for (ix = 1; ix < ag_count; ++ix) {
-        CFStringAppend(sql, CFSTR(",?"));
-    }
-    CFStringAppend(sql, CFSTR(")"));
-}
-
-static void SecDbAppendWhereClause(CFMutableStringRef sql, const Query *q,
-    CFArrayRef accessGroups) {
-    bool needWhere = true;
-    SecDbAppendWhereROWID(sql, CFSTR("ROWID"), q->q_row_id, &needWhere);
-    SecDbAppendWhereAttrs(sql, q, &needWhere);
-    SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere);
-}
-
-static void SecDbAppendLimit(CFMutableStringRef sql, CFIndex limit) {
-    if (limit != kSecMatchUnlimited)
-        CFStringAppendFormat(sql, NULL, CFSTR(" LIMIT %" PRIdCFIndex), limit);
-}
-
-static CFStringRef s3dl_select_sql(Query *q, CFArrayRef accessGroups) {
-    CFMutableStringRef sql = CFStringCreateMutable(NULL, 0);
-       if (q->q_class == &identity_class) {
-        CFStringAppendFormat(sql, NULL, CFSTR("SELECT crowid, "
-            CERTIFICATE_DATA_COLUMN_LABEL ", rowid,data FROM "
-            "(SELECT cert.rowid AS crowid, cert.labl AS labl,"
-            " cert.issr AS issr, cert.slnr AS slnr, cert.skid AS skid,"
-            " keys.*,cert.data AS " CERTIFICATE_DATA_COLUMN_LABEL
-            " FROM keys, cert"
-            " WHERE keys.priv == 1 AND cert.pkhh == keys.klbl"));
-        SecDbAppendWhereAccessGroups(sql, CFSTR("cert.agrp"), accessGroups, 0);
-        /* The next 3 SecDbAppendWhere calls are in the same order as in
-           SecDbAppendWhereClause().  This makes sqlBindWhereClause() work,
-           as long as we do an extra sqlBindAccessGroups first. */
-        SecDbAppendWhereROWID(sql, CFSTR("crowid"), q->q_row_id, 0);
-        CFStringAppend(sql, CFSTR(")"));
-        bool needWhere = true;
-        SecDbAppendWhereAttrs(sql, q, &needWhere);
-        SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere);
-       } else {
-        CFStringAppend(sql, CFSTR("SELECT rowid, data FROM "));
-               CFStringAppend(sql, q->q_class->name);
-        SecDbAppendWhereClause(sql, q, accessGroups);
-    }
-    SecDbAppendLimit(sql, q->q_limit);
-
-    return sql;
-}
-
-static bool sqlBindAccessGroups(sqlite3_stmt *stmt, CFArrayRef accessGroups,
-                               int *pParam, CFErrorRef *error) {
-    bool result = true;
-    int param = *pParam;
-    CFIndex ix, count = accessGroups ? CFArrayGetCount(accessGroups) : 0;
-    for (ix = 0; ix < count; ++ix) {
-        result = SecDbBindObject(stmt, param++,
-                                  CFArrayGetValueAtIndex(accessGroups, ix),
-                                  error);
-        if (!result)
-            break;
-    }
-    *pParam = param;
-    return result;
-}
-
-static bool sqlBindWhereClause(sqlite3_stmt *stmt, const Query *q,
-    CFArrayRef accessGroups, int *pParam, CFErrorRef *error) {
-    bool result = true;
-    int param = *pParam;
-    CFIndex ix, attr_count = query_attr_count(q);
-    for (ix = 0; ix < attr_count; ++ix) {
-        result = SecDbBindObject(stmt, param++, query_attr_at(q, ix).value, error);
-        if (!result)
-            break;
-       }
-
-    /* Bind the access group to the sql. */
-    if (result) {
-        result = sqlBindAccessGroups(stmt, accessGroups, &param, error);
-    }
-
-    *pParam = param;
-    return result;
-}
-
-static bool SecDbItemQuery(SecDbQueryRef query, CFArrayRef accessGroups, SecDbConnectionRef dbconn, CFErrorRef *error,
-                    void (^handle_row)(SecDbItemRef item, bool *stop)) {
-    __block bool ok = true;
-    /* Sanity check the query. */
-    if (query->q_ref)
-        return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by queries"));
-
-    bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
-        return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr;
-    };
-
-    CFStringRef sql = s3dl_select_sql(query, accessGroups);
-    ok = sql;
-    if (sql) {
-        ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
-            /* Bind the values being searched for to the SELECT statement. */
-            int param = 1;
-            if (query->q_class == &identity_class) {
-                /* Bind the access groups to cert.agrp. */
-                ok &= sqlBindAccessGroups(stmt, accessGroups, &param, error);
-            }
-            if (ok)
-                ok &= sqlBindWhereClause(stmt, query, accessGroups, &param, error);
-            if (ok) {
-                SecDbStep(dbconn, stmt, error, ^(bool *stop) {
-                    SecDbItemRef item = SecDbItemCreateWithStatement(kCFAllocatorDefault, query->q_class, stmt, query->q_keybag, error, return_attr);
-                    if (item) {
-                        if (match_item(query, accessGroups, item->attributes))
-                            handle_row(item, stop);
-                        CFRelease(item);
-                    } else {
-                        secerror("failed to create item from stmt: %@", error ? *error : (CFErrorRef)"no error");
-                        if (error) {
-                            CFReleaseNull(*error);
-                        }
-                        //*stop = true;
-                        //ok = false;
-                    }
-                });
-            }
-        });
-        CFRelease(sql);
-    }
-
-    return ok;
-}
-
-static bool
-s3dl_query(SecDbConnectionRef dbt, s3dl_handle_row handle_row,
-           void *context, CFErrorRef *error)
-{
-    struct s3dl_query_ctx *c = context;
-    Query *q = c->q;
-    CFArrayRef accessGroups = c->accessGroups;
-
-    /* Sanity check the query. */
-    if (q->q_ref)
-        return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by queries"));
-
-       /* Actual work here. */
-    if (q->q_limit == 1) {
-        c->result = NULL;
-    } else {
-        c->result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    }
-    CFStringRef sql = s3dl_select_sql(q, accessGroups);
-    bool ok = SecDbWithSQL(dbt, sql, error, ^(sqlite3_stmt *stmt) {
-        bool sql_ok = true;
-        /* Bind the values being searched for to the SELECT statement. */
-        int param = 1;
-        if (q->q_class == &identity_class) {
-            /* Bind the access groups to cert.agrp. */
-            sql_ok = sqlBindAccessGroups(stmt, accessGroups, &param, error);
-        }
-        if (sql_ok)
-            sql_ok = sqlBindWhereClause(stmt, q, accessGroups, &param, error);
-        if (sql_ok) {
-            SecDbForEach(stmt, error, ^bool (int row_index) {
-                handle_row(stmt, context);
-                return (!q->q_error) && (q->q_limit == kSecMatchUnlimited || c->found < q->q_limit);
-            });
-        }
-        return sql_ok;
-    });
-
-    CFRelease(sql);
-
-    // First get the error from the query, since errSecDuplicateItem from an
-    // update query should superceed the errSecItemNotFound below.
-    if (!query_error(q, error))
-        ok = false;
-    if (ok && c->found == 0)
-        ok = SecError(errSecItemNotFound, error, CFSTR("no matching items found"));
-
-    return ok;
-}
-
-#if 0
-/* Gross hack to recover from item corruption */
-static void
-s3dl_cleanup_corrupted(SecDbConnectionRef dbt, Query *q, CFErrorRef *error)
-{
-
-    if(q->corrupted_rows==NULL)
-        return;
-
-    __security_simulatecrash(CFSTR("Corrupted items found in keychain"));
-
-    if (q->q_class == &identity_class) {
-        /* TODO: how to cleanup in that case */
-        secerror("Cleaning up corrupted identities is not implemented yet");
-        goto out;
-    }
-
-    CFArrayForEach(q->corrupted_rows, ^(const void *value) {
-        CFMutableStringRef sql=CFStringCreateMutable(kCFAllocatorDefault, 0);
-
-        if(sql==NULL) {
-            secerror("Could not allocate CFString for sql, out of memory ?");
-        } else {
-            CFStringAppend(sql, CFSTR("DELETE FROM "));
-            CFStringAppend(sql, q->q_class->name);
-            CFStringAppendFormat(sql, NULL, CFSTR(" WHERE rowid=%@"), value);
-
-            secerror("Attempting cleanup with %@", sql);
-
-            if(!SecDbExec(dbt, sql, error)) {
-                secerror("Cleanup Failed using %@, error: %@", sql, error?NULL:*error);
-            } else {
-                secerror("Cleanup Succeeded using %@", sql);
-            }
-
-            CFReleaseSafe(sql);
-        }
-    });
-
-out:
-    CFReleaseNull(q->corrupted_rows);
-}
-#endif
-
-static bool
-s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result,
-                   CFArrayRef accessGroups, CFErrorRef *error)
-{
-    struct s3dl_query_ctx ctx = {
-        .q = q, .accessGroups = accessGroups,
-    };
-    if (q->q_row_id && query_attr_count(q))
-        return SecError(errSecItemIllegalQuery, error,
-                        CFSTR("attributes to query illegal; both row_id and other attributes can't be searched at the same time"));
-
-    // Only copy things that aren't tombstones unless the client explicitly asks otherwise.
-    if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone))
-        query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q);
-    bool ok = s3dl_query(dbt, s3dl_query_row, &ctx, error);
-    if (ok && result)
-        *result = ctx.result;
-    else
-        CFReleaseSafe(ctx.result);
-
-    // s3dl_cleanup_corrupted(dbt, q, error);
-
-    return ok;
-}
-
-/* AUDIT[securityd](done):
-   attributesToUpdate (ok) is a caller provided dictionary,
-       only its cf types have been checked.
- */
-static bool
-s3dl_query_update(SecDbConnectionRef dbt, Query *q,
-    CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups, CFErrorRef *error)
-{
-    /* Sanity check the query. */
-    if (query_match_count(q) != 0)
-        return SecError(errSecItemMatchUnsupported, error, CFSTR("match not supported in attributes to update"));
-    if (q->q_ref)
-        return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported in attributes to update"));
-    if (q->q_row_id && query_attr_count(q))
-        return SecError(errSecItemIllegalQuery, error, CFSTR("attributes to update illegal; both row_id and other attributes can't be updated at the same time"));
-
-    __block bool result = true;
-    Query *u = query_create(q->q_class, attributesToUpdate, error);
-    if (u == NULL) return false;
-    require_action_quiet(query_update_parse(u, attributesToUpdate, error), errOut, result = false);
-    query_pre_update(u);
-    result &= SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) {
-        // Make sure we only update real items, not tombstones, unless the client explicitly asks otherwise.
-        if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone))
-            query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q);
-        result &= SecDbItemQuery(q, accessGroups, dbt, error, ^(SecDbItemRef item, bool *stop) {
-            //We always need to know the error here.
-            CFErrorRef localError = NULL;
-            SecDbItemRef new_item = SecDbItemCopyWithUpdates(item, u->q_item, &localError);
-            if(SecErrorGetOSStatus(localError)==errSecDecode) {
-                // We just ignore this, and treat as if item is not found
-                secerror("Trying to update to a corrupted item");
-                CFReleaseSafe(localError);
-                return;
-            }
-
-            if (error && *error == NULL) {
-                *error = localError;
-                localError = NULL;
-            }
-            CFReleaseSafe(localError);
-
-            result = new_item;
-            if (new_item) {
-                bool item_is_sync = SecDbItemIsSyncable(item);
-                bool makeTombstone = q->q_use_tomb ? CFBooleanGetValue(q->q_use_tomb) : (item_is_sync && !SecDbItemIsTombstone(item));
-                result = SecDbItemUpdate(item, new_item, dbt, makeTombstone, error);
-                if (result) {
-                    q->q_changed = true;
-                    if (item_is_sync || SecDbItemIsSyncable(new_item))
-                        q->q_sync_changed = true;
-                }
-                CFRelease(new_item);
-            }
-            if (!result)
-                *stop = true;
-        });
-        if (!result)
-            *commit = false;
-    });
-    if (result && !q->q_changed)
-        result = SecError(errSecItemNotFound, error, CFSTR("No items updated"));
-errOut:
-    if (!query_destroy(u, error))
-        result = false;
-    return result;
-}
-
-static bool
-s3dl_query_delete(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFErrorRef *error)
-{
-    __block bool ok = true;
-    // Only delete things that aren't tombstones, unless the client explicitly asks otherwise.
-    if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone))
-        query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q);
-    ok &= SecDbItemSelect(q, dbt, error, ^bool(const SecDbAttr *attr) {
-        return false;
-    },^bool(CFMutableStringRef sql, bool *needWhere) {
-        SecDbAppendWhereClause(sql, q, accessGroups);
-        return true;
-    },^bool(sqlite3_stmt * stmt, int col) {
-        return sqlBindWhereClause(stmt, q, accessGroups, &col, error);
-    }, ^(SecDbItemRef item, bool *stop) {
-        bool item_is_sync = SecDbItemIsSyncable(item);
-        bool makeTombstone = q->q_use_tomb ? CFBooleanGetValue(q->q_use_tomb) : (item_is_sync && !SecDbItemIsTombstone(item));
-        ok = SecDbItemDelete(item, dbt, makeTombstone, error);
-        if (ok) {
-            q->q_changed = true;
-            if (item_is_sync)
-                q->q_sync_changed = true;
-        }
-    });
-    if (ok && !q->q_changed) {
-        ok = SecError(errSecItemNotFound, error, CFSTR("Delete failed to delete anything"));
-    }
-    return ok;
-}
-
-/* Return true iff the item in question should not be backed up, nor restored,
-   but when restoring a backup the original version of the item should be
-   added back to the keychain again after the restore completes. */
-static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *class) {
-    CFStringRef agrp = CFDictionaryGetValue(item, kSecAttrAccessGroup);
-    if (!isString(agrp))
-        return false;
-
-    if (CFEqual(agrp, CFSTR("lockdown-identities"))) {
-        secdebug("backup", "found sys_bound item: %@", item);
-        return true;
-    }
-
-    if (CFEqual(agrp, CFSTR("apple")) && class == &genp_class) {
-        CFStringRef service = CFDictionaryGetValue(item, kSecAttrService);
-        CFStringRef account = CFDictionaryGetValue(item, kSecAttrAccount);
-        if (isString(service) && isString(account) &&
-            CFEqual(service, CFSTR("com.apple.managedconfiguration")) &&
-            (CFEqual(account, CFSTR("Public")) ||
-                CFEqual(account, CFSTR("Private")))) {
-            secdebug("backup", "found sys_bound item: %@", item);
-            return true;
-        }
-    }
-    secdebug("backup", "found non sys_bound item: %@", item);
-    return false;
-}
-
-/* Delete all items from the current keychain.  If this is not an in
-   place upgrade we don't delete items in the 'lockdown-identities'
-   access group, this ensures that an import or restore of a backup
-   will never overwrite an existing activation record. */
-static bool SecServerDeleteAll(SecDbConnectionRef dbt, CFErrorRef *error) {
-    return kc_transaction(dbt, error, ^{
-        bool ok = (SecDbExec(dbt, CFSTR("DELETE from genp;"), error) &&
-                   SecDbExec(dbt, CFSTR("DELETE from inet;"), error) &&
-                   SecDbExec(dbt, CFSTR("DELETE from cert;"), error) &&
-                   SecDbExec(dbt, CFSTR("DELETE from keys;"), error));
-        return ok;
-    });
-}
-
-struct s3dl_export_row_ctx {
-    struct s3dl_query_ctx qc;
-    keybag_handle_t dest_keybag;
-    enum SecItemFilter filter;
-    SecDbConnectionRef dbt;
-};
-
-static void s3dl_export_row(sqlite3_stmt *stmt, void *context) {
-    struct s3dl_export_row_ctx *c = context;
-    Query *q = c->qc.q;
-    keyclass_t keyclass = 0;
-    CFErrorRef localError = NULL;
-
-    sqlite_int64 rowid = sqlite3_column_int64(stmt, 0);
-    CFMutableDictionaryRef item = s3dl_item_from_col(stmt, q, 1, c->qc.accessGroups, &keyclass, &localError);
-
-    if (item) {
-        /* Only export sysbound items is do_sys_bound is true, only export non sysbound items otherwise. */
-        bool do_sys_bound = c->filter == kSecSysBoundItemFilter;
-        if (c->filter == kSecNoItemFilter ||
-            SecItemIsSystemBound(item, q->q_class) == do_sys_bound) {
-            /* Re-encode the item. */
-            secdebug("item", "export rowid %llu item: %@", rowid, item);
-            /* The code below could be moved into handle_row. */
-            CFDataRef pref = _SecItemMakePersistentRef(q->q_class->name, rowid);
-            if (pref) {
-                if (c->dest_keybag != KEYBAG_NONE) {
-                    /* Encode and encrypt the item to the specified keybag. */
-                    CFDataRef plain = kc_plist_copy_der(item, &q->q_error);
-                    CFDictionaryRemoveAllValues(item);
-                    if (plain) {
-                        CFDataRef edata = NULL;
-                        if (ks_encrypt_data(c->dest_keybag, keyclass, plain, &edata, &q->q_error)) {
-                            CFDictionarySetValue(item, kSecValueData, edata);
-                            CFReleaseSafe(edata);
-                        } else {
-                            seccritical("ks_encrypt_data %@,rowid=%" PRId64 ": failed: %@", q->q_class->name, rowid, q->q_error);
-                            CFReleaseNull(q->q_error);
-                        }
-                        CFRelease(plain);
-                    }
-                }
-                if (CFDictionaryGetCount(item)) {
-                    CFDictionarySetValue(item, kSecValuePersistentRef, pref);
-                    CFArrayAppendValue((CFMutableArrayRef)c->qc.result, item);
-                    c->qc.found++;
-                }
-                CFReleaseSafe(pref);
-            }
-        }
-        CFRelease(item);
-    } else {
-        /* This happens a lot when trying to migrate keychain before first unlock, so only a notice */
-        /* If the error is "corrupted item" then we just ignore it, otherwise we save it in the query */
-        secnotice("item","Could not export item for rowid %llu: %@", rowid, localError);
-        if(SecErrorGetOSStatus(localError)==errSecDecode) {
-            CFReleaseNull(localError);
-        } else {
-            CFReleaseSafe(q->q_error);
-            q->q_error=localError;
-        }
-    }
-}
-
-static CF_RETURNS_RETAINED CFDictionaryRef SecServerExportKeychainPlist(SecDbConnectionRef dbt,
-    keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
-    enum SecItemFilter filter, CFErrorRef *error) {
-    CFMutableDictionaryRef keychain;
-    keychain = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-        &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    if (!keychain) {
-        if (error && !*error)
-            SecError(errSecAllocate, error, CFSTR("Can't create keychain dictionary"));
-         goto errOut;
-    }
-    unsigned class_ix;
-    Query q = { .q_keybag = src_keybag };
-    q.q_return_type = kSecReturnDataMask | kSecReturnAttributesMask | \
-        kSecReturnPersistentRefMask;
-    q.q_limit = kSecMatchUnlimited;
-
-    /* Get rid of this duplicate. */
-    const SecDbClass *SecDbClasses[] = {
-        &genp_class,
-        &inet_class,
-        &cert_class,
-        &keys_class
-    };
-
-    for (class_ix = 0; class_ix < array_size(SecDbClasses);
-        ++class_ix) {
-        q.q_class = SecDbClasses[class_ix];
-        struct s3dl_export_row_ctx ctx = {
-            .qc = { .q = &q, },
-            .dest_keybag = dest_keybag, .filter = filter,
-            .dbt = dbt,
-        };
-
-        secnotice("item", "exporting class '%@'", q.q_class->name);
-
-        CFErrorRef localError = NULL;
-        if (s3dl_query(dbt, s3dl_export_row, &ctx, &localError)) {
-            if (CFArrayGetCount(ctx.qc.result))
-                CFDictionaryAddValue(keychain, q.q_class->name, ctx.qc.result);
-
-        } else {
-            OSStatus status = (OSStatus)CFErrorGetCode(localError);
-            if (status == errSecItemNotFound) {
-                CFRelease(localError);
-            } else {
-                secerror("Export failed: %@", localError);
-                if (error) {
-                    CFReleaseSafe(*error);
-                    *error = localError;
-                } else {
-                    CFRelease(localError);
-                }
-                CFReleaseNull(keychain);
-                break;
-            }
-        }
-        CFReleaseNull(ctx.qc.result);
-    }
-errOut:
-    return keychain;
-}
-
-static CF_RETURNS_RETAINED CFDataRef SecServerExportKeychain(SecDbConnectionRef dbt,
-    keybag_handle_t src_keybag, keybag_handle_t dest_keybag, CFErrorRef *error) {
-    CFDataRef data_out = NULL;
-    /* Export everything except the items for which SecItemIsSystemBound()
-       returns true. */
-    CFDictionaryRef keychain = SecServerExportKeychainPlist(dbt,
-        src_keybag, dest_keybag, kSecBackupableItemFilter,
-        error);
-    if (keychain) {
-        data_out = CFPropertyListCreateData(kCFAllocatorDefault, keychain,
-                                             kCFPropertyListBinaryFormat_v1_0,
-                                             0, error);
-        CFRelease(keychain);
-    }
-
-    return data_out;
-}
-
-struct SecServerImportClassState {
-       SecDbConnectionRef dbt;
-    CFErrorRef error;
-    keybag_handle_t src_keybag;
-    keybag_handle_t dest_keybag;
-    enum SecItemFilter filter;
-};
-
-struct SecServerImportItemState {
-    const SecDbClass *class;
-       struct SecServerImportClassState *s;
-};
-
-/* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items
- being imported from a backup.  */
-static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) {
-    bool ok = true;
-    CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
-    CFStringRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible);
-
-    if (!isString(agrp) || !isString(accessible))
-        return ok;
-    if (SecDbItemGetClass(item) == &genp_class && CFEqual(accessible, kSecAttrAccessibleAlways)) {
-        CFStringRef svce = SecDbItemGetCachedValueWithName(item, kSecAttrService);
-        if (!isString(svce)) return ok;
-        if (CFEqual(agrp, CFSTR("apple"))) {
-            if (CFEqual(svce, CFSTR("AirPort"))) {
-                ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
-            } else if (CFEqual(svce, CFSTR("com.apple.airplay.password"))) {
-                ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
-            } else if (CFEqual(svce, CFSTR("YouTube"))) {
-                ok = (SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error) &&
-                      SecDbItemSetValueWithName(item, kSecAttrAccessGroup, CFSTR("com.apple.youtube.credentials"), error));
-            } else {
-                CFStringRef desc = SecDbItemGetCachedValueWithName(item, kSecAttrDescription);
-                if (!isString(desc)) return ok;
-                if (CFEqual(desc, CFSTR("IPSec Shared Secret")) || CFEqual(desc, CFSTR("PPP Password"))) {
-                    ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
-                }
-            }
-        }
-    } else if (SecDbItemGetClass(item) == &inet_class && CFEqual(accessible, kSecAttrAccessibleAlways)) {
-        if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) {
-            ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
-        } else if (CFEqual(agrp, CFSTR("apple"))) {
-            CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
-            bool is_proxy = false;
-            if (isNumber(ptcl)) {
-                SInt32 iptcl;
-                CFNumberGetValue(ptcl, kCFNumberSInt32Type, &iptcl);
-                is_proxy = (iptcl == FOUR_CHAR_CODE('htpx') ||
-                            iptcl == FOUR_CHAR_CODE('htsx') ||
-                            iptcl == FOUR_CHAR_CODE('ftpx') ||
-                            iptcl == FOUR_CHAR_CODE('rtsx') ||
-                            iptcl == FOUR_CHAR_CODE('xpth') ||
-                            iptcl == FOUR_CHAR_CODE('xsth') ||
-                            iptcl == FOUR_CHAR_CODE('xptf') ||
-                            iptcl == FOUR_CHAR_CODE('xstr'));
-            } else if (isString(ptcl)) {
-                is_proxy = (CFEqual(ptcl, kSecAttrProtocolHTTPProxy) ||
-                            CFEqual(ptcl, kSecAttrProtocolHTTPSProxy) ||
-                            CFEqual(ptcl, kSecAttrProtocolRTSPProxy) ||
-                            CFEqual(ptcl, kSecAttrProtocolFTPProxy));
-            }
-            if (is_proxy)
-                ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
-        }
-    }
-    return ok;
-}
-
-bool SecDbItemDecrypt(SecDbItemRef item, CFDataRef edata, CFErrorRef *error) {
-    bool ok = true;
-    CFDataRef pdata = NULL;
-    keyclass_t keyclass;
-    uint32_t version;
-    ok = ks_decrypt_data(SecDbItemGetKeybag(item), &keyclass, edata, &pdata, &version, error);
-    if (!ok)
-        return ok;
-
-    if (version < 2) {
-        /* Old V4 style keychain backup being imported. */
-        ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), pdata, error) &&
-        SecDbItemImportMigrate(item, error);
-    } else {
-        CFDictionaryRef dict;
-        if (version < 3) {
-            dict = s3dl_item_v2_decode(pdata, error);
-        } else {
-            dict = s3dl_item_v3_decode(pdata, error);
-        }
-        ok = dict && SecDbItemSetValues(item, dict, error);
-       CFReleaseSafe(dict);
-    }
-
-    CFReleaseSafe(pdata);
-
-    keyclass_t my_keyclass = SecDbItemGetKeyclass(item, NULL);
-    if (!my_keyclass) {
-        ok = ok && SecDbItemSetKeyclass(item, keyclass, error);
-    } else {
-        /* Make sure the keyclass in the dictionary matched what we got
-           back from decoding the data blob. */
-        if (my_keyclass != keyclass) {
-            ok = SecError(errSecDecode, error, CFSTR("keyclass attribute %d doesn't match keyclass in blob %d"), my_keyclass, keyclass);
-        }
-    }
-
-    return ok;
-}
-
-/* Automagically make a item syncable, based on various attributes. */
-static bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error)
-{
-    CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
-
-    if (!isString(agrp))
-        return true;
-
-    if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == &inet_class) {
-        CFTypeRef srvr = SecDbItemGetCachedValueWithName(item, kSecAttrServer);
-        CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
-        CFTypeRef atyp = SecDbItemGetCachedValueWithName(item, kSecAttrAuthenticationType);
-
-        if (isString(srvr) && isString(ptcl) && isString(atyp)) {
-            /* This looks like a Mobile Safari Password,  make syncable */
-            secnotice("item", "Make this item syncable: %@", item);
-            return SecDbItemSetSyncable(item, true, error);
-        }
-    }
-
-    return true;
-}
-
-/* This create a SecDbItem from the item dictionnary that are exported for backups.
-   Item are stored in the backup as a dictionary containing two keys:
-    - v_Data: the encrypted data blob
-    - v_PersistentRef: a persistent Ref.
-   src_keybag is normally the backup keybag.
-   dst_keybag is normally the device keybag.
-*/
-static SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error)
-{
-    CFDataRef edata = CFDictionaryGetValue(dict, CFSTR("v_Data"));
-    SecDbItemRef item = NULL;
-
-    if (edata) {
-        item = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, edata, src_keybag, error);
-        if (item)
-            if (!SecDbItemSetKeybag(item, dst_keybag, error))
-                CFReleaseNull(item);
-    } else {
-        SecError(errSecDecode, error, CFSTR("No v_Data in backup dictionary %@"), dict);
-    }
-
-    return item;
-}
-
-static bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error) {
-    CFDataRef ref = CFDictionaryGetValue(dict, CFSTR("v_PersistentRef"));
-    if (!ref)
-        return SecError(errSecDecode, error, CFSTR("No v_PersistentRef in backup dictionary %@"), dict);
-
-    CFStringRef className;
-    sqlite3_int64 rowid;
-    if (!_SecItemParsePersistentRef(ref, &className, &rowid))
-        return SecError(errSecDecode, error, CFSTR("v_PersistentRef %@ failed to decode"), ref);
-
-    if (!CFEqual(SecDbItemGetClass(item)->name, className))
-        return SecError(errSecDecode, error, CFSTR("v_PersistentRef has unexpected class %@"), className);
-
-    return SecDbItemSetRowId(item, rowid, error);
-}
-
-static void SecServerImportItem(const void *value, void *context) {
-    struct SecServerImportItemState *state =
-        (struct SecServerImportItemState *)context;
-    if (state->s->error)
-        return;
-    if (!isDictionary(value)) {
-        SecError(errSecParam, &state->s->error, CFSTR("value %@ is not a dictionary"), value);
-        return;
-    }
-
-    CFDictionaryRef dict = (CFDictionaryRef)value;
-
-    secdebug("item", "Import Item : %@", dict);
-
-    /* We don't filter non sys_bound items during import since we know we
-       will never have any in this case, we use the kSecSysBoundItemFilter
-       to indicate that we don't preserve rowid's during import instead. */
-    if (state->s->filter == kSecBackupableItemFilter &&
-        SecItemIsSystemBound(dict, state->class))
-        return;
-
-    SecDbItemRef item;
-
-    /* This is sligthly confusing:
-       - During upgrade all items are exported with KEYBAG_NONE.
-       - During restore from backup, existing sys_bound items are exported with KEYBAG_NONE, and are exported as dictionary of attributes.
-       - Item in the actual backup are export with a real keybag, and are exported as encrypted v_Data and v_PersistentRef
-    */
-    if (state->s->src_keybag == KEYBAG_NONE) {
-        item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, state->class, dict, state->s->dest_keybag,  &state->s->error);
-    } else {
-        item = SecDbItemCreateWithBackupDictionary(kCFAllocatorDefault, state->class, dict, state->s->src_keybag, state->s->dest_keybag, &state->s->error);
-    }
-
-    if (item) {
-        if(state->s->filter != kSecSysBoundItemFilter) {
-            SecDbItemExtractRowIdFromBackupDictionary(item, dict, &state->s->error);
-        }
-        SecDbItemInferSyncable(item, &state->s->error);
-        SecDbItemInsert(item, state->s->dbt, &state->s->error);
-    }
-
-    /* Reset error if we had one, since we just skip the current item
-       and continue importing what we can. */
-    if (state->s->error) {
-        secwarning("Failed to import an item (%@) of class '%@': %@ - ignoring error.",
-                 item, state->class->name, state->s->error);
-        CFReleaseNull(state->s->error);
-    }
-
-    CFReleaseSafe(item);
-}
-
-static void SecServerImportClass(const void *key, const void *value,
-    void *context) {
-    struct SecServerImportClassState *state =
-        (struct SecServerImportClassState *)context;
-    if (state->error)
-        return;
-    if (!isString(key)) {
-        SecError(errSecParam, &state->error, CFSTR("class name %@ is not a string"), key);
-        return;
-    }
-    const SecDbClass *class = kc_class_with_name(key);
-    if (!class || class == &identity_class) {
-        SecError(errSecParam, &state->error, CFSTR("attempt to import an identity"));
-        return;
-    }
-    struct SecServerImportItemState item_state = {
-        .class = class, .s = state
-    };
-    if (isArray(value)) {
-        CFArrayRef items = (CFArrayRef)value;
-        CFArrayApplyFunction(items, CFRangeMake(0, CFArrayGetCount(items)),
-            SecServerImportItem, &item_state);
-    } else {
-        CFDictionaryRef item = (CFDictionaryRef)value;
-        SecServerImportItem(item, &item_state);
-    }
-}
-
-static bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt,
-    keybag_handle_t src_keybag, keybag_handle_t dest_keybag,
-    CFDictionaryRef keychain, enum SecItemFilter filter, CFErrorRef *error) {
-    bool ok = true;
-
-    CFDictionaryRef sys_bound = NULL;
-    if (filter == kSecBackupableItemFilter) {
-        /* Grab a copy of all the items for which SecItemIsSystemBound()
-           returns true. */
-        require(sys_bound = SecServerExportKeychainPlist(dbt, KEYBAG_DEVICE,
-                                                         KEYBAG_NONE, kSecSysBoundItemFilter,
-                                                         error), errOut);
-    }
-
-    /* Delete everything in the keychain. */
-    require(ok = SecServerDeleteAll(dbt, error), errOut);
-
-    struct SecServerImportClassState state = {
-        .dbt = dbt,
-        .src_keybag = src_keybag,
-        .dest_keybag = dest_keybag,
-        .filter = filter,
-    };
-    /* Import the provided items, preserving rowids. */
-    CFDictionaryApplyFunction(keychain, SecServerImportClass, &state);
-
-    if (sys_bound) {
-        state.src_keybag = KEYBAG_NONE;
-        /* Import the items we preserved with random rowids. */
-        state.filter = kSecSysBoundItemFilter;
-        CFDictionaryApplyFunction(sys_bound, SecServerImportClass, &state);
-        CFRelease(sys_bound);
-    }
-    if (state.error) {
-        if (error) {
-            CFReleaseSafe(*error);
-            *error = state.error;
-        } else {
-            CFRelease(state.error);
-        }
-        ok = false;
-    }
-
-errOut:
-    return ok;
-}
-
-static bool SecServerImportKeychain(SecDbConnectionRef dbt,
-    keybag_handle_t src_keybag,
-    keybag_handle_t dest_keybag, CFDataRef data, CFErrorRef *error) {
-    return kc_transaction(dbt, error, ^{
-        bool ok = false;
-        CFDictionaryRef keychain;
-        keychain = CFPropertyListCreateWithData(kCFAllocatorDefault, data,
-                                                kCFPropertyListImmutable, NULL,
-                                                error);
-        if (keychain) {
-            if (isDictionary(keychain)) {
-                ok = SecServerImportKeychainInPlist(dbt, src_keybag,
-                                                    dest_keybag, keychain,
-                                                    kSecBackupableItemFilter,
-                                                    error);
-            } else {
-                ok = SecError(errSecParam, error, CFSTR("import: keychain is not a dictionary"));
-            }
-            CFRelease(keychain);
-        }
-        return ok;
-    });
-}
-
-static bool ks_open_keybag(CFDataRef keybag, CFDataRef password, keybag_handle_t *handle, CFErrorRef *error) {
-#if USE_KEYSTORE
-    kern_return_t kernResult;
-    kernResult = aks_load_bag(CFDataGetBytePtr(keybag), (int)CFDataGetLength(keybag), handle);
-    if (kernResult)
-        return SecKernError(kernResult, error, CFSTR("aks_load_bag failed: %@"), keybag);
-
-    if (password) {
-        kernResult = aks_unlock_bag(*handle, CFDataGetBytePtr(password), (int)CFDataGetLength(password));
-        if (kernResult) {
-            aks_unload_bag(*handle);
-            return SecKernError(kernResult, error, CFSTR("aks_unlock_bag failed"));
-        }
-    }
-    return true;
-#else /* !USE_KEYSTORE */
-    *handle = KEYBAG_NONE;
-    return true;
-#endif /* USE_KEYSTORE */
-}
-
-static bool ks_close_keybag(keybag_handle_t keybag, CFErrorRef *error) {
-#if USE_KEYSTORE
-       IOReturn kernResult = aks_unload_bag(keybag);
-    if (kernResult) {
-        return SecKernError(kernResult, error, CFSTR("aks_unload_bag failed"));
-    }
-#endif /* USE_KEYSTORE */
-    return true;
-}
-
-static CF_RETURNS_RETAINED CFDataRef SecServerKeychainBackup(SecDbConnectionRef dbt, CFDataRef keybag,
-    CFDataRef password, CFErrorRef *error) {
-    CFDataRef backup = NULL;
-    keybag_handle_t backup_keybag;
-    if (ks_open_keybag(keybag, password, &backup_keybag, error)) {
-        /* Export from system keybag to backup keybag. */
-        backup = SecServerExportKeychain(dbt, KEYBAG_DEVICE, backup_keybag, error);
-        if (!ks_close_keybag(backup_keybag, error)) {
-            CFReleaseNull(backup);
-        }
-    }
-    return backup;
-}
-
-static bool SecServerKeychainRestore(SecDbConnectionRef dbt, CFDataRef backup,
-    CFDataRef keybag, CFDataRef password, CFErrorRef *error) {
-    keybag_handle_t backup_keybag;
-    if (!ks_open_keybag(keybag, password, &backup_keybag, error))
-        return false;
-
-    /* Import from backup keybag to system keybag. */
-    bool ok = SecServerImportKeychain(dbt, backup_keybag, KEYBAG_DEVICE,
-                                      backup, error);
-    ok &= ks_close_keybag(backup_keybag, error);
-
-    return ok;
-}
-
-
-// MARK - External SPI support code.
-
-CFStringRef __SecKeychainCopyPath(void) {
-    CFStringRef kcRelPath = NULL;
-    if (use_hwaes()) {
-        kcRelPath = CFSTR("keychain-2.db");
-    } else {
-        kcRelPath = CFSTR("keychain-2-debug.db");
-    }
-
-    CFStringRef kcPath = NULL;
-    CFURLRef kcURL = SecCopyURLForFileInKeychainDirectory(kcRelPath);
-    if (kcURL) {
-        kcPath = CFURLCopyFileSystemPath(kcURL, kCFURLPOSIXPathStyle);
-        CFRelease(kcURL);
-    }
-    return kcPath;
-
-}
-
-// MARK; -
-// MARK: kc_dbhandle init and reset
-
-static SecDbRef SecKeychainDbCreate(CFStringRef path) {
-    return SecDbCreate(path, ^bool (SecDbConnectionRef dbconn, bool didCreate, CFErrorRef *localError) {
-        bool ok;
-        if (didCreate)
-            ok = s3dl_dbt_upgrade_from_version(dbconn, 0, localError);
-        else
-            ok = s3dl_dbt_upgrade(dbconn, localError);
-
-        if (!ok)
-            secerror("Upgrade %sfailed: %@", didCreate ? "from v0 " : "", localError ? *localError : NULL);
-
-        return ok;
-    });
-}
-
-static SecDbRef _kc_dbhandle = NULL;
-
-static void kc_dbhandle_init(void) {
-    SecDbRef oldHandle = _kc_dbhandle;
-    _kc_dbhandle = NULL;
-    CFStringRef dbPath = __SecKeychainCopyPath();
-    if (dbPath) {
-        _kc_dbhandle = SecKeychainDbCreate(dbPath);
-        CFRelease(dbPath);
-    }
-    if (oldHandle) {
-        secerror("replaced %@ with %@", oldHandle, _kc_dbhandle);
-        CFRelease(oldHandle);
-    }
-}
-
-static dispatch_once_t _kc_dbhandle_once;
-
-static SecDbRef kc_dbhandle(void) {
-    dispatch_once(&_kc_dbhandle_once, ^{
-        kc_dbhandle_init();
-    });
-    return _kc_dbhandle;
-}
-
-/* For whitebox testing only */
-void kc_dbhandle_reset(void);
-void kc_dbhandle_reset(void)
-{
-    __block bool done = false;
-    dispatch_once(&_kc_dbhandle_once, ^{
-        kc_dbhandle_init();
-        done = true;
-    });
-    // TODO: Not thread safe at all! - FOR DEBUGGING ONLY
-    if (!done)
-        kc_dbhandle_init();
-}
-
-static SecDbConnectionRef kc_aquire_dbt(bool writeAndRead, CFErrorRef *error) {
-    return SecDbConnectionAquire(kc_dbhandle(), !writeAndRead, error);
-}
-
-/* Return a per thread dbt handle for the keychain.  If create is true create
- the database if it does not yet exist.  If it is false, just return an
- error if it fails to auto-create. */
-static bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt))
-{
-    bool ok = false;
-    SecDbConnectionRef dbt = kc_aquire_dbt(writeAndRead, error);
-    if (dbt) {
-        ok = perform(dbt);
-        SecDbConnectionRelease(dbt);
-    }
-    return ok;
-}
-
-static bool
-items_matching_issuer_parent(CFArrayRef accessGroups,
-                            CFDataRef issuer, CFArrayRef issuers, int recurse)
-{
-    Query *q;
-    CFArrayRef results = NULL;
-    SecDbConnectionRef dbt = NULL;
-    CFIndex i, count;
-    bool found = false;
-
-    if (CFArrayContainsValue(issuers, CFRangeMake(0, CFArrayGetCount(issuers)), issuer))
-        return true;
-
-    const void *keys[] = { kSecClass, kSecReturnRef, kSecAttrSubject };
-    const void *vals[] = { kSecClassCertificate, kCFBooleanTrue, issuer };
-    CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, array_size(keys), NULL, NULL);
-
-    if (!query)
-        return false;
-
-    CFErrorRef localError = NULL;
-    q = query_create_with_limit(query, kSecMatchUnlimited, &localError);
-    CFRelease(query);
-    if (q) {
-        if ((dbt = SecDbConnectionAquire(kc_dbhandle(), true, &localError))) {
-            s3dl_copy_matching(dbt, q, (CFTypeRef*)&results, accessGroups, &localError);
-            SecDbConnectionRelease(dbt);
-        }
-        query_destroy(q, &localError);
-    }
-    if (localError) {
-        secerror("items matching issuer parent: %@", localError);
-        CFReleaseNull(localError);
-        return false;
-    }
-
-    count = CFArrayGetCount(results);
-    for (i = 0; (i < count) && !found; i++) {
-        CFDictionaryRef cert_dict = (CFDictionaryRef)CFArrayGetValueAtIndex(results, i);
-        CFDataRef cert_issuer = CFDictionaryGetValue(cert_dict, kSecAttrIssuer);
-        if (CFEqual(cert_issuer, issuer))
-            continue;
-        if (recurse-- > 0)
-            found = items_matching_issuer_parent(accessGroups, cert_issuer, issuers, recurse);
-    }
-    CFRelease(results);
-
-    return found;
-}
-
-static bool match_item(Query *q, CFArrayRef accessGroups, CFDictionaryRef item)
-{
-    if (q->q_match_issuer) {
-        CFDataRef issuer = CFDictionaryGetValue(item, kSecAttrIssuer);
-        if (!items_matching_issuer_parent(accessGroups, issuer, q->q_match_issuer, 10 /*max depth*/))
-            return false;
-    }
-
-    /* Add future match checks here. */
-
-    return true;
-}
-
-/****************************************************************************
- **************** Beginning of Externally Callable Interface ****************
- ****************************************************************************/
-
-#if 0
-// TODO Use as a safety wrapper
-static bool SecErrorWith(CFErrorRef *in_error, bool (^perform)(CFErrorRef *error)) {
-    CFErrorRef error = in_error ? *in_error : NULL;
-    bool ok;
-    if ((ok = perform(&error))) {
-        assert(error == NULL);
-        if (error)
-            secerror("error + success: %@", error);
-    } else {
-        assert(error);
-        OSStatus status = SecErrorGetOSStatus(error);
-        if (status != errSecItemNotFound)           // Occurs in normal operation, so exclude
-            secerror("error:[%" PRIdOSStatus "] %@", status, error);
-        if (in_error) {
-            *in_error = error;
-        } else {
-            CFReleaseNull(error);
-        }
-    }
-    return ok;
-}
-#endif
-
-/* AUDIT[securityd](done):
-   query (ok) is a caller provided dictionary, only its cf type has been checked.
- */
-static bool
-SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result,
-    CFArrayRef accessGroups, CFErrorRef *error)
-{
-    CFIndex ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
-        return SecError(errSecMissingEntitlement, error,
-                         CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
-    }
-
-    if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
-        /* Having the special accessGroup "*" allows access to all accessGroups. */
-        accessGroups = NULL;
-    }
-
-    bool ok = false;
-    Query *q = query_create_with_limit(query, 1, error);
-    if (q) {
-        CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup);
-        if (agrp && accessGroupsAllows(accessGroups, agrp)) {
-            // TODO: Return an error if agrp is not NULL and accessGroupsAllows() fails above.
-            const void *val = agrp;
-            accessGroups = CFArrayCreate(0, &val, 1, &kCFTypeArrayCallBacks);
-        } else {
-            CFRetainSafe(accessGroups);
-        }
-
-        /* Sanity check the query. */
-        if (q->q_use_item_list) {
-            ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list unsupported"));
-#if defined(MULTIPLE_KEYCHAINS)
-        } else if (q->q_use_keychain) {
-            ok = SecError(errSecUseKeychainUnsupported, error, CFSTR("use keychain list unsupported"));
-#endif
-        } else if (q->q_match_issuer && ((q->q_class != &cert_class) &&
-                    (q->q_class != &identity_class))) {
-            ok = SecError(errSecUnsupportedOperation, error, CFSTR("unsupported match attribute"));
-        } else if (q->q_return_type != 0 && result == NULL) {
-            ok = SecError(errSecReturnMissingPointer, error, CFSTR("missing pointer"));
-        } else if (!q->q_error) {
-            ok = kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) {
-                return s3dl_copy_matching(dbt, q, result, accessGroups, error);
-            });
-        }
-
-        CFReleaseSafe(accessGroups);
-        if (!query_destroy(q, error))
-            ok = false;
-    }
-
-       return ok;
-}
-
-bool
-_SecItemCopyMatching(CFDictionaryRef query, CFArrayRef accessGroups, CFTypeRef *result, CFErrorRef *error) {
-    return SecItemServerCopyMatching(query, result, accessGroups, error);
-}
-
-/* AUDIT[securityd](done):
-   attributes (ok) is a caller provided dictionary, only its cf type has
-       been checked.
- */
-bool
-_SecItemAdd(CFDictionaryRef attributes, CFArrayRef accessGroups,
-            CFTypeRef *result, CFErrorRef *error)
-{
-    bool ok = true;
-    CFIndex ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)))
-        return SecError(errSecMissingEntitlement, error,
-                           CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
-
-    Query *q = query_create_with_limit(attributes, 0, error);
-    if (q) {
-        /* Access group sanity checking. */
-        CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributes,
-            kSecAttrAccessGroup);
-
-        CFArrayRef ag = accessGroups;
-        /* Having the special accessGroup "*" allows access to all accessGroups. */
-        if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*")))
-            accessGroups = NULL;
-
-        if (agrp) {
-            /* The user specified an explicit access group, validate it. */
-            if (!accessGroupsAllows(accessGroups, agrp))
-                return SecError(errSecNoAccessForItem, error, CFSTR("NoAccessForItem"));
-        } else {
-            agrp = (CFStringRef)CFArrayGetValueAtIndex(ag, 0);
-
-            /* We are using an implicit access group, add it as if the user
-               specified it as an attribute. */
-            query_add_attribute(kSecAttrAccessGroup, agrp, q);
-        }
-
-        query_ensure_keyclass(q, agrp);
-
-        if (q->q_row_id)
-            ok = SecError(errSecValuePersistentRefUnsupported, error, CFSTR("q_row_id"));  // TODO: better error string
-    #if defined(MULTIPLE_KEYCHAINS)
-        else if (q->q_use_keychain_list)
-            ok = SecError(errSecUseKeychainListUnsupported, error, CFSTR("q_use_keychain_list"));  // TODO: better error string;
-    #endif
-        else if (!q->q_error) {
-            ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt){
-                return kc_transaction(dbt, error, ^{
-                    query_pre_add(q, true);
-                    return s3dl_query_add(dbt, q, result, error);
-                });
-            });
-        }
-        ok = query_notify_and_destroy(q, ok, error);
-    } else {
-        ok = false;
-    }
-    return ok;
-}
-
-/* AUDIT[securityd](done):
-   query (ok) and attributesToUpdate (ok) are a caller provided dictionaries,
-       only their cf types have been checked.
- */
-bool
-_SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate,
-               CFArrayRef accessGroups, CFErrorRef *error)
-{
-    CFIndex ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
-        return SecError(errSecMissingEntitlement, error,
-                         CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
-    }
-
-    if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
-        /* Having the special accessGroup "*" allows access to all accessGroups. */
-        accessGroups = NULL;
-    }
-
-    bool ok = true;
-    Query *q = query_create_with_limit(query, kSecMatchUnlimited, error);
-    if (!q) {
-        ok = false;
-    }
-    if (ok) {
-        /* Sanity check the query. */
-        if (q->q_use_item_list) {
-            ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list not supported"));
-        } else if (q->q_return_type & kSecReturnDataMask) {
-            /* Update doesn't return anything so don't ask for it. */
-            ok = SecError(errSecReturnDataUnsupported, error, CFSTR("return data not supported by update"));
-        } else if (q->q_return_type & kSecReturnAttributesMask) {
-            ok = SecError(errSecReturnAttributesUnsupported, error, CFSTR("return attributes not supported by update"));
-        } else if (q->q_return_type & kSecReturnRefMask) {
-            ok = SecError(errSecReturnRefUnsupported, error, CFSTR("return ref not supported by update"));
-        } else if (q->q_return_type & kSecReturnPersistentRefMask) {
-            ok = SecError(errSecReturnPersitentRefUnsupported, error, CFSTR("return persistent ref not supported by update"));
-        } else {
-            /* Access group sanity checking. */
-            CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributesToUpdate,
-                kSecAttrAccessGroup);
-            if (agrp) {
-                /* The user is attempting to modify the access group column,
-                   validate it to make sure the new value is allowable. */
-                if (!accessGroupsAllows(accessGroups, agrp)) {
-                    ok = SecError(errSecNoAccessForItem, error, CFSTR("accessGroup %@ not in %@"), agrp, accessGroups);
-                }
-            }
-        }
-    }
-    if (ok) {
-        if (!q->q_use_tomb && SOSCCThisDeviceDefinitelyNotActiveInCircle()) {
-            q->q_use_tomb = kCFBooleanFalse;
-        }
-        ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) {
-            return s3dl_query_update(dbt, q, attributesToUpdate, accessGroups, error);
-        });
-    }
-    if (q) {
-        ok = query_notify_and_destroy(q, ok, error);
-    }
-    return ok;
-}
-
-
-/* AUDIT[securityd](done):
-   query (ok) is a caller provided dictionary, only its cf type has been checked.
- */
-bool
-_SecItemDelete(CFDictionaryRef query, CFArrayRef accessGroups, CFErrorRef *error)
-{
-    CFIndex ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
-        return SecError(errSecMissingEntitlement, error,
-                           CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
-    }
-
-    if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
-        /* Having the special accessGroup "*" allows access to all accessGroups. */
-        accessGroups = NULL;
-    }
-
-    Query *q = query_create_with_limit(query, kSecMatchUnlimited, error);
-    bool ok;
-    if (q) {
-        /* Sanity check the query. */
-        if (q->q_limit != kSecMatchUnlimited)
-            ok = SecError(errSecMatchLimitUnsupported, error, CFSTR("match limit not supported by delete"));
-        else if (query_match_count(q) != 0)
-            ok = SecError(errSecItemMatchUnsupported, error, CFSTR("match not supported by delete"));
-        else if (q->q_ref)
-            ok = SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by delete"));
-        else if (q->q_row_id && query_attr_count(q))
-            ok = SecError(errSecItemIllegalQuery, error, CFSTR("rowid and other attributes are mutually exclusive"));
-        else {
-            if (!q->q_use_tomb && SOSCCThisDeviceDefinitelyNotActiveInCircle()) {
-                q->q_use_tomb = kCFBooleanFalse;
-            }
-            ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) {
-                return s3dl_query_delete(dbt, q, accessGroups, error);
-            });
-        }
-        ok = query_notify_and_destroy(q, ok, error);
-    } else {
-        ok = false;
-    }
-    return ok;
-}
-
-
-/* AUDIT[securityd](done):
-   No caller provided inputs.
- */
-static bool
-SecItemServerDeleteAll(CFErrorRef *error) {
-    return kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) {
-        return (kc_transaction(dbt, error, ^bool {
-            return (SecDbExec(dbt, CFSTR("DELETE from genp;"), error) &&
-                    SecDbExec(dbt, CFSTR("DELETE from inet;"), error) &&
-                    SecDbExec(dbt, CFSTR("DELETE from cert;"), error) &&
-                    SecDbExec(dbt, CFSTR("DELETE from keys;"), error));
-        }) && SecDbExec(dbt, CFSTR("VACUUM;"), error));
-    });
-}
-
-bool
-_SecItemDeleteAll(CFErrorRef *error) {
-    return SecItemServerDeleteAll(error);
-}
-
-CFDataRef
-_SecServerKeychainBackup(CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
-    CFDataRef backup;
-       SecDbConnectionRef dbt = SecDbConnectionAquire(kc_dbhandle(), false, error);
-
-       if (!dbt)
-               return NULL;
-
-    if (keybag == NULL && passcode == NULL) {
-#if USE_KEYSTORE
-        backup = SecServerExportKeychain(dbt, KEYBAG_DEVICE, backup_keybag_handle, error);
-#else /* !USE_KEYSTORE */
-        SecError(errSecParam, error, CFSTR("Why are you doing this?"));
-        backup = NULL;
-#endif /* USE_KEYSTORE */
-    } else {
-        backup = SecServerKeychainBackup(dbt, keybag, passcode, error);
-    }
-
-    SecDbConnectionRelease(dbt);
-
-    return backup;
-}
-
-bool
-_SecServerKeychainRestore(CFDataRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
-    if (backup == NULL || keybag == NULL)
-        return SecError(errSecParam, error, CFSTR("backup or keybag missing"));
-
-    __block bool ok = true;
-    ok &= SecDbPerformWrite(kc_dbhandle(), error, ^(SecDbConnectionRef dbconn) {
-        ok = SecServerKeychainRestore(dbconn, backup, keybag, passcode, error);
-    });
-
-    if (ok) {
-        SecKeychainChanged(true);
-    }
-
-    return ok;
-}
-
-
-/*
- *
- *
- * SecItemDataSource
- *
- *
- */
-static CFStringRef kSecItemDataSourceErrorDomain = CFSTR("com.apple.secitem.datasource");
-
-enum {
-    kSecObjectMallocFailed = 1,
-    kSecAddDuplicateEntry,
-    kSecObjectNotFoundError,
-    kSOSAccountCreationFailed,
-};
-
-typedef struct SecItemDataSource *SecItemDataSourceRef;
-
-struct SecItemDataSource {
-    struct SOSDataSource ds;
-    SecDbRef db;
-    bool readOnly;
-    SecDbConnectionRef _dbconn;
-    unsigned gm_count;
-    unsigned cm_count;
-    unsigned co_count;
-    bool dv_loaded;
-    struct SOSDigestVector dv;
-    struct SOSDigestVector toadd;
-    struct SOSDigestVector todel;
-    SOSManifestRef manifest;
-    uint8_t manifest_digest[SOSDigestSize];
-    bool changed;
-    bool syncWithPeersWhenDone;
-};
-
-static SecDbConnectionRef SecItemDataSourceGetConnection(SecItemDataSourceRef ds, CFErrorRef *error) {
-    if (!ds->_dbconn) {
-        ds->_dbconn = SecDbConnectionAquire(ds->db, ds->readOnly, error);
-        if (ds->_dbconn) {
-            ds->changed = false;
-        } else {
-            secerror("SecDbConnectionAquire failed: %@", error ? *error : NULL);
-        }
-    }
-    return ds->_dbconn;
-}
-
-static bool SecItemDataSourceRecordUpdate(SecItemDataSourceRef ds, SecDbItemRef deleted, SecDbItemRef inserted, CFErrorRef *error) {
-    bool ok = true;
-    CFDataRef digest;
-    if (ds->dv_loaded) {
-        if (inserted) {
-            ok = digest = SecDbItemGetSHA1(inserted, error);
-            if (ok) SOSDigestVectorAppend(&ds->toadd, CFDataGetBytePtr(digest));
-        }
-        if (ok && deleted) {
-            ok = digest = SecDbItemGetSHA1(deleted, error);
-            if (ok) SOSDigestVectorAppend(&ds->todel, CFDataGetBytePtr(digest));
-        }
-        if (inserted || deleted) {
-            CFReleaseNull(ds->manifest);
-            ds->changed = true;
-        }
-
-        if (!ok) {
-            ds->dv_loaded = false;
-        }
-    }
-    return ok;
-}
-
-static bool SecItemDataSourceRecordAdd(SecItemDataSourceRef ds, SecDbItemRef inserted, CFErrorRef *error) {
-    return SecItemDataSourceRecordUpdate(ds, NULL, inserted, error);
-}
-
-static bool SecDbItemSelectSHA1(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error,
-                                bool (^use_attr_in_where)(const SecDbAttr *attr),
-                                bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere),
-                                bool (^bind_added_where)(sqlite3_stmt *stmt, int col),
-                                void (^row)(sqlite3_stmt *stmt, bool *stop)) {
-    __block bool ok = true;
-    bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
-        return attr->kind == kSecDbSHA1Attr;
-    };
-    CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql);
-    if (sql) {
-        ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
-            ok = (SecDbItemSelectBind(query, stmt, error, use_attr_in_where, bind_added_where) &&
-                  SecDbStep(dbconn, stmt, error, ^(bool *stop){ row(stmt, stop); }));
-        });
-        CFRelease(sql);
-    } else {
-        ok = false;
-    }
-    return ok;
-}
-
-static bool SecItemDataSourceLoadManifest(SecItemDataSourceRef ds, CFErrorRef *error) {
-    bool ok = true;
-    SecDbConnectionRef dbconn;
-    if (!(dbconn = SecItemDataSourceGetConnection(ds, error))) return false;
-
-    /* Fetch all syncable items. */
-    const SecDbClass *synced_classes[] = {
-        &genp_class,
-        &inet_class,
-        &keys_class,
-    };
-
-    ds->dv.count = 0; // Empty the digest vectory before we begin
-    CFErrorRef localError = NULL;
-    for (size_t class_ix = 0; class_ix < array_size(synced_classes);
-         ++class_ix) {
-        Query *q = query_create(synced_classes[class_ix], NULL, &localError);
-        if (q) {
-            q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask;
-            q->q_limit = kSecMatchUnlimited;
-            q->q_keybag = KEYBAG_DEVICE;
-            query_add_attribute(kSecAttrSynchronizable, kCFBooleanTrue, q);
-            //query_add_attribute(kSecAttrAccessible, ds->name, q);
-            // Select everything including tombstones that is synchronizable.
-            if (!SecDbItemSelectSHA1(q, dbconn, &localError, ^bool(const SecDbAttr *attr) {
-                return attr->kind == kSecDbSyncAttr;
-            }, NULL, NULL, ^(sqlite3_stmt *stmt, bool *stop) {
-                const uint8_t *digest = sqlite3_column_blob(stmt, 0);
-                size_t digestLen = sqlite3_column_bytes(stmt, 0);
-                if (digestLen != SOSDigestSize) {
-                    secerror("digest %zu bytes", digestLen);
-                } else {
-                    SOSDigestVectorAppend(&ds->dv, digest);
-                }
-            })) {
-                secerror("SecDbItemSelect failed: %@", localError);
-                CFReleaseNull(localError);
-            }
-            query_destroy(q, &localError);
-            if (localError) {
-                secerror("query_destroy failed: %@", localError);
-                CFReleaseNull(localError);
-            }
-        } else if (localError) {
-            secerror("query_create failed: %@", localError);
-            CFReleaseNull(localError);
-        }
-    }
-    SOSDigestVectorSort(&ds->dv);
-    return ok;
-}
-
-static bool SecItemDataSourceEnsureFreshManifest(SecItemDataSourceRef ds, CFErrorRef *error) {
-    bool ok = true;
-    if (ds->dv_loaded && (ds->toadd.count || ds->todel.count)) {
-        CFErrorRef patchError = NULL;
-        struct SOSDigestVector new_dv = SOSDigestVectorInit;
-        ok = SOSDigestVectorPatch(&ds->dv, &ds->todel, &ds->toadd, &new_dv, &patchError);
-        if (!ok) secerror("patch failed %@ manifest: %@ toadd: %@ todel: %@", patchError, &ds->dv, &ds->todel, &ds->toadd);
-        CFReleaseSafe(patchError);
-        SOSDigestVectorFree(&ds->dv);
-        SOSDigestVectorFree(&ds->toadd);
-        SOSDigestVectorFree(&ds->todel);
-        ds->dv = new_dv;
-    }
-    // If we failed to patch or we haven't loaded yet, force a load from the db.
-    return (ok && ds->dv_loaded) || (ds->dv_loaded = SecItemDataSourceLoadManifest(ds, error));
-}
-
-/* DataSource protocol. */
-static bool ds_get_manifest_digest(SOSDataSourceRef data_source, uint8_t *out_digest, CFErrorRef *error) {
-    struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
-    if (!ds->manifest) {
-        SOSManifestRef mf = data_source->copy_manifest(data_source, error);
-        if (mf) {
-            CFRelease(mf);
-        } else {
-            return false;
-        }
-    }
-    memcpy(out_digest, ds->manifest_digest, SOSDigestSize);
-    ds->gm_count++;
-    return true;
-}
-
-static SOSManifestRef ds_copy_manifest(SOSDataSourceRef data_source, CFErrorRef *error) {
-    struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
-    ds->cm_count++;
-    if (ds->manifest) {
-        CFRetain(ds->manifest);
-        return ds->manifest;
-    }
-
-    if (!SecItemDataSourceEnsureFreshManifest(ds, error)) return NULL;
-
-    ds->manifest = SOSManifestCreateWithBytes((const uint8_t *)ds->dv.digest, ds->dv.count * SOSDigestSize, error);
-    // TODO move digest
-    ccdigest(ccsha1_di(), SOSManifestGetSize(ds->manifest), SOSManifestGetBytePtr(ds->manifest), ds->manifest_digest);
-
-    return (SOSManifestRef)CFRetain(ds->manifest);
-}
-
-static bool ds_foreach_object(SOSDataSourceRef data_source, SOSManifestRef manifest, CFErrorRef *error, bool (^handle_object)(SOSObjectRef object, CFErrorRef *error)) {
-    struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
-    ds->co_count++;
-    __block bool result = true;
-    const SecDbAttr *sha1Attr = SecDbClassAttrWithKind(&genp_class, kSecDbSHA1Attr, error);
-    if (!sha1Attr) return false;
-    bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
-        return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr;
-    };
-    bool (^use_attr_in_where)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
-        return attr->kind == kSecDbSHA1Attr;
-    };
-    const SecDbClass *synced_classes[] = {
-        &genp_class,
-        &inet_class,
-        &keys_class,
-    };
-    Query *select_queries[array_size(synced_classes)];
-    CFStringRef select_sql[array_size(synced_classes)];
-    sqlite3_stmt *select_stmts[array_size(synced_classes)];
-
-    __block Query **queries = select_queries;
-    __block CFStringRef *sqls = select_sql;
-    __block sqlite3_stmt **stmts = select_stmts;
-
-    SecDbConnectionRef dbconn;
-    result = dbconn = SecItemDataSourceGetConnection(ds, error);
-
-    // Setup
-    for (size_t class_ix = 0; class_ix < array_size(synced_classes); ++class_ix) {
-        result = (result
-                  && (queries[class_ix] = query_create(synced_classes[class_ix], NULL, error))
-                  && (sqls[class_ix] = SecDbItemCopySelectSQL(queries[class_ix], return_attr, use_attr_in_where, NULL))
-                  && (stmts[class_ix] = SecDbCopyStmt(dbconn, sqls[class_ix], NULL, error)));
-    }
-
-    if (result) SOSManifestForEach(manifest, ^(CFDataRef key) {
-        __block bool gotItem = false;
-        for (size_t class_ix = 0; result && !gotItem && class_ix < array_size(synced_classes); ++class_ix) {
-            CFDictionarySetValue(queries[class_ix]->q_item, sha1Attr->name, key);
-            result &= (SecDbItemSelectBind(queries[class_ix], stmts[class_ix], error, use_attr_in_where, NULL) && SecDbStep(dbconn, stmts[class_ix], error, ^(bool *stop) {
-                SecDbItemRef item = SecDbItemCreateWithStatement(kCFAllocatorDefault, queries[class_ix]->q_class, stmts[class_ix], KEYBAG_DEVICE, error, return_attr);
-                if (item) {
-                    CFErrorRef localError=NULL;
-                    gotItem = true;
-                    // Stop on errors from handle_object, except decode errors
-                    if(!(result=handle_object((SOSObjectRef)item, &localError))){
-                        if (SecErrorGetOSStatus(localError) == errSecDecode) {
-                            const uint8_t *p=CFDataGetBytePtr(key);
-                            secnotice("item", "Found corrupted item, removing from manifest key=%02X%02X%02X%02X, item=%@", p[0],p[1],p[2],p[3], item);
-                            /* Removing from Manifest: */
-                            SOSDigestVectorAppend(&ds->todel, p);
-                            CFReleaseNull(ds->manifest);
-                        } else {
-                            *stop=true;
-                        }
-                        if(error && *error == NULL) {
-                            *error = localError;
-                            localError = NULL;
-                        }
-                    }
-                    CFRelease(item);
-                    CFReleaseSafe(localError);
-                }
-            })) && SecDbReset(stmts[class_ix], error);
-        }
-        if (!gotItem) {
-            result = false;
-            if (error && !*error) {
-                SecCFCreateErrorWithFormat(kSecObjectNotFoundError, kSecItemDataSourceErrorDomain, NULL, error, 0, CFSTR("key %@ not in database"), key);
-            }
-        }
-    });
-
-    // Cleanup
-    for (size_t class_ix = 0; class_ix < array_size(synced_classes); ++class_ix) {
-        result &= SecDbReleaseCachedStmt(dbconn, sqls[class_ix], stmts[class_ix], error);
-        CFReleaseSafe(sqls[class_ix]);
-        result &= query_destroy(queries[class_ix], error);
-    }
-    return result;
-}
-
-static void ds_dispose(SOSDataSourceRef data_source) {
-    struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
-    if (ds->_dbconn)
-        SecDbConnectionRelease(ds->_dbconn);
-    if (ds->changed)
-        SecKeychainChanged(ds->syncWithPeersWhenDone);
-    CFReleaseSafe(ds->manifest);
-    SOSDigestVectorFree(&ds->dv);
-    free(ds);
-}
-
-static SOSObjectRef ds_create_with_property_list(SOSDataSourceRef ds, CFDictionaryRef plist, CFErrorRef *error) {
-    SecDbItemRef item = NULL;
-    const SecDbClass *class = NULL;
-    CFTypeRef cname = CFDictionaryGetValue(plist, kSecClass);
-    if (cname) {
-        class = kc_class_with_name(cname);
-        if (class) {
-            item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, class, plist, KEYBAG_DEVICE, error);
-        } else {
-            SecError(errSecNoSuchClass, error, CFSTR("can find class named: %@"), cname);
-        }
-    } else {
-        SecError(errSecItemClassMissing, error, CFSTR("query missing %@ attribute"), kSecClass);
-    }
-    return (SOSObjectRef)item;
-}
-
-static CFDataRef ds_copy_digest(SOSObjectRef object, CFErrorRef *error) {
-    SecDbItemRef item = (SecDbItemRef) object;
-    CFDataRef digest = SecDbItemGetSHA1(item, error);
-    CFRetainSafe(digest);
-    return digest;
-}
-
-static CFDataRef ds_copy_primary_key(SOSObjectRef object, CFErrorRef *error) {
-    SecDbItemRef item = (SecDbItemRef) object;
-    CFDataRef pk = SecDbItemGetPrimaryKey(item, error);
-    CFRetainSafe(pk);
-    return pk;
-}
-
-static CFDictionaryRef ds_copy_property_list(SOSObjectRef object, CFErrorRef *error) {
-    SecDbItemRef item = (SecDbItemRef) object;
-    CFMutableDictionaryRef plist = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error);
-    if (plist)
-        CFDictionaryAddValue(plist, kSecClass, SecDbItemGetClass(item)->name);
-    return plist;
-}
-
-// Return the newest object
-static SOSObjectRef ds_copy_merged_object(SOSObjectRef object1, SOSObjectRef object2, CFErrorRef *error) {
-    SecDbItemRef item1 = (SecDbItemRef) object1;
-    SecDbItemRef item2 = (SecDbItemRef) object2;
-    SOSObjectRef result = NULL;
-    CFDateRef m1, m2;
-    const SecDbAttr *desc = SecDbAttrWithKey(SecDbItemGetClass(item1), kSecAttrModificationDate, error);
-    m1 = SecDbItemGetValue(item1, desc, error);
-    if (!m1)
-        return NULL;
-    m2 = SecDbItemGetValue(item2, desc, error);
-    if (!m2)
-        return NULL;
-    switch (CFDateCompare(m1, m2, NULL)) {
-        case kCFCompareGreaterThan:
-            result = (SOSObjectRef)item1;
-            break;
-        case kCFCompareLessThan:
-            result = (SOSObjectRef)item2;
-            break;
-        case kCFCompareEqualTo:
-        {
-            // Return the item with the smallest digest.
-            CFDataRef digest1 = ds_copy_digest(object1, error);
-            CFDataRef digest2 = ds_copy_digest(object2, error);
-            if (digest1 && digest2) switch (CFDataCompare(digest1, digest2)) {
-                case kCFCompareGreaterThan:
-                case kCFCompareEqualTo:
-                    result = (SOSObjectRef)item2;
-                    break;
-                case kCFCompareLessThan:
-                    result = (SOSObjectRef)item1;
-                    break;
-            }
-            CFReleaseSafe(digest2);
-            CFReleaseSafe(digest1);
-            break;
-        }
-    }
-    CFRetainSafe(result);
-    return result;
-}
-
-static SOSMergeResult dsMergeObject(SOSDataSourceRef data_source, SOSObjectRef peersObject, CFErrorRef *error) {
-    struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
-    SecDbItemRef peersItem = (SecDbItemRef)peersObject;
-    SecDbConnectionRef dbconn = SecItemDataSourceGetConnection(ds, error);
-    __block SOSMergeResult mr = kSOSMergeFailure;
-    __block SecDbItemRef mergedItem = NULL;
-    __block SecDbItemRef replacedItem = NULL;
-    if (!peersItem || !dbconn || !SecDbItemSetKeybag(peersItem, KEYBAG_DEVICE, error)) return mr;
-    if (SecDbItemInsertOrReplace(peersItem, dbconn, error, ^(SecDbItemRef myItem, SecDbItemRef *replace) {
-        // An item with the same primary key as dbItem already exists in the the database.  That item is old_item.
-        // Let the conflict resolver choose which item to keep.
-        mergedItem = (SecDbItemRef)ds_copy_merged_object(peersObject, (SOSObjectRef)myItem, error);
-        if (!mergedItem) return;
-        if (CFEqual(mergedItem, myItem)) {
-            // Conflict resolver choose my (local) item
-            mr = kSOSMergeLocalObject;
-        } else {
-            CFRetainSafe(myItem);
-            replacedItem = myItem;
-            CFRetainSafe(mergedItem);
-            *replace = mergedItem;
-            if (CFEqual(mergedItem, peersItem)) {
-                // Conflict resolver choose peers item
-                mr = kSOSMergePeersObject;
-            } else {
-                mr = kSOSMergeCreatedObject;
-            }
-        }
-    })) {
-        if (mr == kSOSMergeFailure) {
-            mr = kSOSMergePeersObject;
-            SecItemDataSourceRecordAdd(ds, peersItem, error);
-        } else if (mr != kSOSMergeLocalObject) {
-            SecItemDataSourceRecordUpdate(ds, replacedItem, mergedItem, error);
-        }
-    }
-
-    if (error && *error && mr != kSOSMergeFailure)
-        CFReleaseNull(*error);
-
-    CFReleaseSafe(mergedItem);
-    CFReleaseSafe(replacedItem);
-    return mr;
-}
-
-
-/*
-    Truthy backup format is a dictionary from sha1 => item.
-    Each item has class, hash and item data.
-
-    TODO: sha1 is included as binary blob to avoid parsing key.
- */
-enum {
-    kSecBackupIndexHash = 0,
-    kSecBackupIndexClass,
-    kSecBackupIndexData,
-};
-
-static const void *kSecBackupKeys[] = {
-    [kSecBackupIndexHash] = CFSTR("hash"),
-    [kSecBackupIndexClass] = CFSTR("class"),
-    [kSecBackupIndexData] = CFSTR("data"),
-};
-
-#define kSecBackupHash kSecBackupKeys[kSecBackupIndexHash]
-#define kSecBackupClass kSecBackupKeys[kSecBackupIndexClass]
-#define kSecBackupData kSecBackupKeys[kSecBackupIndexData]
-
-static CFDictionaryRef ds_backup_object(SOSObjectRef object, uint64_t handle, CFErrorRef *error) {
-    const void *values[array_size(kSecBackupKeys)];
-    SecDbItemRef item = (SecDbItemRef)object;
-    CFDictionaryRef backup_item = NULL;
-
-    if ((values[kSecBackupIndexHash] = SecDbItemGetSHA1(item, error))) {
-        if ((values[kSecBackupIndexData] = SecDbItemCopyEncryptedDataToBackup(item, handle, error))) {
-            values[kSecBackupIndexClass] = SecDbItemGetClass(item)->name;
-            backup_item = CFDictionaryCreate(kCFAllocatorDefault, kSecBackupKeys, values, array_size(kSecBackupKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-            CFRelease(values[kSecBackupIndexData]);
-        }
-    }
-
-    return backup_item;
-}
-
-static bool ds_restore_object(SOSDataSourceRef data_source, uint64_t handle, CFDictionaryRef item, CFErrorRef *error) {
-    struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source;
-    SecDbConnectionRef dbconn = SecItemDataSourceGetConnection(ds, error);
-    if (!dbconn) return false;
-
-    CFStringRef item_class = CFDictionaryGetValue(item, kSecBackupClass);
-    CFDataRef data = CFDictionaryGetValue(item, kSecBackupData);
-    const SecDbClass *dbclass = NULL;
-
-    if (!item_class || !data)
-        return SecError(errSecDecode, error, CFSTR("no class or data in object"));
-    
-    dbclass = kc_class_with_name(item_class);
-    if (!dbclass)
-        return SecError(errSecDecode, error, CFSTR("no such class %@; update kc_class_with_name "), item_class);
-
-    __block SecDbItemRef dbitem = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, data, (keybag_handle_t)handle, error);
-    if (!dbitem)
-        return false;
-    
-    __block bool ok = SecDbItemSetKeybag(dbitem, KEYBAG_DEVICE, error);
-
-    if (ok) {
-        __block SecDbItemRef replaced_item = NULL;
-        ok &= SecDbItemInsertOrReplace(dbitem, dbconn, error, ^(SecDbItemRef old_item, SecDbItemRef *replace) {
-            // An item with the same primary key as dbItem already exists in the the database.  That item is old_item.
-            // Let the conflict resolver choose which item to keep.
-            SecDbItemRef chosen_item = (SecDbItemRef)ds_copy_merged_object((SOSObjectRef)dbitem, (SOSObjectRef)old_item, error);
-            if (chosen_item) {
-                if (CFEqual(chosen_item, old_item)) {
-                    // We're keeping the exisiting item, so we don't need to change anything.
-                    CFRelease(chosen_item);
-                    CFReleaseNull(dbitem);
-                } else {
-                    // We choose a different item than what's in the database already.  Let's set dbitem to what
-                    // we are replacing the item in the database with, and set replaced_item to the item we are replacing.
-                    CFRelease(dbitem); // Release the item created via SecDbItemCreateWithEncryptedData
-                    // Record what we put in the database
-                    CFRetain(chosen_item); // retain what we are about to return in *replace, since SecDbItemInsertOrReplace() CFReleases it.
-                    *replace = dbitem = chosen_item;
-                    // Record that we are replaced old_item in replaced_item.
-                    CFRetain(old_item);
-                    replaced_item = old_item;
-                }
-            } else {
-                ok = false;
-            }
-        })
-        && SecItemDataSourceRecordUpdate(ds, replaced_item, dbitem, error);
-        CFReleaseSafe(replaced_item);
-    }
-    CFReleaseSafe(dbitem);
-
-    return ok;
-}
-
-
-static SOSDataSourceRef SecItemDataSourceCreate(SecDbRef db, bool readOnly, bool syncWithPeersWhenDone, CFErrorRef *error) {
-    __block SecItemDataSourceRef ds = calloc(1, sizeof(struct SecItemDataSource));
-    ds->ds.get_manifest_digest = ds_get_manifest_digest;
-    ds->ds.copy_manifest = ds_copy_manifest;
-    ds->ds.foreach_object = ds_foreach_object;
-    ds->ds.release = ds_dispose;
-    ds->ds.add = dsMergeObject;
-
-    ds->ds.createWithPropertyList = ds_create_with_property_list;
-    ds->ds.copyDigest = ds_copy_digest;
-    ds->ds.copyPrimaryKey = ds_copy_primary_key;
-    ds->ds.copyPropertyList = ds_copy_property_list;
-    ds->ds.copyMergedObject = ds_copy_merged_object;
-    ds->ds.backupObject = ds_backup_object;
-    ds->ds.restoreObject = ds_restore_object;
-
-    ds->syncWithPeersWhenDone = syncWithPeersWhenDone;
-    ds->db = (SecDbRef)CFRetain(db);
-    ds->readOnly = readOnly;
-
-    ds->changed = false;
-    struct SOSDigestVector dv = SOSDigestVectorInit;
-    ds->dv = dv;
-
-    return (SOSDataSourceRef)ds;
-}
-
-static CFArrayRef SecItemDataSourceFactoryCopyNames(SOSDataSourceFactoryRef factory)
-{
-    return CFArrayCreateForCFTypes(kCFAllocatorDefault,
-                                   kSecAttrAccessibleWhenUnlocked,
-                                   //kSecAttrAccessibleAfterFirstUnlock,
-                                   //kSecAttrAccessibleAlways,
-                                   NULL);
-}
-
-struct SecItemDataSourceFactory {
-    struct SOSDataSourceFactory factory;
-    SecDbRef db;
-};
-
-
-static SOSDataSourceRef SecItemDataSourceFactoryCopyDataSource(SOSDataSourceFactoryRef factory, CFStringRef dataSourceName, bool readOnly, CFErrorRef *error)
-{
-    struct SecItemDataSourceFactory *f = (struct SecItemDataSourceFactory *)factory;
-    return SecItemDataSourceCreate(f->db, readOnly, false, error);
-}
-
-static void SecItemDataSourceFactoryDispose(SOSDataSourceFactoryRef factory)
-{
-    struct SecItemDataSourceFactory *f = (struct SecItemDataSourceFactory *)factory;
-    CFReleaseSafe(f->db);
-    free(f);
-}
-
-SOSDataSourceFactoryRef SecItemDataSourceFactoryCreate(SecDbRef db) {
-    struct SecItemDataSourceFactory *dsf = calloc(1, sizeof(struct SecItemDataSourceFactory));
-    dsf->factory.copy_names = SecItemDataSourceFactoryCopyNames;
-    dsf->factory.create_datasource = SecItemDataSourceFactoryCopyDataSource;
-    dsf->factory.release = SecItemDataSourceFactoryDispose;
-    CFRetainSafe(db);
-    dsf->db = db;
-
-    return &dsf->factory;
-}
-
-SOSDataSourceFactoryRef SecItemDataSourceFactoryCreateDefault(void) {
-    return SecItemDataSourceFactoryCreate(kc_dbhandle());
-}
-
-void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object) {
-    SOSObjectRef item = ds_create_with_property_list(NULL, object, NULL);
-    if (item) {
-        CFStringRef itemDesc = CFCopyDescription(item);
-        if (itemDesc) {
-            CFStringAppend(desc, itemDesc);
-            CFReleaseSafe(itemDesc);
-        }
-        CFRelease(item);
-    }
-}
-
-/* AUDIT[securityd]:
-   args_in (ok) is a caller provided, CFDictionaryRef.
- */
-bool
-_SecServerKeychainSyncUpdate(CFDictionaryRef updates, CFErrorRef *error) {
-    // This never fails, trust us!
-    CFRetainSafe(updates);
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-        SOSCCHandleUpdate(updates);
-        CFReleaseSafe(updates);
-    });
-    return true;
-}
-
-//
-// Truthiness in the cloud backup/restore support.
-//
-
-static CFStringRef SOSCopyItemKey(SOSDataSourceRef ds, SOSObjectRef object, CFErrorRef *error)
-{
-    CFStringRef item_key = NULL;
-    CFDataRef digest_data = ds->copyDigest(object, error);
-    if (digest_data) {
-        item_key = CFDataCopyHexString(digest_data);
-        CFRelease(digest_data);
-    }
-    return item_key;
-}
-
-static SOSManifestRef SOSCopyManifestFromBackup(CFDictionaryRef backup)
-{
-    CFMutableDataRef manifest = CFDataCreateMutable(kCFAllocatorDefault, 0);
-    if (backup) {
-        CFDictionaryForEach(backup, ^void (const void * key, const void * value) {
-            if (isDictionary(value)) {
-                /* converting key back to binary blob is horrible */
-                CFDataRef sha1 = CFDictionaryGetValue(value, kSecBackupHash);
-                if (isData(sha1))
-                    CFDataAppend(manifest, sha1);
-            }
-        });
-    }
-    return (SOSManifestRef)manifest;
-}
-
-static CFDictionaryRef
-_SecServerCopyTruthInTheCloud(CFDataRef keybag, CFDataRef password,
-    CFDictionaryRef backup, CFErrorRef *error)
-{
-    SOSManifestRef mold = NULL, mnow = NULL, mdelete = NULL, madd = NULL;
-    CFErrorRef foreachError = NULL;
-    CFDictionaryRef backup_out = NULL;
-    keybag_handle_t bag_handle;
-    if (!ks_open_keybag(keybag, password, &bag_handle, error))
-        return NULL;
-
-    CFMutableDictionaryRef backup_new = NULL;
-    SOSDataSourceRef ds = SecItemDataSourceCreate(kc_dbhandle(), true, false, error);
-    if (ds) {
-        backup_new = backup ? CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, backup) : CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-        mold = SOSCopyManifestFromBackup(backup);
-        mnow = ds->copy_manifest(ds, error);
-        SOSManifestDiff(mold, mnow, &mdelete, &madd, error);
-
-        // Delete everything from the new_backup that is no longer in the datasource according to the datasources manifest.
-        SOSManifestForEach(mdelete, ^(CFDataRef digest_data) {
-            CFStringRef deleted_item_key = CFDataCopyHexString(digest_data);
-            CFDictionaryRemoveValue(backup_new, deleted_item_key);
-            CFRelease(deleted_item_key);
-        });
-
-        if(!ds->foreach_object(ds, madd, &foreachError, ^bool(SOSObjectRef object, CFErrorRef *localError) {
-            bool ok = true;
-            CFStringRef key = SOSCopyItemKey(ds, object, localError);
-            CFTypeRef value = ds->backupObject(object, bag_handle, localError);
-
-            if (!key || !value) {
-                ok = false;
-            } else {
-                CFDictionarySetValue(backup_new, key, value);
-            }
-            CFReleaseSafe(key);
-            CFReleaseSafe(value);
-            return ok;
-        })) {
-            if(!SecErrorGetOSStatus(foreachError)==errSecDecode) {
-                if(error && *error==NULL) {
-                    *error = foreachError;
-                    foreachError = NULL;
-                }
-                goto out;
-            }
-        }
-
-        backup_out = backup_new;
-        backup_new = NULL;
-    }
-
-out:
-    if(ds)
-        ds->release(ds);
-
-    CFReleaseSafe(foreachError);
-    CFReleaseSafe(mold);
-    CFReleaseSafe(mnow);
-    CFReleaseSafe(madd);
-    CFReleaseSafe(mdelete);
-    CFReleaseSafe(backup_new);
-
-    if (!ks_close_keybag(bag_handle, error))
-        CFReleaseNull(backup_out);
-
-    return backup_out;
-}
-
-static bool
-_SecServerRestoreTruthInTheCloud(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFErrorRef *error) {
-    __block bool ok = true;
-    keybag_handle_t bag_handle;
-    if (!ks_open_keybag(keybag, password, &bag_handle, error))
-        return false;
-
-    SOSManifestRef mbackup = SOSCopyManifestFromBackup(backup_in);
-    if (mbackup) {
-        SOSDataSourceRef ds = SecItemDataSourceCreate(kc_dbhandle(), false, true, error);
-        if (ds) {
-            SOSManifestRef mnow = ds->copy_manifest(ds, error);
-            SOSManifestRef mdelete = NULL, madd = NULL;
-            SOSManifestDiff(mnow, mbackup, &mdelete, &madd, error);
-
-            // Don't delete everything in datasource not in backup.
-
-            // Add items from the backup
-            SOSManifestForEach(madd, ^void(CFDataRef e) {
-                CFDictionaryRef item = NULL;
-                CFStringRef sha1 = CFDataCopyHexString(e);
-                if (sha1) {
-                    item = CFDictionaryGetValue(backup_in, sha1);
-                    CFRelease(sha1);
-                }
-                if (item) {
-                    CFErrorRef localError = NULL;
-                    if (!ds->restoreObject(ds, bag_handle, item, &localError)) {
-                        if (SecErrorGetOSStatus(localError) == errSecDuplicateItem) {
-                            // Log and ignore duplicate item errors during restore
-                            secnotice("titc", "restore %@ not replacing existing item", item);
-                        } else {
-                            // Propagate the first other error upwards (causing the restore to fail).
-                            secerror("restore %@ failed %@", item, localError);
-                            ok = false;
-                            if (error && !*error) {
-                                *error = localError;
-                                localError = NULL;
-                            }
-                        }
-                        CFReleaseSafe(localError);
-                    }
-                }
-            });
-
-            ds->release(ds);
-            CFReleaseNull(mdelete);
-            CFReleaseNull(madd);
-            CFReleaseNull(mnow);
-        } else {
-            ok = false;
-        }
-        CFRelease(mbackup);
-    }
-
-    ok &= ks_close_keybag(bag_handle, error);
-
-    return ok;
-}
-
-
-CF_RETURNS_RETAINED CFDictionaryRef
-_SecServerBackupSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) {
-    require_action_quiet(isData(keybag), errOut, SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag));
-    require_action_quiet(!backup || isDictionary(backup), errOut, SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup));
-    require_action_quiet(!password || isData(password), errOut, SecError(errSecParam, error, CFSTR("password %@ not a data"), password));
-
-    return _SecServerCopyTruthInTheCloud(keybag, password, backup, error);
-
-errOut:
-    return NULL;
-}
-
-bool
-_SecServerRestoreSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) {
-    bool ok;
-    require_action_quiet(isData(keybag), errOut, ok = SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag));
-    require_action_quiet(isDictionary(backup), errOut, ok = SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup));
-    if (password) {
-        require_action_quiet(isData(password), errOut, ok = SecError(errSecParam, error, CFSTR("password not a data")));
-    }
-
-    ok = _SecServerRestoreTruthInTheCloud(keybag, password, backup, error);
-
-errOut:
-    return ok;
-}
-
-
-