]> git.saurik.com Git - apple/security.git/blob - SecurityTests/cspxutils/clearPubKeyTest/clearPubKeyTest.cpp
Security-57740.31.2.tar.gz
[apple/security.git] / SecurityTests / cspxutils / clearPubKeyTest / clearPubKeyTest.cpp
1 /*
2 * clearPubKeyTest.cpp
3 *
4 * Test CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT. This cannot be run on a handsoff environment;
5 * it forces Keychain unlock dialogs.
6 */
7
8 #include <stdlib.h>
9 #include <strings.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <Security/Security.h>
13 #include "cspwrap.h"
14 #include "common.h"
15
16 #define KEYCHAIN_NAME "/tmp/clearPubKey.keychain"
17 #define KEYCHAIN_PWD "pwd"
18 #define KEY_ALG CSSM_ALGID_RSA
19 #define KEYSIZE 1024
20 #define ENCRALG CSSM_ALGID_RSA
21
22 static void usage(char **argv)
23 {
24 printf("usage: %s -v(erbose)\n", argv[0]);
25 exit(1);
26 }
27
28 static void printNoDialog()
29 {
30 printf("*** If you get a keychain unlock dialog here the test is failing ***\n");
31 }
32
33 static void printExpectDialog()
34 {
35 printf("*** You MUST get a keychain unlock dialog here (password = '%s') ***\n",
36 KEYCHAIN_PWD);
37 }
38
39 static bool didGetDialog()
40 {
41 fpurge(stdin);
42 printf("Enter 'y' if you just got a keychain unlock dialog: ");
43 if(getchar() == 'y') {
44 return 1;
45 }
46 printf("***Well, you really should have. Test failed.\n");
47 return 0;
48 }
49
50 static void verboseDisp(bool verbose, const char *str)
51 {
52 if(verbose) {
53 printf("...%s\n", str);
54 }
55 }
56
57 /* generate key pair, optionally storing the public key in encrypted form */
58 static int genKeyPair(
59 bool pubKeyIsEncrypted,
60 SecKeychainRef kcRef,
61 SecKeyRef *pubKeyRef,
62 SecKeyRef *privKeyRef)
63 {
64 /* gather keygen args */
65 CSSM_ALGORITHMS keyAlg = KEY_ALG;
66 uint32 keySizeInBits = KEYSIZE;
67 CSSM_KEYUSE pubKeyUsage = CSSM_KEYUSE_ANY;
68 uint32 pubKeyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
69 if(pubKeyIsEncrypted) {
70 pubKeyAttr |= CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT;
71 }
72 CSSM_KEYUSE privKeyUsage = CSSM_KEYUSE_ANY;
73 uint32 privKeyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE |
74 CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE;
75
76 OSStatus ortn = SecKeyCreatePair(kcRef, keyAlg, keySizeInBits, 0,
77 pubKeyUsage, pubKeyAttr,
78 privKeyUsage, privKeyAttr,
79 NULL, // default initial access for now
80 pubKeyRef, privKeyRef);
81 if(ortn) {
82 cssmPerror("SecKeyCreatePair", ortn);
83 return 1;
84 }
85 return 0;
86 }
87
88 /* encrypt something with a public key */
89 static int pubKeyEncrypt(
90 SecKeyRef pubKeyRef)
91 {
92 const CSSM_KEY *cssmKey;
93 OSStatus ortn;
94 CSSM_CSP_HANDLE cspHand;
95
96 ortn = SecKeyGetCSSMKey(pubKeyRef, &cssmKey);
97 if(ortn) {
98 cssmPerror("SecKeyGetCSSMKey", ortn);
99 return -1;
100 }
101 ortn = SecKeyGetCSPHandle(pubKeyRef, &cspHand);
102 if(ortn) {
103 cssmPerror("SecKeyGetCSPHandle", ortn);
104 return -1;
105 }
106
107 char *ptext = "something to encrypt";
108 CSSM_DATA ptextData = {strlen(ptext), (uint8 *)ptext};
109 CSSM_DATA ctextData = { 0, NULL };
110 CSSM_RETURN crtn;
111
112 crtn = cspEncrypt(cspHand, CSSM_ALGID_RSA,
113 0, CSSM_PADDING_PKCS1, // mode/pad
114 cssmKey, NULL,
115 0, 0, // effect/rounds
116 NULL, // IV
117 &ptextData, &ctextData, CSSM_FALSE);
118 if(crtn) {
119 return -1;
120 }
121 /* slighyly hazardous, allocated by CSPDL's allocator */
122 free(ctextData.Data);
123 return 0;
124 }
125
126 int main(int argc, char **argv)
127 {
128 bool verbose = false;
129
130 int arg;
131 while ((arg = getopt(argc, argv, "vh")) != -1) {
132 switch (arg) {
133 case 'v':
134 verbose = true;
135 break;
136 case 'h':
137 usage(argv);
138 }
139 }
140 if(optind != argc) {
141 usage(argv);
142 }
143
144 printNoDialog();
145
146 /* initial setup */
147 verboseDisp(verbose, "deleting keychain");
148 unlink(KEYCHAIN_NAME);
149
150 verboseDisp(verbose, "creating keychain");
151 SecKeychainRef kcRef = NULL;
152 OSStatus ortn = SecKeychainCreate(KEYCHAIN_NAME,
153 strlen(KEYCHAIN_PWD), KEYCHAIN_PWD,
154 false, NULL, &kcRef);
155 if(ortn) {
156 cssmPerror("SecKeychainCreate", ortn);
157 exit(1);
158 }
159
160 /*
161 * 1. Generate key pair with cleartext public key.
162 * Ensure we can use the public key when keychain is locked with no
163 * user interaction.
164 */
165
166 /* generate key pair, cleartext public key */
167 verboseDisp(verbose, "creating key pair, cleartext public key");
168 SecKeyRef pubKeyRef = NULL;
169 SecKeyRef privKeyRef = NULL;
170 if(genKeyPair(false, kcRef, &pubKeyRef, &privKeyRef)) {
171 exit(1);
172 }
173
174 /* Use generated cleartext public key with locked keychain */
175 verboseDisp(verbose, "locking keychain, exporting public key");
176 SecKeychainLock(kcRef);
177 CFDataRef exportData = NULL;
178 ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
179 if(ortn) {
180 cssmPerror("SecKeychainCreate", ortn);
181 exit(1);
182 }
183 CFRelease(exportData);
184
185 verboseDisp(verbose, "locking keychain, encrypting with public key");
186 SecKeychainLock(kcRef);
187 if(pubKeyEncrypt(pubKeyRef)) {
188 exit(1);
189 }
190
191 /* reset */
192 verboseDisp(verbose, "deleting keys");
193 ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
194 if(ortn) {
195 cssmPerror("SecKeychainItemDelete", ortn);
196 exit(1);
197 }
198 ortn = SecKeychainItemDelete((SecKeychainItemRef)privKeyRef);
199 if(ortn) {
200 cssmPerror("SecKeychainItemDelete", ortn);
201 exit(1);
202 }
203 CFRelease(pubKeyRef);
204 CFRelease(privKeyRef);
205
206 /*
207 * 2. Generate key pair with encrypted public key.
208 * Ensure that user interaction is required when we use the public key
209 * when keychain is locked.
210 */
211
212 verboseDisp(verbose, "programmatically unlocking keychain");
213 ortn = SecKeychainUnlock(kcRef, strlen(KEYCHAIN_PWD), KEYCHAIN_PWD, TRUE);
214 if(ortn) {
215 cssmPerror("SecKeychainItemDelete", ortn);
216 exit(1);
217 }
218
219 /* generate key pair, encrypted public key */
220 verboseDisp(verbose, "creating key pair, encrypted public key");
221 if(genKeyPair(true, kcRef, &pubKeyRef, &privKeyRef)) {
222 exit(1);
223 }
224
225 /* Use generated encrypted public key with locked keychain */
226 verboseDisp(verbose, "locking keychain, exporting public key");
227 SecKeychainLock(kcRef);
228 printExpectDialog();
229 ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
230 if(ortn) {
231 cssmPerror("SecKeychainCreate", ortn);
232 exit(1);
233 }
234 /* we'll use that exported blob later to test import */
235 if(!didGetDialog()) {
236 exit(1);
237 }
238
239 verboseDisp(verbose, "locking keychain, encrypting with public key");
240 SecKeychainLock(kcRef);
241 printExpectDialog();
242 if(pubKeyEncrypt(pubKeyRef)) {
243 exit(1);
244 }
245 if(!didGetDialog()) {
246 exit(1);
247 }
248
249 /* reset */
250 printNoDialog();
251 verboseDisp(verbose, "locking keychain");
252 SecKeychainLock(kcRef);
253 verboseDisp(verbose, "deleting keys");
254 ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
255 if(ortn) {
256 cssmPerror("SecKeychainItemDelete", ortn);
257 exit(1);
258 }
259 ortn = SecKeychainItemDelete((SecKeychainItemRef)privKeyRef);
260 if(ortn) {
261 cssmPerror("SecKeychainItemDelete", ortn);
262 exit(1);
263 }
264 CFRelease(pubKeyRef);
265 CFRelease(privKeyRef);
266
267 /*
268 * 3. Import public key, storing in cleartext. Ensure that the import
269 * doesn't require unlock, and ensure we can use the public key
270 * when keychain is locked with no user interaction.
271 */
272
273 printNoDialog();
274 verboseDisp(verbose, "locking keychain");
275 SecKeychainLock(kcRef);
276
277 /* import public key - default is in the clear */
278 verboseDisp(verbose, "importing public key, store in the clear (default)");
279 CFArrayRef outArray = NULL;
280 SecExternalFormat format = kSecFormatOpenSSL;
281 SecExternalItemType type = kSecItemTypePublicKey;
282 ortn = SecKeychainItemImport(exportData,
283 NULL, &format, &type,
284 0, NULL,
285 kcRef, &outArray);
286 if(ortn) {
287 cssmPerror("SecKeychainItemImport", ortn);
288 exit(1);
289 }
290 CFRelease(exportData);
291 if(CFArrayGetCount(outArray) != 1) {
292 printf("***Unexpected outArray size (%ld) after import\n",
293 (long)CFArrayGetCount(outArray));
294 exit(1);
295 }
296 pubKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
297 if(CFGetTypeID(pubKeyRef) != SecKeyGetTypeID()) {
298 printf("***Unexpected item type after import\n");
299 exit(1);
300 }
301
302 /* Use imported cleartext public key with locked keychain */
303 verboseDisp(verbose, "locking keychain, exporting public key");
304 SecKeychainLock(kcRef);
305 exportData = NULL;
306 ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
307 if(ortn) {
308 cssmPerror("SecKeychainItemExport", ortn);
309 exit(1);
310 }
311 /* we'll use exportData again */
312
313 verboseDisp(verbose, "locking keychain, encrypting with public key");
314 SecKeychainLock(kcRef);
315 if(pubKeyEncrypt(pubKeyRef)) {
316 exit(1);
317 }
318
319 /* reset */
320 verboseDisp(verbose, "deleting key");
321 ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
322 if(ortn) {
323 cssmPerror("SecKeychainItemDelete", ortn);
324 exit(1);
325 }
326 CFRelease(pubKeyRef);
327
328 /*
329 * Import public key, storing in encrypted form.
330 * Ensure that user interaction is required when we use the public key
331 * when keychain is locked.
332 */
333
334 /* import public key, encrypted in the keychain */
335 SecKeyImportExportParameters impExpParams;
336 memset(&impExpParams, 0, sizeof(impExpParams));
337 impExpParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
338 impExpParams.keyAttributes = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE |
339 CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT;
340 verboseDisp(verbose, "importing public key, store encrypted");
341 printExpectDialog();
342 outArray = NULL;
343 format = kSecFormatOpenSSL;
344 type = kSecItemTypePublicKey;
345 ortn = SecKeychainItemImport(exportData,
346 NULL, &format, &type,
347 0, &impExpParams,
348 kcRef, &outArray);
349 if(ortn) {
350 cssmPerror("SecKeychainItemImport", ortn);
351 exit(1);
352 }
353 if(!didGetDialog()) {
354 exit(1);
355 }
356 CFRelease(exportData);
357 if(CFArrayGetCount(outArray) != 1) {
358 printf("***Unexpected outArray size (%ld) after import\n",
359 (long)CFArrayGetCount(outArray));
360 exit(1);
361 }
362 pubKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
363 if(CFGetTypeID(pubKeyRef) != SecKeyGetTypeID()) {
364 printf("***Unexpected item type after import\n");
365 exit(1);
366 }
367
368 /* Use imported encrypted public key with locked keychain */
369 verboseDisp(verbose, "locking keychain, exporting public key");
370 SecKeychainLock(kcRef);
371 printExpectDialog();
372 ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
373 if(ortn) {
374 cssmPerror("SecKeychainItemExport", ortn);
375 exit(1);
376 }
377 if(!didGetDialog()) {
378 exit(1);
379 }
380 CFRelease(exportData);
381
382 verboseDisp(verbose, "locking keychain, encrypting with public key");
383 SecKeychainLock(kcRef);
384 printExpectDialog();
385 if(pubKeyEncrypt(pubKeyRef)) {
386 exit(1);
387 }
388 if(!didGetDialog()) {
389 exit(1);
390 }
391
392 SecKeychainDelete(kcRef);
393 printf("...test succeeded.\n");
394 return 0;
395 }