]> git.saurik.com Git - apple/security.git/blob - keychain/securityd/SecDbKeychainItemV7.m
Security-59306.41.2.tar.gz
[apple/security.git] / keychain / 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 <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:(SecDbBackupWrappedItemKey*)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:(SecDbBackupWrappedItemKey*)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:errSecItemNotFound 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 createKeyIfMissing:false
416 overwriteCorruptKey:false
417 error:error];
418 if (metadataClassKey) {
419 NSError* localError = nil;
420 NSData* keyData = [[self.class decryptionOperation] decrypt:_encryptedMetadata.wrappedKey withKey:metadataClassKey error:&localError];
421 if (!keyData) {
422 secerror("SecDbKeychainItemV7: error unwrapping item metadata key (class %d, bag %d): %@", (int)self.keyclass, _keybag, localError);
423 // TODO: track this in LocalKeychainAnalytics
424 if (error) {
425 CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error
426 SecError(errSecDecode, &secError, CFSTR("failed to unwrap item metadata key"));
427 *error = CFBridgingRelease(secError);
428 }
429 return nil;
430 }
431 SFAESKey* key = [[SFAESKey alloc] initWithData:keyData specifier:[self.class keySpecifier] error:error];
432 if (!key) {
433 return nil;
434 }
435
436 NSData* metadata = [[self.class decryptionOperation] decrypt:_encryptedMetadata.ciphertext withKey:key error:&localError];
437 if (!metadata) {
438 secerror("SecDbKeychainItemV7: error decrypting metadata content: %@", localError);
439 if (error) {
440 CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error
441 SecError(errSecDecode, &secError, CFSTR("failed to decrypt item metadata contents"));
442 *error = CFBridgingRelease(secError);
443 }
444 return nil;
445 }
446 NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(metadata).mutableCopy;
447 NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck];
448 if ([tamperCheck isEqualToString:_encryptedMetadata.tamperCheck]) {
449 [decryptedAttributes removeObjectForKey:SecDBTamperCheck];
450 _metadataAttributes = decryptedAttributes;
451 }
452 else {
453 secerror("SecDbKeychainItemV7: tamper check failed for metadata decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck);
454 if (error) {
455 CFErrorRef secError = NULL;
456 SecError(errSecDecode, &secError, CFSTR("tamper check failed for metadata decryption"));
457 *error = CFBridgingRelease(secError);
458 }
459 }
460 }
461 }
462
463 return _metadataAttributes;
464 }
465
466 - (NSDictionary*)secretAttributesWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error
467 {
468 if (!_secretAttributes) {
469 SFAESKey* key = [self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:NO error:error];
470 if (key) {
471 NSError* localError = nil;
472 NSData* secretDataWithPadding = [[self.class decryptionOperation] decrypt:_encryptedSecretData.ciphertext withKey:key error:&localError];
473 if (!secretDataWithPadding) {
474 secerror("SecDbKeychainItemV7: error decrypting item secret data contents: %@", localError);
475 if (error) {
476 CFErrorRef secError = (CFErrorRef)CFBridgingRetain(localError); // this makes localError become the underlying error
477 SecError(errSecDecode, &secError, CFSTR("error decrypting item secret data contents"));
478 *error = CFBridgingRelease(secError);
479 }
480 return nil;
481 }
482 int8_t paddingLength = *((int8_t*)secretDataWithPadding.bytes + secretDataWithPadding.length - 1);
483 NSData* secretDataWithoutPadding = [secretDataWithPadding subdataWithRange:NSMakeRange(0, secretDataWithPadding.length - paddingLength)];
484
485 NSMutableDictionary* decryptedAttributes = dictionaryFromDERData(secretDataWithoutPadding).mutableCopy;
486 NSString* tamperCheck = decryptedAttributes[SecDBTamperCheck];
487 if ([tamperCheck isEqualToString:_encryptedSecretData.tamperCheck]) {
488 [decryptedAttributes removeObjectForKey:SecDBTamperCheck];
489 _secretAttributes = decryptedAttributes;
490 }
491 else {
492 secerror("SecDbKeychainItemV7: tamper check failed for secret data decryption, expected %@ found %@", tamperCheck, _encryptedMetadata.tamperCheck);
493 }
494 }
495 }
496
497 return _secretAttributes;
498 }
499
500 - (BOOL)deleteWithAcmContext:(NSData*)acmContext accessControl:(SecAccessControlRef)accessControl callerAccessGroups:(NSArray*)callerAccessGroups error:(NSError**)error
501 {
502 NSError* localError = nil;
503 (void)[self unwrapFromAKS:_encryptedSecretData.wrappedKey accessControl:accessControl acmContext:acmContext callerAccessGroups:callerAccessGroups delete:YES error:&localError];
504 if (localError) {
505 secerror("SecDbKeychainItemV7: failed to delete item secret key from aks");
506 if (error) {
507 *error = localError;
508 }
509
510 return NO;
511 }
512
513 return YES;
514 }
515
516 - (NSData*)encryptedBlobWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error
517 {
518 NSError* localError = nil;
519 BOOL success = [self encryptMetadataWithKeybag:keybag error:&localError];
520 if (!success || !_encryptedMetadata || localError) {
521 if (error) {
522 *error = localError;
523 }
524 return nil;
525 }
526
527 success = [self encryptSecretDataWithKeybag:keybag accessControl:accessControl acmContext:acmContext error:&localError];
528 if (!success || !_encryptedSecretData || localError) {
529 if (error) {
530 *error = localError;
531 }
532 return nil;
533 }
534
535 SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] init];
536 serializedItem.encryptedMetadata = self.encryptedMetadataBlob;
537 serializedItem.encryptedSecretData = self.encryptedSecretDataBlob;
538 serializedItem.keyclass = _keyclass;
539 return serializedItem.data;
540 }
541
542 - (NSData*)encryptedMetadataBlob
543 {
544 return _encryptedMetadata.serializedRepresentation;
545 }
546
547 - (NSData*)encryptedSecretDataBlob
548 {
549 return _encryptedSecretData.serializedRepresentation;
550 }
551
552 - (BOOL)encryptMetadataWithKeybag:(keybag_handle_t)keybag error:(NSError**)error
553 {
554 SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error];
555 if (!key) {
556 return NO;
557 }
558 SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation];
559
560 NSMutableDictionary* attributesToEncrypt = _metadataAttributes.mutableCopy;
561 attributesToEncrypt[SecDBTamperCheck] = _tamperCheck;
562 NSData* metadata = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL);
563
564 if (metadata.length > REASONABLE_METADATA_SIZE) {
565 NSString *agrp = _metadataAttributes[(__bridge NSString *)kSecAttrAccessGroup];
566 secwarning("SecDbKeychainItemV7: item's metadata exceeds reasonable size (%lu bytes) (%@)", (unsigned long)metadata.length, agrp);
567 }
568
569 SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:metadata withKey:key error:error];
570
571 SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:keybag
572 createKeyIfMissing:true
573 overwriteCorruptKey:true
574 error:error];
575 if (metadataClassKey) {
576 SFAuthenticatedCiphertext* wrappedKey = [encryptionOperation encrypt:key.keyData withKey:metadataClassKey error:error];
577 _encryptedMetadata = [[SecDbKeychainMetadata alloc] initWithCiphertext:ciphertext wrappedKey:wrappedKey tamperCheck:_tamperCheck error:error];
578 }
579
580 return _encryptedMetadata != nil;
581 }
582
583 - (BOOL)encryptSecretDataWithKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error
584 {
585 SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:[self.class keySpecifier] error:error];
586 if (!key) {
587 return NO;
588 }
589 SFAuthenticatedEncryptionOperation* encryptionOperation = [self.class encryptionOperation];
590
591 NSMutableDictionary* attributesToEncrypt = _secretAttributes.mutableCopy;
592 attributesToEncrypt[SecDBTamperCheck] = _tamperCheck;
593 NSMutableData* secretData = [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)attributesToEncrypt, NULL) mutableCopy];
594
595 if (secretData.length > REASONABLE_SECRET_DATA_SIZE) {
596 NSString *agrp = _metadataAttributes[(__bridge NSString *)kSecAttrAccessGroup];
597 secwarning("SecDbKeychainItemV7: item's secret data exceeds reasonable size (%lu bytes) (%@)", (unsigned long)secretData.length, agrp);
598 }
599
600 int8_t paddingLength = KEYCHAIN_ITEM_PADDING_MODULUS - (secretData.length % KEYCHAIN_ITEM_PADDING_MODULUS);
601 int8_t paddingBytes[KEYCHAIN_ITEM_PADDING_MODULUS];
602 for (int i = 0; i < KEYCHAIN_ITEM_PADDING_MODULUS; i++) {
603 paddingBytes[i] = paddingLength;
604 }
605 [secretData appendBytes:paddingBytes length:paddingLength];
606
607 SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:secretData withKey:key error:error];
608 SecDbKeychainAKSWrappedKey* wrappedKey = [self wrapToAKS:key withKeybag:keybag accessControl:accessControl acmContext:acmContext error:error];
609
610 SecDbBackupWrappedItemKey* backupWrappedKey;
611 if (checkV12DevEnabled()) {
612 backupWrappedKey = [[SecDbBackupManager manager] wrapItemKey:key forKeyclass:_keyclass error:error];
613 if (backupWrappedKey) {
614 _backupUUID = backupWrappedKey.baguuid;
615 } else {
616 secwarning("SecDbKeychainItemV7: backup manager didn't return wrapped key: %@", error ? *error : nil);
617 if (error) {
618 *error = nil;
619 }
620 }
621 }
622
623 _encryptedSecretData = [[SecDbKeychainSecretData alloc] initWithCiphertext:ciphertext
624 wrappedKey:wrappedKey
625 tamperCheck:_tamperCheck
626 backupWrappedKey:backupWrappedKey
627 error:error];
628 return _encryptedSecretData != nil;
629 }
630
631 - (SFAESKey*)metadataClassKeyWithKeybag:(keybag_handle_t)keybag
632 createKeyIfMissing:(bool)createIfMissing
633 overwriteCorruptKey:(bool)force
634 error:(NSError**)error
635 {
636 return [[SecDbKeychainMetadataKeyStore sharedStore] keyForKeyclass:_keyclass
637 keybag:keybag
638 keySpecifier:[self.class keySpecifier]
639 createKeyIfMissing:(bool)createIfMissing
640 overwriteCorruptKey:force
641 error:error];
642 }
643
644 - (SecDbKeychainAKSWrappedKey*)wrapToAKS:(SFAESKey*)key withKeybag:(keybag_handle_t)keybag accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext error:(NSError**)error
645 {
646 NSData* keyData = key.keyData;
647
648 #if USE_KEYSTORE
649 NSDictionary* constraints = (__bridge NSDictionary*)SecAccessControlGetConstraints(accessControl);
650 if (constraints) {
651 aks_ref_key_t refKey = NULL;
652 CFErrorRef cfError = NULL;
653 NSData* authData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)@{(id)kAKSKeyAcl : constraints}, &cfError);
654
655 if (!acmContext || !SecAccessControlIsBound(accessControl)) {
656 secerror("SecDbKeychainItemV7: access control error");
657 if (error) {
658 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
659 ks_access_control_needed_error(&cfError, accessControlData, SecAccessControlIsBound(accessControl) ? kAKSKeyOpEncrypt : CFSTR(""));
660 CFReleaseNull(accessControlData);
661 }
662
663 BridgeCFErrorToNSErrorOut(error, cfError);
664 return nil;
665 }
666
667 void* aksParams = NULL;
668 size_t aksParamsLength = 0;
669 aks_operation_optional_params(0, 0, authData.bytes, authData.length, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength);
670
671 int aksResult = aks_ref_key_create(keybag, _keyclass, key_type_sym, aksParams, aksParamsLength, &refKey);
672 if (aksResult != 0) {
673 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
674 create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError);
675 CFReleaseNull(accessControlData);
676 free(aksParams);
677 BridgeCFErrorToNSErrorOut(error, cfError);
678 return nil;
679 }
680
681 size_t wrappedKeySize = 0;
682 void* wrappedKeyBytes = NULL;
683 aksResult = aks_ref_key_encrypt(refKey, aksParams, aksParamsLength, keyData.bytes, keyData.length, &wrappedKeyBytes, &wrappedKeySize);
684 if (aksResult != 0) {
685 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
686 create_cferror_from_aks(aksResult, kAKSKeyOpEncrypt, keybag, _keyclass, accessControlData, (__bridge CFDataRef)acmContext, &cfError);
687 CFReleaseNull(accessControlData);
688 free(aksParams);
689 aks_ref_key_free(&refKey);
690 BridgeCFErrorToNSErrorOut(error, cfError);
691 return nil;
692 }
693 free(aksParams);
694
695 BridgeCFErrorToNSErrorOut(error, cfError);
696
697 NSData* wrappedKey = [[NSData alloc] initWithBytesNoCopy:wrappedKeyBytes length:wrappedKeySize];
698
699 size_t refKeyBlobLength = 0;
700 const void* refKeyBlobBytes = aks_ref_key_get_blob(refKey, &refKeyBlobLength);
701 NSData* refKeyBlob = [[NSData alloc] initWithBytesNoCopy:(void*)refKeyBlobBytes length:refKeyBlobLength];
702 aks_ref_key_free(&refKey);
703 return [[SecDbKeychainAKSWrappedKey alloc] initRefKeyWrappedKeyWithData:wrappedKey refKeyBlob:refKeyBlob];
704 }
705 else {
706 NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40];
707 bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error];
708 return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil;
709 }
710 #else
711 NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40];
712 bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error];
713 return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil;
714 #endif
715 }
716
717 - (SFAESKey*)unwrapFromAKS:(SecDbKeychainAKSWrappedKey*)wrappedKey accessControl:(SecAccessControlRef)accessControl acmContext:(NSData*)acmContext callerAccessGroups:(NSArray*)callerAccessGroups delete:(BOOL)delete error:(NSError**)error
718 {
719 NSData* wrappedKeyData = wrappedKey.wrappedKey;
720
721 if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRegular) {
722 NSMutableData* unwrappedKey = [NSMutableData dataWithCapacity:wrappedKeyData.length + 40];
723 unwrappedKey.length = wrappedKeyData.length + 40;
724 bool result = [SecAKSObjCWrappers aksDecryptWithKeybag:_keybag keyclass:_keyclass ciphertext:wrappedKeyData outKeyclass:&_keyclass plaintext:unwrappedKey error:error];
725 if (result) {
726 return [[SFAESKey alloc] initWithData:unwrappedKey specifier:[self.class keySpecifier] error:error];
727 }
728 else {
729 return nil;
730 }
731 }
732 #if USE_KEYSTORE
733 else if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRefKey) {
734 aks_ref_key_t refKey = NULL;
735 aks_ref_key_create_with_blob(_keybag, wrappedKey.refKeyBlob.bytes, wrappedKey.refKeyBlob.length, &refKey);
736
737 CFErrorRef cfError = NULL;
738 size_t refKeyExternalDataLength = 0;
739 const uint8_t* refKeyExternalDataBytes = aks_ref_key_get_external_data(refKey, &refKeyExternalDataLength);
740 if (!refKeyExternalDataBytes) {
741 aks_ref_key_free(&refKey);
742 return nil;
743 }
744 NSDictionary* aclDict = nil;
745 der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)(void*)&aclDict, &cfError, refKeyExternalDataBytes, refKeyExternalDataBytes + refKeyExternalDataLength);
746 if (!aclDict) {
747 SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decode acl dict"));
748 }
749 SecAccessControlSetConstraints(accessControl, (__bridge CFDictionaryRef)aclDict);
750 if (!SecAccessControlGetConstraint(accessControl, kAKSKeyOpEncrypt)) {
751 SecAccessControlAddConstraintForOperation(accessControl, kAKSKeyOpEncrypt, kCFBooleanTrue, &cfError);
752 }
753
754 size_t derPlistLength = der_sizeof_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError);
755 NSMutableData* accessGroupDERData = [[NSMutableData alloc] initWithLength:derPlistLength];
756 der_encode_plist((__bridge CFPropertyListRef)callerAccessGroups, &cfError, accessGroupDERData.mutableBytes, accessGroupDERData.mutableBytes + derPlistLength);
757 void* aksParams = NULL;
758 size_t aksParamsLength = 0;
759 aks_operation_optional_params(accessGroupDERData.bytes, derPlistLength, NULL, 0, acmContext.bytes, (int)acmContext.length, &aksParams, &aksParamsLength);
760
761 void* unwrappedKeyDERData = NULL;
762 size_t unwrappedKeyDERLength = 0;
763 int aksResult = aks_ref_key_decrypt(refKey, aksParams, aksParamsLength, wrappedKeyData.bytes, wrappedKeyData.length, &unwrappedKeyDERData, &unwrappedKeyDERLength);
764 if (aksResult != 0) {
765 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
766 create_cferror_from_aks(aksResult, kAKSKeyOpDecrypt, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError);
767 CFReleaseNull(accessControlData);
768 aks_ref_key_free(&refKey);
769 free(aksParams);
770 BridgeCFErrorToNSErrorOut(error, cfError);
771 return nil;
772 }
773 if (!unwrappedKeyDERData) {
774 SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item."));
775 aks_ref_key_free(&refKey);
776 free(aksParams);
777 BridgeCFErrorToNSErrorOut(error, cfError);
778 return nil;
779 }
780
781 CFPropertyListRef unwrappedKeyData = NULL;
782 der_decode_plist(NULL, kCFPropertyListImmutable, &unwrappedKeyData, &cfError, unwrappedKeyDERData, unwrappedKeyDERData + unwrappedKeyDERLength);
783 SFAESKey* result = nil;
784 if ([(__bridge NSData*)unwrappedKeyData isKindOfClass:[NSData class]]) {
785 result = [[SFAESKey alloc] initWithData:(__bridge NSData*)unwrappedKeyData specifier:[self.class keySpecifier] error:error];
786 CFReleaseNull(unwrappedKeyDERData);
787 }
788 else {
789 SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decrypt item, Item can't be decrypted due to failed decode der, so drop the item."));
790 aks_ref_key_free(&refKey);
791 free(aksParams);
792 free(unwrappedKeyDERData);
793 BridgeCFErrorToNSErrorOut(error, cfError);
794 return nil;
795 }
796
797 if (delete) {
798 aksResult = aks_ref_key_delete(refKey, aksParams, aksParamsLength);
799 if (aksResult != 0) {
800 CFDataRef accessControlData = SecAccessControlCopyData(accessControl);
801 create_cferror_from_aks(aksResult, kAKSKeyOpDelete, 0, 0, accessControlData, (__bridge CFDataRef)acmContext, &cfError);
802 CFReleaseNull(accessControlData);
803 aks_ref_key_free(&refKey);
804 free(aksParams);
805 free(unwrappedKeyDERData);
806 BridgeCFErrorToNSErrorOut(error, cfError);
807 return nil;
808 }
809 }
810
811 BridgeCFErrorToNSErrorOut(error, cfError);
812 aks_ref_key_free(&refKey);
813 free(aksParams);
814 free(unwrappedKeyDERData);
815 return result;
816 }
817 #endif
818 else {
819 return nil;
820 }
821 }
822
823 @end