2 * Copyright (c) 2019 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@
25 #import <XCTest/XCTest.h>
27 @interface SecItemTests : XCTestCase
31 @implementation SecItemTests
43 - (void)testAddGenericPassword {
46 attrs = [self addGenericPassword:@"delete-me" service:@"delete-me"];
47 XCTAssertNotNil(attrs, "should create genp");
48 XCTAssertNil(attrs[@"OSStatus"], "should have no error");
51 - (void)testAddTwoGenericPassword {
54 attrs = [self addGenericPassword:@"delete-me" service:@"delete-me"];
55 XCTAssertNotNil(attrs, "should create genp");
56 XCTAssertNil(attrs[@"OSStatus"], "should have no error");
58 attrs = [self addGenericPassword:@"delete-me2s" service:@"delete-me"];
59 XCTAssertNotNil(attrs, "should create genp");
60 XCTAssertNil(attrs[@"OSStatus"], "should have no error");
63 - (void)testAddCollidingGenericPassword {
66 attrs = [self addGenericPassword:@"delete-me" service:@"delete-me"];
67 XCTAssertNotNil(attrs, "should create genp");
69 attrs = [self addGenericPassword:@"delete-me" service:@"delete-me"];
70 XCTAssertNotNil(attrs, "should create genp");
71 XCTAssertEqual([attrs[@"OSStatus"] integerValue], errSecDuplicateItem, "should have duplicate item");
75 - (void)testMoveGenericPassword {
78 attrs = [self addGenericPassword:@"delete-me" service:@"delete-me"];
79 XCTAssertNotNil(attrs, "should create genp");
81 attrs = [self addGenericPassword:@"delete-me" service:@"delete-me"];
82 XCTAssertNotNil(attrs, "should create genp");
83 XCTAssertEqual([attrs[@"OSStatus"] integerValue], errSecDuplicateItem, "should have duplicate item");
85 XCTAssertEqual([self moveGenericPassword:@"delete-me" service:@"delete-me"
86 newAccount:@"delete-me2" newService:@"delete-me2"],
89 XCTAssertEqual([self moveGenericPassword:@"delete-me" service:@"delete-me"
90 newAccount:@"delete-me2" newService:@"delete-me2"],
95 //-MARK: helper functions
98 NSDictionary *allGenericPassword = @{
99 (id)kSecClass : (id)kSecClassGenericPassword,
100 (id)kSecUseDataProtectionKeychain : @(YES),
102 (void)SecItemDelete((__bridge CFDictionaryRef)allGenericPassword);
106 - (NSDictionary *)addGenericPassword:(NSString *)account service:(NSString *)service
108 NSDictionary* addQuery = @{
109 (id)kSecClass : (id)kSecClassGenericPassword,
110 (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
111 (id)kSecAttrAccount : account,
112 (id)kSecAttrService : service,
113 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
114 (id)kSecUseDataProtectionKeychain : @(YES),
115 (id)kSecReturnAttributes : @(YES),
117 CFTypeRef result = NULL;
119 OSStatus status = SecItemAdd((__bridge CFDictionaryRef)addQuery, &result);
121 return @{ @"OSStatus": @(status) };
123 if (result == NULL) {
126 if (CFGetTypeID(result) != CFDictionaryGetTypeID()) {
131 return (__bridge NSDictionary *)result;
135 - (OSStatus)moveGenericPassword:(NSString *)account service:(NSString *)service
136 newAccount:(NSString *)newAccount newService:(NSString *)newService
138 NSDictionary* updateQuery = @{
139 (id)kSecClass : (id)kSecClassGenericPassword,
140 (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
141 (id)kSecAttrAccount : account,
142 (id)kSecAttrService : service,
143 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
144 (id)kSecUseDataProtectionKeychain : @(YES),
145 (id)kSecReturnAttributes : @(YES),
147 NSDictionary *newAttributes = @{
148 (id)kSecAttrAccount : newAccount,
149 (id)kSecAttrService : newService,
152 OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)updateQuery, (__bridge CFDictionaryRef)newAttributes);