]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.m
Security-58286.60.28.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountFullPeerInfo.m
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 #include <AssertMacros.h>
25
26 #include <stdio.h>
27 #include "SOSAccountPriv.h"
28 #include "SOSInternal.h"
29 #include "SOSViews.h"
30 #include "SOSPeerInfoV2.h"
31 #import <Security/SecureObjectSync/SOSAccountTrust.h>
32 #import <Security/SecureObjectSync/SOSAccountTrustClassic.h>
33
34 static CFStringRef kicloud_identity_name = CFSTR("Cloud Identity");
35
36 SecKeyRef SOSAccountCopyDeviceKey(SOSAccount* account, CFErrorRef *error) {
37 SecKeyRef privateKey = NULL;
38 SOSFullPeerInfoRef identity = NULL;
39
40 SOSAccountTrustClassic *trust = account.trust;
41 identity = trust.fullPeerInfo;
42 require_action_quiet(identity, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No identity to get key from")));
43
44 privateKey = SOSFullPeerInfoCopyDeviceKey(identity, error);
45
46 fail:
47 return privateKey;
48 }
49
50 SOSFullPeerInfoRef CopyCloudKeychainIdentity(SOSPeerInfoRef cloudPeer, CFErrorRef *error) {
51 return SOSFullPeerInfoCreateCloudIdentity(NULL, cloudPeer, error);
52 }
53
54
55 static CF_RETURNS_RETAINED SecKeyRef GeneratePermanentFullECKey_internal(int keySize, CFStringRef name, CFTypeRef accessibility, CFBooleanRef sync, CFErrorRef* error)
56 {
57 SecKeyRef full_key = NULL;
58
59 CFNumberRef key_size_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
60
61 CFDictionaryRef priv_key_attrs = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
62 kSecAttrIsPermanent, kCFBooleanTrue,
63 NULL);
64
65 CFDictionaryRef keygen_parameters = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
66 kSecAttrKeyType, kSecAttrKeyTypeEC,
67 kSecAttrKeySizeInBits, key_size_num,
68 kSecPrivateKeyAttrs, priv_key_attrs,
69 kSecAttrAccessible, accessibility,
70 kSecAttrAccessGroup, kSOSInternalAccessGroup,
71 kSecAttrLabel, name,
72 kSecAttrSynchronizable, sync,
73 kSecUseTombstones, kCFBooleanTrue,
74 NULL);
75
76 CFReleaseNull(priv_key_attrs);
77
78 CFReleaseNull(key_size_num);
79 OSStatus status = SecKeyGeneratePair(keygen_parameters, NULL, &full_key);
80 CFReleaseNull(keygen_parameters);
81
82 if (status)
83 secerror("status: %ld", (long)status);
84 if (status != errSecSuccess && error != NULL && *error == NULL) {
85 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
86 }
87
88 return full_key;
89 }
90
91 CF_RETURNS_RETAINED SecKeyRef GeneratePermanentFullECKey(int keySize, CFStringRef name, CFErrorRef* error) {
92 return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kCFBooleanFalse, error);
93 }
94
95 static CF_RETURNS_RETAINED SecKeyRef GeneratePermanentFullECKeyForCloudIdentity(int keySize, CFStringRef name, CFErrorRef* error) {
96 return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlocked, kCFBooleanTrue, error);
97 }
98
99 bool SOSAccountHasCircle(SOSAccount* account, CFErrorRef* error) {
100 SOSAccountTrustClassic *trust = account.trust;
101 SOSCircleRef circle = trust.trustedCircle;
102
103 if (!circle)
104 SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No trusted circle"));
105
106 return circle != NULL;
107 }
108
109 bool SOSAccountHasFullPeerInfo(SOSAccount* account, CFErrorRef* error) {
110 bool hasPeer = false;
111 SOSAccountTrustClassic *trust = account.trust;
112 SOSFullPeerInfoRef identity = trust.fullPeerInfo;
113
114 require(SOSAccountHasCircle(account, error), fail);
115
116 hasPeer = identity != NULL;
117
118 if (!hasPeer)
119 SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("No peer for circle"));
120
121 fail:
122 return hasPeer;
123 }
124
125 bool SOSAccountIsAccountIdentity(SOSAccount* account, SOSPeerInfoRef peer_info, CFErrorRef *error)
126 {
127 SOSFullPeerInfoRef identity = NULL;
128
129 SOSAccountTrustClassic *trust = account.trust;
130 identity = trust.fullPeerInfo;
131 return CFEqualSafe(peer_info, SOSFullPeerInfoGetPeerInfo(identity));
132 }
133
134 bool SOSAccountFullPeerInfoVerify(SOSAccount* account, SecKeyRef privKey, CFErrorRef *error) {
135 SOSFullPeerInfoRef identity = NULL;
136
137 SOSAccountTrustClassic *trust = account.trust;
138 identity = trust.fullPeerInfo;
139 if(!identity) return false;
140 SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey);
141 bool retval = SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(identity), pubKey, error);
142 CFReleaseNull(pubKey);
143 return retval;
144 }
145
146 static bool UpdateKeyName(SecKeyRef key, SOSPeerInfoRef peer, CFErrorRef* error)
147 {
148 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
149 kSecClass, kSecClassKey,
150 kSecAttrSynchronizable,kCFBooleanTrue,
151 kSecUseTombstones, kCFBooleanTrue,
152 kSecValueRef, key,
153 NULL);
154
155 CFStringRef new_name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
156 CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(peer));
157
158 CFDictionaryRef change = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
159 kSecAttrLabel, new_name,
160 NULL);
161
162 bool result = SecError(SecItemUpdate(query, change), error, CFSTR("Couldn't update name"));
163
164 CFReleaseNull(new_name);
165 CFReleaseNull(query);
166 CFReleaseNull(change);
167 return result;
168 }
169
170 SOSPeerInfoRef GenerateNewCloudIdentityPeerInfo(CFErrorRef *error) {
171 SecKeyRef cloud_key = GeneratePermanentFullECKeyForCloudIdentity(256, kicloud_identity_name, error);
172 SOSPeerInfoRef cloud_peer = NULL;
173
174 CFDictionaryRef gestalt = NULL;
175
176 require_action_quiet(cloud_key, fail, SecError(errSecAllocate, error, CFSTR("Can't generate keypair for icloud identity")));
177
178 gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
179 kPIUserDefinedDeviceNameKey, CFSTR("iCloud"),
180 NULL);
181 require_action_quiet(gestalt, fail, SecError(errSecAllocate, error, CFSTR("Can't allocate gestalt")));
182
183 cloud_peer = SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault, gestalt, cloud_key, error);
184
185 require(cloud_peer, fail);
186
187 UpdateKeyName(cloud_key, cloud_peer, error);
188
189 fail:
190 CFReleaseNull(gestalt);
191 CFReleaseNull(cloud_key);
192
193 return cloud_peer;
194 }