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 <dispatch/dispatch.h> 33 #import <utilities/SecAKSWrappers.h> 34 #import "SecAKSObjCWrappers.h" 35 #import <utilities/der_plist.h> 36 #import <SecurityFoundation/SFEncryptionOperation.h> 37 #import <SecurityFoundation/SFKey_Private.h> 38 #import <SecurityFoundation/SFCryptoServicesErrors.h> 39 40 #import <Foundation/NSKeyedArchiver_Private.h> 41 42 #if USE_KEYSTORE && __has_include(<Kernel/IOKit/crypto/AppleKeyStoreDefs.h>) 43 #import <Kernel/IOKit/crypto/AppleKeyStoreDefs.h> 44 #endif 45 46 #import "SecDbKeychainMetadataKeyStore.h" 47 #import "SecDbBackupManager.h" 48 49 #define KEYCHAIN_ITEM_PADDING_MODULUS 20 50 51 // See corresponding "reasonable size" client-side limit(s) in SecItem. 52 53 // Generally the secret data dictionary contains a single key 54 // with the client's password/key NSData therein, so 4k feels extremely luxurious 55 #define REASONABLE_SECRET_DATA_SIZE 4096 56 57 // This feels similarly generous, but let's find out 58 #define REASONABLE_METADATA_SIZE 2048 59 60 NSString* const SecDbKeychainErrorDomain = @"SecDbKeychainErrorDomain"; 61 const NSInteger SecDbKeychainErrorDeserializationFailed = 1; 62 63 static NSString* const SecDBTamperCheck = @"TamperCheck"; 64 65 static NSDictionary* dictionaryFromDERData(NSData* data) 66 { 67 NSDictionary* dict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)data, 0, NULL, NULL); 68 return [dict isKindOfClass:[NSDictionary class]] ? dict : nil; 69 } 70 71 typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) { 72 SecDbKeychainAKSWrappedKeyTypeRegular, 73 SecDbKeychainAKSWrappedKeyTypeRefKey 74 }; 75 76 @interface SecDbKeychainAKSWrappedKey : NSObject 77 78 @property (readonly) NSData* wrappedKey; 79 @property (readonly) NSData* refKeyBlob; 80 @property (readonly) SecDbKeychainAKSWrappedKeyType type; 81 82 @property (readonly) NSData* serializedRepresentation; 83 84 - (instancetype)initWithData:(NSData*)data; 85 - (instancetype)initRegularWrappedKeyWithData:(NSData*)wrappedKey; 86 - (instancetype)initRefKeyWrappedKeyWithData:(NSData*)wrappedKey refKeyBlob:(NSData*)refKeyBlob; 87 88 @end 89 90 @interface SecDbKeychainMetadata : NSObject 91 92 @property (readonly) SFAuthenticatedCiphertext* ciphertext; 93 @property (readonly) SFAuthenticatedCiphertext* wrappedKey; 94 @property (readonly) NSString* tamperCheck; 95 96 @property (readonly) NSData* serializedRepresentation; 97 98 - (instancetype)initWithData:(NSData*)data; 99 - (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SFAuthenticatedCiphertext*)wrappedKey tamperCheck:(NSString*)tamperCheck error:(NSError**)error; 100 101 @end 102 103 @interface SecDbKeychainSecretData : NSObject 104 105 @property (readonly) SFAuthenticatedCiphertext* ciphertext; 106 @property (readonly) SecDbKeychainAKSWrappedKey* wrappedKey; 107 @property (readonly) NSString* tamperCheck; 108 109 @property (readonly) NSData* serializedRepresentation; 110 111 - (instancetype)initWithData:(NSData*)data; 112 - (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey tamperCheck:(NSString*)tamperCheck backupWrappedKey:(SecDbBackupWrappedKey*)backupWrappedKey error:(NSError**)error; 113 114 @end 115 116 @implementation SecDbKeychainAKSWrappedKey { 117 SecDbKeychainSerializedAKSWrappedKey* _serializedHolder; 118 } 119 120 - (instancetype)initRegularWrappedKeyWithData:(NSData*)wrappedKey 121 { 122 if (self = [super init]) { 123 _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] init]; 124 _serializedHolder.wrappedKey = wrappedKey; 125 _serializedHolder.type = SecDbKeychainAKSWrappedKeyTypeRegular; 126 } 127 128 return self; 129 } 130 131 - (instancetype)initRefKeyWrappedKeyWithData:(NSData*)wrappedKey refKeyBlob:(NSData*)refKeyBlob 132 { 133 if (self = [super init]) { 134 _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] init]; 135 _serializedHolder.wrappedKey = wrappedKey; 136 _serializedHolder.refKeyBlob = refKeyBlob; 137 _serializedHolder.type = SecDbKeychainAKSWrappedKeyTypeRefKey; 138 } 139 140 return self; 141 } 142 143 - (instancetype)initWithData:(NSData*)data 144 { 145 if (self = [super init]) { 146 _serializedHolder = [[SecDbKeychainSerializedAKSWrappedKey alloc] initWithData:data]; 147 if (!_serializedHolder.wrappedKey || (_serializedHolder.type == SecDbKeychainAKSWrappedKeyTypeRefKey && !_serializedHolder.refKeyBlob)) { 148 self = nil; 149 } 150 } 151 152 return self; 153 } 154 155 - (NSData*)serializedRepresentation 156 { 157 return _serializedHolder.data; 158 } 159 160 - (NSData*)wrappedKey 161 { 162 return _serializedHolder.wrappedKey; 163 } 164 165 - (NSData*)refKeyBlob 166 { 167 return _serializedHolder.refKeyBlob; 168 } 169 170 - (SecDbKeychainAKSWrappedKeyType)type 171 { 172 return _serializedHolder.type; 173 } 174 175 @end 176 177 @implementation SecDbKeychainMetadata { 178 SecDbKeychainSerializedMetadata* _serializedHolder; 179 } 180 181 - (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext 182 wrappedKey:(SFAuthenticatedCiphertext*)wrappedKey 183 tamperCheck:(NSString*)tamperCheck 184 error:(NSError**)error 185 { 186 if (self = [super init]) { 187 _serializedHolder = [[SecDbKeychainSerializedMetadata alloc] init]; 188 _serializedHolder.ciphertext = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:error]; 189 _serializedHolder.wrappedKey = [NSKeyedArchiver archivedDataWithRootObject:wrappedKey requiringSecureCoding:YES error:error]; 190 _serializedHolder.tamperCheck = tamperCheck; 191 if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { 192 self = nil; 193 } 194 } 195 196 return self; 197 } 198 199 - (instancetype)initWithData:(NSData*)data 200 { 201 if (self = [super init]) { 202 _serializedHolder = [[SecDbKeychainSerializedMetadata alloc] initWithData:data]; 203 if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { 204 self = nil; 205 } 206 } 207 208 return self; 209 } 210 211 - (NSData*)serializedRepresentation 212 { 213 return _serializedHolder.data; 214 } 215 216 - (SFAuthenticatedCiphertext*)ciphertext 217 { 218 NSError* error = nil; 219 SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error]; 220 if (!ciphertext) { 221 secerror("SecDbKeychainItemV7: error deserializing ciphertext from metadata: %@", error); 222 } 223 224 return ciphertext; 225 } 226 227 - (SFAuthenticatedCiphertext*)wrappedKey 228 { 229 NSError* error = nil; 230 SFAuthenticatedCiphertext* wrappedKey = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.wrappedKey error:&error]; 231 if (!wrappedKey) { 232 secerror("SecDbKeychainItemV7: error deserializing wrappedKey from metadata: %@", error); 233 } 234 235 return wrappedKey; 236 } 237 238 - (NSString*)tamperCheck 239 { 240 return _serializedHolder.tamperCheck; 241 } 242 243 @end 244 245 @implementation SecDbKeychainSecretData { 246 SecDbKeychainSerializedSecretData* _serializedHolder; 247 } 248 249 - (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext 250 wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey 251 tamperCheck:(NSString*)tamperCheck 252 backupWrappedKey:(SecDbBackupWrappedKey*)backupWrappedKey 253 error:(NSError**)error 254 { 255 if (self = [super init]) { 256 _serializedHolder = [[SecDbKeychainSerializedSecretData alloc] init]; 257 _serializedHolder.ciphertext = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:error]; 258 _serializedHolder.wrappedKey = wrappedKey.serializedRepresentation; 259 _serializedHolder.tamperCheck = tamperCheck; 260 _serializedHolder.secDbBackupWrappedItemKey = backupWrappedKey ? [NSKeyedArchiver archivedDataWithRootObject:backupWrappedKey requiringSecureCoding:YES error:error] : nil; 261 if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { 262 self = nil; 263 } 264 } 265 266 return self; 267 } 268 269 - (instancetype)initWithData:(NSData*)data 270 { 271 if (self = [super init]) { 272 _serializedHolder = [[SecDbKeychainSerializedSecretData alloc] initWithData:data]; 273 if (!_serializedHolder.ciphertext || !_serializedHolder.wrappedKey || !_serializedHolder.tamperCheck) { 274 self = nil; 275 } 276 } 277 278 return self; 279 } 280 281 - (NSData*)serializedRepresentation 282 { 283 return _serializedHolder.data; 284 } 285 286 - (SFAuthenticatedCiphertext*)ciphertext 287 { 288 NSError* error = nil; 289 SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error]; 290 if (!ciphertext) { 291 secerror("SecDbKeychainItemV7: error deserializing ciphertext from secret data: %@", error); 292 } 293 294 return ciphertext; 295 } 296 297 - (SecDbKeychainAKSWrappedKey*)wrappedKey 298 { 299 return [[SecDbKeychainAKSWrappedKey alloc] initWithData:_serializedHolder.wrappedKey]; 300 } 301 302 - (NSString*)tamperCheck 303 { 304 return _serializedHolder.tamperCheck; 305 } 306 307 @end 308 309 @interface SecDbKeychainItemV7 () 310 @property (nonatomic) NSData* backupUUID; 311 @end; 312 313 @implementation SecDbKeychainItemV7 { 314 SecDbKeychainSecretData* _encryptedSecretData; 315 SecDbKeychainMetadata* _encryptedMetadata; 316 NSDictionary* _secretAttributes; 317 NSDictionary* _metadataAttributes; 318 NSString* _tamperCheck; 319 keyclass_t _keyclass; 320 keybag_handle_t _keybag; 321 } 322 323 @synthesize keyclass = _keyclass; 324 325 // bring back with <rdar://problem/37523001> 326 #if 0 327 + (bool)isKeychainUnlocked 328 { 329 return kc_is_unlocked(); 330 } 331 #endif 332 333 - (instancetype)initWithData:(NSData*)data decryptionKeybag:(keybag_handle_t)decryptionKeybag error:(NSError**)error 334 { 335 if (self = [super init]) { 336 SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] initWithData:data]; 337 if (serializedItem) { 338 339 // Add 10% for serializing overhead. We're trying to catch blatant overstuffing, not enforce hard limits 340 if (data.length > ((REASONABLE_SECRET_DATA_SIZE + REASONABLE_METADATA_SIZE) * 1.1)) { 341 secwarning("SecDbKeychainItemV7: serialized item exceeds reasonable size (%lu bytes)", (unsigned long)data.length); 342 } 343 344 _keybag = decryptionKeybag; 345 _encryptedSecretData = [[SecDbKeychainSecretData alloc] initWithData:serializedItem.encryptedSecretData]; 346 _encryptedMetadata = [[SecDbKeychainMetadata alloc] initWithData:serializedItem.encryptedMetadata]; 347 _keyclass = serializedItem.keyclass; 348 if (![_encryptedSecretData.tamperCheck isEqualToString:_encryptedMetadata.tamperCheck]) { 349 self = nil; 350 } 351 } 352 else { 353 self = nil; 354 } 355 } 356 357 if (!self && error) { 358 *error = [NSError errorWithDomain:(id)kCFErrorDomainOSStatus code:errSecDecode userInfo:@{NSLocalizedDescriptionKey : @"failed to deserialize keychain item blob"}]; 359 } 360 361 return self; 362 } 363 364 - (instancetype)initWithSecretAttributes:(NSDictionary*)secretAttributes metadataAttributes:(NSDictionary*)metadataAttributes tamperCheck:(NSString*)tamperCheck keyclass:(keyclass_t)keyclass 365 { 366 NSParameterAssert(tamperCheck); 367 368 if (self = [super init]) { 369 _secretAttributes = secretAttributes ? secretAttributes.copy : [NSDictionary dictionary]; 370 _metadataAttributes = metadataAttributes ? metadataAttributes.copy : [NSDictionary dictionary]; 371 _tamperCheck = tamperCheck.copy; 372 _keyclass = keyclass; 373 } 374 375 return self; 376 } 377 378 + (SFAESKeySpecifier*)keySpecifier 379 { 380 static SFAESKeySpecifier* keySpecifier = nil; 381 static dispatch_once_t onceToken; 382 dispatch_once(&onceToken, ^{ 383 keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]; 384 }); 385 386 return keySpecifier; 387 } 388 389 + (SFAuthenticatedEncryptionOperation*)encryptionOperation 390 { 391 static SFAuthenticatedEncryptionOperation* encryptionOperation = nil; 392 static dispatch_once_t onceToken; 393 dispatch_once(&onceToken, ^{ 394 encryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[self keySpecifier]]; 395 }); 396 397 return encryptionOperation; 398 } 399 400 + (SFAuthenticatedEncryptionOperation*)decryptionOperation 401 { 402 static SFAuthenticatedEncryptionOperation* decryptionOperation = nil; 403 static dispatch_once_t onceToken; 404 dispatch_once(&onceToken, ^{ 405 decryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[self keySpecifier]]; 406 }); 407 408 return decryptionOperation; 409 } 410 411 - (NSDictionary*)metadataAttributesWithError:(NSError**)error 412 { 413 if (!_metadataAttributes) { 414 SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:_keybag 415 allowWrites:false 416 error:error]; 417 if (metadataClassKey) { 418 NSError* localError = nil; 419 NSData* keyData = [[self.class decryptionOperation] decrypt:_encryptedMetadata.wrappedKey withKey:metadataClassKey error:&localError]; 420 if (!keyData) { 421 secerror("SecDbKeychainItemV7: error unwrapping item metadata key (class %d, bag %d): %@", (int)self.keyclass, _keybag, localError); 422 // TODO: track this in LocalKeychainAnalytics 423 if (error) { 424 CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error 425 SecError(errSecDecode, &secError, CFSTR("failed to unwrap item metadata key")); 426 *error = CFBridgingRelease(secError); 427 } 428 return nil; 429 } 430 SFAESKey* key = [[SFAESKey alloc] initWithData:keyData specifier:[self.class keySpecifier] error:error]; 431 if (!key) { 432 return nil; 433 } 434 435 NSData* metadata = [[self.class decryptionOperation] decrypt:_encryptedMetadata.ciphertext withKey:key error:&localError]; 436 if (!metadata) { 437 secerror("SecDbKeychainItemV7: error decrypting metadata content: %@", localError); 438 if (error) { 439 CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error 440 SecError(errSecDecode, &secError, CFSTR("failed to decrypt item metadata contents")); 441 *error = CFBridgingRelease(secError); 442 } 443 return nil; 444 } 445 NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(metadata).mutableCopy; 446 NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck]; 447 if ([tamperCheck isEqualToString:_encryptedMetadata.tamperCheck]) { 448 [decryptedAttributes removeObjectForKey:SecDBTamperCheck]; 449 _metadataAttributes = decryptedAttributes; 450 } 451 else { 452 secerror("SecDbKeychainItemV7: tamper check failed for metadata decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck); 453 if (error) { 454 CFErrorRef secError = NULL; 455 SecError(errSecDecode, &secError, CFSTR("tamper check failed for metadata decryption")); 456 *error = CFBridgingRelease(secError); 457 } 458 } 459 } 460 } 461 462 return _metadataAttributes; 463 } 464 465 - (NSDictionary*)secretAttributesWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error 466 { 467 if (!_secretAttributes) { 468 SFAESKey* key = [self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:NO error:error]; 469 if (key) { 470 NSError* localError = nil; 471 NSData* secretDataWithPadding = [[self.class decryptionOperation] decrypt:_encryptedSecretData.ciphertext withKey:key error:&localError]; 472 if (!secretDataWithPadding) { 473 secerror("SecDbKeychainItemV7: error decrypting item secret data contents: %@", localError); 474 if (error) { 475 CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error 476 SecError(errSecDecode, &secError, CFSTR("error decrypting item secret data contents")); 477 *error = CFBridgingRelease(secError); 478 } 479 return nil; 480 } 481 int8_t paddingLength = *((int8_t*)secretDataWithPadding.bytes + secretDataWithPadding.length - 1); 482 NSData* secretDataWithoutPadding = [secretDataWithPadding subdataWithRange:NSMakeRange(0, secretDataWithPadding.length - paddingLength)]; 483 484 NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(secretDataWithoutPadding).mutableCopy; 485 NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck]; 486 if ([tamperCheck isEqualToString:_encryptedSecretData.tamperCheck]) { 487 [decryptedAttributes removeObjectForKey:SecDBTamperCheck]; 488 _secretAttributes = decryptedAttributes; 489 } 490 else { 491 secerror("SecDbKeychainItemV7: tamper check failed for secret data decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck); 492 } 493 } 494 } 495 496 return _secretAttributes; 497 } 498 499 - (BOOL)deleteWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error 500 { 501 NSError* localError = nil; 502 (void)[self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:YES error:&localError]; 503 if (localError) { 504 secerror("SecDbKeychainItemV7: failed to delete item secret key from aks"); 505 if (error) { 506 *error = localError; 507 } 508 509 return NO; 510 } 511 512 return YES; 513 } 514 515 - (NSData*)encryptedBlobWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error 516 { 517 NSError* localError = nil; 518 BOOL success = [self encryptMetadataWithKeybag:keybag error:&localError]; 519 if (!success || !_encryptedMetadata || localError) { 520 if (error) { 521 *error = localError; 522 } 523 return nil; 524 } 525 526 success = [self encryptSecretDataWithKeybag:keybag accessControl:accessControl acmContext:acmContext error:&localError]; 527 if (!success || !_encryptedSecretData || localError) { 528 if (error) { 529 *error = localError; 530 } 531 return nil; 532 } 533 534 SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] init]; 535 serializedItem.encryptedMetadata = self.encryptedMetadataBlob; 536 serializedItem.encryptedSecretData = self.encryptedSecretDataBlob; 537 serializedItem.keyclass = _keyclass; 538 return serializedItem.data; 539 } 540 541 - (NSData*)encryptedMetadataBlob 542 { 543 return _encryptedMetadata.serializedRepresentation; 544 } 545 546 - (NSData*)encryptedSecretDataBlob 547 { 548 return _encryptedSecretData.serializedRepresentation; 549 } 550 551 - (BOOL)encryptMetadataWithKeybag:(keybag_handle_t)keybag error:(NSError**)error 552 { 553 SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error]; 554 if (!key) { 555 return NO; 556 } 557 SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation]; 558 559 NSMutableDictionary* attributesToEncrypt = _metadataAttributes.mutableCopy; 560 attributesToEncrypt[SecDBTamperCheck] = _tamperCheck; 561 NSData* metadata = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL); 562 563 if (metadata.length > REASONABLE_METADATA_SIZE) { 564 NSString *agrp = _metadataAttributes[(__bridge NSString *)kSecAttrAccessGroup]; 565 secwarning("SecDbKeychainItemV7: item's metadata exceeds reasonable size (%lu bytes) (%@)", (unsigned long)metadata.length, agrp); 566 } 567 568 SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:metadata withKey:key error:error]; 569 570 SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:keybag 571 allowWrites:true 572 error:error]; 573 if (metadataClassKey) { 574 SFAuthenticatedCiphertext* wrappedKey = [encryptionOperation encrypt:key.keyData withKey:metadataClassKey error:error]; 575 _encryptedMetadata = [[SecDbKeychainMetadata alloc] initWithCiphertext:ciphertext wrappedKey:wrappedKey tamperCheck:_tamperCheck error:error]; 576 } 577 578 return _encryptedMetadata != nil; 579 } 580 581 - (BOOL)encryptSecretDataWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error 582 { 583 SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error]; 584 if (!key) { 585 return NO; 586 } 587 SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation]; 588 589 NSMutableDictionary* attributesToEncrypt = _secretAttributes.mutableCopy; 590 attributesToEncrypt[SecDBTamperCheck] = _tamperCheck; 591 NSMutableData* secretData = [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL) mutableCopy]; 592 593 if (secretData.length > REASONABLE_SECRET_DATA_SIZE) { 594 NSString *agrp = _metadataAttributes[(__bridge NSString *)kSecAttrAccessGroup]; 595 secwarning("SecDbKeychainItemV7: item's secret data exceeds reasonable size (%lu bytes) (%@)", (unsigned long)secretData.length, agrp); 596 } 597 598 int8_t paddingLength = KEYCHAIN_ITEM_PADDING_MODULUS - (secretData.length % KEYCHAIN_ITEM_PADDING_MODULUS); 599 int8_t paddingBytes[KEYCHAIN_ITEM_PADDING_MODULUS]; 600 for (int i = 0; i < KEYCHAIN_ITEM_PADDING_MODULUS; i++) { 601 paddingBytes[i] = paddingLength; 602 } 603 [secretData appendBytes:paddingBytes length:paddingLength]; 604 605 SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:secretData withKey:key error:error]; 606 SecDbKeychainAKSWrappedKey* wrappedKey = [self wrapToAKS:key withKeybag:keybag accessControl:accessControl acmContext:acmContext error:error]; 607 608 SecDbBackupWrappedKey* backupWrappedKey; 609 if (checkV12DevEnabled()) { 610 backupWrappedKey = [[SecDbBackupManager manager] wrapItemKey:key forKeyclass:_keyclass error:error]; 611 if (backupWrappedKey) { 612 _backupUUID = backupWrappedKey.baguuid; 613 } else { 614 secwarning("SecDbKeychainItemV7: backup manager didn't return wrapped key: %@", error ? *error : nil); 615 if (error) { 616 *error = nil; 617 } 618 } 619 } 620 621 _encryptedSecretData = [[SecDbKeychainSecretData alloc] initWithCiphertext:ciphertext 622 wrappedKey:wrappedKey 623 tamperCheck:_tamperCheck 624 backupWrappedKey:backupWrappedKey 625 error:error]; 626 return _encryptedSecretData != nil; 627 } 628 629 - (SFAESKey*)metadataClassKeyWithKeybag:(keybag_handle_t)keybag 630 allowWrites:(bool)allowWrites 631 error:(NSError**)error 632 { 633 return [[SecDbKeychainMetadataKeyStore sharedStore] keyForKeyclass:_keyclass 634 keybag:keybag 635 keySpecifier:[self.class keySpecifier] 636 allowWrites:allowWrites 637 error:error]; 638 } 639 640 - (SecDbKeychainAKSWrappedKey*)wrapToAKS:(SFAESKey*)key withKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error 641 { 642 NSData* keyData = key.keyData; 643 644 #if USE_KEYSTORE 645 NSDictionary* constraints = (__bridge NSDictionary*)SecAccessControlGetConstraints(accessControl); 646 if (constraints) { 647 aks_ref_key_t refKey = NULL; 648 CFErrorRef cfError = NULL; 649 NSData* authData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)@{(id)kAKSKeyAcl : constraints}, &cfError); 650 651 if (!acmContext || !SecAccessControlIsBound(accessControl)) { 652 secerror("SecDbKeychainItemV7: access control error"); 653 if (error) { 654 CFDataRef accessControlData = SecAccessControlCopyData(accessControl); 655 ks_access_control_needed_error(&cfError, accessControlData, SecAccessControlIsBound(accessControl) ? kAKSKeyOpEncrypt : CFSTR("")); 656 CFReleaseNull(accessControlData); 657 } 658 659 BridgeCFErrorToNSErrorOut(error, cfError); 660 return nil; 661 } 662 663 void* aksParams = NULL; 664 size_t aksParamsLength = 0; 665 aks_operation_optional_params(0, 0, authData.bytes, authData.length, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength); 666 667 int aksResult = aks_ref_key_create(keybag, _keyclass, key_type_sym, aksParams, aksParamsLength, &refKey); 668 if (aksResult != 0) { 669 CFDataRef accessControlData = SecAccessControlCopyData(accessControl); 670 create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError); 671 CFReleaseNull(accessControlData); 672 free(aksParams); 673 BridgeCFErrorToNSErrorOut(error, cfError); 674 return nil; 675 } 676 677 size_t wrappedKeySize = 0; 678 void* wrappedKeyBytes = NULL; 679 aksResult = aks_ref_key_encrypt(refKey, aksParams, aksParamsLength, keyData.bytes, keyData.length, &wrappedKeyBytes, &wrappedKeySize); 680 if (aksResult != 0) { 681 CFDataRef accessControlData = SecAccessControlCopyData(accessControl); 682 create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError); 683 CFReleaseNull(accessControlData); 684 free(aksParams); 685 aks_ref_key_free(&refKey); 686 BridgeCFErrorToNSErrorOut(error, cfError); 687 return nil; 688 } 689 free(aksParams); 690 691 BridgeCFErrorToNSErrorOut(error, cfError); 692 693 NSData* wrappedKey = [[NSData alloc] initWithBytesNoCopy:wrappedKeyBytes length:wrappedKeySize]; 694 695 size_t refKeyBlobLength = 0; 696 const void* refKeyBlobBytes = aks_ref_key_get_blob(refKey, &refKeyBlobLength); 697 NSData* refKeyBlob = [[NSData alloc] initWithBytes:(void*)refKeyBlobBytes length:refKeyBlobLength]; 698 aks_ref_key_free(&refKey); 699 return [[SecDbKeychainAKSWrappedKey alloc] initRefKeyWrappedKeyWithData:wrappedKey refKeyBlob:refKeyBlob]; 700 } 701 else { 702 NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:APPLE_KEYSTORE_MAX_SYM_WRAPPED_KEY_LEN]; 703 bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error]; 704 return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil; 705 } 706 #else 707 NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:APPLE_KEYSTORE_MAX_SYM_WRAPPED_KEY_LEN]; 708 bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error]; 709 return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil; 710 #endif 711 } 712 713 - (SFAESKey*)unwrapFromAKS:(SecDbKeychainAKSWrappedKey*)wrappedKey accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext callerAccessGroups:(NSArray*)callerAccessGroups delete:(BOOL)delete error:(NSError**)error 714 { 715 NSData* wrappedKeyData = wrappedKey.wrappedKey; 716 717 if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRegular) { 718 NSMutableData* unwrappedKey = [NSMutableData dataWithLength:APPLE_KEYSTORE_MAX_KEY_LEN]; 719 bool result = [SecAKSObjCWrappers aksDecryptWithKeybag:_keybag keyclass:_keyclass ciphertext:wrappedKeyData outKeyclass:&_keyclass plaintext:unwrappedKey error:error]; 720 if (result) { 721 return [[SFAESKey alloc] initWithData:unwrappedKey specifier:[self.class keySpecifier] error:error]; 722 } 723 else { 724 return nil; 725 } 726 } 727 #if USE_KEYSTORE 728 else if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRefKey) { 729 aks_ref_key_t refKey = NULL; 730 aks_ref_key_create_with_blob(_keybag, wrappedKey.refKeyBlob.bytes, wrappedKey.refKeyBlob.length, &refKey); 731 732 CFErrorRef cfError = NULL; 733 size_t refKeyExternalDataLength = 0; 734 const uint8_t* refKeyExternalDataBytes = aks_ref_key_get_external_data(refKey, &refKeyExternalDataLength); 735 if (!refKeyExternalDataBytes) { 736 aks_ref_key_free(&refKey); 737 return nil; 738 } 739 NSDictionary* aclDict = nil; 740 der_decode_plist(NULL, (CFPropertyListRef*)(void*)&aclDict, &cfError, refKeyExternalDataBytes, refKeyExternalDataBytes + refKeyExternalDataLength); 741 if (!aclDict) { 742 SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decode acl dict")); 743 } 744 SecAccessControlSetConstraints(accessControl, (__bridge CFDictionaryRef)aclDict); 745 if (!SecAccessControlGetConstraint(accessControl, kAKSKeyOpEncrypt)) { 746 SecAccessControlAddConstraintForOperation(accessControl, kAKSKeyOpEncrypt, kCFBooleanTrue, &cfError); 747 } 748 749 size_t derPlistLength = der_sizeof_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError); 750 NSMutableData* accessGroupDERData = [[NSMutableData alloc] initWithLength:derPlistLength]; 751 der_encode_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError, accessGroupDERData.mutableBytes, accessGroupDERData.mutableBytes + derPlistLength); 752 void* aksParams = NULL; 753 size_t aksParamsLength = 0; 754 aks_operation_optional_params(accessGroupDERData.bytes, derPlistLength, NULL, 0, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength); 755 756 void* unwrappedKeyDERData = NULL; 757 size_t unwrappedKeyDERLength = 0; 758 int aksResult = aks_ref_key_decrypt(refKey, aksParams, aksParamsLength, wrappedKeyData.bytes, wrappedKeyData.length, &unwrappedKeyDERData, &unwrappedKeyDERLength); 759 if (aksResult != 0) { 760 CFDataRef accessControlData = SecAccessControlCopyData(accessControl); 761 create_cferror_from_aks(aksResult, kAKSKeyOpDecrypt, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError); 762 CFReleaseNull(accessControlData); 763 aks_ref_key_free(&refKey); 764 free(aksParams); 765 BridgeCFErrorToNSErrorOut(error, cfError); 766 return nil; 767 } 768 if (!unwrappedKeyDERData) { 769 SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item.")); 770 aks_ref_key_free(&refKey); 771 free(aksParams); 772 BridgeCFErrorToNSErrorOut(error, cfError); 773 return nil; 774 } 775 776 CFPropertyListRef unwrappedKeyData = NULL; 777 der_decode_plist(NULL, &unwrappedKeyData, &cfError, unwrappedKeyDERData, unwrappedKeyDERData + unwrappedKeyDERLength); 778 SFAESKey* result = nil; 779 if ([(__bridge NSData*)unwrappedKeyData isKindOfClass:[NSData class]]) { 780 result = [[SFAESKey alloc] initWithData:(__bridge NSData*)unwrappedKeyData specifier:[self.class keySpecifier] error:error]; 781 CFReleaseNull(unwrappedKeyData); 782 } 783 else { 784 SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item.")); 785 CFReleaseNull(unwrappedKeyData); 786 aks_ref_key_free(&refKey); 787 free(aksParams); 788 free(unwrappedKeyDERData); 789 BridgeCFErrorToNSErrorOut(error, cfError); 790 return nil; 791 } 792 793 if (delete) { 794 aksResult = aks_ref_key_delete(refKey, aksParams, aksParamsLength); 795 if (aksResult != 0) { 796 CFDataRef accessControlData = SecAccessControlCopyData(accessControl); 797 create_cferror_from_aks(aksResult, kAKSKeyOpDelete, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError); 798 CFReleaseNull(accessControlData); 799 aks_ref_key_free(&refKey); 800 free(aksParams); 801 free(unwrappedKeyDERData); 802 BridgeCFErrorToNSErrorOut(error, cfError); 803 return nil; 804 } 805 } 806 807 BridgeCFErrorToNSErrorOut(error, cfError); 808 aks_ref_key_free(&refKey); 809 free(aksParams); 810 free(unwrappedKeyDERData); 811 return result; 812 } 813 #endif 814 else { 815 return nil; 816 } 817 } 818 819 @end