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"
27 #include "SOSInternal.h"
30 static CFStringRef kicloud_identity_name
= CFSTR("Cloud Identity");
33 SecKeyRef
SOSAccountCopyDeviceKey(SOSAccountRef account
, CFErrorRef
*error
) {
34 SecKeyRef privateKey
= NULL
;
36 require_action_quiet(account
->my_identity
, fail
, SOSErrorCreate(kSOSErrorPeerNotFound
, error
, NULL
, CFSTR("No identity to get key from")));
38 privateKey
= SOSFullPeerInfoCopyDeviceKey(account
->my_identity
, error
);
44 SOSFullPeerInfoRef
CopyCloudKeychainIdentity(SOSPeerInfoRef cloudPeer
, CFErrorRef
*error
) {
45 return SOSFullPeerInfoCreateCloudIdentity(NULL
, cloudPeer
, error
);
49 static SecKeyRef
GeneratePermanentFullECKey_internal(int keySize
, CFStringRef name
, CFTypeRef accessibility
, CFBooleanRef sync
, CFErrorRef
* error
)
51 SecKeyRef full_key
= NULL
;
53 CFNumberRef key_size_num
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &keySize
);
55 CFDictionaryRef priv_key_attrs
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
56 kSecAttrIsPermanent
, kCFBooleanTrue
,
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
,
66 kSecAttrSynchronizable
, sync
,
67 kSecUseTombstones
, kCFBooleanTrue
,
70 CFReleaseNull(priv_key_attrs
);
72 CFReleaseNull(key_size_num
);
73 OSStatus status
= SecKeyGeneratePair(keygen_parameters
, NULL
, &full_key
);
74 CFReleaseNull(keygen_parameters
);
77 secerror("status: %ld", (long)status
);
78 if (status
!= errSecSuccess
&& error
!= NULL
&& *error
== NULL
) {
79 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, status
, NULL
);
85 SecKeyRef
GeneratePermanentFullECKey(int keySize
, CFStringRef name
, CFErrorRef
* error
) {
86 return GeneratePermanentFullECKey_internal(keySize
, name
, kSecAttrAccessibleWhenUnlockedThisDeviceOnly
, kCFBooleanFalse
, error
);
89 static SecKeyRef
GeneratePermanentFullECKeyForCloudIdentity(int keySize
, CFStringRef name
, CFErrorRef
* error
) {
90 return GeneratePermanentFullECKey_internal(keySize
, name
, kSecAttrAccessibleWhenUnlocked
, kCFBooleanTrue
, error
);
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")));
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
);
102 CFSetRef defaultViews
= SOSViewsCreateDefault(false, NULL
);
104 CFReleaseNull(account
->my_identity
);
105 account
->my_identity
= SOSFullPeerInfoCreateWithViews(kCFAllocatorDefault
, account
->gestalt
, account
->backup_key
, defaultViews
,
107 CFReleaseNull(defaultViews
);
108 CFReleaseNull(full_key
);
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("-"));
115 secerror("No full_key: %@:", error
? *error
: NULL
);
121 return account
->my_identity
!= NULL
;
124 bool SOSAccountHasCircle(SOSAccountRef account
, CFErrorRef
* error
) {
125 if (!account
->trusted_circle
)
126 SOSCreateErrorWithFormat(kSOSErrorNoCircle
, NULL
, error
, NULL
, CFSTR("No trusted circle"));
128 return account
->trusted_circle
!= NULL
;
131 bool SOSAccountHasFullPeerInfo(SOSAccountRef account
, CFErrorRef
* error
) {
132 bool hasPeer
= false;
134 require(SOSAccountHasCircle(account
, error
), fail
);
136 hasPeer
= account
->my_identity
!= NULL
;
139 SOSCreateErrorWithFormat(kSOSErrorPeerNotFound
, NULL
, error
, NULL
, CFSTR("No peer for circle"));
145 bool SOSAccountIsAccountIdentity(SOSAccountRef account
, SOSPeerInfoRef peer_info
, CFErrorRef
*error
)
147 return CFEqualSafe(peer_info
, SOSFullPeerInfoGetPeerInfo(account
->my_identity
));
150 SOSPeerInfoRef
SOSAccountGetMyPeerInfo(SOSAccountRef account
) {
151 return SOSFullPeerInfoGetPeerInfo(SOSAccountGetMyFullPeerInfo(account
));
155 SOSFullPeerInfoRef
SOSAccountGetMyFullPeerInfo(SOSAccountRef account
) {
156 return account
->trusted_circle
? account
->my_identity
: NULL
;
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
;
166 CFDictionaryRef gestalt
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
167 kPIUserDefinedDeviceNameKey
, CFSTR("iCloud"),
169 require_action_quiet(gestalt
, fail
, SecError(errSecAllocate
, error
, CFSTR("Can't allocate gestalt")));
171 cloud_peer
= SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault
, gestalt
, cloud_key
, error
);
173 require(cloud_peer
, fail
);
175 query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
176 kSecClass
, kSecClassKey
,
177 kSecAttrSynchronizable
,kCFBooleanTrue
,
178 kSecUseTombstones
, kCFBooleanTrue
,
179 kSecValueRef
, cloud_key
,
182 new_name
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
183 CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(cloud_peer
));
185 change
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
186 kSecAttrLabel
, new_name
,
189 SecError(SecItemUpdate(query
, change
), error
, CFSTR("Couldn't update name"));
192 CFReleaseNull(new_name
);
193 CFReleaseNull(query
);
194 CFReleaseNull(change
);
195 CFReleaseNull(gestalt
);
196 CFReleaseNull(cloud_key
);