]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.c
ee42fe36d02f820764e7b388627201d2f7120293
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountFullPeerInfo.c
1 /*
2 * Copyright (c) 2013-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 #include <stdio.h>
26 #include "SOSAccountPriv.h"
27 #include "SOSInternal.h"
28 #include "SOSViews.h"
29 #include "SOSPeerInfoV2.h"
30
31 static CFStringRef kicloud_identity_name = CFSTR("Cloud Identity");
32
33 SecKeyRef SOSAccountCopyDeviceKey(SOSAccountRef account, CFErrorRef *error) {
34 SecKeyRef privateKey = NULL;
35
36 require_action_quiet(account->my_identity, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No identity to get key from")));
37
38 privateKey = SOSFullPeerInfoCopyDeviceKey(account->my_identity, error);
39
40 fail:
41 return privateKey;
42 }
43
44 SOSFullPeerInfoRef CopyCloudKeychainIdentity(SOSPeerInfoRef cloudPeer, CFErrorRef *error) {
45 return SOSFullPeerInfoCreateCloudIdentity(NULL, cloudPeer, error);
46 }
47
48
49 static SecKeyRef GeneratePermanentFullECKey_internal(int keySize, CFStringRef name, CFTypeRef accessibility, CFBooleanRef sync, CFErrorRef* error)
50 {
51 SecKeyRef full_key = NULL;
52
53 CFNumberRef key_size_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
54
55 CFDictionaryRef priv_key_attrs = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
56 kSecAttrIsPermanent, kCFBooleanTrue,
57 NULL);
58
59 CFDictionaryRef keygen_parameters = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
60 kSecAttrKeyType, kSecAttrKeyTypeEC,
61 kSecAttrKeySizeInBits, key_size_num,
62 kSecPrivateKeyAttrs, priv_key_attrs,
63 kSecAttrAccessible, accessibility,
64 kSecAttrAccessGroup, kSOSInternalAccessGroup,
65 kSecAttrLabel, name,
66 kSecAttrSynchronizable, sync,
67 kSecUseTombstones, kCFBooleanTrue,
68 NULL);
69
70 CFReleaseNull(priv_key_attrs);
71
72 CFReleaseNull(key_size_num);
73 OSStatus status = SecKeyGeneratePair(keygen_parameters, NULL, &full_key);
74 CFReleaseNull(keygen_parameters);
75
76 if (status)
77 secerror("status: %ld", (long)status);
78 if (status != errSecSuccess && error != NULL && *error == NULL) {
79 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
80 }
81
82 return full_key;
83 }
84
85 SecKeyRef GeneratePermanentFullECKey(int keySize, CFStringRef name, CFErrorRef* error) {
86 return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kCFBooleanFalse, error);
87 }
88
89 static SecKeyRef GeneratePermanentFullECKeyForCloudIdentity(int keySize, CFStringRef name, CFErrorRef* error) {
90 return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlocked, kCFBooleanTrue, error);
91 }
92
93 bool SOSAccountEnsureFullPeerAvailable(SOSAccountRef account, CFErrorRef * error) {
94 require_action_quiet(account->trusted_circle, fail, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("Don't have circle")));
95
96 if (account->my_identity == NULL) {
97 CFStringRef keyName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("ID for %@-%@"), SOSPeerGestaltGetName(account->gestalt), SOSCircleGetName(account->trusted_circle));
98 SecKeyRef full_key = GeneratePermanentFullECKey(256, keyName, error);
99 CFReleaseNull(keyName);
100
101 if (full_key) {
102 CFSetRef initialViews = SOSViewCopyViewSet(kViewSetInitial);
103
104 CFReleaseNull(account->my_identity);
105 account->my_identity = SOSFullPeerInfoCreateWithViews(kCFAllocatorDefault, account->gestalt, account->backup_key, initialViews,
106 full_key, error);
107 CFDictionaryRef v2dictionaryTestUpdates = SOSAccountGetValue(account, kSOSTestV2Settings, NULL);
108 if(v2dictionaryTestUpdates) SOSFullPeerInfoUpdateV2Dictionary(account->my_identity, v2dictionaryTestUpdates, NULL);
109 CFReleaseNull(initialViews);
110 CFReleaseNull(full_key);
111
112 CFSetRef pendingDefaultViews = SOSViewCopyViewSet(kViewSetDefault);
113 SOSAccountPendEnableViewSet(account, pendingDefaultViews);
114 CFReleaseNull(pendingDefaultViews);
115
116 SOSAccountSetValue(account, kSOSUnsyncedViewsKey, kCFBooleanTrue, NULL);
117
118 if (!account->my_identity) {
119 secerror("Can't make FullPeerInfo for %@-%@ (%@) - is AKS ok?", SOSPeerGestaltGetName(account->gestalt), SOSCircleGetName(account->trusted_circle), error ? (void*)*error : (void*)CFSTR("-"));
120 }
121 else{
122 secnotice("fpi", "alert KeychainSyncingOverIDSProxy the fpi is available");
123 notify_post(kSecServerPeerInfoAvailable);
124 if(account->deviceID)
125 SOSFullPeerInfoUpdateDeviceID(account->my_identity, account->deviceID, error);
126 }
127 }
128 else {
129 secerror("No full_key: %@:", error ? *error : NULL);
130
131 }
132 }
133
134 fail:
135 return account->my_identity != NULL;
136 }
137
138 bool SOSAccountHasCircle(SOSAccountRef account, CFErrorRef* error) {
139 if (!account->trusted_circle)
140 SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No trusted circle"));
141
142 return account->trusted_circle != NULL;
143 }
144
145 bool SOSAccountHasFullPeerInfo(SOSAccountRef account, CFErrorRef* error) {
146 bool hasPeer = false;
147
148 require(SOSAccountHasCircle(account, error), fail);
149
150 hasPeer = account->my_identity != NULL;
151
152 if (!hasPeer)
153 SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("No peer for circle"));
154
155 fail:
156 return hasPeer;
157 }
158
159 bool SOSAccountIsAccountIdentity(SOSAccountRef account, SOSPeerInfoRef peer_info, CFErrorRef *error)
160 {
161 return CFEqualSafe(peer_info, SOSFullPeerInfoGetPeerInfo(account->my_identity));
162 }
163
164 SOSPeerInfoRef SOSAccountGetMyPeerInfo(SOSAccountRef account) {
165 return SOSFullPeerInfoGetPeerInfo(SOSAccountGetMyFullPeerInfo(account));
166 }
167
168 CFStringRef SOSAccountGetMyPeerID(SOSAccountRef a) {
169 return SOSPeerInfoGetPeerID(SOSAccountGetMyPeerInfo(a));
170 }
171
172 SOSFullPeerInfoRef SOSAccountGetMyFullPeerInfo(SOSAccountRef account) {
173 return account->trusted_circle ? account->my_identity : NULL;
174 }
175
176 bool SOSAccountFullPeerInfoVerify(SOSAccountRef account, SecKeyRef privKey, CFErrorRef *error) {
177 if(!account->my_identity) return false;
178 SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey);
179 bool retval = SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(account->my_identity), pubKey, error);
180 CFReleaseNull(pubKey);
181 return retval;
182 }
183
184 SOSPeerInfoRef GenerateNewCloudIdentityPeerInfo(CFErrorRef *error) {
185 SecKeyRef cloud_key = GeneratePermanentFullECKeyForCloudIdentity(256, kicloud_identity_name, error);
186 SOSPeerInfoRef cloud_peer = NULL;
187 CFDictionaryRef query = NULL;
188 CFDictionaryRef change = NULL;
189 CFStringRef new_name = NULL;
190
191 CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
192 kPIUserDefinedDeviceNameKey, CFSTR("iCloud"),
193 NULL);
194 require_action_quiet(gestalt, fail, SecError(errSecAllocate, error, CFSTR("Can't allocate gestalt")));
195
196 cloud_peer = SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault, gestalt, cloud_key, error);
197
198 require(cloud_peer, fail);
199
200 query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
201 kSecClass, kSecClassKey,
202 kSecAttrSynchronizable,kCFBooleanTrue,
203 kSecUseTombstones, kCFBooleanTrue,
204 kSecValueRef, cloud_key,
205 NULL);
206
207 new_name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
208 CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(cloud_peer));
209
210 change = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
211 kSecAttrLabel, new_name,
212 NULL);
213
214 SecError(SecItemUpdate(query, change), error, CFSTR("Couldn't update name"));
215
216 fail:
217 CFReleaseNull(new_name);
218 CFReleaseNull(query);
219 CFReleaseNull(change);
220 CFReleaseNull(gestalt);
221 CFReleaseNull(cloud_key);
222
223 return cloud_peer;
224 }