]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.m
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountFullPeerInfo.m
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 #include <AssertMacros.h>
25
26 #include <stdio.h>
27 #include "SOSAccountPriv.h"
28 #include "SOSInternal.h"
29 #include "SOSViews.h"
30 #include "SOSPeerInfoV2.h"
31 #include "SOSPeerInfoPriv.h"
32 #import <Security/SecureObjectSync/SOSAccountPriv.h>
33 #import <Security/SecureObjectSync/SOSAccountTrust.h>
34 #import <Security/SecureObjectSync/SOSAccountTrustClassic.h>
35 #include <Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h>
36 #include <Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h>
37
38
39 static CFStringRef kicloud_identity_name = CFSTR("Cloud Identity");
40
41 SecKeyRef SOSAccountCopyDeviceKey(SOSAccount* account, CFErrorRef *error) {
42 SecKeyRef privateKey = NULL;
43 SOSFullPeerInfoRef identity = NULL;
44
45 SOSAccountTrustClassic *trust = account.trust;
46 identity = trust.fullPeerInfo;
47 require_action_quiet(identity, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No identity to get key from")));
48
49 privateKey = SOSFullPeerInfoCopyDeviceKey(identity, error);
50
51 fail:
52 return privateKey;
53 }
54
55 SOSFullPeerInfoRef CopyCloudKeychainIdentity(SOSPeerInfoRef cloudPeer, CFErrorRef *error) {
56 return SOSFullPeerInfoCreateCloudIdentity(NULL, cloudPeer, error);
57 }
58
59
60 static CF_RETURNS_RETAINED SecKeyRef GeneratePermanentFullECKey_internal(int keySize, CFStringRef name, CFTypeRef accessibility, CFBooleanRef sync, CFErrorRef* error)
61 {
62 SecKeyRef full_key = NULL;
63
64 CFNumberRef key_size_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
65
66 CFDictionaryRef priv_key_attrs = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
67 kSecAttrIsPermanent, kCFBooleanTrue,
68 NULL);
69
70 CFDictionaryRef keygen_parameters = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
71 kSecAttrKeyType, kSecAttrKeyTypeEC,
72 kSecAttrKeySizeInBits, key_size_num,
73 kSecPrivateKeyAttrs, priv_key_attrs,
74 kSecAttrAccessible, accessibility,
75 kSecAttrAccessGroup, kSOSInternalAccessGroup,
76 kSecAttrLabel, name,
77 kSecAttrSynchronizable, sync,
78 kSecUseTombstones, kCFBooleanTrue,
79 NULL);
80
81 CFReleaseNull(priv_key_attrs);
82
83 CFReleaseNull(key_size_num);
84 OSStatus status = SecKeyGeneratePair(keygen_parameters, NULL, &full_key);
85 CFReleaseNull(keygen_parameters);
86
87 if (status)
88 secerror("status: %ld", (long)status);
89 if (status != errSecSuccess && error != NULL && *error == NULL) {
90 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
91 }
92
93 return full_key;
94 }
95
96 CF_RETURNS_RETAINED SecKeyRef GeneratePermanentFullECKey(int keySize, CFStringRef name, CFErrorRef* error) {
97 return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kCFBooleanFalse, error);
98 }
99
100 static CF_RETURNS_RETAINED SecKeyRef GeneratePermanentFullECKeyForCloudIdentity(int keySize, CFStringRef name, CFErrorRef* error) {
101 return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlocked, kCFBooleanTrue, error);
102 }
103
104 bool SOSAccountHasCircle(SOSAccount* account, CFErrorRef* error) {
105 SOSAccountTrustClassic *trust = account.trust;
106 SOSCircleRef circle = trust.trustedCircle;
107
108 if (!circle)
109 SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No trusted circle"));
110
111 return circle != NULL;
112 }
113
114 bool SOSAccountHasFullPeerInfo(SOSAccount* account, CFErrorRef* error) {
115 bool hasPeer = false;
116 SOSAccountTrustClassic *trust = account.trust;
117 SOSFullPeerInfoRef identity = trust.fullPeerInfo;
118
119 require(SOSAccountHasCircle(account, error), fail);
120
121 hasPeer = identity != NULL;
122
123 if (!hasPeer)
124 SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("No peer for circle"));
125
126 fail:
127 return hasPeer;
128 }
129
130 bool SOSAccountIsAccountIdentity(SOSAccount* account, SOSPeerInfoRef peer_info, CFErrorRef *error)
131 {
132 SOSFullPeerInfoRef identity = NULL;
133
134 SOSAccountTrustClassic *trust = account.trust;
135 identity = trust.fullPeerInfo;
136 return CFEqualSafe(peer_info, SOSFullPeerInfoGetPeerInfo(identity));
137 }
138
139 bool SOSAccountFullPeerInfoVerify(SOSAccount* account, SecKeyRef privKey, CFErrorRef *error) {
140 SOSFullPeerInfoRef identity = NULL;
141
142 SOSAccountTrustClassic *trust = account.trust;
143 identity = trust.fullPeerInfo;
144 if(!identity) return false;
145 SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey);
146 bool retval = SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(identity), pubKey, error);
147 CFReleaseNull(pubKey);
148 return retval;
149 }
150
151 static bool UpdateKeyName(SecKeyRef key, SOSPeerInfoRef peer, CFErrorRef* error)
152 {
153 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
154 kSecClass, kSecClassKey,
155 kSecAttrSynchronizable,kCFBooleanTrue,
156 kSecUseTombstones, kCFBooleanTrue,
157 kSecValueRef, key,
158 NULL);
159
160 CFStringRef new_name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
161 CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(peer));
162
163 CFDictionaryRef change = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
164 kSecAttrLabel, new_name,
165 NULL);
166
167 bool result = SecError(SecItemUpdate(query, change), error, CFSTR("Couldn't update name"));
168
169 CFReleaseNull(new_name);
170 CFReleaseNull(query);
171 CFReleaseNull(change);
172 return result;
173 }
174
175 SOSPeerInfoRef GenerateNewCloudIdentityPeerInfo(CFErrorRef *error) {
176 SecKeyRef cloud_key = GeneratePermanentFullECKeyForCloudIdentity(256, kicloud_identity_name, error);
177 SOSPeerInfoRef cloud_peer = NULL;
178
179 CFDictionaryRef gestalt = NULL;
180
181 require_action_quiet(cloud_key, fail, SecError(errSecAllocate, error, CFSTR("Can't generate keypair for icloud identity")));
182
183 gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
184 kPIUserDefinedDeviceNameKey, CFSTR("iCloud"),
185 NULL);
186 require_action_quiet(gestalt, fail, SecError(errSecAllocate, error, CFSTR("Can't allocate gestalt")));
187
188 cloud_peer = SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault, gestalt, cloud_key, error);
189
190 require(cloud_peer, fail);
191
192 UpdateKeyName(cloud_key, cloud_peer, error);
193
194 fail:
195 CFReleaseNull(gestalt);
196 CFReleaseNull(cloud_key);
197
198 return cloud_peer;
199 }
200
201
202 bool SOSAccountUpdatePeerInfo(SOSAccount* account, CFStringRef updateDescription, CFErrorRef *error, bool (^update)(SOSFullPeerInfoRef fpi, CFErrorRef *error)) {
203
204 if (!account.hasPeerInfo)
205 return true;
206
207 bool result = update(account.fullPeerInfo, error);
208
209 if (result && SOSAccountHasCircle(account, NULL)) {
210 return [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle_to_change) {
211 secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for %@", updateDescription);
212 return SOSCircleUpdatePeerInfo(circle_to_change, account.peerInfo);
213 }];
214 }
215
216 return result;
217 }
218
219
220 bool SOSAccountUpdatePeerInfoAndPush(SOSAccount* account, CFStringRef updateDescription, CFErrorRef *error,
221 bool (^update)(SOSPeerInfoRef pi, CFErrorRef *error)) {
222 return SOSAccountUpdatePeerInfo(account, updateDescription, error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *localError) {
223 return SOSFullPeerInfoUpdate(fpi, localError, ^SOSPeerInfoRef(SOSPeerInfoRef pi, SecKeyRef peerPriv, CFErrorRef *localError) {
224 SOSPeerInfoRef newPI = SOSPeerInfoCreateCopy(kCFAllocatorDefault, pi, localError);
225 if(update(newPI, error)) {
226 if(peerPriv && SOSPeerInfoSign(peerPriv, newPI, localError)) {
227 secnotice("circleOp", "Signed Peerinfo to update");
228 return newPI;
229 }
230 }
231 secnotice("circleOp", "Failed updating PeerInfo");
232 CFReleaseNull(newPI);
233 return NULL;
234 });
235 });
236 }