2 * Copyright (c) 2012-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@
25 #include <Security/SecureObjectSync/SOSInternal.h>
26 #include <Security/SecureObjectSync/SOSCircle.h>
27 #include <Security/SecureObjectSync/SOSCloudCircle.h>
28 #include <Security/SecureObjectSync/SOSKVSKeys.h>
29 #include "utilities/SecCFError.h"
30 #include "utilities/SecCFRelease.h"
31 #include "utilities/SecCFWrappers.h"
32 #include "utilities/iOSforOSX.h"
34 #include <CoreFoundation/CoreFoundation.h>
36 #include <Security/SecKey.h>
37 #include <Security/SecKeyPriv.h>
38 #include <Security/SecItem.h>
39 #include <securityd/SecDbItem.h> // For SecError
40 #include "utilities/iOSforOSX.h"
42 #include <Security/SecBase64.h>
43 #include <utilities/der_plist.h>
44 #include <utilities/der_plist_internal.h>
45 #include <corecrypto/ccder.h>
46 #include <utilities/der_date.h>
48 #include <corecrypto/ccrng.h>
49 #include <corecrypto/ccrng_pbkdf2_prng.h>
51 #include <CommonCrypto/CommonRandomSPI.h>
53 #include <AssertMacros.h>
55 CFStringRef kSOSErrorDomain
= CFSTR("com.apple.security.sos.error");
57 bool SOSErrorCreate(CFIndex errorCode
, CFErrorRef
*error
, CFDictionaryRef formatOptions
, CFStringRef format
, ...) {
58 if (!errorCode
) return true;
59 if (error
&& !*error
) {
62 SecCFCreateErrorWithFormatAndArguments(errorCode
, kSOSErrorDomain
, NULL
, error
, formatOptions
, format
, va
);
68 bool SOSCreateError(CFIndex errorCode
, CFStringRef descriptionString
, CFErrorRef previousError
, CFErrorRef
*newError
) {
69 SOSCreateErrorWithFormat(errorCode
, previousError
, newError
, NULL
, CFSTR("%@"), descriptionString
);
73 bool SOSCreateErrorWithFormat(CFIndex errorCode
, CFErrorRef previousError
, CFErrorRef
*newError
,
74 CFDictionaryRef formatOptions
, CFStringRef format
, ...) {
77 bool res
= SOSCreateErrorWithFormatAndArguments(errorCode
, previousError
, newError
, formatOptions
, format
, va
);
82 bool SOSCreateErrorWithFormatAndArguments(CFIndex errorCode
, CFErrorRef previousError
, CFErrorRef
*newError
,
83 CFDictionaryRef formatOptions
, CFStringRef format
, va_list args
) {
84 SecCFCreateErrorWithFormatAndArguments(errorCode
, kSOSErrorDomain
, previousError
, newError
, formatOptions
, format
, args
);
93 static OSStatus
GenerateECPairImp(int keySize
, CFBooleanRef permanent
, SecKeyRef
* public, SecKeyRef
*full
)
95 static const CFStringRef sTempNameToUse
= CFSTR("GenerateECPair Temporary Key - Shouldn't be live");
97 CFNumberRef signing_bitsize
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &keySize
);
99 CFDictionaryRef keygen_parameters
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
100 kSecAttrKeyType
, kSecAttrKeyTypeEC
,
101 kSecAttrKeySizeInBits
, signing_bitsize
,
102 kSecAttrIsPermanent
, permanent
,
103 kSecAttrLabel
, sTempNameToUse
,
105 CFReleaseNull(signing_bitsize
);
106 OSStatus result
= SecKeyGeneratePair(keygen_parameters
, public, full
);
107 CFReleaseNull(keygen_parameters
);
112 OSStatus
GenerateECPair(int keySize
, SecKeyRef
* public, SecKeyRef
*full
)
114 return GenerateECPairImp(keySize
, kCFBooleanFalse
, public, full
);
117 OSStatus
GeneratePermanentECPair(int keySize
, SecKeyRef
* public, SecKeyRef
*full
)
119 return GenerateECPairImp(keySize
, kCFBooleanTrue
, public, full
);
122 static CFStringRef
SOSCircleCopyDescriptionFromData(CFDataRef data
)
124 CFErrorRef error
= NULL
;
125 CFStringRef result
= NULL
;
127 SOSCircleRef circle
= SOSCircleCreateFromData(kCFAllocatorDefault
, data
, &error
);
130 result
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@"), circle
);
132 CFReleaseSafe(circle
);
137 CFStringRef
SOSItemsChangedCopyDescription(CFDictionaryRef changes
, bool is_sender
)
139 CFMutableStringRef string
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("<Changes: {\n"));
141 CFDictionaryForEach(changes
, ^(const void *key
, const void *value
) {
142 CFStringRef value_description
= NULL
;
143 if (isString(key
) && isData(value
)) {
144 CFDataRef value_data
= (CFDataRef
) value
;
145 switch (SOSKVSKeyGetKeyType(key
)) {
147 value_description
= SOSCircleCopyDescriptionFromData(value_data
);
150 value_description
= CFCopyDescription(value_data
);
157 CFStringAppendFormat(string
, NULL
, CFSTR(" '%@' %s %@\n"),
159 is_sender
? "<=" : "=>",
160 value_description
? value_description
: value
);
162 CFReleaseNull(value_description
);
165 CFStringAppendFormat(string
, NULL
, CFSTR("}"));
170 CFStringRef
SOSCopyIDOfKey(SecKeyRef key
, CFErrorRef
*error
)
172 const struct ccdigest_info
* di
= ccsha1_di();
173 CFDataRef publicBytes
= NULL
;
174 CFStringRef result
= NULL
;
176 uint8_t digest
[di
->output_size
];
177 char encoded
[2 * di
->output_size
]; // Big enough for base64 encoding.
179 require_quiet(SecError(SecKeyCopyPublicBytes(key
, &publicBytes
), error
, CFSTR("Failed to export public bytes %@"), key
), fail
);
181 ccdigest(di
, CFDataGetLength(publicBytes
), CFDataGetBytePtr(publicBytes
), digest
);
183 size_t length
= SecBase64Encode(digest
, sizeof(digest
), encoded
, sizeof(encoded
));
184 assert(length
&& length
< sizeof(encoded
));
188 CFReleaseNull(publicBytes
);
189 return CFStringCreateWithCString(kCFAllocatorDefault
, encoded
, kCFStringEncodingASCII
);
192 CFReleaseNull(publicBytes
);
196 CFGiblisGetSingleton(ccec_const_cp_t
, SOSGetBackupKeyCurveParameters
, sBackupKeyCurveParameters
, ^{
197 *sBackupKeyCurveParameters
= ccec_cp_256();
202 // We're expecting full entropy here, so we just need to stretch
203 // via the PBKDF entropy rng. We'll choose a few iterations and no salt
204 // since we don't get sent any.
206 const int kBackupKeyIterations
= 20;
207 const uint8_t sBackupKeySalt
[] = { 0 };
208 const int kBackupKeyMaxBytes
= 256;
210 bool SOSPerformWithDeviceBackupFullKey(ccec_const_cp_t cp
, CFDataRef entropy
, CFErrorRef
*error
, void (^operation
)(ccec_full_ctx_t fullKey
))
213 ccec_full_ctx_decl_cp(cp
, fullKey
);
215 require_quiet(SOSGenerateDeviceBackupFullKey(fullKey
, cp
, entropy
, error
), exit
);
221 ccec_full_ctx_clear_cp(cp
, fullKey
);
227 bool SOSGenerateDeviceBackupFullKey(ccec_full_ctx_t generatedKey
, ccec_const_cp_t cp
, CFDataRef entropy
, CFErrorRef
* error
)
231 struct ccrng_pbkdf2_prng_state pbkdf2_prng
;
233 cc_result
= ccrng_pbkdf2_prng_init(&pbkdf2_prng
, kBackupKeyMaxBytes
,
234 CFDataGetLength(entropy
), CFDataGetBytePtr(entropy
),
235 sizeof(sBackupKeySalt
), sBackupKeySalt
,
236 kBackupKeyIterations
);
237 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorProcessingFailure
, error
, NULL
, CFSTR("pbkdf rng init failed: %d"), cc_result
));
239 cc_result
= ccec_compact_generate_key(cp
, (struct ccrng_state
*) &pbkdf2_prng
, generatedKey
);
240 require_action_quiet(cc_result
== 0, exit
, SOSErrorCreate(kSOSErrorProcessingFailure
, error
, NULL
, CFSTR("Generate key failed: %d"), cc_result
));
244 bzero(&pbkdf2_prng
, sizeof(pbkdf2_prng
));
249 CFDataRef
SOSCopyDeviceBackupPublicKey(CFDataRef entropy
, CFErrorRef
*error
)
251 CFDataRef result
= NULL
;
252 CFMutableDataRef publicKeyData
= NULL
;
254 ccec_full_ctx_decl_cp(SOSGetBackupKeyCurveParameters(), fullKey
);
256 require_quiet(SOSGenerateDeviceBackupFullKey(fullKey
, SOSGetBackupKeyCurveParameters(), entropy
, error
), exit
);
258 size_t space
= ccec_compact_export_size(false, fullKey
);
259 publicKeyData
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, space
);
260 require_quiet(SecAllocationError(publicKeyData
, error
, CFSTR("Mutable data allocation")), exit
);
262 ccec_compact_export(false, CFDataGetMutableBytePtr(publicKeyData
), fullKey
);
264 CFTransferRetained(result
, publicKeyData
);
267 CFReleaseNull(publicKeyData
);
272 CFDataRef
SOSDateCreate(void) {
273 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
274 size_t bufsiz
= der_sizeof_date(now
, NULL
);
276 der_encode_date(now
, NULL
, buf
, buf
+bufsiz
);
278 return CFDataCreate(NULL
, buf
, bufsiz
);