2 * Copyright (c) 2017 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 #import "OTEscrowKeys.h"
27 #import <Security/SecItemPriv.h>
28 #include <Security/SecKey.h>
29 #include <Security/SecKeyPriv.h>
30 #import <Foundation/Foundation.h>
31 #import <utilities/debugging.h>
32 #import <utilities/SecCFWrappers.h>
34 #import <SecurityFoundation/SFEncryptionOperation.h>
35 #import <SecurityFoundation/SFSigningOperation.h>
36 #import <SecurityFoundation/SFDigestOperation.h>
37 #import <SecurityFoundation/SFKey.h>
38 #import <SecurityFoundation/SFKey_Private.h>
40 #import "keychain/ot/OTDefines.h"
42 #import <corecrypto/cchkdf.h>
43 #import <corecrypto/ccsha2.h>
44 #import <corecrypto/ccec.h>
46 #import <CommonCrypto/CommonRandomSPI.h>
47 #import <Security/SecCFAllocator.h>
48 #import <Foundation/NSKeyedArchiver_Private.h>
50 static uint8_t escrowedSigningPrivKey[] = {'E', 's', 'c', 'r', 'o', 'w', ' ', 'S', 'i', 'g', 'n', 'i', 'n', 'g', ' ', 'P', 'r', 'i', 'v', 'a', 't', 'e', ' ', 'K', 'e', 'y'};
51 static uint8_t escrowedEncryptionPrivKey[] = { 'E', 's', 'c', 'r', 'o', 'w', ' ','E', 'n', 'c', 'r', 'y', 'p', 't', 'i', 'o', 'n', ' ', 'P', 'r', 'v', 'a', 't', 'e', ' ', 'K', 'e', 'y' };
52 static uint8_t escrowedSymmetric[] = {'E', 's', 'c', 'r', 'o', 'w', ' ', 'S', 'y', 'm', 'm', 'e', 't', 'r', 'i','c',' ', 'K', 'e', 'y' };
54 #define OT_ESCROW_SIGNING_HKDF_SIZE 56
55 #define OT_ESCROW_ENCRYPTION_HKDF_SIZE 56
56 #define OT_ESCROW_SYMMETRIC_HKDF_SIZE 32
58 @interface OTEscrowKeys ()
59 @property (nonatomic, strong) SFECKeyPair* encryptionKey;
60 @property (nonatomic, strong) SFECKeyPair* signingKey;
61 @property (nonatomic, strong) SFAESKey* symmetricKey;
62 @property (nonatomic, strong) NSData* secret;
63 @property (nonatomic, strong) NSString* dsid;
66 @implementation OTEscrowKeys
68 - (nullable instancetype) initWithSecret:(NSData*)secret
70 error:(NSError* __autoreleasing *)error
74 NSError* localError = nil;
76 if([secret length] == 0){
78 *error = [NSError errorWithDomain:octagonErrorDomain code:OTErrorEmptySecret userInfo:@{NSLocalizedDescriptionKey: @"entropy/secret is nil"}];
82 _secret = [secret copy];
84 if([dsid length] == 0){
86 *error = [NSError errorWithDomain:octagonErrorDomain code:OTErrorEmptyDSID userInfo:@{NSLocalizedDescriptionKey: @"dsid is nil"}];
92 NSData *data = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySigning masterSecret:secret dsid:self.dsid error:&localError];
99 _signingKey = [[SFECKeyPair alloc] initWithSecKey:[OTEscrowKeys createSecKey:data]];
102 *error = [NSError errorWithDomain:octagonErrorDomain code:OTErrorKeyGeneration userInfo:@{NSLocalizedDescriptionKey: @"failed to create EC signing key"}];
106 data = [OTEscrowKeys generateEscrowKey:kOTEscrowKeyEncryption masterSecret:secret dsid:self.dsid error:&localError];
113 _encryptionKey = [[SFECKeyPair alloc] initWithSecKey:[OTEscrowKeys createSecKey:data]];
116 *error = [NSError errorWithDomain:octagonErrorDomain code:OTErrorKeyGeneration userInfo:@{NSLocalizedDescriptionKey: @"failed to create EC encryption key"}];
120 data = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySymmetric masterSecret:secret dsid:self.dsid error:&localError];
127 _symmetricKey = [[SFAESKey alloc] initWithData:data specifier:[[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256] error:&localError];
128 if (!_symmetricKey) {
135 BOOL result = [OTEscrowKeys storeEscrowedSigningKeyPair:[_signingKey keyData] error:&localError];
136 if(!result || localError){
137 secerror("octagon: could not store escrowed signing SPKI in keychain: %@", localError);
143 result = [OTEscrowKeys storeEscrowedEncryptionKeyPair:[_encryptionKey keyData] error:error];
144 if(!result || localError){
145 secerror("octagon: could not store escrowed signing SPKI in keychain: %@", localError);
151 result = [OTEscrowKeys storeEscrowedSymmetricKey:[_symmetricKey keyData] error:error];
152 if(!result || localError){
153 secerror("octagon: could not store escrowed signing SPKI in keychain: %@", localError);
163 + (NSData* _Nullable) generateEscrowKey:(escrowKeyType)keyType
164 masterSecret:(NSData*)masterSecret
165 dsid:(NSString *)dsid
166 error:(NSError**)error
168 NSUInteger keyLength = 0;
169 const void *info = nil;
170 size_t infoLength = 0;
171 NSMutableData* derivedKey = NULL;
175 case kOTEscrowKeySymmetric:
176 keyLength = OT_ESCROW_SYMMETRIC_HKDF_SIZE;
177 info = escrowedSymmetric;
178 infoLength = sizeof(escrowedSymmetric);
180 case kOTEscrowKeyEncryption:
181 keyLength = OT_ESCROW_ENCRYPTION_HKDF_SIZE;
182 info = escrowedEncryptionPrivKey;
183 infoLength = sizeof(escrowedEncryptionPrivKey);
185 case kOTEscrowKeySigning:
186 keyLength = OT_ESCROW_SIGNING_HKDF_SIZE;
187 info = escrowedSigningPrivKey;
188 infoLength = sizeof(escrowedSigningPrivKey);
194 ccec_const_cp_t cp = ccec_cp_384();
197 ccec_full_ctx_decl_cp(cp, fullKey);
199 derivedKey = [NSMutableData dataWithLength:keyLength];
200 status = cchkdf(ccsha384_di(),
201 [masterSecret length], [masterSecret bytes],
202 strlen([dsid UTF8String]),[dsid UTF8String],
204 keyLength, [derivedKey mutableBytes]);
209 *error = [NSError errorWithDomain:octagonErrorDomain code:OTErrorKeyGeneration userInfo:nil];
211 secerror("octagon: could not generate seed for signing keys");
214 if(keyType == kOTEscrowKeySymmetric){
217 else if(keyType == kOTEscrowKeyEncryption || keyType == kOTEscrowKeySigning){
219 status = ccec_generate_key_deterministic(cp,
220 [derivedKey length], [derivedKey mutableBytes],
222 CCEC_GENKEY_DETERMINISTIC_FIPS,
226 *error = [NSError errorWithDomain:octagonErrorDomain code:OTErrorKeyGeneration userInfo:nil];
228 secerror("octagon: could not generate signing keys");
232 size_t space = ccec_x963_export_size(true, ccec_ctx_pub(fullKey));
233 NSMutableData* key = [[NSMutableData alloc]initWithLength:space];
234 ccec_x963_export(true, [key mutableBytes], fullKey);
240 + (SecKeyRef) createSecKey:(NSData*)keyData
242 NSDictionary *keyAttributes = @{
243 (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate,
244 (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC,
247 SecKeyRef key = SecKeyCreateWithData((__bridge CFDataRef)keyData, (__bridge CFDictionaryRef)keyAttributes, NULL);
251 + (BOOL) setKeyMaterialInKeychain:(NSDictionary*)query error:(NSError* __autoreleasing *)error
255 CFTypeRef results = NULL;
256 OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &results);
258 NSError* localerror = nil;
260 if(status == errSecDuplicateItem || status == errSecSuccess) {
263 localerror = [NSError errorWithDomain:@"securityd"
267 if(status != errSecSuccess) {
268 CFReleaseNull(results);
278 +(NSString*) hashIt:(NSData*)keyData
280 const struct ccdigest_info *di = ccsha384_di();
281 NSMutableData* result = [[NSMutableData alloc] initWithLength:ccsha384_di()->output_size];
283 ccdigest(di, [keyData length], [keyData bytes], [result mutableBytes]);
285 NSString* hash = [result base64EncodedStringWithOptions:0];
289 + (BOOL)storeEscrowedEncryptionKeyPair:(NSData*)keyData error:(NSError**)error
291 NSDictionary* query = @{
292 (id)kSecClass : (id)kSecClassInternetPassword,
293 (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked,
294 (id)kSecAttrNoLegacy : @YES,
295 (id)kSecAttrAccessGroup: @"com.apple.security.ckks",
296 (id)kSecAttrSynchronizable : (id)kCFBooleanFalse,
297 (id)kSecAttrServer : [self hashIt:keyData],
298 (id)kSecAttrLabel : @"Escrowed Encryption Key",
299 (id)kSecValueData : keyData,
301 return [OTEscrowKeys setKeyMaterialInKeychain:query error:error];
304 + (BOOL)storeEscrowedSigningKeyPair:(NSData*)keyData error:(NSError**)error
306 NSDictionary* query = @{
307 (id)kSecClass : (id)kSecClassInternetPassword,
308 (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked,
309 (id)kSecAttrNoLegacy : @YES,
310 (id)kSecAttrAccessGroup: @"com.apple.security.ckks",
311 (id)kSecAttrSynchronizable : (id)kCFBooleanFalse,
312 (id)kSecAttrLabel : @"Escrowed Signing Key",
313 (id)kSecAttrServer : [self hashIt:keyData],
314 (id)kSecValueData : keyData,
316 return [OTEscrowKeys setKeyMaterialInKeychain:query error:error];
319 + (BOOL)storeEscrowedSymmetricKey:(NSData*)keyData error:(NSError**)error
321 NSDictionary* query = @{
322 (id)kSecClass : (id)kSecClassInternetPassword,
323 (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked,
324 (id)kSecAttrNoLegacy : @YES,
325 (id)kSecAttrAccessGroup: @"com.apple.security.ckks",
326 (id)kSecAttrSynchronizable : (id)kCFBooleanFalse,
327 (id)kSecAttrLabel : @"Escrowed Symmetric Key",
328 (id)kSecAttrServer : [self hashIt:keyData],
329 (id)kSecValueData : keyData,
331 return [OTEscrowKeys setKeyMaterialInKeychain:query error:error];