2 * Copyright (c) 2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #import <Security/Security.h>
25 #import <Security/SecItemPriv.h>
27 #import "KeychainXCTest.h"
30 @interface KeychainEntitlementsTest : KeychainXCTest
33 @implementation KeychainEntitlementsTest
35 - (void)testNoEntitlements {
36 NSDictionary *params = @{ (id)kSecAttrNoLegacy: @YES,
37 (id)kSecClass: (id)kSecClassGenericPassword, (id)kSecAttrLabel: @"label", };
39 // Application with no keychain-related entitlements at all, but CopyMatching must work in order to support
40 // backward compatibility with smart-card-enabled macos applications (com.apple.token AG is added automatically in this case).
41 [self setEntitlements:@{} validated:false];
42 XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
44 // However, write access is declined for such application.
45 XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
46 XCTAssertEqual(SecItemDelete((CFDictionaryRef)params), errSecMissingEntitlement);
50 - (void)testInvalidEntitlementsAppID {
52 params = @{ (id)kSecAttrNoLegacy: @YES,
53 (id)kSecClass: (id)kSecClassGenericPassword,
54 (id)kSecAttrLabel: @"label", };
56 // Un-validated app-identifier entitlements must disallow any access to the keychain.
57 [self setEntitlements:@{ @"com.apple.application-identifier": @"com.apple.test-app-identifier" } validated:false];
58 XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
59 XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
60 XCTAssertEqual(SecItemDelete((CFDictionaryRef)params), errSecMissingEntitlement);
62 // However, keychain-access-groups entitlements should work even if not validated, AMFI will take care
63 // about cases when keychain-access-groups is not correctly used and we have to support cases when
64 // process contains application-groups entitlement but that entitlement is not present in provisioned profile, thus
65 // failing entitlement validation test.
66 [self setEntitlements:@{ @"keychain-access-groups": @[@"com.apple.test-app-identifier"] } validated:false];
67 XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
68 XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecSuccess);
69 XCTAssertEqual(SecItemDelete((CFDictionaryRef)params), errSecSuccess);
71 #endif // TARGET_OS_OSX
73 - (void)testValidEntitlementsAppID {
75 params = @{ (id)kSecAttrNoLegacy: @YES,
76 (id)kSecClass: (id)kSecClassGenericPassword,
77 (id)kSecAttrLabel: @"label",
78 (id)kSecAttrAccessGroup: @"com.apple.test-app-identifier", };
80 [self setEntitlements:@{ @"com.apple.application-identifier": @"com.apple.test-app-identifier" } validated:true];
82 [self setEntitlements:@{ @"application-identifier": @"com.apple.test-app-identifier" } validated:true];
84 XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
85 XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecSuccess);
86 XCTAssertEqual(SecItemDelete((CFDictionaryRef)params), errSecSuccess);
89 - (void)testDisallowTokenGroupWrite {
92 // Explicit com.apple.token agrp is not acceptable for writing operations, but acceptable for reading.
93 params = @{ (id)kSecAttrNoLegacy: @YES,
94 (id)kSecClass: (id)kSecClassGenericPassword,
95 (id)kSecAttrLabel: @"label",
96 (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, };
97 [self setEntitlements:@{ @"com.apple.application-identifier": (id)kSecAttrAccessGroupToken } validated:true];
98 XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
99 XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
100 XCTAssertEqual(SecItemDelete((CFDictionaryRef)params), errSecMissingEntitlement);
104 - (void)testInvalidAppGroups {
105 NSDictionary *params;
106 params = @{ (id)kSecAttrNoLegacy: @YES,
107 (id)kSecClass: (id)kSecClassGenericPassword,
108 (id)kSecAttrLabel: @"label", };
109 [self setEntitlements:@{ @"com.apple.security.application-groups": @[@"com.apple.test-app-groups"] } validated:false];
111 // Invalid access group entitlement should still allow querying com.apple.token
112 XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
114 // But write-access is forbidden,
115 XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
116 XCTAssertEqual(SecItemDelete((CFDictionaryRef)params), errSecMissingEntitlement);
118 // Similarly as explicitly referring to AG specified in unverified entitlements.
119 params = @{ (id)kSecAttrNoLegacy: @YES,
120 (id)kSecClass: (id)kSecClassGenericPassword,
121 (id)kSecAttrLabel: @"label",
122 (id)kSecAttrAccessGroup: @"com.apple.test-app-groups", };
123 XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
124 XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
125 XCTAssertEqual(SecItemDelete((CFDictionaryRef)params), errSecMissingEntitlement);
127 // Explicitly referring to com.apple.token should work fine too.
128 params = @{ (id)kSecAttrNoLegacy: @YES,
129 (id)kSecClass: (id)kSecClassGenericPassword,
130 (id)kSecAttrLabel: @"label",
131 (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, };
132 XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
134 #endif // TARGET_OS_OSX
138 #endif // USE_KEYSTORE