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