]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecDbKeychainItemV7.m
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / sec / securityd / SecDbKeychainItemV7.m
1 /*
2 * Copyright (c) 2017 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 #import "SecDbKeychainItemV7.h"
25 #import "SecKeybagSupport.h"
26 #import "SecItemServer.h"
27 #import "SecAccessControl.h"
28 #import "SecDbKeychainSerializedItemV7.h"
29 #import "SecDbKeychainSerializedAKSWrappedKey.h"
30 #import "SecDbKeychainSerializedMetadata.h"
31 #import "SecDbKeychainSerializedSecretData.h"
32 #import <notify.h>
33 #import <dispatch/dispatch.h>
34 #import <utilities/SecAKSWrappers.h>
35 #import <utilities/der_plist.h>
36 #import "sec_action.h"
37 #if !TARGET_OS_BRIDGE
38 #import <SecurityFoundation/SFEncryptionOperation.h>
39 #import <SecurityFoundation/SFKey_Private.h>
40 #import <SecurityFoundation/SFCryptoServicesErrors.h>
41 #endif
42 #import <Foundation/NSKeyedArchiver_Private.h>
43
44 #if USE_KEYSTORE
45 #import <Kernel/IOKit/crypto/AppleKeyStoreDefs.h>
46 #endif
47
48 #define KEYCHAIN_ITEM_PADDING_MODULUS 20
49
50 NSString* const SecDbKeychainErrorDomain = @"SecDbKeychainErrorDomain";
51 const NSInteger SecDbKeychainErrorDeserializationFailed = 1;
52
53 static NSString* const SecDBTamperCheck = @"TamperCheck";
54
55 #define BridgeCFErrorToNSErrorOut(nsErrorOut, CFErr) \
56 { \
57 if (nsErrorOut) { \
58 *nsErrorOut = CFBridgingRelease(CFErr); \
59 CFErr = NULL; \
60 } \
61 else { \
62 CFReleaseNull(CFErr); \
63 } \
64 }
65
66 #if TARGET_OS_BRIDGE
67
68 @implementation SecDbKeychainItemV7
69
70 - (instancetype)initWithData:(NSData*)data decryptionKeybag:(keybag_handle_t)decryptionKeybag error:(NSError**)error
71 {
72 return nil;
73 }
74
75 - (instancetype)initWithSecretAttributes:(NSDictionary*)secretAttributes metadataAttributes:(NSDictionary*)metadataAttributes tamperCheck:(NSString*)tamperCheck keyclass:(keyclass_t)keyclass
76 {
77 return nil;
78 }
79
80 - (NSDictionary*)metadataAttributesWithError:(NSError**)error
81 {
82 return nil;
83 }
84
85 - (NSDictionary*)secretAttributesWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error
86 {
87 return nil;
88 }
89
90 - (BOOL)deleteWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error
91 {
92 return NO;
93 }
94
95 - (NSData*)encryptedBlobWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error
96 {
97 return nil;
98 }
99
100 @end
101
102 #else
103
104 static NSDictionary* dictionaryFromDERData(NSData* data)
105 {
106 NSDictionary* dict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)data, 0, NULL, NULL);
107 return [dict isKindOfClass:[NSDictionary class]] ? dict : nil;
108 }
109
110 typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
111 SecDbKeychainAKSWrappedKeyTypeRegular,
112 SecDbKeychainAKSWrappedKeyTypeRefKey
113 };
114
115 @interface SecDbKeychainAKSWrappedKey : NSObject
116
117 @property (readonly) NSData* wrappedKey;
118 @property (readonly) NSData* refKeyBlob;
119 @property (readonly) SecDbKeychainAKSWrappedKeyType type;
120
121 @property (readonly) NSData* serializedRepresentation;
122
123 - (instancetype)initWithData:(NSData*)data;
124 - (instancetype)initRegularWrappedKeyWithData:(NSData*)wrappedKey;
125 - (instancetype)initRefKeyWrappedKeyWithData:(NSData*)wrappedKey refKeyBlob:(NSData*)refKeyBlob;
126
127 @end
128
129 @interface SecDbKeychainMetadata : NSObject
130
131 @property (readonly) SFAuthenticatedCiphertext* ciphertext;
132 @property (readonly) SFAuthenticatedCiphertext* wrappedKey;
133 @property (readonly) NSString* tamperCheck;
134
135 @property (readonly) NSData* serializedRepresentation;
136
137 - (instancetype)initWithData:(NSData*)data;
138 - (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SFAuthenticatedCiphertext*)wrappedKey tamperCheck:(NSString*)tamperCheck error:(NSError**)error;
139
140 @end
141
142 @interface SecDbKeychainSecretData : NSObject
143
144 @property (readonly) SFAuthenticatedCiphertext* ciphertext;
145 @property (readonly) SecDbKeychainAKSWrappedKey* wrappedKey;
146 @property (readonly) NSString* tamperCheck;
147
148 @property (readonly) NSData* serializedRepresentation;
149
150 - (instancetype)initWithData:(NSData*)data;
151 - (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey tamperCheck:(NSString*)tamperCheck error:(NSError**)error;
152
153 @end
154
155 @implementation SecDbKeychainAKSWrappedKey {
156 SecDbKeychainSerializedAKSWrappedKey* _serializedHolder;
157 }
158
159 - (instancetype)initRegularWrappedKeyWithData:(NSData*)wrappedKey
160 {
161 if (self = [super init]) {
162 _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] init];
163 _serializedHolder.wrappedKey = wrappedKey;
164 _serializedHolder.type = SecDbKeychainAKSWrappedKeyTypeRegular;
165 }
166
167 return self;
168 }
169
170 - (instancetype)initRefKeyWrappedKeyWithData:(NSData*)wrappedKey refKeyBlob:(NSData*)refKeyBlob
171 {
172 if (self = [super init]) {
173 _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] init];
174 _serializedHolder.wrappedKey = wrappedKey;
175 _serializedHolder.refKeyBlob = refKeyBlob;
176 _serializedHolder.type = SecDbKeychainAKSWrappedKeyTypeRefKey;
177 }
178
179 return self;
180 }
181
182 - (instancetype)initWithData:(NSData*)data
183 {
184 if (self = [super init]) {
185 _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] initWithData:data];
186 if (!_serializedHolder.wrappedKey || (_serializedHolder.type == SecDbKeychainAKSWrappedKeyTypeRefKey && !_serializedHolder.refKeyBlob)) {
187 self = nil;
188 }
189 }
190
191 return self;
192 }
193
194 - (NSData*)serializedRepresentation
195 {
196 return _serializedHolder.data;
197 }
198
199 - (NSData*)wrappedKey
200 {
201 return _serializedHolder.wrappedKey;
202 }
203
204 - (NSData*)refKeyBlob
205 {
206 return _serializedHolder.refKeyBlob;
207 }
208
209 - (SecDbKeychainAKSWrappedKeyType)type
210 {
211 return _serializedHolder.type;
212 }
213
214 @end
215
216 @implementation SecDbKeychainMetadata {
217 SecDbKeychainSerializedMetadata* _serializedHolder;
218 }
219
220 - (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SFAuthenticatedCiphertext*)wrappedKey tamperCheck:(NSString*)tamperCheck error:(NSError**)error
221 {
222 if (self = [super init]) {
223 _serializedHolder = [[SecDbKeychainSerializedMetadata alloc] init];
224 _serializedHolder.ciphertext = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:error];
225 _serializedHolder.wrappedKey = [NSKeyedArchiver archivedDataWithRootObject:wrappedKey requiringSecureCoding:YES error:error];
226 _serializedHolder.tamperCheck = tamperCheck;
227 if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) {
228 self = nil;
229 }
230 }
231
232 return self;
233 }
234
235 - (instancetype)initWithData:(NSData*)data
236 {
237 if (self = [super init]) {
238 _serializedHolder = [[SecDbKeychainSerializedMetadata alloc] initWithData:data];
239 if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) {
240 self = nil;
241 }
242 }
243
244 return self;
245 }
246
247 - (NSData*)serializedRepresentation
248 {
249 return _serializedHolder.data;
250 }
251
252 - (SFAuthenticatedCiphertext*)ciphertext
253 {
254 NSError* error = nil;
255 SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error];
256 if (!ciphertext) {
257 secerror("SecDbKeychainItemV7: error deserializing ciphertext from metadata: %@", error);
258 }
259
260 return ciphertext;
261 }
262
263 - (SFAuthenticatedCiphertext*)wrappedKey
264 {
265 NSError* error = nil;
266 SFAuthenticatedCiphertext* wrappedKey = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.wrappedKey error:&error];
267 if (!wrappedKey) {
268 secerror("SecDbKeychainItemV7: error deserializing wrappedKey from metadata: %@", error);
269 }
270
271 return wrappedKey;
272 }
273
274 - (NSString*)tamperCheck
275 {
276 return _serializedHolder.tamperCheck;
277 }
278
279 @end
280
281 @implementation SecDbKeychainSecretData {
282 SecDbKeychainSerializedSecretData* _serializedHolder;
283 }
284
285 - (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey tamperCheck:(NSString*)tamperCheck error:(NSError**)error
286 {
287 if (self = [super init]) {
288 _serializedHolder = [[SecDbKeychainSerializedSecretData alloc] init];
289 _serializedHolder.ciphertext = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:error];
290 _serializedHolder.wrappedKey = wrappedKey.serializedRepresentation;
291 _serializedHolder.tamperCheck = tamperCheck;
292 if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) {
293 self = nil;
294 }
295 }
296
297 return self;
298 }
299
300 - (instancetype)initWithData:(NSData*)data
301 {
302 if (self = [super init]) {
303 _serializedHolder = [[SecDbKeychainSerializedSecretData alloc] initWithData:data];
304 if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) {
305 self = nil;
306 }
307 }
308
309 return self;
310 }
311
312 - (NSData*)serializedRepresentation
313 {
314 return _serializedHolder.data;
315 }
316
317 - (SFAuthenticatedCiphertext*)ciphertext
318 {
319 NSError* error = nil;
320 SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error];
321 if (!ciphertext) {
322 secerror("SecDbKeychainItemV7: error deserializing ciphertext from secret data: %@", error);
323 }
324
325 return ciphertext;
326 }
327
328 - (SecDbKeychainAKSWrappedKey*)wrappedKey
329 {
330 return [[SecDbKeychainAKSWrappedKey alloc] initWithData:_serializedHolder.wrappedKey];
331 }
332
333 - (NSString*)tamperCheck
334 {
335 return _serializedHolder.tamperCheck;
336 }
337
338 @end
339
340 ////// SecDbKeychainMetadataKeyStore
341
342 @interface SecDbKeychainMetadataKeyStore ()
343 - (SFAESKey*)keyForKeyclass:(keyclass_t)keyClass
344 keybag:(keybag_handle_t)keybag
345 keySpecifier:(SFAESKeySpecifier*)keySpecifier
346 createKeyIfMissing:(bool)createIfMissing
347 overwriteCorruptKey:(bool)overwriteCorruptKey
348 error:(NSError**)error;
349 @end
350
351 static SecDbKeychainMetadataKeyStore* sharedStore = nil;
352 static dispatch_queue_t sharedMetadataStoreQueue;
353 static void initializeSharedMetadataStoreQueue(void) {
354 static dispatch_once_t onceToken;
355 dispatch_once(&onceToken, ^{
356 sharedMetadataStoreQueue = dispatch_queue_create("metadata_store", DISPATCH_QUEUE_SERIAL);
357 });
358 }
359
360 @implementation SecDbKeychainMetadataKeyStore {
361 NSMutableDictionary* _keysDict;
362 dispatch_queue_t _queue;
363 }
364
365 + (void)resetSharedStore
366 {
367 initializeSharedMetadataStoreQueue();
368 dispatch_sync(sharedMetadataStoreQueue, ^{
369 if(sharedStore) {
370 dispatch_sync(sharedStore->_queue, ^{
371 [sharedStore _onQueueDropAllKeys];
372 });
373 }
374 sharedStore = nil;
375 });
376 }
377
378 + (instancetype)sharedStore
379 {
380 __block SecDbKeychainMetadataKeyStore* ret;
381 initializeSharedMetadataStoreQueue();
382 dispatch_sync(sharedMetadataStoreQueue, ^{
383 if(!sharedStore) {
384 sharedStore = [[self alloc] _init];
385 }
386
387 ret = sharedStore;
388 });
389
390 return ret;
391 }
392
393 + (bool)cachingEnabled
394 {
395 return true;
396 }
397
398 - (instancetype)_init
399 {
400 if (self = [super init]) {
401 _keysDict = [[NSMutableDictionary alloc] init];
402 _queue = dispatch_queue_create("SecDbKeychainMetadataKeyStore", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
403 int token = 0;
404 __weak __typeof(self) weakSelf = self;
405 notify_register_dispatch(kUserKeybagStateChangeNotification, &token, _queue, ^(int inToken) {
406 bool locked = true;
407 CFErrorRef error = NULL;
408 if (!SecAKSGetIsLocked(&locked, &error)) {
409 secerror("SecDbKeychainMetadataKeyStore: error getting lock state: %@", error);
410 CFReleaseNull(error);
411 }
412
413 if (locked) {
414 [weakSelf _onQueueDropClassAKeys];
415 }
416 });
417 }
418
419 return self;
420 }
421
422 - (void)dropClassAKeys
423 {
424 dispatch_sync(_queue, ^{
425 [self _onQueueDropClassAKeys];
426 });
427 }
428
429 - (void)_onQueueDropClassAKeys
430 {
431 dispatch_assert_queue(_queue);
432
433 secnotice("SecDbKeychainMetadataKeyStore", "dropping class A metadata keys");
434 _keysDict[@(key_class_ak)] = nil;
435 _keysDict[@(key_class_aku)] = nil;
436 _keysDict[@(key_class_akpu)] = nil;
437 }
438
439 - (void)_onQueueDropAllKeys
440 {
441 dispatch_assert_queue(_queue);
442
443 secnotice("SecDbKeychainMetadataKeyStore", "dropping all metadata keys");
444 [_keysDict removeAllObjects];
445 }
446
447 - (void)_updateActualKeyclassIfNeeded:(keyclass_t)actualKeyclassToWriteBackToDB keyclass:(keyclass_t)keyclass
448 {
449 __block CFErrorRef cfError = NULL;
450
451 secnotice("SecDbKeychainItemV7", "saving actualKeyclass %d for metadata keyclass %d", actualKeyclassToWriteBackToDB, keyclass);
452
453 kc_with_dbt_non_item_tables(true, &cfError, ^bool(SecDbConnectionRef dbt) {
454 __block bool actualKeyWriteBackOk = true;
455
456 // we did not find an actualKeyclass entry in the db, so let's add one in now.
457 NSString *sql = @"UPDATE metadatakeys SET actualKeyclass = ? WHERE keyclass = ? AND actualKeyclass IS NULL";
458 __block CFErrorRef actualKeyWriteBackError = NULL;
459 actualKeyWriteBackOk &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &actualKeyWriteBackError, ^(sqlite3_stmt* stmt) {
460 actualKeyWriteBackOk &= SecDbBindInt(stmt, 1, actualKeyclassToWriteBackToDB, &actualKeyWriteBackError);
461 actualKeyWriteBackOk &= SecDbBindInt(stmt, 2, keyclass, &actualKeyWriteBackError);
462 actualKeyWriteBackOk &= SecDbStep(dbt, stmt, &actualKeyWriteBackError, ^(bool* stop) {
463 // woohoo
464 });
465 });
466
467 if (actualKeyWriteBackOk) {
468 secnotice("SecDbKeychainItemV7", "successfully saved actualKeyclass %d for metadata keyclass %d", actualKeyclassToWriteBackToDB, keyclass);
469
470 }
471 else {
472 // we can always try this again in the future if it failed
473 secerror("SecDbKeychainItemV7: failed to save actualKeyclass %d for metadata keyclass %d; error: %@", actualKeyclassToWriteBackToDB, keyclass, actualKeyWriteBackError);
474 }
475 return actualKeyWriteBackOk;
476 });
477 }
478
479 - (SFAESKey*)keyForKeyclass:(keyclass_t)keyclass
480 keybag:(keybag_handle_t)keybag
481 keySpecifier:(SFAESKeySpecifier*)keySpecifier
482 createKeyIfMissing:(bool)createIfMissing
483 overwriteCorruptKey:(bool)overwriteCorruptKey
484 error:(NSError**)error
485 {
486 __block SFAESKey* key = nil;
487 __block NSError* nsErrorLocal = nil;
488 __block CFErrorRef cfError = NULL;
489 static __thread BOOL reentrant = NO;
490
491 NSAssert(!reentrant, @"re-entering -[%@ %@] - that shouldn't happen!", NSStringFromClass(self.class), NSStringFromSelector(_cmd));
492 reentrant = YES;
493
494 #if USE_KEYSTORE
495 if (keyclass > key_class_last) {
496 // idea is that AKS may return a keyclass value with extra bits above key_class_last from aks_wrap_key, but we only keep metadata keys for the canonical key classes
497 // so just sanitize all our inputs to the canonical values
498 keyclass_t sanitizedKeyclass = keyclass & key_class_last;
499 secinfo("SecDbKeychainItemV7", "sanitizing request for metadata keyclass %d to keyclass %d", keyclass, sanitizedKeyclass);
500 keyclass = sanitizedKeyclass;
501 }
502 #endif
503
504 dispatch_sync(_queue, ^{
505 // if we think we're locked, it's possible AKS will still give us access to keys, such as during backup,
506 // but we should force AKS to be the truth and not used cached class A keys while locked
507 bool allowKeyCaching = [SecDbKeychainMetadataKeyStore cachingEnabled];
508
509 // However, we must not cache a newly-created key, just in case someone above us in the stack rolls back our database transaction and the stored key is lost.
510 __block bool keyIsNewlyCreated = false;
511 #if 0
512 // <rdar://problem/37523001> Fix keychain lock state check to be both secure and fast for EDU mode
513 if (![SecDbKeychainItemV7 isKeychainUnlocked]) {
514 [self _onQueueDropClassAKeys];
515 allowKeyCaching = !(keyclass == key_class_ak || keyclass == key_class_aku || keyclass == key_class_akpu);
516 }
517 #endif
518
519 key = allowKeyCaching ? self->_keysDict[@(keyclass)] : nil;
520 if (!key) {
521 __block bool ok = true;
522 __block bool metadataKeyDoesntAuthenticate = false;
523 ok &= kc_with_dbt_non_item_tables(createIfMissing, &cfError, ^bool(SecDbConnectionRef dbt) {
524 __block NSString* sql = [NSString stringWithFormat:@"SELECT data, actualKeyclass FROM metadatakeys WHERE keyclass = %d", keyclass];
525 ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) {
526 ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) {
527 NSData* wrappedKeyData = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)];
528 NSMutableData* unwrappedKeyData = [NSMutableData dataWithLength:wrappedKeyData.length];
529
530 keyclass_t actualKeyclass = sqlite3_column_int(stmt, 1);
531
532 keyclass_t actualKeyclassToWriteBackToDB = 0;
533 keyclass_t keyclassForUnwrapping = actualKeyclass == 0 ? keyclass : actualKeyclass;
534 ok &= [SecDbKeychainItemV7 aksDecryptWithKeybag:keybag keyclass:keyclassForUnwrapping wrappedKeyData:wrappedKeyData outKeyclass:NULL unwrappedKey:unwrappedKeyData error:&nsErrorLocal];
535 if (ok) {
536 key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&nsErrorLocal];
537
538 if(!key) {
539 os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) decrypted, but didn't become a key: %@", keyclass, nsErrorLocal);
540 }
541
542 if (actualKeyclass == 0) {
543 actualKeyclassToWriteBackToDB = keyclassForUnwrapping;
544 }
545 }
546 #if USE_KEYSTORE
547 else if (actualKeyclass == 0 && keyclass <= key_class_last) {
548 // in this case we might have luck decrypting with a key-rolled keyclass
549 keyclass_t keyrolledKeyclass = keyclass | (key_class_last + 1);
550 secerror("SecDbKeychainItemV7: failed to decrypt metadata key for class %d, but trying keyrolled keyclass (%d); error: %@", keyclass, keyrolledKeyclass, nsErrorLocal);
551
552 // we don't want to pollute subsequent error-handling logic with what happens on our retry
553 // we'll give it a shot, and if it works, great - if it doesn't work, we'll just report that error in the log and move on
554 NSError* retryError = nil;
555 ok = [SecDbKeychainItemV7 aksDecryptWithKeybag:keybag keyclass:keyrolledKeyclass wrappedKeyData:wrappedKeyData outKeyclass:NULL unwrappedKey:unwrappedKeyData error:&retryError];
556
557 if (ok) {
558 secerror("SecDbKeychainItemV7: successfully decrypted metadata key using keyrolled keyclass %d", keyrolledKeyclass);
559 key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&retryError];
560
561 if(!key) {
562 os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) decrypted using keyrolled keyclass %d, but didn't become a key: %@", keyclass, keyrolledKeyclass, retryError);
563 nsErrorLocal = retryError;
564 }
565 }
566 else {
567 secerror("SecDbKeychainItemV7: failed to decrypt metadata key with keyrolled keyclass %d; error: %@", keyrolledKeyclass, retryError);
568 }
569 }
570 #endif
571
572 if (ok && key) {
573 if (actualKeyclassToWriteBackToDB > 0) {
574 // check if we have updated this keyclass or not already
575 static NSMutableDictionary* updated = NULL;
576 if (!updated) {
577 updated = [NSMutableDictionary dictionary];
578 }
579 if (!updated[@(keyclass)]) {
580 updated[@(keyclass)] = @YES;
581 dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
582 [self _updateActualKeyclassIfNeeded:actualKeyclassToWriteBackToDB keyclass:keyclass];
583 });
584 }
585 }
586 }
587 else {
588 if (nsErrorLocal && [nsErrorLocal.domain isEqualToString:(__bridge NSString*)kSecErrorDomain] && nsErrorLocal.code == errSecInteractionNotAllowed) {
589 static dispatch_once_t kclockedtoken;
590 static sec_action_t kclockedaction;
591 dispatch_once(&kclockedtoken, ^{
592 kclockedaction = sec_action_create("keychainlockedlogmessage", 1);
593 sec_action_set_handler(kclockedaction, ^{
594 secerror("SecDbKeychainItemV7: failed to decrypt metadata key because the keychain is locked (%d)", (int)errSecInteractionNotAllowed);
595 });
596 });
597 sec_action_perform(kclockedaction);
598 } else {
599 secerror("SecDbKeychainItemV7: failed to decrypt and create metadata key for class %d; error: %@", keyclass, nsErrorLocal);
600
601 // If this error is errSecDecode, then it's failed authentication and likely will forever. Other errors are scary.
602 metadataKeyDoesntAuthenticate = [nsErrorLocal.domain isEqualToString:NSOSStatusErrorDomain] && nsErrorLocal.code == errSecDecode;
603 if(metadataKeyDoesntAuthenticate) {
604 os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) failed to decrypt: %@", keyclass, nsErrorLocal);
605 }
606 }
607 }
608 });
609 });
610
611 bool keyNotYetCreated = ok && !key;
612 bool forceOverwriteBadKey = !key && metadataKeyDoesntAuthenticate && overwriteCorruptKey;
613
614 if (createIfMissing && (keyNotYetCreated || forceOverwriteBadKey)) {
615 // we completed the database query, but no key exists or it's broken - we should create one
616 if(forceOverwriteBadKey) {
617 secerror("SecDbKeychainItemV7: metadata key is irreparably corrupt; throwing away forever");
618 // TODO: track this in LocalKeychainAnalytics
619 }
620
621 ok = true; // Reset 'ok': we have a second chance
622
623 key = [[SFAESKey alloc] initRandomKeyWithSpecifier:keySpecifier error:&nsErrorLocal];
624 keyIsNewlyCreated = true;
625
626 if (key) {
627 NSMutableData* wrappedKey = [NSMutableData dataWithLength:key.keyData.length + 40];
628 keyclass_t outKeyclass = keyclass;
629 ok &= [SecDbKeychainItemV7 aksEncryptWithKeybag:keybag keyclass:keyclass keyData:key.keyData outKeyclass:&outKeyclass wrappedKey:wrappedKey error:&nsErrorLocal];
630 if (ok) {
631 secinfo("SecDbKeychainItemV7", "attempting to save new metadata key for keyclass %d with actualKeyclass %d", keyclass, outKeyclass);
632 NSString* insertString = forceOverwriteBadKey ? @"INSERT OR REPLACE" : @"INSERT";
633 sql = [NSString stringWithFormat:@"%@ into metadatakeys (keyclass, actualKeyclass, data) VALUES (?, ?, ?)", insertString];
634 ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt* stmt) {
635 ok &= SecDbBindInt(stmt, 1, keyclass, &cfError);
636 ok &= SecDbBindInt(stmt, 2, outKeyclass, &cfError);
637 ok &= SecDbBindBlob(stmt, 3, wrappedKey.bytes, wrappedKey.length, SQLITE_TRANSIENT, NULL);
638 ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) {
639 // woohoo
640 });
641 });
642
643 if (ok) {
644 secnotice("SecDbKeychainItemV7", "successfully saved new metadata key for keyclass %d", keyclass);
645 }
646 else {
647 secerror("SecDbKeychainItemV7: failed to save new metadata key for keyclass %d - probably there is already one in the database: %@", keyclass, cfError);
648 }
649 } else {
650 secerror("SecDbKeychainItemV7: unable to encrypt new metadata key(%d) with keybag(%d): %@", keyclass, keybag, nsErrorLocal);
651 }
652 }
653 else {
654 ok = false;
655 }
656 } else if(!key) {
657 // No key, but we're not supposed to make one. Make an error if one doesn't yet exist.
658 ok = false;
659 if(!nsErrorLocal) {
660 nsErrorLocal = [NSError errorWithDomain:(id)kSecErrorDomain code:errSecDecode userInfo:@{NSLocalizedDescriptionKey: @"Unable to find or create a suitable metadata key"}];
661 }
662 }
663
664 return ok;
665 });
666
667 if (ok && key) {
668 // We can't cache a newly-created key, just in case this db transaction is rolled back and we lose the persisted key.
669 // Don't worry, we'll cache it as soon as it's used again.
670 if (allowKeyCaching && !keyIsNewlyCreated) {
671 self->_keysDict[@(keyclass)] = key;
672 __weak __typeof(self) weakSelf = self;
673 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60 * 5 * NSEC_PER_SEC)), self->_queue, ^{
674 [weakSelf _onQueueDropClassAKeys];
675 });
676 }
677 }
678 else {
679 key = nil;
680 }
681 }
682 });
683
684 reentrant = NO;
685
686 if (error && nsErrorLocal) {
687 *error = nsErrorLocal;
688 CFReleaseNull(cfError);
689 }
690 else {
691 BridgeCFErrorToNSErrorOut(error, cfError);
692 }
693
694 return key;
695 }
696
697 @end
698
699 @implementation SecDbKeychainItemV7 {
700 SecDbKeychainSecretData* _encryptedSecretData;
701 SecDbKeychainMetadata* _encryptedMetadata;
702 NSDictionary* _secretAttributes;
703 NSDictionary* _metadataAttributes;
704 NSString* _tamperCheck;
705 keyclass_t _keyclass;
706 keybag_handle_t _keybag;
707 }
708
709 @synthesize keyclass = _keyclass;
710
711 + (bool)aksEncryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass keyData:(NSData*)keyData outKeyclass:(keyclass_t*)outKeyclass wrappedKey:(NSMutableData*)wrappedKey error:(NSError**)error
712 {
713 CFErrorRef cfError = NULL;
714 bool result = ks_crypt(kAKSKeyOpEncrypt, keybag, keyclass, (uint32_t)keyData.length, keyData.bytes, outKeyclass, (__bridge CFMutableDataRef)wrappedKey, &cfError);
715 BridgeCFErrorToNSErrorOut(error, cfError);
716 return result;
717 }
718
719 + (bool)aksDecryptWithKeybag:(keybag_handle_t)keybag keyclass:(keyclass_t)keyclass wrappedKeyData:(NSData*)wrappedKeyData outKeyclass:(keyclass_t*)outKeyclass unwrappedKey:(NSMutableData*)unwrappedKey error:(NSError**)error
720 {
721 CFErrorRef cfError = NULL;
722 bool result = ks_crypt(kAKSKeyOpDecrypt, keybag, keyclass, (uint32_t)wrappedKeyData.length, wrappedKeyData.bytes, outKeyclass, (__bridge CFMutableDataRef)unwrappedKey, &cfError);
723 BridgeCFErrorToNSErrorOut(error, cfError);
724 return result;
725 }
726
727 // bring back with <rdar://problem/37523001>
728 #if 0
729 + (bool)isKeychainUnlocked
730 {
731 return kc_is_unlocked();
732 }
733 #endif
734
735 - (instancetype)initWithData:(NSData*)data decryptionKeybag:(keybag_handle_t)decryptionKeybag error:(NSError**)error
736 {
737 if (self = [super init]) {
738 SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] initWithData:data];
739 if (serializedItem) {
740 _keybag = decryptionKeybag;
741 _encryptedSecretData = [[SecDbKeychainSecretData alloc] initWithData:serializedItem.encryptedSecretData];
742 _encryptedMetadata = [[SecDbKeychainMetadata alloc] initWithData:serializedItem.encryptedMetadata];
743 _keyclass = serializedItem.keyclass;
744 if (![_encryptedSecretData.tamperCheck isEqualToString:_encryptedMetadata.tamperCheck]) {
745 self = nil;
746 }
747 }
748 else {
749 self = nil;
750 }
751 }
752
753 if (!self && error) {
754 *error = [NSError errorWithDomain:(id)kCFErrorDomainOSStatus code:errSecItemNotFound userInfo:@{NSLocalizedDescriptionKey : @"failed to deserialize keychain item blob"}];
755 }
756
757 return self;
758 }
759
760 - (instancetype)initWithSecretAttributes:(NSDictionary*)secretAttributes metadataAttributes:(NSDictionary*)metadataAttributes tamperCheck:(NSString*)tamperCheck keyclass:(keyclass_t)keyclass
761 {
762 NSParameterAssert(tamperCheck);
763
764 if (self = [super init]) {
765 _secretAttributes = secretAttributes ? secretAttributes.copy : [NSDictionary dictionary];
766 _metadataAttributes = metadataAttributes ? metadataAttributes.copy : [NSDictionary dictionary];
767 _tamperCheck = tamperCheck.copy;
768 _keyclass = keyclass;
769 }
770
771 return self;
772 }
773
774 + (SFAESKeySpecifier*)keySpecifier
775 {
776 static SFAESKeySpecifier* keySpecifier = nil;
777 static dispatch_once_t onceToken;
778 dispatch_once(&onceToken, ^{
779 keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256];
780 });
781
782 return keySpecifier;
783 }
784
785 + (SFAuthenticatedEncryptionOperation*)encryptionOperation
786 {
787 static SFAuthenticatedEncryptionOperation* encryptionOperation = nil;
788 static dispatch_once_t onceToken;
789 dispatch_once(&onceToken, ^{
790 encryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[self keySpecifier]];
791 });
792
793 return encryptionOperation;
794 }
795
796 + (SFAuthenticatedEncryptionOperation*)decryptionOperation
797 {
798 static SFAuthenticatedEncryptionOperation* decryptionOperation = nil;
799 static dispatch_once_t onceToken;
800 dispatch_once(&onceToken, ^{
801 decryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[self keySpecifier]];
802 });
803
804 return decryptionOperation;
805 }
806
807 - (NSDictionary*)metadataAttributesWithError:(NSError**)error
808 {
809 if (!_metadataAttributes) {
810 SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:_keybag
811 createKeyIfMissing:false
812 overwriteCorruptKey:false
813 error:error];
814 if (metadataClassKey) {
815 NSError* localError = nil;
816 NSData* keyData = [[self.class decryptionOperation] decrypt:_encryptedMetadata.wrappedKey withKey:metadataClassKey error:&localError];
817 if (!keyData) {
818 secerror("SecDbKeychainItemV7: error unwrapping item metadata key (class %d, bag %d): %@", (int)self.keyclass, _keybag, localError);
819 // TODO: track this in LocalKeychainAnalytics
820 if (error) {
821 CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error
822 SecError(errSecDecode, &secError, CFSTR("failed to unwrap item metadata key"));
823 *error = CFBridgingRelease(secError);
824 }
825 return nil;
826 }
827 SFAESKey* key = [[SFAESKey alloc] initWithData:keyData specifier:[self.class keySpecifier] error:error];
828 if (!key) {
829 return nil;
830 }
831
832 NSData* metadata = [[self.class decryptionOperation] decrypt:_encryptedMetadata.ciphertext withKey:key error:&localError];
833 if (!metadata) {
834 secerror("SecDbKeychainItemV7: error decrypting metadata content: %@", localError);
835 if (error) {
836 CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error
837 SecError(errSecDecode, &secError, CFSTR("failed to decrypt item metadata contents"));
838 *error = CFBridgingRelease(secError);
839 }
840 return nil;
841 }
842 NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(metadata).mutableCopy;
843 NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck];
844 if ([tamperCheck isEqualToString:_encryptedMetadata.tamperCheck]) {
845 [decryptedAttributes removeObjectForKey:SecDBTamperCheck];
846 _metadataAttributes = decryptedAttributes;
847 }
848 else {
849 secerror("SecDbKeychainItemV7: tamper check failed for metadata decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck);
850 if (error) {
851 CFErrorRef secError = NULL;
852 SecError(errSecDecode, &secError, CFSTR("tamper check failed for metadata decryption"));
853 *error = CFBridgingRelease(secError);
854 }
855 }
856 }
857 }
858
859 return _metadataAttributes;
860 }
861
862 - (NSDictionary*)secretAttributesWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error
863 {
864 if (!_secretAttributes) {
865 SFAESKey* key = [self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:NO error:error];
866 if (key) {
867 NSError* localError = nil;
868 NSData* secretDataWithPadding = [[self.class decryptionOperation] decrypt:_encryptedSecretData.ciphertext withKey:key error:&localError];
869 if (!secretDataWithPadding) {
870 secerror("SecDbKeychainItemV7: error decrypting item secret data contents: %@", localError);
871 if (error) {
872 CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error
873 SecError(errSecDecode, &secError, CFSTR("error decrypting item secret data contents"));
874 *error = CFBridgingRelease(secError);
875 }
876 return nil;
877 }
878 int8_t paddingLength = *((int8_t*)secretDataWithPadding.bytes + secretDataWithPadding.length - 1);
879 NSData* secretDataWithoutPadding = [secretDataWithPadding subdataWithRange:NSMakeRange(0, secretDataWithPadding.length - paddingLength)];
880
881 NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(secretDataWithoutPadding).mutableCopy;
882 NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck];
883 if ([tamperCheck isEqualToString:_encryptedSecretData.tamperCheck]) {
884 [decryptedAttributes removeObjectForKey:SecDBTamperCheck];
885 _secretAttributes = decryptedAttributes;
886 }
887 else {
888 secerror("SecDbKeychainItemV7: tamper check failed for secret data decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck);
889 }
890 }
891 }
892
893 return _secretAttributes;
894 }
895
896 - (BOOL)deleteWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error
897 {
898 NSError* localError = nil;
899 (void)[self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:YES error:&localError];
900 if (localError) {
901 secerror("SecDbKeychainItemV7: failed to delete item secret key from aks");
902 if (error) {
903 *error = localError;
904 }
905
906 return NO;
907 }
908
909 return YES;
910 }
911
912 - (NSData*)encryptedBlobWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error
913 {
914 NSError* localError = nil;
915 BOOL success = [self encryptMetadataWithKeybag:keybag error:&localError];
916 if (!success || !_encryptedMetadata || localError) {
917 if (error) {
918 *error = localError;
919 }
920 return nil;
921 }
922
923 success = [self encryptSecretDataWithKeybag:keybag accessControl:accessControl acmContext:acmContext error:&localError];
924 if (!success || !_encryptedSecretData || localError) {
925 if (error) {
926 *error = localError;
927 }
928 return nil;
929 }
930
931 SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] init];
932 serializedItem.encryptedMetadata = self.encryptedMetadataBlob;
933 serializedItem.encryptedSecretData = self.encryptedSecretDataBlob;
934 serializedItem.keyclass = _keyclass;
935 return serializedItem.data;
936 }
937
938 - (NSData*)encryptedMetadataBlob
939 {
940 return _encryptedMetadata.serializedRepresentation;
941 }
942
943 - (NSData*)encryptedSecretDataBlob
944 {
945 return _encryptedSecretData.serializedRepresentation;
946 }
947
948 - (BOOL)encryptMetadataWithKeybag:(keybag_handle_t)keybag error:(NSError**)error
949 {
950 SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error];
951 if (!key) {
952 return NO;
953 }
954 SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation];
955
956 NSMutableDictionary* attributesToEncrypt = _metadataAttributes.mutableCopy;
957 attributesToEncrypt[SecDBTamperCheck] = _tamperCheck;
958 NSData* metadata = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL);
959 SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:metadata withKey:key error:error];
960
961 SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:keybag
962 createKeyIfMissing:true
963 overwriteCorruptKey:true
964 error:error];
965 if (metadataClassKey) {
966 SFAuthenticatedCiphertext* wrappedKey = [encryptionOperation encrypt:key.keyData withKey:metadataClassKey error:error];
967 _encryptedMetadata = [[SecDbKeychainMetadata alloc] initWithCiphertext:ciphertext wrappedKey:wrappedKey tamperCheck:_tamperCheck error:error];
968 }
969
970 return _encryptedMetadata != nil;
971 }
972
973 - (BOOL)encryptSecretDataWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error
974 {
975 SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error];
976 if (!key) {
977 return NO;
978 }
979 SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation];
980
981 NSMutableDictionary* attributesToEncrypt = _secretAttributes.mutableCopy;
982 attributesToEncrypt[SecDBTamperCheck] = _tamperCheck;
983 NSMutableData* secretData = [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL) mutableCopy];
984
985 int8_t paddingLength = KEYCHAIN_ITEM_PADDING_MODULUS - (secretData.length % KEYCHAIN_ITEM_PADDING_MODULUS);
986 int8_t paddingBytes[KEYCHAIN_ITEM_PADDING_MODULUS];
987 for (int i = 0; i < KEYCHAIN_ITEM_PADDING_MODULUS; i++) {
988 paddingBytes[i] = paddingLength;
989 }
990 [secretData appendBytes:paddingBytes length:paddingLength];
991
992 SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:secretData withKey:key error:error];
993 SecDbKeychainAKSWrappedKey* wrappedKey = [self wrapToAKS:key withKeybag:keybag accessControl:accessControl acmContext:acmContext error:error];
994
995 _encryptedSecretData = [[SecDbKeychainSecretData alloc] initWithCiphertext:ciphertext wrappedKey:wrappedKey tamperCheck:_tamperCheck error:error];
996 return _encryptedSecretData != nil;
997 }
998
999 - (SFAESKey*)metadataClassKeyWithKeybag:(keybag_handle_t)keybag
1000 createKeyIfMissing:(bool)createIfMissing
1001 overwriteCorruptKey:(bool)force
1002 error:(NSError**)error
1003 {
1004 return [[SecDbKeychainMetadataKeyStore sharedStore] keyForKeyclass:_keyclass
1005 keybag:keybag
1006 keySpecifier:[self.class keySpecifier]
1007 createKeyIfMissing:(bool)createIfMissing
1008 overwriteCorruptKey:force
1009 error:error];
1010 }
1011
1012 - (SecDbKeychainAKSWrappedKey*)wrapToAKS:(SFAESKey*)key withKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error
1013 {
1014 NSData* keyData = key.keyData;
1015
1016 #if USE_KEYSTORE
1017 NSDictionary* constraints = (__bridge NSDictionary*)SecAccessControlGetConstraints(accessControl);
1018 if (constraints) {
1019 aks_ref_key_t refKey = NULL;
1020 CFErrorRef cfError = NULL;
1021 NSData* authData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)@{(id)kAKSKeyAcl : constraints}, &cfError);
1022
1023 if (!acmContext || !SecAccessControlIsBound(accessControl)) {
1024 secerror("SecDbKeychainItemV7: access control error");
1025 if (error) {
1026 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
1027 ks_access_control_needed_error(&cfError, accessControlData, SecAccessControlIsBound(accessControl) ? kAKSKeyOpEncrypt : CFSTR(""));
1028 CFReleaseNull(accessControlData);
1029 }
1030
1031 BridgeCFErrorToNSErrorOut(error, cfError);
1032 return nil;
1033 }
1034
1035 void* aksParams = NULL;
1036 size_t aksParamsLength = 0;
1037 aks_operation_optional_params(0, 0, authData.bytes, authData.length, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength);
1038
1039 int aksResult = aks_ref_key_create(keybag, _keyclass, key_type_sym, aksParams, aksParamsLength, &refKey);
1040 if (aksResult != 0) {
1041 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
1042 create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError);
1043 CFReleaseNull(accessControlData);
1044 free(aksParams);
1045 BridgeCFErrorToNSErrorOut(error, cfError);
1046 return nil;
1047 }
1048
1049 size_t wrappedKeySize = 0;
1050 void* wrappedKeyBytes = NULL;
1051 aksResult = aks_ref_key_encrypt(refKey, aksParams, aksParamsLength, keyData.bytes, keyData.length, &wrappedKeyBytes, &wrappedKeySize);
1052 if (aksResult != 0) {
1053 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
1054 create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError);
1055 CFReleaseNull(accessControlData);
1056 free(aksParams);
1057 aks_ref_key_free(&refKey);
1058 BridgeCFErrorToNSErrorOut(error, cfError);
1059 return nil;
1060 }
1061 free(aksParams);
1062
1063 BridgeCFErrorToNSErrorOut(error, cfError);
1064
1065 NSData* wrappedKey = [[NSData alloc] initWithBytesNoCopy:wrappedKeyBytes length:wrappedKeySize];
1066
1067 size_t refKeyBlobLength = 0;
1068 const void* refKeyBlobBytes = aks_ref_key_get_blob(refKey, &refKeyBlobLength);
1069 NSData* refKeyBlob = [[NSData alloc] initWithBytesNoCopy:(void*)refKeyBlobBytes length:refKeyBlobLength];
1070 aks_ref_key_free(&refKey);
1071 return [[SecDbKeychainAKSWrappedKey alloc] initRefKeyWrappedKeyWithData:wrappedKey refKeyBlob:refKeyBlob];
1072 }
1073 else {
1074 NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40];
1075 bool success = [self.class aksEncryptWithKeybag:keybag keyclass:_keyclass keyData:keyData outKeyclass:&_keyclass wrappedKey:wrappedKey error:error];
1076 return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil;
1077 }
1078 #else
1079 NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40];
1080 bool success = [self.class aksEncryptWithKeybag:keybag keyclass:_keyclass keyData:keyData outKeyclass:&_keyclass wrappedKey:wrappedKey error:error];
1081 return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil;
1082 #endif
1083 }
1084
1085 - (SFAESKey*)unwrapFromAKS:(SecDbKeychainAKSWrappedKey*)wrappedKey accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext callerAccessGroups:(NSArray*)callerAccessGroups delete:(BOOL)delete error:(NSError**)error
1086 {
1087 NSData* wrappedKeyData = wrappedKey.wrappedKey;
1088
1089 if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRegular) {
1090 NSMutableData* unwrappedKey = [NSMutableData dataWithCapacity:wrappedKeyData.length + 40];
1091 unwrappedKey.length = wrappedKeyData.length + 40;
1092 bool result = [self.class aksDecryptWithKeybag:_keybag keyclass:_keyclass wrappedKeyData:wrappedKeyData outKeyclass:&_keyclass unwrappedKey:unwrappedKey error:error];
1093 if (result) {
1094 return [[SFAESKey alloc] initWithData:unwrappedKey specifier:[self.class keySpecifier] error:error];
1095 }
1096 else {
1097 return nil;
1098 }
1099 }
1100 #if USE_KEYSTORE
1101 else if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRefKey) {
1102 aks_ref_key_t refKey = NULL;
1103 aks_ref_key_create_with_blob(_keybag, wrappedKey.refKeyBlob.bytes, wrappedKey.refKeyBlob.length, &refKey);
1104
1105 CFErrorRef cfError = NULL;
1106 size_t refKeyExternalDataLength = 0;
1107 const uint8_t* refKeyExternalDataBytes = aks_ref_key_get_external_data(refKey, &refKeyExternalDataLength);
1108 if (!refKeyExternalDataBytes) {
1109 aks_ref_key_free(&refKey);
1110 return nil;
1111 }
1112 NSDictionary* aclDict = nil;
1113 der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)(void*)&aclDict, &cfError, refKeyExternalDataBytes, refKeyExternalDataBytes + refKeyExternalDataLength);
1114 if (!aclDict) {
1115 SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decode acl dict"));
1116 }
1117 SecAccessControlSetConstraints(accessControl, (__bridge CFDictionaryRef)aclDict);
1118 if (!SecAccessControlGetConstraint(accessControl, kAKSKeyOpEncrypt)) {
1119 SecAccessControlAddConstraintForOperation(accessControl, kAKSKeyOpEncrypt, kCFBooleanTrue, &cfError);
1120 }
1121
1122 size_t derPlistLength = der_sizeof_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError);
1123 NSMutableData* accessGroupDERData = [[NSMutableData alloc] initWithLength:derPlistLength];
1124 der_encode_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError, accessGroupDERData.mutableBytes, accessGroupDERData.mutableBytes + derPlistLength);
1125 void* aksParams = NULL;
1126 size_t aksParamsLength = 0;
1127 aks_operation_optional_params(accessGroupDERData.bytes, derPlistLength, NULL, 0, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength);
1128
1129 void* unwrappedKeyDERData = NULL;
1130 size_t unwrappedKeyDERLength = 0;
1131 int aksResult = aks_ref_key_decrypt(refKey, aksParams, aksParamsLength, wrappedKeyData.bytes, wrappedKeyData.length, &unwrappedKeyDERData, &unwrappedKeyDERLength);
1132 if (aksResult != 0) {
1133 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
1134 create_cferror_from_aks(aksResult, kAKSKeyOpDecrypt, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError);
1135 CFReleaseNull(accessControlData);
1136 aks_ref_key_free(&refKey);
1137 free(aksParams);
1138 BridgeCFErrorToNSErrorOut(error, cfError);
1139 return nil;
1140 }
1141 if (!unwrappedKeyDERData) {
1142 SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item."));
1143 aks_ref_key_free(&refKey);
1144 free(aksParams);
1145 BridgeCFErrorToNSErrorOut(error, cfError);
1146 return nil;
1147 }
1148
1149 CFPropertyListRef unwrappedKeyData = NULL;
1150 der_decode_plist(NULL, kCFPropertyListImmutable, &unwrappedKeyData, &cfError, unwrappedKeyDERData, unwrappedKeyDERData + unwrappedKeyDERLength);
1151 SFAESKey* result = nil;
1152 if ([(__bridge NSData*)unwrappedKeyData isKindOfClass:[NSData class]]) {
1153 result = [[SFAESKey alloc] initWithData:(__bridge NSData*)unwrappedKeyData specifier:[self.class keySpecifier] error:error];
1154 CFReleaseNull(unwrappedKeyDERData);
1155 }
1156 else {
1157 SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item."));
1158 aks_ref_key_free(&refKey);
1159 free(aksParams);
1160 free(unwrappedKeyDERData);
1161 BridgeCFErrorToNSErrorOut(error, cfError);
1162 return nil;
1163 }
1164
1165 if (delete) {
1166 aksResult = aks_ref_key_delete(refKey, aksParams, aksParamsLength);
1167 if (aksResult != 0) {
1168 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
1169 create_cferror_from_aks(aksResult, kAKSKeyOpDelete, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError);
1170 CFReleaseNull(accessControlData);
1171 aks_ref_key_free(&refKey);
1172 free(aksParams);
1173 free(unwrappedKeyDERData);
1174 BridgeCFErrorToNSErrorOut(error, cfError);
1175 return nil;
1176 }
1177 }
1178
1179 BridgeCFErrorToNSErrorOut(error, cfError);
1180 aks_ref_key_free(&refKey);
1181 free(aksParams);
1182 free(unwrappedKeyDERData);
1183 return result;
1184 }
1185 #endif
1186 else {
1187 return nil;
1188 }
1189 }
1190
1191 @end
1192
1193 #endif // TARGET_OS_BRIDGE