]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / 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
28 static CFStringRef kicloud_identity_name = CFSTR("Cloud Identity");
29
30
31 SOSFullPeerInfoRef CopyCloudKeychainIdentity(SOSPeerInfoRef cloudPeer, CFErrorRef *error) {
32 return SOSFullPeerInfoCreateCloudIdentity(NULL, cloudPeer, error);
33 }
34
35
36 SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircleNamedIfPresent(SOSAccountRef account, CFStringRef name, CFErrorRef *error) {
37 if (CFDictionaryGetValue(account->circles, name) == NULL) {
38 SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No circle named '%@'"), name);
39 return NULL;
40 }
41
42 return (SOSFullPeerInfoRef) CFDictionaryGetValue(account->circle_identities, name);
43 }
44
45
46
47 static SecKeyRef GeneratePermanentFullECKey_internal(int keySize, CFStringRef name, CFTypeRef accessibility, CFBooleanRef sync, CFErrorRef* error)
48 {
49 SecKeyRef full_key = NULL;
50
51 CFNumberRef key_size_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
52
53 CFDictionaryRef priv_key_attrs = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
54 kSecAttrIsPermanent, kCFBooleanTrue,
55 NULL);
56
57 CFDictionaryRef keygen_parameters = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
58 kSecAttrKeyType, kSecAttrKeyTypeEC,
59 kSecAttrKeySizeInBits, key_size_num,
60 kSecPrivateKeyAttrs, priv_key_attrs,
61 kSecAttrAccessible, accessibility,
62 kSecAttrAccessGroup, kSOSInternalAccessGroup,
63 kSecAttrLabel, name,
64 kSecAttrSynchronizable, sync,
65 kSecUseTombstones, kCFBooleanTrue,
66 NULL);
67
68 CFReleaseNull(priv_key_attrs);
69
70 CFReleaseNull(key_size_num);
71 OSStatus status = SecKeyGeneratePair(keygen_parameters, NULL, &full_key);
72 CFReleaseNull(keygen_parameters);
73
74 if (status)
75 secerror("status: %ld", (long)status);
76 if (status != errSecSuccess && error != NULL && *error == NULL) {
77 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
78 }
79
80 return full_key;
81 }
82
83 static SecKeyRef GeneratePermanentFullECKey(int keySize, CFStringRef name, CFErrorRef* error) {
84 return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kCFBooleanFalse, error);
85 }
86
87 static SecKeyRef GeneratePermanentFullECKeyForCloudIdentity(int keySize, CFStringRef name, CFErrorRef* error) {
88 return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlocked, kCFBooleanTrue, error);
89 }
90
91
92 bool SOSAccountIsAccountIdentity(SOSAccountRef account, SOSPeerInfoRef peer_info, CFErrorRef *error)
93 {
94 __block bool matches = false;
95 CFDictionaryForEach(account->circle_identities, ^(const void *key, const void *value) {
96 if (!matches) {
97 matches = CFEqual(peer_info, SOSFullPeerInfoGetPeerInfo((SOSFullPeerInfoRef) value));
98 }
99 });
100
101 return matches;
102 }
103
104
105
106 SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error) {
107 if (CFDictionaryGetValue(account->circles, name) == NULL) {
108 SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No circle named '%@'"), name);
109 return NULL;
110 }
111 SOSFullPeerInfoRef circle_full_peer_info = (SOSFullPeerInfoRef) CFDictionaryGetValue(account->circle_identities, name);
112
113
114 if (circle_full_peer_info == NULL) {
115 CFStringRef keyName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("ID for %@-%@"), SOSPeerGestaltGetName(account->gestalt), name);
116 SecKeyRef full_key = GeneratePermanentFullECKey(256, keyName, error);
117 CFReleaseNull(keyName);
118
119 if (full_key) {
120 circle_full_peer_info = SOSFullPeerInfoCreate(kCFAllocatorDefault, account->gestalt, full_key, error);
121
122 CFReleaseNull(full_key);
123
124 if (!circle_full_peer_info) {
125 secerror("Can't make FullPeerInfo for %@-%@ (%@) - is AKS ok?", SOSPeerGestaltGetName(account->gestalt), name, error ? (void*)*error : (void*)CFSTR("-"));
126 return circle_full_peer_info;
127 }
128
129 CFDictionarySetValue(account->circle_identities, name, circle_full_peer_info);
130 CFReleaseNull(circle_full_peer_info);
131 circle_full_peer_info = (SOSFullPeerInfoRef) CFDictionaryGetValue(account->circle_identities, name);
132 }
133 else
134 secerror("No full_key: %@:", error ? *error : NULL);
135 }
136
137 return circle_full_peer_info;
138 }
139
140
141 SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef* error) {
142 return SOSAccountGetMyFullPeerInCircleNamed(account, SOSCircleGetName(circle), error);
143 }
144
145
146 SOSPeerInfoRef GenerateNewCloudIdentityPeerInfo(CFErrorRef *error) {
147 SecKeyRef cloud_key = GeneratePermanentFullECKeyForCloudIdentity(256, kicloud_identity_name, error);
148 SOSPeerInfoRef cloud_peer = NULL;
149 CFDictionaryRef query = NULL;
150 CFDictionaryRef change = NULL;
151 CFStringRef new_name = NULL;
152
153 CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
154 kPIUserDefinedDeviceName, CFSTR("iCloud"),
155 NULL);
156 require_action_quiet(gestalt, fail, SecError(errSecAllocate, error, CFSTR("Can't allocate gestalt")));
157
158 cloud_peer = SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault, gestalt, cloud_key, error);
159
160 require(cloud_peer, fail);
161
162 query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
163 kSecClass, kSecClassKey,
164 kSecAttrSynchronizable,kCFBooleanTrue,
165 kSecUseTombstones, kCFBooleanTrue,
166 kSecValueRef, cloud_key,
167 NULL);
168
169 new_name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
170 CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(cloud_peer));
171
172 change = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
173 kSecAttrLabel, new_name,
174 NULL);
175
176 SecError(SecItemUpdate(query, change), error, CFSTR("Couldn't update name"));
177
178 fail:
179 CFReleaseNull(new_name);
180 CFReleaseNull(query);
181 CFReleaseNull(change);
182 CFReleaseNull(gestalt);
183 CFReleaseNull(cloud_key);
184
185 return cloud_peer;
186 }