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 bool SOSAccountFullPeerInfoVerify(SOSAccountRef account
, SecKeyRef privKey
, CFErrorRef
*error
) {
160 if(!account
->my_identity
) return false;
161 SecKeyRef pubKey
= SecKeyCreatePublicFromPrivate(privKey
);
162 bool retval
= SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(account
->my_identity
), pubKey
, error
);
163 CFReleaseNull(pubKey
);
167 SOSPeerInfoRef
GenerateNewCloudIdentityPeerInfo(CFErrorRef
*error
) {
168 SecKeyRef cloud_key
= GeneratePermanentFullECKeyForCloudIdentity(256, kicloud_identity_name
, error
);
169 SOSPeerInfoRef cloud_peer
= NULL
;
170 CFDictionaryRef query
= NULL
;
171 CFDictionaryRef change
= NULL
;
172 CFStringRef new_name
= NULL
;
174 CFDictionaryRef gestalt
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
175 kPIUserDefinedDeviceNameKey
, CFSTR("iCloud"),
177 require_action_quiet(gestalt
, fail
, SecError(errSecAllocate
, error
, CFSTR("Can't allocate gestalt")));
179 cloud_peer
= SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault
, gestalt
, cloud_key
, error
);
181 require(cloud_peer
, fail
);
183 query
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
184 kSecClass
, kSecClassKey
,
185 kSecAttrSynchronizable
,kCFBooleanTrue
,
186 kSecUseTombstones
, kCFBooleanTrue
,
187 kSecValueRef
, cloud_key
,
190 new_name
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
191 CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(cloud_peer
));
193 change
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
194 kSecAttrLabel
, new_name
,
197 SecError(SecItemUpdate(query
, change
), error
, CFSTR("Couldn't update name"));
200 CFReleaseNull(new_name
);
201 CFReleaseNull(query
);
202 CFReleaseNull(change
);
203 CFReleaseNull(gestalt
);
204 CFReleaseNull(cloud_key
);