]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ProjectHeaders/Security/SecureObjectSync/SOSAccountFullPeerInfo.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / ProjectHeaders / Security / 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
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 defaultViews = SOSViewsCreateDefault(false, NULL);
103
104 CFReleaseNull(account->my_identity);
105 account->my_identity = SOSFullPeerInfoCreateWithViews(kCFAllocatorDefault, account->gestalt, account->backup_key, defaultViews,
106 full_key, error);
107 CFReleaseNull(defaultViews);
108 CFReleaseNull(full_key);
109
110 if (!account->my_identity) {
111 secerror("Can't make FullPeerInfo for %@-%@ (%@) - is AKS ok?", SOSPeerGestaltGetName(account->gestalt), SOSCircleGetName(account->trusted_circle), error ? (void*)*error : (void*)CFSTR("-"));
112 }
113 }
114 else {
115 secerror("No full_key: %@:", error ? *error : NULL);
116
117 }
118 }
119
120 fail:
121 return account->my_identity != NULL;
122 }
123
124 bool SOSAccountHasCircle(SOSAccountRef account, CFErrorRef* error) {
125 if (!account->trusted_circle)
126 SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No trusted circle"));
127
128 return account->trusted_circle != NULL;
129 }
130
131 bool SOSAccountHasFullPeerInfo(SOSAccountRef account, CFErrorRef* error) {
132 bool hasPeer = false;
133
134 require(SOSAccountHasCircle(account, error), fail);
135
136 hasPeer = account->my_identity != NULL;
137
138 if (!hasPeer)
139 SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("No peer for circle"));
140
141 fail:
142 return hasPeer;
143 }
144
145 bool SOSAccountIsAccountIdentity(SOSAccountRef account, SOSPeerInfoRef peer_info, CFErrorRef *error)
146 {
147 return CFEqualSafe(peer_info, SOSFullPeerInfoGetPeerInfo(account->my_identity));
148 }
149
150 SOSPeerInfoRef SOSAccountGetMyPeerInfo(SOSAccountRef account) {
151 return SOSFullPeerInfoGetPeerInfo(SOSAccountGetMyFullPeerInfo(account));
152 }
153
154
155 SOSFullPeerInfoRef SOSAccountGetMyFullPeerInfo(SOSAccountRef account) {
156 return account->trusted_circle ? account->my_identity : NULL;
157 }
158
159 SOSPeerInfoRef GenerateNewCloudIdentityPeerInfo(CFErrorRef *error) {
160 SecKeyRef cloud_key = GeneratePermanentFullECKeyForCloudIdentity(256, kicloud_identity_name, error);
161 SOSPeerInfoRef cloud_peer = NULL;
162 CFDictionaryRef query = NULL;
163 CFDictionaryRef change = NULL;
164 CFStringRef new_name = NULL;
165
166 CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
167 kPIUserDefinedDeviceNameKey, CFSTR("iCloud"),
168 NULL);
169 require_action_quiet(gestalt, fail, SecError(errSecAllocate, error, CFSTR("Can't allocate gestalt")));
170
171 cloud_peer = SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault, gestalt, cloud_key, error);
172
173 require(cloud_peer, fail);
174
175 query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
176 kSecClass, kSecClassKey,
177 kSecAttrSynchronizable,kCFBooleanTrue,
178 kSecUseTombstones, kCFBooleanTrue,
179 kSecValueRef, cloud_key,
180 NULL);
181
182 new_name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
183 CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(cloud_peer));
184
185 change = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
186 kSecAttrLabel, new_name,
187 NULL);
188
189 SecError(SecItemUpdate(query, change), error, CFSTR("Couldn't update name"));
190
191 fail:
192 CFReleaseNull(new_name);
193 CFReleaseNull(query);
194 CFReleaseNull(change);
195 CFReleaseNull(gestalt);
196 CFReleaseNull(cloud_key);
197
198 return cloud_peer;
199 }