2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include "SOSAccountPriv.h"
28 static CFStringRef kicloud_identity_name
= CFSTR("Cloud Identity");
31 SOSFullPeerInfoRef
CopyCloudKeychainIdentity(SOSPeerInfoRef cloudPeer
, CFErrorRef
*error
) {
32 return SOSFullPeerInfoCreateCloudIdentity(NULL
, cloudPeer
, error
);
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
);
42 return (SOSFullPeerInfoRef
) CFDictionaryGetValue(account
->circle_identities
, name
);
47 static SecKeyRef
GeneratePermanentFullECKey_internal(int keySize
, CFStringRef name
, CFTypeRef accessibility
, CFBooleanRef sync
, CFErrorRef
* error
)
49 SecKeyRef full_key
= NULL
;
51 CFNumberRef key_size_num
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &keySize
);
53 CFDictionaryRef priv_key_attrs
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
54 kSecAttrIsPermanent
, kCFBooleanTrue
,
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
,
64 kSecAttrSynchronizable
, sync
,
65 kSecUseTombstones
, kCFBooleanTrue
,
68 CFReleaseNull(priv_key_attrs
);
70 CFReleaseNull(key_size_num
);
71 OSStatus status
= SecKeyGeneratePair(keygen_parameters
, NULL
, &full_key
);
72 CFReleaseNull(keygen_parameters
);
75 secerror("status: %ld", (long)status
);
76 if (status
!= errSecSuccess
&& error
!= NULL
&& *error
== NULL
) {
77 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, status
, NULL
);
83 static SecKeyRef
GeneratePermanentFullECKey(int keySize
, CFStringRef name
, CFErrorRef
* error
) {
84 return GeneratePermanentFullECKey_internal(keySize
, name
, kSecAttrAccessibleWhenUnlockedThisDeviceOnly
, kCFBooleanFalse
, error
);
87 static SecKeyRef
GeneratePermanentFullECKeyForCloudIdentity(int keySize
, CFStringRef name
, CFErrorRef
* error
) {
88 return GeneratePermanentFullECKey_internal(keySize
, name
, kSecAttrAccessibleWhenUnlocked
, kCFBooleanTrue
, error
);
92 bool SOSAccountIsAccountIdentity(SOSAccountRef account
, SOSPeerInfoRef peer_info
, CFErrorRef
*error
)
94 __block
bool matches
= false;
95 CFDictionaryForEach(account
->circle_identities
, ^(const void *key
, const void *value
) {
97 matches
= CFEqual(peer_info
, SOSFullPeerInfoGetPeerInfo((SOSFullPeerInfoRef
) value
));
106 SOSFullPeerInfoRef
SOSAccountMakeMyFullPeerInCircleNamed(SOSAccountRef account
, CFStringRef name
, CFErrorRef
*error
) {
107 if (CFDictionaryGetValue(account
->circles
, name
) == NULL
) {
108 SOSCreateErrorWithFormat(kSOSErrorNoCircle
, NULL
, error
, NULL
, CFSTR("No circle named '%@'"), name
);
111 SOSFullPeerInfoRef circle_full_peer_info
= (SOSFullPeerInfoRef
) CFDictionaryGetValue(account
->circle_identities
, name
);
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
);
120 circle_full_peer_info
= SOSFullPeerInfoCreate(kCFAllocatorDefault
, account
->gestalt
, full_key
, error
);
122 CFReleaseNull(full_key
);
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
;
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
);
134 secerror("No full_key: %@:", error
? *error
: NULL
);
137 return circle_full_peer_info
;
141 SOSFullPeerInfoRef
SOSAccountGetMyFullPeerInCircle(SOSAccountRef account
, SOSCircleRef circle
, CFErrorRef
* error
) {
142 return SOSAccountGetMyFullPeerInCircleNamedIfPresent(account
, SOSCircleGetName(circle
), error
);
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
;
153 CFDictionaryRef gestalt
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
154 kPIUserDefinedDeviceName
, CFSTR("iCloud"),
156 require_action_quiet(gestalt
, fail
, SecError(errSecAllocate
, error
, CFSTR("Can't allocate gestalt")));
158 cloud_peer
= SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault
, gestalt
, cloud_key
, error
);
160 require(cloud_peer
, fail
);
162 query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
163 kSecClass
, kSecClassKey
,
164 kSecAttrSynchronizable
,kCFBooleanTrue
,
165 kSecUseTombstones
, kCFBooleanTrue
,
166 kSecValueRef
, cloud_key
,
169 new_name
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
170 CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(cloud_peer
));
172 change
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
173 kSecAttrLabel
, new_name
,
176 SecError(SecItemUpdate(query
, change
), error
, CFSTR("Couldn't update name"));
179 CFReleaseNull(new_name
);
180 CFReleaseNull(query
);
181 CFReleaseNull(change
);
182 CFReleaseNull(gestalt
);
183 CFReleaseNull(cloud_key
);