]> git.saurik.com Git - apple/security.git/blob - secdxctests/KeychainXCTest.m
Security-58286.51.6.tar.gz
[apple/security.git] / secdxctests / KeychainXCTest.m
1 /*
2 * Copyright (c) 2018 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 "KeychainXCTest.h"
25 #import "SecDbKeychainItem.h"
26 #import "SecdTestKeychainUtilities.h"
27 #import "CKKS.h"
28 #import "SecDbKeychainItemV7.h"
29 #import "SecItemPriv.h"
30 #import "SecItemServer.h"
31 #import "spi.h"
32 #import "SecDbKeychainSerializedItemV7.h"
33 #import "SecDbKeychainSerializedMetadata.h"
34 #import "SecDbKeychainSerializedSecretData.h"
35 #import "SecDbKeychainSerializedAKSWrappedKey.h"
36 #import <utilities/SecCFWrappers.h>
37 #import <SecurityFoundation/SFEncryptionOperation.h>
38 #import <SecurityFoundation/SFCryptoServicesErrors.h>
39 #import <XCTest/XCTest.h>
40 #import <OCMock/OCMock.h>
41
42 #if USE_KEYSTORE
43
44 @interface SecDbKeychainItemV7 ()
45
46 + (SFAESKeySpecifier*)keySpecifier;
47
48 @end
49
50 @implementation KeychainXCTest
51
52 + (void)setUp
53 {
54 [super setUp];
55
56 SecCKKSDisable();
57 securityd_init(NULL);
58 }
59
60 - (void)setUp
61 {
62 [super setUp];
63
64 self.lockState = LockStateUnlocked;
65 self.allowDecryption = true;
66 self.didAKSDecrypt = NO;
67 self.simulateRolledAKSKey = NO;
68
69
70 self.keyclassUsedForAKSDecryption = 0;
71
72 self.keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256];
73 [self setNewFakeAKSKey:[NSData dataWithBytes:"1234567890123456789012" length:32]];
74
75 [SecDbKeychainMetadataKeyStore resetSharedStore];
76
77 self.mockSecDbKeychainItemV7 = OCMClassMock([SecDbKeychainItemV7 class]);
78 [[[[self.mockSecDbKeychainItemV7 stub] andCall:@selector(fakeAKSEncryptWithKeybag:keyclass:keyData:outKeyclass:wrappedKey:error:) onObject:self] ignoringNonObjectArgs] aksEncryptWithKeybag:0 keyclass:0 keyData:[OCMArg any] outKeyclass:NULL wrappedKey:[OCMArg any] error:NULL];
79 [[[[self.mockSecDbKeychainItemV7 stub] andCall:@selector(fakeAKSDecryptWithKeybag:keyclass:wrappedKeyData:outKeyclass:unwrappedKey:error:) onObject:self] ignoringNonObjectArgs] aksDecryptWithKeybag:0 keyclass:0 wrappedKeyData:[OCMArg any] outKeyclass:NULL unwrappedKey:[OCMArg any] error:NULL];
80 [[[self.mockSecDbKeychainItemV7 stub] andCall:@selector(decryptionOperation) onObject:self] decryptionOperation];
81 [[[self.mockSecDbKeychainItemV7 stub] andCall:@selector(isKeychainUnlocked) onObject:self] isKeychainUnlocked];
82
83 NSArray* partsOfName = [self.name componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" ]"]];
84 secd_test_setup_temp_keychain([partsOfName[1] UTF8String], NULL);
85 }
86
87 - (void)tearDown
88 {
89 [self.mockSecDbKeychainItemV7 stopMocking];
90 [super tearDown];
91 }
92
93 - (bool)isKeychainUnlocked
94 {
95 return self.lockState == LockStateUnlocked;
96 }
97
98 - (id)decryptionOperation
99 {
100 return self.allowDecryption ? [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:[SecDbKeychainItemV7 keySpecifier]] : nil;
101 }
102
103 - (bool)setNewFakeAKSKey:(NSData*)newKeyData
104 {
105 NSError* error = nil;
106 self.fakeAKSKey = [[SFAESKey alloc] initWithData:newKeyData specifier:self.keySpecifier error:&error];
107 XCTAssertNil(error, "Should be no error making a fake AKS key");
108 XCTAssertNotNil(self.fakeAKSKey, "Should have received a fake AKS key");
109 return true;
110 }
111
112 - (bool)fakeAKSEncryptWithKeybag:(keybag_handle_t)keybag
113 keyclass:(keyclass_t)keyclass
114 keyData:(NSData*)keyData
115 outKeyclass:(keyclass_t*)outKeyclass
116 wrappedKey:(NSMutableData*)wrappedKey
117 error:(NSError**)error
118 {
119 if (self.lockState == LockStateLockedAndDisallowAKS) {
120 if (error) {
121 *error = [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:NULL];
122 }
123 return false;
124 }
125
126 uint32_t keyLength = (uint32_t)keyData.length;
127 const uint8_t* keyBytes = keyData.bytes;
128
129 NSData* dataToEncrypt = [NSData dataWithBytes:keyBytes length:keyLength];
130 NSError* localError = nil;
131
132 SFAuthenticatedEncryptionOperation* encryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:self.keySpecifier];
133 encryptionOperation.authenticationCodeLength = 8;
134 SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:dataToEncrypt withKey:self.fakeAKSKey error:&localError];
135
136 if (error) {
137 *error = localError;
138 }
139
140 if (ciphertext) {
141 void* wrappedKeyMutableBytes = wrappedKey.mutableBytes;
142 memcpy(wrappedKeyMutableBytes, ciphertext.ciphertext.bytes, 32);
143 memcpy(wrappedKeyMutableBytes + 32, ciphertext.initializationVector.bytes, 32);
144 memcpy(wrappedKeyMutableBytes + 64, ciphertext.authenticationCode.bytes, 8);
145
146 if (self.simulateRolledAKSKey && outKeyclass) {
147 *outKeyclass = keyclass | (key_class_last + 1);
148 }
149
150 return true;
151 }
152 else {
153 return false;
154 }
155 }
156
157 - (bool)fakeAKSDecryptWithKeybag:(keybag_handle_t)keybag
158 keyclass:(keyclass_t)keyclass
159 wrappedKeyData:(NSData*)wrappedKeyData
160 outKeyclass:(keyclass_t*)outKeyclass
161 unwrappedKey:(NSMutableData*)unwrappedKey
162 error:(NSError**)error
163 {
164 if (self.lockState == LockStateLockedAndDisallowAKS) {
165 if (error) {
166 *error = [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:NULL];
167 }
168 return false;
169 }
170
171 if (self.simulateRolledAKSKey && keyclass < key_class_last) {
172 // let's make decryption fail like it would if this were an old metadata key entry made with a generational AKS key, but we didn't store that info in the database
173 return false;
174 }
175
176 const uint8_t* wrappedKeyBytes = wrappedKeyData.bytes;
177
178 NSData* ciphertextData = [NSData dataWithBytes:wrappedKeyBytes length:32];
179 NSData* ivData = [NSData dataWithBytes:wrappedKeyBytes + 32 length:32];
180 NSData* authCodeData = [NSData dataWithBytes:wrappedKeyBytes + 64 length:8];
181 SFAuthenticatedCiphertext* ciphertext = [[SFAuthenticatedCiphertext alloc] initWithCiphertext:ciphertextData authenticationCode:authCodeData initializationVector:ivData];
182
183 NSError* localError = nil;
184
185 SFAuthenticatedEncryptionOperation* encryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:self.keySpecifier];
186 encryptionOperation.authenticationCodeLength = 8;
187 NSData* decryptedData = [encryptionOperation decrypt:ciphertext withKey:self.fakeAKSKey error:&localError];
188
189 // in real securityd, we go through AKS rather than SFCryptoServices
190 // we need to translate the error for proper handling
191 if ([localError.domain isEqualToString:SFCryptoServicesErrorDomain] && localError.code == SFCryptoServicesErrorDecryptionFailed) {
192 if (!self.simulateRolledAKSKey && keyclass > key_class_last) {
193 // for this case we want to simulate what happens when we try decrypting with a rolled keyclass on a device which has never been rolled, which is it ends up with a NotPermitted error from AKS which the security layer translates as locked keybag
194 localError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecInteractionNotAllowed userInfo:nil];
195 }
196 else {
197 localError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecDecode userInfo:nil];
198 }
199 }
200
201 if (error) {
202 *error = localError;
203 }
204
205 self.keyclassUsedForAKSDecryption = keyclass;
206 if (decryptedData && decryptedData.length <= unwrappedKey.length) {
207 memcpy(unwrappedKey.mutableBytes, decryptedData.bytes, decryptedData.length);
208 unwrappedKey.length = decryptedData.length;
209 self.didAKSDecrypt = YES;
210 return true;
211 }
212 else {
213 return false;
214 }
215 }
216
217 @end
218
219 #endif