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