2 * Copyright (c) 2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 // Test syncing between SecItemDataSource and SOSTestDataSource
27 #include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h"
28 #include "keychain/SecureObjectSync/Regressions/SOSTestDataSource.h"
29 #include "secd_regressions.h"
30 #include "SecdTestKeychainUtilities.h"
32 #include "keychain/SecureObjectSync/SOSDigestVector.h"
33 #include "keychain/SecureObjectSync/SOSEngine.h"
34 #include "keychain/SecureObjectSync/SOSPeer.h"
35 #import "keychain/SecureObjectSync/SOSChangeTracker.h"
36 #include <Security/SecBase64.h>
37 #include <Security/SecItem.h>
38 #include <Security/SecItemPriv.h>
39 #include <corecrypto/ccsha2.h>
40 #include "keychain/securityd/SecItemServer.h"
41 #include "keychain/securityd/SecItemDataSource.h"
42 #include <utilities/SecCFWrappers.h>
43 #include <utilities/SecIOFormat.h>
44 #include <utilities/SecFileLocations.h>
46 #include <AssertMacros.h>
49 static int kTestTestCount = 121;
51 static void nosha1(void) {
52 __block int iteration = 0;
53 __block CFErrorRef error = NULL;
54 SOSTestDeviceListTestSync("nosha1", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
56 // Add 10 items in first 10 sync messages
58 CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration);
59 SOSTestDeviceAddGenericItem(source, account, CFSTR("nosha1"));
60 CFReleaseSafe(account);
61 // Corrupt the 4th item added
63 ok(SecDbPerformWrite(source->db, &error, ^(SecDbConnectionRef dbconn) {
64 ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) {
65 ok(SecDbExec(dbconn, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=5;"), &error),
66 "Corrupting rowid 5 by zeroing sha1: %@", error);
68 }), "SecDbTransaction: %@", error);
70 }), "SecDbPerformWrite: %@", error);
79 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
81 }, CFSTR("Bad"), CFSTR("Good"), NULL);
84 static void drop_item(void) {
85 __block int iteration = 0;
86 __block CFErrorRef error = NULL;
87 SOSTestDeviceListTestSync("drop_item", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
89 // Add 10 items in first 10 sync messages
91 CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration);
92 SOSTestDeviceAddGenericItem(source, account, CFSTR("drop_item"));
93 CFReleaseSafe(account);
94 // Corrupt the 4th item added
96 ok(SecDbPerformWrite(source->db, &error, ^(SecDbConnectionRef dbconn) {
97 ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) {
98 ok(SecDbExec(dbconn, CFSTR("DELETE FROM genp WHERE rowid=5;"), &error),
99 "Corrupting rowid 5 by deleting object: %@", error);
100 CFReleaseNull(error);
101 }), "SecDbTransaction: %@", error);
102 CFReleaseNull(error);
103 }), "SecDbPerformWrite: %@", error);
104 CFReleaseNull(error);
112 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
114 }, CFSTR("Abegail"), CFSTR("Billy"), NULL);
117 static void drop_manifest(void) {
118 __block int iteration = 0;
119 SOSTestDeviceListTestSync("drop_manifest", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
121 // Add 5 items on Alice and 4 on Bob in first 9 sync messages
122 if (iteration <= 9) {
123 CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration / 2);
124 SOSTestDeviceAddGenericItem(source, account, CFSTR("drop_manifest"));
125 CFReleaseSafe(account);
126 // Corrupt the manifest after 4th item added
127 if (iteration == 4) {
128 SOSEngineRef engine = SOSDataSourceGetSharedEngine(source->ds, NULL);
129 SOSPeerRef peer = SOSEngineCopyPeerWithID(engine, SOSTestDeviceGetID(dest), NULL);
130 SOSManifestRef mf = SOSEngineCopyLocalPeerManifest(engine, peer, NULL);
132 CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
133 SOSManifestForEach(mf, ^(CFDataRef e, bool *stop) {
134 SOSChangesAppendDelete(changes, e);
136 ok(SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, NULL), "droped manifest from %@", source);
137 CFReleaseNull(changes);
145 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
147 }, CFSTR("Ann"), CFSTR("Ben"), NULL);
150 static void add_sha1(void) {
152 //todo("this never stops syncing");
153 __block int iteration = 0;
154 __block CFErrorRef error = NULL;
155 SOSTestDeviceListTestSync("add_sha1", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
157 // Add 9 items in first 9 sync messages
158 if (iteration <= 9) {
159 CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration);
160 SOSTestDeviceAddGenericItem(source, account, CFSTR("add_sha1"));
161 CFReleaseSafe(account);
162 // Corrupt the manifest after 4th item added
163 if (iteration == 4) {
164 ok(SecDbPerformWrite(source->db, &error, ^(SecDbConnectionRef dbconn) {
165 ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) {
166 ok(SecDbExec(dbconn, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=5;"), &error),
167 "Corrupting rowid 5 by zeroing sha1: %@", error);
168 CFReleaseNull(error);
169 }), "SecDbTransaction: %@", error);
170 CFReleaseNull(error);
171 }), "SecDbPerformWrite: %@", error);
172 CFReleaseNull(error);
174 SOSEngineRef engine = SOSDataSourceGetSharedEngine(source->ds, NULL);
175 uint8_t zeroDigest[20] = {};
176 CFDataRef zDigest = CFDataCreate(kCFAllocatorDefault, zeroDigest, 20);
177 CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
178 SOSChangesAppendAdd(changes, zDigest);
179 ok(SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, NULL), "corrupting manifest");
180 CFReleaseSafe(zDigest);
181 CFReleaseNull(changes);
188 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
190 }, CFSTR("Andy"), CFSTR("Bill"), NULL);
194 static void change_sha1(void) {
196 //todo("this never stops syncing");
197 __block int iteration = 0;
198 __block CFErrorRef error = NULL;
199 SOSTestDeviceListTestSync("change_sha1", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
201 // Add 9 items in first 9 sync messages
202 if (iteration <= 9) {
203 CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration);
204 CFStringRef server = CFSTR("change_sha1");
205 // Corrupt the manifest after 4th item added
206 if (!SOSDataSourceWithAPI(source->ds, true, &error, ^(SOSTransactionRef txn, bool *commit) {
207 SOSObjectRef object = SOSDataSourceCreateGenericItem(source->ds, account, server);
208 ok(SOSDataSourceMergeObject(source->ds, txn, object, NULL, &error), "%@ added API object %@", SOSTestDeviceGetID(source), error ? (CFTypeRef)error : (CFTypeRef)CFSTR("ok"));
209 if (iteration == 3) {
210 sqlite_int64 rowid = SecDbItemGetRowId((SecDbItemRef)object, NULL);
211 CFStringRef sql = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=%lld;"), rowid);
212 ok(SecDbExec((SecDbConnectionRef)txn, sql, &error),
213 "Corrupting rowid %lld by zeroing sha1: %@", rowid, error);
215 SOSEngineRef engine = SOSDataSourceGetSharedEngine(source->ds, NULL);
216 CFMutableArrayRef changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
217 uint8_t zeroDigest[20] = {};
218 CFDataRef zDigest = CFDataCreate(kCFAllocatorDefault, zeroDigest, 20);
219 SOSChangesAppendAdd(changes, zDigest);
220 CFDataRef digest = SOSObjectCopyDigest(source->ds, object, NULL);
221 SOSChangesAppendDelete(changes, digest);
222 const uint8_t *d = CFDataGetBytePtr(digest);
223 ok(SOSEngineUpdateChanges(engine, kSOSDataSourceSOSTransaction, changes, NULL), "corrupting manifest %lld %02X%02x%02x%02x",
224 rowid, d[0], d[1], d[2], d[3]);
225 CFReleaseSafe(zDigest);
226 CFReleaseSafe(digest);
227 CFReleaseNull(changes);
229 CFReleaseSafe(object);
230 CFReleaseNull(error);
232 fail("ds transaction %@", error);
233 CFReleaseNull(error);
234 CFReleaseNull(account);
238 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
242 }, CFSTR("Alice"), CFSTR("Bob"), NULL);
246 int secd_70_engine_corrupt(int argc, char *const *argv)
248 plan_tests(kTestTestCount);
250 __security_simulatecrash_enable(false);
252 /* custom keychain dir */
253 secd_test_setup_temp_keychain(__FUNCTION__, NULL);
261 __security_simulatecrash_enable(true);