1/*
2 * Copyright (c) 2012-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
25#include <AssertMacros.h>
26
27#include <SecureObjectSync/SOSFullPeerInfo.h>
28#include <SecureObjectSync/SOSCircle.h>
29
30#include <SecureObjectSync/SOSInternal.h>
31
32#include <Security/SecKeyPriv.h>
33#include <Security/SecItemPriv.h>
34#include <Security/SecOTR.h>
35#include <CoreFoundation/CFArray.h>
36#include <dispatch/dispatch.h>
37
38#include <stdlib.h>
39#include <assert.h>
40
41#include <utilities/SecCFWrappers.h>
42#include <utilities/SecCFRelease.h>
43
44#include <utilities/der_plist.h>
45#include <utilities/der_plist_internal.h>
46#include <corecrypto/ccder.h>
47
48#include <CommonCrypto/CommonDigest.h>
49#include <CommonCrypto/CommonDigestSPI.h>
50
51#include <CoreFoundation/CoreFoundation.h>
52
53#include "utilities/iOSforOSX.h"
54
55#include <AssertMacros.h>
56
57#include <utilities/SecCFError.h>
58
59// for OS X
60#ifdef __cplusplus
61extern "C" {
62#endif
63
64//---- missing
65
66extern OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes);
67extern SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey);
68#ifdef __cplusplus
69}
70#endif
71
72struct __OpaqueSOSFullPeerInfo {
73    CFRuntimeBase          _base;
74
75    SOSPeerInfoRef         peer_info;
76    CFDataRef              key_ref;
77};
78
79CFGiblisWithHashFor(SOSFullPeerInfo);
80
81
82static CFStringRef sPublicKeyKey = CFSTR("PublicSigningKey");
83static CFStringRef sNameKey      = CFSTR("DeviceName");
84static CFStringRef sVersionKey   = CFSTR("ConflictVersion");
85
86CFStringRef kSOSFullPeerInfoDescriptionKey = CFSTR("SOSFullPeerInfoDescription");
87CFStringRef kSOSFullPeerInfoSignatureKey = CFSTR("SOSFullPeerInfoSignature");
88CFStringRef kSOSFullPeerInfoNameKey = CFSTR("SOSFullPeerInfoName");
89
90SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
91    SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
92
93    fpi->peer_info = SOSPeerInfoCreate(allocator, gestalt, signingKey, error);
94    if (fpi->peer_info == NULL) {
95        CFReleaseNull(fpi);
96        goto exit;
97    }
98
99    OSStatus result = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref);
100
101    if (result != errSecSuccess) {
102        CFReleaseNull(fpi);
103        goto exit;
104    }
105
106exit:
107    return fpi;
108}
109
110
111
112SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) {
113    SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
114
115    SecKeyRef pubKey = NULL;
116
117    fpi->peer_info = peer;
118    CFRetainSafe(fpi->peer_info);
119    if (fpi->peer_info == NULL) {
120        CFReleaseNull(fpi);
121        goto exit;
122    }
123
124    pubKey = SOSPeerInfoCopyPubKey(peer);
125
126    fpi->key_ref = SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey, error);
127
128    if (fpi->key_ref == NULL) {
129        CFReleaseNull(fpi);
130        goto exit;
131    }
132
133exit:
134    CFReleaseNull(pubKey);
135    return fpi;
136}
137
138
139SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
140                                        const uint8_t** der_p, const uint8_t *der_end) {
141    SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
142    SecKeyRef device_key = NULL;
143
144    const uint8_t *sequence_end;
145
146    *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
147
148    fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end);
149    require_quiet(fpi->peer_info != NULL, fail);
150
151    *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end);
152
153    OSStatus result = SecKeyFindWithPersistentRef(fpi->key_ref, &device_key);
154
155    require_quiet(result == errSecSuccess, fail);
156    require_quiet(*der_p != NULL, fail);
157
158    CFReleaseNull(device_key);
159    return fpi;
160
161fail:
162    CFReleaseNull(fpi);
163    CFReleaseNull(device_key);
164    return NULL;
165}
166
167SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error)
168{
169    size_t size = CFDataGetLength(fullPeerData);
170    const uint8_t *der = CFDataGetBytePtr(fullPeerData);
171    SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size);
172    return inflated;
173}
174
175static void SOSFullPeerInfoDestroy(CFTypeRef aObj) {
176    SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
177
178    CFReleaseNull(fpi->peer_info);
179    CFReleaseNull(fpi->key_ref);
180}
181
182static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) {
183    SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs;
184    SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs;
185
186    if (!CFEqual(lpeer->peer_info, rpeer->peer_info))
187        return false;
188
189    if (CFEqual(lpeer->key_ref, rpeer->key_ref))
190        return true;
191
192    SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL);
193    SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL);
194
195    bool match = lpk && rpk && CFEqual(lpk, rpk);
196
197    CFReleaseNull(lpk);
198    CFReleaseNull(rpk);
199
200    return match;
201}
202
203static CFHashCode   SOSFullPeerInfoHash(CFTypeRef cf) {
204    SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf;
205
206    return CFHash(peer->peer_info);
207}
208
209static CFStringRef SOSFullPeerInfoCopyDescription(CFTypeRef aObj) {
210    SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj;
211
212    return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info);
213}
214
215bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error)
216{
217    SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error);
218    require_quiet(device_key, fail);
219
220    SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer->peer_info,
221                                                              gestalt, device_key, error);
222
223    require_quiet(newPeer, fail);
224
225    CFReleaseNull(peer->peer_info);
226    peer->peer_info = newPeer;
227    newPeer = NULL;
228
229    CFReleaseNull(device_key);
230    return true;
231
232fail:
233    CFReleaseNull(device_key);
234    return false;
235}
236
237
238bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) {
239    return true;
240}
241
242bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) {
243    CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
244                                                         kSecValuePersistentRef, fullPeer->key_ref,
245                                                         kSecUseTombstones, kCFBooleanFalse,
246                                                         NULL);
247    SecItemDelete(query);
248    CFReleaseNull(query);
249    CFReleaseNull(fullPeer->key_ref);
250
251    return true;
252}
253
254SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer)
255{
256    return fullPeer?fullPeer->peer_info:NULL;
257}
258
259SecKeyRef  SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error)
260{
261    SecKeyRef device_key = NULL;
262
263    require(fullPeer && fullPeer->key_ref, fail);
264
265    OSStatus result = SecKeyFindWithPersistentRef(fullPeer->key_ref, &device_key);
266
267    require_action_quiet(result == errSecSuccess, fail, SecError(result, error, CFSTR("Finding Persistent Ref")));
268
269    return device_key;
270
271fail:
272    CFReleaseNull(device_key);
273    return NULL;
274}
275
276//
277// MARK: Encode and decode
278//
279size_t      SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error)
280{
281    size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error);
282    if (peer_size == 0)
283        return 0;
284
285    size_t ref_size = der_sizeof_data(peer->key_ref, error);
286    if (ref_size == 0)
287        return 0;
288
289    return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE,
290                        peer_size + ref_size);
291}
292
293uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end)
294{
295    return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
296           SOSPeerInfoEncodeToDER(peer->peer_info, error, der,
297           der_encode_data(peer->key_ref, error, der, der_end)));
298}
299
300CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error)
301{
302    size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error);
303    if (size == 0)
304        return NULL;
305    uint8_t buffer[size];
306    uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer));
307    CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
308    return result;
309}
310
311bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
312{
313    bool success = false;
314    SOSPeerInfoRef old_pi = NULL;
315
316    SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
317    require_quiet(device_key, exit);
318
319    old_pi = fpi->peer_info;
320    fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error);
321
322    require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
323
324    success = true;
325
326exit:
327    CFReleaseSafe(old_pi);
328    CFReleaseSafe(device_key);
329    return success;
330}
331
332bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
333{
334    bool success = false;
335    SOSPeerInfoRef old_pi = NULL;
336
337    SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
338    require_quiet(device_key, exit);
339
340    old_pi = fpi->peer_info;
341    fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error);
342
343    require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL);
344
345    success = true;
346
347exit:
348    CFReleaseSafe(old_pi);
349    CFReleaseSafe(device_key);
350    return success;
351}
352
353//
354//
355//
356
357SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error)
358{
359    SOSPeerInfoRef peer_to_free = NULL;
360    SOSPeerInfoRef retired_peer = NULL;
361    SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error);
362    require_quiet(key, error_out);
363
364    retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error);
365
366    require_quiet(retired_peer, error_out);
367
368    peer_to_free = fpi->peer_info;
369    fpi->peer_info = retired_peer;
370    CFRetainSafe(fpi->peer_info);
371
372error_out:
373    CFReleaseNull(key);
374    CFReleaseNull(peer_to_free);
375    return retired_peer;
376}
377
378
379
380