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");
31 #define kSecServerPeerInfoAvailable "com.apple.security.fpiAvailable"
34 SecKeyRef
SOSAccountCopyDeviceKey(SOSAccountRef account
, CFErrorRef
*error
) {
35 SecKeyRef privateKey
= NULL
;
37 require_action_quiet(account
->my_identity
, fail
, SOSErrorCreate(kSOSErrorPeerNotFound
, error
, NULL
, CFSTR("No identity to get key from")));
39 privateKey
= SOSFullPeerInfoCopyDeviceKey(account
->my_identity
, error
);
45 SOSFullPeerInfoRef
CopyCloudKeychainIdentity(SOSPeerInfoRef cloudPeer
, CFErrorRef
*error
) {
46 return SOSFullPeerInfoCreateCloudIdentity(NULL
, cloudPeer
, error
);
50 static SecKeyRef
GeneratePermanentFullECKey_internal(int keySize
, CFStringRef name
, CFTypeRef accessibility
, CFBooleanRef sync
, CFErrorRef
* error
)
52 SecKeyRef full_key
= NULL
;
54 CFNumberRef key_size_num
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &keySize
);
56 CFDictionaryRef priv_key_attrs
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
57 kSecAttrIsPermanent
, kCFBooleanTrue
,
60 CFDictionaryRef keygen_parameters
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
61 kSecAttrKeyType
, kSecAttrKeyTypeEC
,
62 kSecAttrKeySizeInBits
, key_size_num
,
63 kSecPrivateKeyAttrs
, priv_key_attrs
,
64 kSecAttrAccessible
, accessibility
,
65 kSecAttrAccessGroup
, kSOSInternalAccessGroup
,
67 kSecAttrSynchronizable
, sync
,
68 kSecUseTombstones
, kCFBooleanTrue
,
71 CFReleaseNull(priv_key_attrs
);
73 CFReleaseNull(key_size_num
);
74 OSStatus status
= SecKeyGeneratePair(keygen_parameters
, NULL
, &full_key
);
75 CFReleaseNull(keygen_parameters
);
78 secerror("status: %ld", (long)status
);
79 if (status
!= errSecSuccess
&& error
!= NULL
&& *error
== NULL
) {
80 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, status
, NULL
);
86 SecKeyRef
GeneratePermanentFullECKey(int keySize
, CFStringRef name
, CFErrorRef
* error
) {
87 return GeneratePermanentFullECKey_internal(keySize
, name
, kSecAttrAccessibleWhenUnlockedThisDeviceOnly
, kCFBooleanFalse
, error
);
90 static SecKeyRef
GeneratePermanentFullECKeyForCloudIdentity(int keySize
, CFStringRef name
, CFErrorRef
* error
) {
91 return GeneratePermanentFullECKey_internal(keySize
, name
, kSecAttrAccessibleWhenUnlocked
, kCFBooleanTrue
, error
);
94 bool SOSAccountEnsureFullPeerAvailable(SOSAccountRef account
, CFErrorRef
* error
) {
95 require_action_quiet(account
->trusted_circle
, fail
, SOSCreateErrorWithFormat(kSOSErrorNoCircle
, NULL
, error
, NULL
, CFSTR("Don't have circle")));
97 if (account
->my_identity
== NULL
) {
98 CFStringRef keyName
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("ID for %@-%@"), SOSPeerGestaltGetName(account
->gestalt
), SOSCircleGetName(account
->trusted_circle
));
99 SecKeyRef full_key
= GeneratePermanentFullECKey(256, keyName
, error
);
100 CFReleaseNull(keyName
);
103 CFSetRef initialViews
= SOSViewCopyViewSet(kViewSetInitial
);
105 CFReleaseNull(account
->my_identity
);
106 account
->my_identity
= SOSFullPeerInfoCreateWithViews(kCFAllocatorDefault
, account
->gestalt
, account
->backup_key
, initialViews
,
108 CFReleaseNull(initialViews
);
109 CFReleaseNull(full_key
);
111 CFSetRef pendingDefaultViews
= SOSViewCopyViewSet(kViewSetDefault
);
112 SOSAccountPendEnableViewSet(account
, pendingDefaultViews
);
113 CFReleaseNull(pendingDefaultViews
);
115 SOSAccountSetValue(account
, kSOSUnsyncedViewsKey
, kCFBooleanTrue
, NULL
);
117 if (!account
->my_identity
) {
118 secerror("Can't make FullPeerInfo for %@-%@ (%@) - is AKS ok?", SOSPeerGestaltGetName(account
->gestalt
), SOSCircleGetName(account
->trusted_circle
), error
? (void*)*error
: (void*)CFSTR("-"));
121 secnotice("fpi", "alert IDSKeychainSyncingProxy the fpi is available");
122 notify_post(kSecServerPeerInfoAvailable
);
123 if(account
->deviceID
)
124 SOSFullPeerInfoUpdateDeviceID(account
->my_identity
, account
->deviceID
, error
);
128 secerror("No full_key: %@:", error
? *error
: NULL
);
134 return account
->my_identity
!= NULL
;
137 bool SOSAccountHasCircle(SOSAccountRef account
, CFErrorRef
* error
) {
138 if (!account
->trusted_circle
)
139 SOSCreateErrorWithFormat(kSOSErrorNoCircle
, NULL
, error
, NULL
, CFSTR("No trusted circle"));
141 return account
->trusted_circle
!= NULL
;
144 bool SOSAccountHasFullPeerInfo(SOSAccountRef account
, CFErrorRef
* error
) {
145 bool hasPeer
= false;
147 require(SOSAccountHasCircle(account
, error
), fail
);
149 hasPeer
= account
->my_identity
!= NULL
;
152 SOSCreateErrorWithFormat(kSOSErrorPeerNotFound
, NULL
, error
, NULL
, CFSTR("No peer for circle"));
158 bool SOSAccountIsAccountIdentity(SOSAccountRef account
, SOSPeerInfoRef peer_info
, CFErrorRef
*error
)
160 return CFEqualSafe(peer_info
, SOSFullPeerInfoGetPeerInfo(account
->my_identity
));
163 SOSPeerInfoRef
SOSAccountGetMyPeerInfo(SOSAccountRef account
) {
164 return SOSFullPeerInfoGetPeerInfo(SOSAccountGetMyFullPeerInfo(account
));
168 SOSFullPeerInfoRef
SOSAccountGetMyFullPeerInfo(SOSAccountRef account
) {
169 return account
->trusted_circle
? account
->my_identity
: NULL
;
172 bool SOSAccountFullPeerInfoVerify(SOSAccountRef account
, SecKeyRef privKey
, CFErrorRef
*error
) {
173 if(!account
->my_identity
) return false;
174 SecKeyRef pubKey
= SecKeyCreatePublicFromPrivate(privKey
);
175 bool retval
= SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(account
->my_identity
), pubKey
, error
);
176 CFReleaseNull(pubKey
);
180 SOSPeerInfoRef
GenerateNewCloudIdentityPeerInfo(CFErrorRef
*error
) {
181 SecKeyRef cloud_key
= GeneratePermanentFullECKeyForCloudIdentity(256, kicloud_identity_name
, error
);
182 SOSPeerInfoRef cloud_peer
= NULL
;
183 CFDictionaryRef query
= NULL
;
184 CFDictionaryRef change
= NULL
;
185 CFStringRef new_name
= NULL
;
187 CFDictionaryRef gestalt
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
188 kPIUserDefinedDeviceNameKey
, CFSTR("iCloud"),
190 require_action_quiet(gestalt
, fail
, SecError(errSecAllocate
, error
, CFSTR("Can't allocate gestalt")));
192 cloud_peer
= SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault
, gestalt
, cloud_key
, error
);
194 require(cloud_peer
, fail
);
196 query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
197 kSecClass
, kSecClassKey
,
198 kSecAttrSynchronizable
,kCFBooleanTrue
,
199 kSecUseTombstones
, kCFBooleanTrue
,
200 kSecValueRef
, cloud_key
,
203 new_name
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
204 CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(cloud_peer
));
206 change
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
207 kSecAttrLabel
, new_name
,
210 SecError(SecItemUpdate(query
, change
), error
, CFSTR("Couldn't update name"));
213 CFReleaseNull(new_name
);
214 CFReleaseNull(query
);
215 CFReleaseNull(change
);
216 CFReleaseNull(gestalt
);
217 CFReleaseNull(cloud_key
);