]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/regressions/kc-27-key-non-extractable.c
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-27-key-non-extractable.c
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 #import <Security/SecCertificatePriv.h>
26
27 #include "keychain_regressions.h"
28 #include "kc-helpers.h"
29
30 //
31 // Test for <rdar://9251635>
32 //
33
34 #include <stdlib.h>
35 #include <err.h>
36
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <Security/Security.h>
39 #include <Security/SecItemPriv.h>
40
41 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
42
43 /*
44 Note: the following will show all private keys with their label
45 and extractable attribute value (in attribute 0x00000010):
46
47 $ security dump | grep -A 16 "0x00000000 <uint32>=0x00000010" | grep -e ^\ *0x000000[01][01] -e --
48 */
49
50
51 static OSStatus GenerateRSAKeyPair(
52 SecKeychainRef keychain,
53 CFStringRef keyLabel,
54 int keySizeValue,
55 Boolean *extractable,
56 SecKeyRef *publicKeyRef,
57 SecKeyRef *privateKeyRef)
58 {
59 OSStatus status;
60 CFNumberRef keySize = CFNumberCreate(NULL, kCFNumberIntType, &keySizeValue);
61
62 // create a SecAccessRef to set up the initial access control settings for this key
63 // (this step is optional; if omitted, the creating application has access to the key)
64 // note: the access descriptor should be the same string as will be used for the item's label,
65 // since it's the string that is displayed by the access confirmation dialog to describe the item.
66 SecAccessRef access = NULL;
67 status = SecAccessCreate(keyLabel, NULL, &access);
68
69 // create a dictionary of parameters describing the key we want to create
70 CFMutableDictionaryRef params = CFDictionaryCreateMutable(NULL, 0,
71 &kCFTypeDictionaryKeyCallBacks,
72 &kCFTypeDictionaryValueCallBacks);
73 /*
74 From the header doc for SecKeyGeneratePair (seems to be incomplete...):
75 * kSecAttrLabel default NULL
76 * kSecAttrIsPermanent if this key is present and has a Boolean
77 value of true, the key or key pair will be added to the default
78 keychain.
79 * kSecAttrApplicationTag default NULL
80 * kSecAttrEffectiveKeySize default NULL same as kSecAttrKeySizeInBits
81 * kSecAttrCanEncrypt default false for private keys, true for public keys
82 * kSecAttrCanDecrypt default true for private keys, false for public keys
83 * kSecAttrCanDerive default true
84 * kSecAttrCanSign default true for private keys, false for public keys
85 * kSecAttrCanVerify default false for private keys, true for public keys
86 * kSecAttrCanWrap default false for private keys, true for public keys
87 * kSecAttrCanUnwrap default true for private keys, false for public keys
88 */
89 CFDictionaryAddValue( params, kSecUseKeychain, keychain );
90 CFDictionaryAddValue( params, kSecAttrAccess, access );
91 CFDictionaryAddValue( params, kSecAttrKeyType, kSecAttrKeyTypeRSA );
92 CFDictionaryAddValue( params, kSecAttrKeySizeInBits, keySize ); CFReleaseNull(keySize);
93 CFDictionaryAddValue( params, kSecAttrIsPermanent, kCFBooleanTrue );
94
95 if (extractable)
96 CFDictionaryAddValue( params, kSecAttrIsExtractable, (*extractable) ? kCFBooleanTrue : kCFBooleanFalse );
97 if (keyLabel)
98 CFDictionaryAddValue( params, kSecAttrLabel, keyLabel );
99
100 // generate the key
101 status = SecKeyGeneratePair(params, publicKeyRef, privateKeyRef);
102 ok_status(status, "%s: SecKeyGeneratePair", testName);
103
104 if (params) CFRelease(params);
105 if (access) CFRelease(access);
106
107 return status;
108 }
109
110 static int testExtractable(
111 SecKeychainRef keychain,
112 Boolean extractable,
113 Boolean explicit)
114 {
115 OSStatus status;
116 SecKeyRef publicKeyRef = NULL;
117 SecKeyRef privateKeyRef = NULL;
118 CFStringRef label = (extractable) ? CFSTR("test-extractable-YES") : CFSTR("test-extractable-NO");
119 Boolean *extractablePtr = (explicit) ? &extractable : NULL;
120
121 status = GenerateRSAKeyPair(keychain,
122 label,
123 1024, // size
124 extractablePtr,
125 &publicKeyRef,
126 &privateKeyRef);
127
128 if (status != noErr) {
129 //errx(EXIT_FAILURE, "Unable to get key pair (err = %d)", status);
130 return status;
131 }
132
133 // check that the attributes of the generated private key are what we think they are
134 const CSSM_KEY *cssmPrivKey;
135 status = SecKeyGetCSSMKey(privateKeyRef, &cssmPrivKey);
136 ok_status(status, "%s: SecKeyGetCSSMKey", testName);
137
138 if (status != noErr) {
139 //errx(EXIT_FAILURE, "Unable to get CSSM reference key (err = %d)", status);
140 return status;
141 }
142 if (extractable) {
143 ok(cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE, "%s: check private key marked as extractable (as requested)", testName);
144 if (!(cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
145 //errx(EXIT_FAILURE, "Oops! the private key was not marked as extractable!");
146 return 1;
147 }
148 }
149 else {
150 ok(!(cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE), "%s: check private key marked as non-extractable (as requested)", testName);
151 if (cssmPrivKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE) {
152 //errx(EXIT_FAILURE, "Oops! the private key was marked as extractable!");
153 return 1;
154 }
155 }
156
157 SecKeyImportExportParameters keyParams;
158 memset(&keyParams, 0, sizeof(keyParams));
159 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
160 keyParams.passphrase = CFSTR("borken");
161
162 CFDataRef exportedData = NULL;
163
164 status = SecKeychainItemExport(privateKeyRef, kSecFormatWrappedPKCS8, 0, &keyParams, &exportedData);
165 if(extractable) {
166 ok_status(status, "%s: SecKeychainItemExport (PKCS8) (and we expected it to succeed)", testName);
167 } else {
168 is(status, errSecDataNotAvailable, "%s: SecKeychainItemExport (PKCS8) (and we expected this to fail with errSecDataNotAvailable)", testName);
169 }
170
171 status = SecKeychainItemExport(privateKeyRef, kSecFormatPKCS12, 0, &keyParams, &exportedData);
172 if(extractable) {
173 ok_status(status, "%s: SecKeychainItemExport(and we expected it to succeed)", testName);
174 } else {
175 is(status, errSecDataNotAvailable, "%s: SecKeychainItemExport (PKCS12) (and we expected this to fail with errSecDataNotAvailable)", testName);
176 }
177
178 if (status != noErr) {
179 if (extractable) {
180 //errx(EXIT_FAILURE, "Unable to export extractable key! (err = %d)", status);
181 return 1;
182 }
183 else {
184 status = 0; // wasn't extractable, so this is the expected result
185 }
186 }
187 else if (status == noErr && !extractable) {
188 //errx(EXIT_FAILURE, "Was able to export non-extractable key! (err = %d)", status);
189 return 1;
190 }
191
192 status = SecKeychainItemDelete((SecKeychainItemRef)publicKeyRef);
193 ok_status(status, "%s: SecKeychainItemDelete", testName);
194 if (status != noErr) {
195 warnx("Unable to delete created public key from keychain (err = %d)", (int)status);
196 }
197
198 status = SecKeychainItemDelete((SecKeychainItemRef)privateKeyRef);
199 ok_status(status, "%s: SecKeychainItemDelete", testName);
200 if (status != noErr) {
201 warnx("Unable to delete created private key from keychain (err = %d)", (int)status);
202 }
203
204 CFRelease(publicKeyRef);
205 CFRelease(privateKeyRef);
206
207 return 0;
208 }
209
210
211 int kc_27_key_non_extractable(int argc, char *const *argv)
212 {
213 plan_tests(24);
214 initializeKeychainTests(__FUNCTION__);
215
216 SecKeychainRef kc = getPopulatedTestKeychain();
217
218 // test case 1: extractable
219 startTest("Extract extractable key");
220 testExtractable(kc, TRUE, TRUE);
221
222 // test case 2: non-extractable
223 startTest("Extract non-extractable key");
224 testExtractable(kc, FALSE, TRUE);
225
226 // test case 3: extractable (when not explicitly specified)
227 startTest("Extract implicitly extractable key");
228 testExtractable(kc, TRUE, FALSE);
229
230 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", testName);
231 CFRelease(kc);
232
233 deleteTestFiles();
234 return 0;
235 }
236