4 * Test CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT. This cannot be run on a handsoff environment;
5 * it forces Keychain unlock dialogs.
12 #include <Security/Security.h>
16 #define KEYCHAIN_NAME "/tmp/clearPubKey.keychain"
17 #define KEYCHAIN_PWD "pwd"
18 #define KEY_ALG CSSM_ALGID_RSA
20 #define ENCRALG CSSM_ALGID_RSA
22 static void usage(char **argv
)
24 printf("usage: %s -v(erbose)\n", argv
[0]);
28 static void printNoDialog()
30 printf("*** If you get a keychain unlock dialog here the test is failing ***\n");
33 static void printExpectDialog()
35 printf("*** You MUST get a keychain unlock dialog here (password = '%s') ***\n",
39 static bool didGetDialog()
42 printf("Enter 'y' if you just got a keychain unlock dialog: ");
43 if(getchar() == 'y') {
46 printf("***Well, you really should have. Test failed.\n");
50 static void verboseDisp(bool verbose
, const char *str
)
53 printf("...%s\n", str
);
57 /* generate key pair, optionally storing the public key in encrypted form */
58 static int genKeyPair(
59 bool pubKeyIsEncrypted
,
62 SecKeyRef
*privKeyRef
)
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
;
72 CSSM_KEYUSE privKeyUsage
= CSSM_KEYUSE_ANY
;
73 uint32 privKeyAttr
= CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
|
74 CSSM_KEYATTR_PERMANENT
| CSSM_KEYATTR_SENSITIVE
;
76 OSStatus ortn
= SecKeyCreatePair(kcRef
, keyAlg
, keySizeInBits
, 0,
77 pubKeyUsage
, pubKeyAttr
,
78 privKeyUsage
, privKeyAttr
,
79 NULL
, // default initial access for now
80 pubKeyRef
, privKeyRef
);
82 cssmPerror("SecKeyCreatePair", ortn
);
88 /* encrypt something with a public key */
89 static int pubKeyEncrypt(
92 const CSSM_KEY
*cssmKey
;
94 CSSM_CSP_HANDLE cspHand
;
96 ortn
= SecKeyGetCSSMKey(pubKeyRef
, &cssmKey
);
98 cssmPerror("SecKeyGetCSSMKey", ortn
);
101 ortn
= SecKeyGetCSPHandle(pubKeyRef
, &cspHand
);
103 cssmPerror("SecKeyGetCSPHandle", ortn
);
107 char *ptext
= "something to encrypt";
108 CSSM_DATA ptextData
= {strlen(ptext
), (uint8
*)ptext
};
109 CSSM_DATA ctextData
= { 0, NULL
};
112 crtn
= cspEncrypt(cspHand
, CSSM_ALGID_RSA
,
113 0, CSSM_PADDING_PKCS1
, // mode/pad
115 0, 0, // effect/rounds
117 &ptextData
, &ctextData
, CSSM_FALSE
);
121 /* slighyly hazardous, allocated by CSPDL's allocator */
122 free(ctextData
.Data
);
126 int main(int argc
, char **argv
)
128 bool verbose
= false;
131 while ((arg
= getopt(argc
, argv
, "vh")) != -1) {
147 verboseDisp(verbose
, "deleting keychain");
148 unlink(KEYCHAIN_NAME
);
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
);
156 cssmPerror("SecKeychainCreate", ortn
);
161 * 1. Generate key pair with cleartext public key.
162 * Ensure we can use the public key when keychain is locked with no
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
)) {
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
);
180 cssmPerror("SecKeychainCreate", ortn
);
183 CFRelease(exportData
);
185 verboseDisp(verbose
, "locking keychain, encrypting with public key");
186 SecKeychainLock(kcRef
);
187 if(pubKeyEncrypt(pubKeyRef
)) {
192 verboseDisp(verbose
, "deleting keys");
193 ortn
= SecKeychainItemDelete((SecKeychainItemRef
)pubKeyRef
);
195 cssmPerror("SecKeychainItemDelete", ortn
);
198 ortn
= SecKeychainItemDelete((SecKeychainItemRef
)privKeyRef
);
200 cssmPerror("SecKeychainItemDelete", ortn
);
203 CFRelease(pubKeyRef
);
204 CFRelease(privKeyRef
);
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.
212 verboseDisp(verbose
, "programmatically unlocking keychain");
213 ortn
= SecKeychainUnlock(kcRef
, strlen(KEYCHAIN_PWD
), KEYCHAIN_PWD
, TRUE
);
215 cssmPerror("SecKeychainItemDelete", ortn
);
219 /* generate key pair, encrypted public key */
220 verboseDisp(verbose
, "creating key pair, encrypted public key");
221 if(genKeyPair(true, kcRef
, &pubKeyRef
, &privKeyRef
)) {
225 /* Use generated encrypted public key with locked keychain */
226 verboseDisp(verbose
, "locking keychain, exporting public key");
227 SecKeychainLock(kcRef
);
229 ortn
= SecKeychainItemExport(pubKeyRef
, kSecFormatOpenSSL
, 0, NULL
, &exportData
);
231 cssmPerror("SecKeychainCreate", ortn
);
234 /* we'll use that exported blob later to test import */
235 if(!didGetDialog()) {
239 verboseDisp(verbose
, "locking keychain, encrypting with public key");
240 SecKeychainLock(kcRef
);
242 if(pubKeyEncrypt(pubKeyRef
)) {
245 if(!didGetDialog()) {
251 verboseDisp(verbose
, "locking keychain");
252 SecKeychainLock(kcRef
);
253 verboseDisp(verbose
, "deleting keys");
254 ortn
= SecKeychainItemDelete((SecKeychainItemRef
)pubKeyRef
);
256 cssmPerror("SecKeychainItemDelete", ortn
);
259 ortn
= SecKeychainItemDelete((SecKeychainItemRef
)privKeyRef
);
261 cssmPerror("SecKeychainItemDelete", ortn
);
264 CFRelease(pubKeyRef
);
265 CFRelease(privKeyRef
);
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.
274 verboseDisp(verbose
, "locking keychain");
275 SecKeychainLock(kcRef
);
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
,
287 cssmPerror("SecKeychainItemImport", ortn
);
290 CFRelease(exportData
);
291 if(CFArrayGetCount(outArray
) != 1) {
292 printf("***Unexpected outArray size (%ld) after import\n",
293 (long)CFArrayGetCount(outArray
));
296 pubKeyRef
= (SecKeyRef
)CFArrayGetValueAtIndex(outArray
, 0);
297 if(CFGetTypeID(pubKeyRef
) != SecKeyGetTypeID()) {
298 printf("***Unexpected item type after import\n");
302 /* Use imported cleartext public key with locked keychain */
303 verboseDisp(verbose
, "locking keychain, exporting public key");
304 SecKeychainLock(kcRef
);
306 ortn
= SecKeychainItemExport(pubKeyRef
, kSecFormatOpenSSL
, 0, NULL
, &exportData
);
308 cssmPerror("SecKeychainItemExport", ortn
);
311 /* we'll use exportData again */
313 verboseDisp(verbose
, "locking keychain, encrypting with public key");
314 SecKeychainLock(kcRef
);
315 if(pubKeyEncrypt(pubKeyRef
)) {
320 verboseDisp(verbose
, "deleting key");
321 ortn
= SecKeychainItemDelete((SecKeychainItemRef
)pubKeyRef
);
323 cssmPerror("SecKeychainItemDelete", ortn
);
326 CFRelease(pubKeyRef
);
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.
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");
343 format
= kSecFormatOpenSSL
;
344 type
= kSecItemTypePublicKey
;
345 ortn
= SecKeychainItemImport(exportData
,
346 NULL
, &format
, &type
,
350 cssmPerror("SecKeychainItemImport", ortn
);
353 if(!didGetDialog()) {
356 CFRelease(exportData
);
357 if(CFArrayGetCount(outArray
) != 1) {
358 printf("***Unexpected outArray size (%ld) after import\n",
359 (long)CFArrayGetCount(outArray
));
362 pubKeyRef
= (SecKeyRef
)CFArrayGetValueAtIndex(outArray
, 0);
363 if(CFGetTypeID(pubKeyRef
) != SecKeyGetTypeID()) {
364 printf("***Unexpected item type after import\n");
368 /* Use imported encrypted public key with locked keychain */
369 verboseDisp(verbose
, "locking keychain, exporting public key");
370 SecKeychainLock(kcRef
);
372 ortn
= SecKeychainItemExport(pubKeyRef
, kSecFormatOpenSSL
, 0, NULL
, &exportData
);
374 cssmPerror("SecKeychainItemExport", ortn
);
377 if(!didGetDialog()) {
380 CFRelease(exportData
);
382 verboseDisp(verbose
, "locking keychain, encrypting with public key");
383 SecKeychainLock(kcRef
);
385 if(pubKeyEncrypt(pubKeyRef
)) {
388 if(!didGetDialog()) {
392 SecKeychainDelete(kcRef
);
393 printf("...test succeeded.\n");