]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/regressions/kc-28-p12-import.m
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-28-p12-import.m
1 /*
2 * Copyright (c) 2016 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 xLicense.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #import <Security/Security.h>
25 #include "keychain_regressions.h"
26 #include "kc-helpers.h"
27 #include "kc-item-helpers.h"
28 #include "kc-key-helpers.h"
29 #include "kc-identity-helpers.h"
30
31 #import <Foundation/Foundation.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <Security/oidscert.h>
37 #include <Security/oidsattr.h>
38 #include <Security/oidsalg.h>
39 #include <Security/x509defs.h>
40 #include <Security/cssmapi.h>
41 #include <Security/cssmapple.h>
42 #include <Security/certextensions.h>
43
44 #include <Security/SecKeychain.h>
45 #include <Security/SecKeychainItem.h>
46 #include <Security/SecImportExport.h>
47 #include <Security/SecIdentity.h>
48 #include <Security/SecIdentitySearch.h>
49 #include <Security/SecKey.h>
50 #include <Security/SecCertificate.h>
51 #include <Security/SecItem.h>
52
53 // Turn off deprecated API warnings
54 //#pragma clang diagnostic ignored "-Wdeprecated-declarations"
55
56 static void
57 verifyPrivateKeyExtractability(BOOL extractable, NSArray *items)
58 {
59 // After importing items, check that private keys (if any) have
60 // the expected extractable attribute value.
61
62 CFIndex count = [items count];
63 is(count, 1, "One identity added");
64
65 for (id item in items)
66 {
67 OSStatus status;
68 SecKeyRef aKey = NULL;
69 if (SecKeyGetTypeID() == CFGetTypeID((CFTypeRef)item)) {
70 aKey = (SecKeyRef) CFRetain((CFTypeRef)item);
71 fprintf(stdout, "Verifying imported SecKey\n");
72 }
73 else if (SecIdentityGetTypeID() == CFGetTypeID((CFTypeRef)item)) {
74 status = SecIdentityCopyPrivateKey((SecIdentityRef)item, &aKey);
75 ok_status(status, "%s: SecIdentityCopyPrivateKey", testName);
76 }
77
78 ok(aKey, "%s: Have a key to test", testName);
79
80 if (aKey)
81 {
82 const CSSM_KEY *cssmKey;
83 OSStatus status = SecKeyGetCSSMKey(aKey, &cssmKey);
84 ok_status(status, "%s: SecKeyGetCSSMKey", testName);
85 if (status != noErr) {
86 continue;
87 }
88 is(cssmKey->KeyHeader.KeyClass, CSSM_KEYCLASS_PRIVATE_KEY, "%s: key is private key", testName);
89
90 if (!(cssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)) {
91 fprintf(stdout, "Skipping non-private key (KeyClass=%d)\n", cssmKey->KeyHeader.KeyClass);
92 continue; // only checking private keys
93 }
94 BOOL isExtractable = (cssmKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE) ? YES : NO;
95 is(isExtractable, extractable, "%s: key extractability matches expectations", testName);
96
97 CFRelease(aKey);
98 }
99 }
100 }
101
102 static void
103 setIdentityPreferenceForImportedIdentity(SecKeychainRef importKeychain, NSString *name, NSArray *items)
104 {
105 CFArrayRef importedItems = (CFArrayRef)items;
106
107 if (importedItems)
108 {
109 SecIdentityRef importedIdRef = NULL;
110 CFIndex dex, numItems = CFArrayGetCount(importedItems);
111 for(dex=0; dex<numItems; dex++)
112 {
113 CFTypeRef item = CFArrayGetValueAtIndex(importedItems, dex);
114 if(CFGetTypeID(item) == SecIdentityGetTypeID())
115 {
116 OSStatus status = noErr;
117 importedIdRef = (SecIdentityRef)item;
118
119 status = SecIdentitySetPreference(importedIdRef, (CFStringRef)name, (CSSM_KEYUSE)0);
120 ok_status(status, "%s: SecIdentitySetPreference", testName);
121 break;
122 }
123 }
124 ok(importedIdRef, "%s: identity found?", testName);
125 }
126 else
127 {
128 fail("%s: no items passed to setIdentityPreferenceForImportedIdentity", testName);
129 pass("test numbers match");
130 }
131 }
132
133 static void removeIdentityPreference(bool test) {
134 // Clean up the identity preference, since it's in the default keychain
135 CFMutableDictionaryRef q = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
136 CFDictionarySetValue(q, kSecClass, kSecClassGenericPassword);
137 q = addLabel(q, CFSTR("kc-28-p12-import@apple.com"));
138
139 if(test) {
140 ok_status(SecItemDelete(q), "%s: SecItemDelete (identity preference)", testName);
141 } else {
142 // Our caller doesn't care if this works or not.
143 SecItemDelete(q);
144 }
145 CFReleaseNull(q);
146 }
147
148
149 static OSStatus
150 testP12Import(BOOL extractable, SecKeychainRef keychain, const char *p12Path, CFStringRef password, bool useDeprecatedAPI)
151 {
152 OSStatus status = paramErr;
153
154 NSString *file = [NSString stringWithUTF8String:p12Path];
155 NSData *p12Data = [[NSData alloc] initWithContentsOfFile:file];
156 NSArray *keyAttrs = nil;
157 NSArray *outItems = nil;
158
159 SecExternalFormat externFormat = kSecFormatPKCS12;
160 SecExternalItemType itemType = kSecItemTypeAggregate; // certificates and keys
161
162 // Decide which parameter structure to use.
163 SecKeyImportExportParameters keyParamsOld; // for SecKeychainItemImport, deprecated as of 10.7
164 SecItemImportExportKeyParameters keyParamsNew; // for SecItemImport, 10.7 and later
165
166 void *keyParamsPtr = (useDeprecatedAPI) ? (void*)&keyParamsOld : (void*)&keyParamsNew;
167
168 if (useDeprecatedAPI) // SecKeychainItemImport, deprecated as of 10.7
169 {
170 SecKeyImportExportParameters *keyParams = (SecKeyImportExportParameters *)keyParamsPtr;
171 memset(keyParams, 0, sizeof(SecKeyImportExportParameters));
172 keyParams->version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
173 keyParams->passphrase = password;
174 if (!extractable)
175 {
176 // explicitly set the key attributes, omitting the CSSM_KEYATTR_EXTRACTABLE bit
177 keyParams->keyAttributes = CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE;
178 }
179 }
180 else // SecItemImport, 10.7 and later (preferred interface)
181 {
182 SecItemImportExportKeyParameters *keyParams = (SecItemImportExportKeyParameters *)keyParamsPtr;
183 memset(keyParams, 0, sizeof(SecItemImportExportKeyParameters));
184 keyParams->version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
185 keyParams->passphrase = password;
186 if (!extractable)
187 {
188 // explicitly set the key attributes, omitting kSecAttrIsExtractable
189 keyAttrs = [[NSArray alloc] initWithObjects: (id) kSecAttrIsPermanent, kSecAttrIsSensitive, nil];
190 keyParams->keyAttributes = (CFArrayRef) keyAttrs;
191 }
192 }
193
194 if (useDeprecatedAPI) // SecKeychainItemImport, deprecated as of 10.7
195 {
196 SecKeyImportExportParameters *keyParams = (SecKeyImportExportParameters *)keyParamsPtr;
197
198 status = SecKeychainItemImport((CFDataRef)p12Data,
199 NULL,
200 &externFormat,
201 &itemType,
202 0, /* flags not used (yet) */
203 keyParamsPtr,
204 keychain,
205 (CFArrayRef*)&outItems);
206 ok_status(status, "%s: SecKeychainItemImport", testName);
207 }
208 else // SecItemImport
209 {
210 SecItemImportExportKeyParameters *keyParams = (SecItemImportExportKeyParameters *)keyParamsPtr;
211
212 status = SecItemImport((CFDataRef)p12Data,
213 NULL,
214 &externFormat,
215 &itemType,
216 0, /* flags not used (yet) */
217 keyParamsPtr,
218 keychain,
219 (CFArrayRef*)&outItems);
220 ok_status(status, "%s: SecItemImport", testName);
221 }
222
223 verifyPrivateKeyExtractability(extractable, outItems);
224
225 checkN(testName, makeQueryKeyDictionaryWithLabel(keychain, kSecAttrKeyClassPrivate, CFSTR("test_import")), 1);
226 checkN(testName, addLabel(makeBaseQueryDictionary(keychain, kSecClassCertificate), CFSTR("test_import")), 1);
227
228 setIdentityPreferenceForImportedIdentity(keychain, @"kc-28-p12-import@apple.com", outItems);
229
230 deleteItems((__bridge CFArrayRef) outItems);
231
232 [keyAttrs release];
233 [p12Data release];
234 [outItems release];
235
236 return status;
237 }
238
239 int kc_28_p12_import(int argc, char *const *argv)
240 {
241 plan_tests(70);
242 initializeKeychainTests(__FUNCTION__);
243
244 SecKeychainRef kc = getPopulatedTestKeychain();
245
246 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
247
248 removeIdentityPreference(false); // if there's still an identity preference in the keychain, we'll get prompts. Delete it pre-emptively (but don't test about it)
249
250 writeFile(keychainTempFile, test_import_p12, test_import_p12_len);
251 testP12Import(true, kc, keychainTempFile, CFSTR("password"), false);
252 testP12Import(true, kc, keychainTempFile, CFSTR("password"), true);
253
254 testP12Import(false, kc, keychainTempFile, CFSTR("password"), false);
255 testP12Import(false, kc, keychainTempFile, CFSTR("password"), true);
256
257 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", testName);
258 CFReleaseNull(kc);
259
260 removeIdentityPreference(true);
261
262 checkPrompts(0, "No prompts while importing items");
263
264 [pool release];
265
266 deleteTestFiles();
267 return 0;
268 }