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 <Regressions/SOSTestDevice.h>
28 #include <Regressions/SOSTestDataSource.h>
29 #include "secd_regressions.h"
30 #include "SecdTestKeychainUtilities.h"
32 #include <SecureObjectSync/SOSDigestVector.h>
33 #include <SecureObjectSync/SOSEngine.h>
34 #include <SecureObjectSync/SOSPeer.h>
35 #include <Security/SecBase64.h>
36 #include <Security/SecItem.h>
37 #include <Security/SecItemPriv.h>
38 #include <corecrypto/ccsha2.h>
39 #include <securityd/SecItemServer.h>
40 #include <securityd/SecItemDataSource.h>
41 #include <utilities/SecCFWrappers.h>
42 #include <utilities/SecIOFormat.h>
43 #include <utilities/SecFileLocations.h>
45 #include <AssertMacros.h>
48 static int kTestTestCount
= 125;
50 static void nosha1(void) {
51 __block
int iteration
= 0;
52 __block CFErrorRef error
= NULL
;
53 SOSTestDeviceListTestSync("nosha1", test_directive
, test_reason
, 0, true, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
) {
55 // Add 10 items in first 10 sync messages
57 CFStringRef account
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("item%d"), iteration
);
58 SOSTestDeviceAddGenericItem(source
, account
, CFSTR("nosha1"));
59 CFReleaseSafe(account
);
60 // Corrupt the 4th item added
62 ok(SecDbPerformWrite(source
->db
, &error
, ^(SecDbConnectionRef dbconn
) {
63 ok(SecDbTransaction(dbconn
, kSecDbExclusiveTransactionType
, &error
, ^(bool *commit
) {
64 ok(SecDbExec(dbconn
, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=5;"), &error
),
65 "Corrupting rowid 5 by zeroing sha1: %@", error
);
67 }), "SecDbTransaction: %@", error
);
69 }), "SecDbPerformWrite: %@", error
);
78 }, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
, SOSMessageRef message
) {
80 }, CFSTR("Bad"), CFSTR("Good"), NULL
);
83 static void drop_item(void) {
84 __block
int iteration
= 0;
85 __block CFErrorRef error
= NULL
;
86 SOSTestDeviceListTestSync("drop_item", test_directive
, test_reason
, 0, true, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
) {
88 // Add 10 items in first 10 sync messages
90 CFStringRef account
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("item%d"), iteration
);
91 SOSTestDeviceAddGenericItem(source
, account
, CFSTR("drop_item"));
92 CFReleaseSafe(account
);
93 // Corrupt the 4th item added
95 ok(SecDbPerformWrite(source
->db
, &error
, ^(SecDbConnectionRef dbconn
) {
96 ok(SecDbTransaction(dbconn
, kSecDbExclusiveTransactionType
, &error
, ^(bool *commit
) {
97 ok(SecDbExec(dbconn
, CFSTR("DELETE FROM genp WHERE rowid=5;"), &error
),
98 "Corrupting rowid 5 by deleting object: %@", error
);
100 }), "SecDbTransaction: %@", error
);
101 CFReleaseNull(error
);
102 }), "SecDbPerformWrite: %@", error
);
103 CFReleaseNull(error
);
111 }, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
, SOSMessageRef message
) {
113 }, CFSTR("Abegail"), CFSTR("Billy"), NULL
);
116 static void drop_manifest(void) {
117 __block
int iteration
= 0;
118 SOSTestDeviceListTestSync("drop_manifest", test_directive
, test_reason
, 0, true, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
) {
120 // Add 5 items on Alice and 4 on Bob in first 9 sync messages
121 if (iteration
<= 9) {
122 CFStringRef account
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("item%d"), iteration
/ 2);
123 SOSTestDeviceAddGenericItem(source
, account
, CFSTR("drop_manifest"));
124 CFReleaseSafe(account
);
125 // Corrupt the manifest after 4th item added
126 if (iteration
== 4) {
127 SOSEngineRef engine
= SOSDataSourceGetSharedEngine(source
->ds
, NULL
);
128 SOSManifestRef mf
= SOSEngineCopyManifest(engine
, NULL
);
129 struct SOSDigestVector empty
= SOSDigestVectorInit
;
130 ok(SOSEngineUpdateLocalManifest(engine
, kSOSDataSourceSOSTransaction
,
131 (struct SOSDigestVector
*)SOSManifestGetDigestVector(mf
), &empty
, NULL
),
132 "droped manifest from %@", source
);
140 }, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
, SOSMessageRef message
) {
142 }, CFSTR("Ann"), CFSTR("Ben"), NULL
);
145 static void add_sha1(void) {
147 //todo("this never stops syncing");
148 __block
int iteration
= 0;
149 __block CFErrorRef error
= NULL
;
150 SOSTestDeviceListTestSync("add_sha1", test_directive
, test_reason
, 0, true, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
) {
152 // Add 9 items in first 9 sync messages
153 if (iteration
<= 9) {
154 CFStringRef account
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("item%d"), iteration
);
155 SOSTestDeviceAddGenericItem(source
, account
, CFSTR("add_sha1"));
156 CFReleaseSafe(account
);
157 // Corrupt the manifest after 4th item added
158 if (iteration
== 4) {
159 ok(SecDbPerformWrite(source
->db
, &error
, ^(SecDbConnectionRef dbconn
) {
160 ok(SecDbTransaction(dbconn
, kSecDbExclusiveTransactionType
, &error
, ^(bool *commit
) {
161 ok(SecDbExec(dbconn
, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=5;"), &error
),
162 "Corrupting rowid 5 by zeroing sha1: %@", error
);
163 CFReleaseNull(error
);
164 }), "SecDbTransaction: %@", error
);
165 CFReleaseNull(error
);
166 }), "SecDbPerformWrite: %@", error
);
167 CFReleaseNull(error
);
169 SOSEngineRef engine
= SOSDataSourceGetSharedEngine(source
->ds
, NULL
);
170 struct SOSDigestVector del
= SOSDigestVectorInit
;
171 struct SOSDigestVector add
= SOSDigestVectorInit
;
172 uint8_t zeroDigest
[20] = {};
173 SOSDigestVectorAppend(&add
, zeroDigest
);
174 ok(SOSEngineUpdateLocalManifest(engine
, kSOSDataSourceSOSTransaction
,
175 &del
, &add
, NULL
), "corrupting manifest");
182 }, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
, SOSMessageRef message
) {
184 }, CFSTR("Andy"), CFSTR("Bill"), NULL
);
188 static void change_sha1(void) {
190 //todo("this never stops syncing");
191 __block
int iteration
= 0;
192 __block CFErrorRef error
= NULL
;
193 SOSTestDeviceListTestSync("change_sha1", test_directive
, test_reason
, 0, true, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
) {
195 // Add 9 items in first 9 sync messages
196 if (iteration
<= 9) {
197 CFStringRef account
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("item%d"), iteration
);
198 CFStringRef server
= CFSTR("change_sha1");
199 // Corrupt the manifest after 4th item added
200 if (!SOSDataSourceWithAPI(source
->ds
, true, &error
, ^(SOSTransactionRef txn
, bool *commit
) {
201 SOSObjectRef object
= SOSDataSourceCreateGenericItem(source
->ds
, account
, server
);
202 ok(SOSDataSourceMergeObject(source
->ds
, txn
, object
, NULL
, &error
), "%@ added API object %@", SOSTestDeviceGetID(source
), error
? (CFTypeRef
)error
: (CFTypeRef
)CFSTR("ok"));
203 if (iteration
== 3) {
204 sqlite_int64 rowid
= SecDbItemGetRowId((SecDbItemRef
)object
, NULL
);
205 CFStringRef sql
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("UPDATE genp SET sha1=X'0000000000000000000000000000000000000000' WHERE rowid=%lld;"), rowid
);
206 ok(SecDbExec((SecDbConnectionRef
)txn
, sql
, &error
),
207 "Corrupting rowid %lld by zeroing sha1: %@", rowid
, error
);
209 SOSEngineRef engine
= SOSDataSourceGetSharedEngine(source
->ds
, NULL
);
210 struct SOSDigestVector del
= SOSDigestVectorInit
;
211 struct SOSDigestVector add
= SOSDigestVectorInit
;
212 uint8_t zeroDigest
[20] = {};
213 SOSDigestVectorAppend(&add
, zeroDigest
);
214 CFDataRef digest
= SOSObjectCopyDigest(source
->ds
, object
, NULL
);
215 const uint8_t *d
= CFDataGetBytePtr(digest
);
216 SOSDigestVectorAppend(&del
, d
);
217 ok(SOSEngineUpdateLocalManifest(engine
, kSOSDataSourceSOSTransaction
,
218 &del
, &add
, NULL
), "corrupting manifest %lld %02X%02x%02x%02x",
219 rowid
, d
[0], d
[1], d
[2], d
[3]);
220 CFReleaseSafe(digest
);
222 CFReleaseSafe(object
);
223 CFReleaseNull(error
);
225 fail("ds transaction %@", error
);
226 CFReleaseNull(error
);
227 CFReleaseNull(account
);
231 }, ^bool(SOSTestDeviceRef source
, SOSTestDeviceRef dest
, SOSMessageRef message
) {
235 }, CFSTR("Alice"), CFSTR("Bob"), NULL
);
239 int secd_70_engine_corrupt(int argc
, char *const *argv
)
241 plan_tests(kTestTestCount
);
243 /* custom keychain dir */
244 secd_test_setup_temp_keychain("secd_70_engine_corrupt", NULL
);