1/* 2 * Copyright (c) 2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// Test syncing between SecItemDataSource and SOSTestDataSource 26 27#include <Regressions/SOSTestDevice.h> 28#include <Regressions/SOSTestDataSource.h> 29#include "secd_regressions.h" 30#include "SecdTestKeychainUtilities.h" 31 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> 44 45#include <AssertMacros.h> 46#include <stdint.h> 47 48static int kTestTestCount = 125; 49 50static 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) { 54 iteration++; 55 // Add 10 items in first 10 sync messages 56 if (iteration <= 6) { 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 61 if (iteration == 4) { 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); 66 CFReleaseNull(error); 67 }), "SecDbTransaction: %@", error); 68 CFReleaseNull(error); 69 }), "SecDbPerformWrite: %@", error); 70 CFReleaseNull(error); 71 return true; 72 } 73 return true; 74 } 75 76 77 return false; 78 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { 79 return false; 80 }, CFSTR("Bad"), CFSTR("Good"), NULL); 81} 82 83static 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) { 87 iteration++; 88 // Add 10 items in first 10 sync messages 89 if (iteration <= 6) { 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 94 if (iteration == 4) { 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); 99 CFReleaseNull(error); 100 }), "SecDbTransaction: %@", error); 101 CFReleaseNull(error); 102 }), "SecDbPerformWrite: %@", error); 103 CFReleaseNull(error); 104 return true; 105 } 106 return true; 107 } 108 109 110 return false; 111 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { 112 return false; 113 }, CFSTR("Abegail"), CFSTR("Billy"), NULL); 114} 115 116static void drop_manifest(void) { 117 __block int iteration = 0; 118 SOSTestDeviceListTestSync("drop_manifest", test_directive, test_reason, 0, true, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) { 119 iteration++; 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); 133 CFReleaseNull(mf); 134 return true; 135 } 136 return true; 137 } 138 139 return false; 140 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { 141 return false; 142 }, CFSTR("Ann"), CFSTR("Ben"), NULL); 143} 144 145static void add_sha1(void) { 146 TODO: { 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) { 151 iteration++; 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); 168 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"); 176 return true; 177 } 178 return true; 179 } 180 181 return false; 182 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { 183 return false; 184 }, CFSTR("Andy"), CFSTR("Bill"), NULL); 185 } 186} 187 188static void change_sha1(void) { 189TODO: { 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) { 194 iteration++; 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); 208 CFReleaseNull(sql); 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); 221 } 222 CFReleaseSafe(object); 223 CFReleaseNull(error); 224 })) 225 fail("ds transaction %@", error); 226 CFReleaseNull(error); 227 CFReleaseNull(account); 228 return true; 229 } 230 return false; 231 }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) { 232 if (iteration >= 3) 233 pass("%@", source); 234 return false; 235 }, CFSTR("Alice"), CFSTR("Bob"), NULL); 236} 237} 238 239int secd_70_engine_corrupt(int argc, char *const *argv) 240{ 241 plan_tests(kTestTestCount); 242 243 /* custom keychain dir */ 244 secd_test_setup_temp_keychain("secd_70_engine_corrupt", NULL); 245 246 nosha1(); 247 drop_item(); 248 drop_manifest(); 249 add_sha1(); 250 change_sha1(); 251 252 return 0; 253} 254