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 save and restore of SOSEngine states
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/SOSEngine.h"
33 #include "keychain/SecureObjectSync/SOSPeer.h"
34 #include <Security/SecBase64.h>
35 #include <Security/SecItem.h>
36 #include <Security/SecItemPriv.h>
37 #include <corecrypto/ccsha2.h>
38 #include "keychain/securityd/SecItemServer.h"
39 #include "keychain/securityd/SecItemDataSource.h"
40 #include <utilities/SecCFWrappers.h>
41 #include <utilities/SecIOFormat.h>
42 #include <utilities/SecFileLocations.h>
44 #include <AssertMacros.h>
47 static int kTestTestCount = 8;
50 Attributes for a v0 engine-state genp item
52 MANGO-iPhone:~ mobile$ security item class=genp,acct=engine-state
54 agrp : com.apple.security.sos
55 cdat : 2016-04-18 20:40:33 +0000
56 mdat : 2016-04-18 20:40:33 +0000
59 svce : SOSDataSource-ak
64 #include "secd-71-engine-save-sample1.h"
66 static bool verifyV2EngineState(SOSDataSourceRef ds, CFStringRef myPeerID) {
68 CFErrorRef error = NULL;
69 SOSTransactionRef txn = NULL;
70 CFDataRef basicEngineState = NULL;
71 CFDictionaryRef engineState = NULL;
74 CFDataRef basicEngineState = SOSDataSourceCopyStateWithKey(ds, kSOSEngineStatev2, kSecAttrAccessibleAlwaysPrivate, txn, &error);
75 skip("Failed to get V2 engine state", 2, basicEngineState);
76 ok(basicEngineState, "SOSDataSourceCopyStateWithKey:kSOSEngineStatev2");
77 engineState = derStateToDictionaryCopy(basicEngineState, &error);
78 skip("Failed to DER decode V2 engine state", 1, basicEngineState);
79 CFStringRef engID = (CFStringRef)asString(CFDictionaryGetValue(engineState, CFSTR("id")), &error);
80 ok(CFEqualSafe(myPeerID, engID),"Check myPeerID");
84 CFReleaseSafe(basicEngineState);
85 CFReleaseSafe(engineState);
90 static bool verifyV2PeerStates(SOSDataSourceRef ds, CFStringRef myPeerID, CFArrayRef peers) {
92 __block CFErrorRef error = NULL;
93 SOSTransactionRef txn = NULL;
94 CFDictionaryRef peerStateDict = NULL;
95 CFDataRef data = NULL;
96 __block CFIndex peerCount = CFArrayGetCount(peers) - 1; // drop myPeerID
99 data = SOSDataSourceCopyStateWithKey(ds, kSOSEnginePeerStates, kSOSEngineProtectionDomainClassD, txn, &error);
100 skip("Failed to get V2 peerStates", 3, data);
102 peerStateDict = derStateToDictionaryCopy(data, &error);
103 skip("Failed to DER decode V2 peerStates", 2, peerStateDict);
104 ok(peerStateDict, "SOSDataSourceCopyStateWithKey:kSOSEnginePeerStates");
106 // Check that each peer passed in exists in peerStateDict
107 CFArrayForEach(peers, ^(const void *key) {
108 CFStringRef peerID = (CFStringRef)asString(key, &error);
109 if (!CFEqualSafe(myPeerID, peerID)) {
110 if (CFDictionaryContainsKey(peerStateDict, peerID))
114 ok(peerCount==0,"Peers exist in peer list (%ld)", (CFArrayGetCount(peers) - 1 - peerCount));
118 CFReleaseSafe(peerStateDict);
120 CFReleaseSafe(error);
124 static bool checkV2EngineStates(SOSTestDeviceRef td, CFStringRef myPeerID, CFArrayRef peers) {
126 CFErrorRef error = NULL;
127 SOSTransactionRef txn = NULL;
128 CFDictionaryRef manifestCache = NULL;
129 CFDataRef data = NULL;
130 // CFMutableDictionaryRef codersDict = NULL; // SOSEngineLoadCoders
132 rx &= verifyV2EngineState(td->ds, myPeerID);
134 data = SOSDataSourceCopyStateWithKey(td->ds, kSOSEngineManifestCache, kSOSEngineProtectionDomainClassD, txn, &error);
135 manifestCache = derStateToDictionaryCopy(data, &error);
138 rx &= verifyV2PeerStates(td->ds, myPeerID, peers);
140 CFReleaseSafe(manifestCache);
144 static void testSaveRestore(void) {
145 CFMutableArrayRef deviceIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
146 CFArrayAppendValue(deviceIDs, CFSTR("lemon"));
147 CFArrayAppendValue(deviceIDs, CFSTR("lime"));
148 CFArrayAppendValue(deviceIDs, CFSTR("orange"));
151 CFErrorRef error = NULL;
152 __block int devIdx = 0;
153 CFMutableDictionaryRef testDevices = SOSTestDeviceListCreate(false, version, deviceIDs, ^(SOSDataSourceRef ds) {
154 // This block is called before SOSEngineLoad
156 // Test migration of v0 to v2 engine state
157 CFDataRef engineStateData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, es_mango_bin, es_mango_bin_len, kCFAllocatorNull);
158 SOSTestDeviceAddV0EngineStateWithData(ds, engineStateData);
159 CFReleaseSafe(engineStateData);
164 CFStringRef sourceID = (CFStringRef)CFArrayGetValueAtIndex(deviceIDs, 0);
165 SOSTestDeviceRef source = (SOSTestDeviceRef)CFDictionaryGetValue(testDevices, sourceID);
167 ok(SOSTestDeviceEngineSave(source, &error),"SOSTestDeviceEngineSave: %@",error);
169 bx = SOSTestDeviceEngineLoad(source, &error);
170 ok(bx,"SOSTestEngineLoad: %@",error);
172 bx = checkV2EngineStates(source, sourceID, deviceIDs);
173 ok(bx,"getV2EngineStates: %@",error);
175 bx = SOSTestDeviceEngineSave(source, &error);
176 ok(bx,"SOSTestDeviceEngineSave v2: %@",error);
178 SOSTestDeviceDestroyEngine(testDevices);
179 CFReleaseSafe(deviceIDs);
180 CFReleaseSafe(testDevices);
181 CFReleaseSafe(error);
184 int secd_71_engine_save(int argc, char *const *argv)
186 plan_tests(kTestTestCount);