9 #include <Security/SecKeychainItemExtendedAttributes.h>
10 #include <Security/Security.h>
11 #include <security_cdsa_utils/cuFileIo.h>
12 #include <utilLib/common.h>
14 #define DEFAULT_KC_NAME "extendAttr.keychain"
16 static void usage(char **argv
)
18 printf("usage: %s [options]\n", argv
[0]);
20 printf(" -k keychain -- default is %s\n", DEFAULT_KC_NAME
);
21 printf(" -n -- don't delete attributes or keychain\n");
22 printf(" -q -- quiet\n");
26 /* RSA keys, both in OpenSSL format */
27 #define PUB_KEY "rsakey_pub.der"
28 #define PRIV_KEY "rsakey_priv.der"
29 #define CERT_FILE "amazon_v3.100.cer"
30 #define PWD_SERVICE "some service"
31 #define PWD_ACCOUNT "some account"
32 #define PWD_PWD "some password"
34 /* set up unique extended attributes for each tested item */
36 CFStringRef attr1Name
;
37 const char *attr1Value
;
38 CFStringRef attr2Name
;
39 const char *attr2Value
;
42 static const ItemAttrs pubKeyAttrs
= {
43 CFSTR("one pub key Attribute"),
45 CFSTR("another pub key Attribute"),
46 "another pub key value"
49 static const ItemAttrs privKeyAttrs
= {
50 CFSTR("one priv key Attribute"),
51 "some priv key value",
52 CFSTR("another priv key Attribute"),
53 "another priv key value"
56 static const ItemAttrs certAttrs
= {
57 CFSTR("one cert Attribute"),
59 CFSTR("another cert Attribute"),
63 static const ItemAttrs pwdAttrs
= {
64 CFSTR("one pwd Attribute"),
66 CFSTR("another pwd Attribute"),
70 #define CFRELEASE(cf) if(cf) { CFRelease(cf); }
72 /* import file as key into specified keychain */
73 static int doImportKey(
75 SecExternalFormat format
,
76 SecExternalItemType itemType
,
78 SecKeyRef
*keyRef
) // RETURNED
80 unsigned char *item
= NULL
;
83 if(readFile(fileName
, &item
, &itemLen
)) {
84 printf("***Error reading %s. \n", fileName
);
86 CFDataRef cfd
= CFDataCreate(NULL
, (const UInt8
*)item
, itemLen
);
88 SecKeyImportExportParameters params
;
89 memset(¶ms
, 0, sizeof(params
));
90 params
.version
= SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
;
91 params
.keyUsage
= CSSM_KEYUSE_ANY
;
92 params
.keyAttributes
= CSSM_KEYATTR_PERMANENT
;
93 if(itemType
== kSecItemTypePrivateKey
) {
94 params
.keyAttributes
|= CSSM_KEYATTR_SENSITIVE
;
96 CFArrayRef outArray
= NULL
;
98 ortn
= SecKeychainItemImport(cfd
, NULL
, &format
, &itemType
, 0, ¶ms
, kcRef
, &outArray
);
100 cssmPerror("SecKeychainItemImport", ortn
);
106 if((outArray
== NULL
) || (CFArrayGetCount(outArray
) == 0)) {
107 printf("SecKeychainItemImport succeeded, but no returned items\n");
110 *keyRef
= (SecKeyRef
)CFArrayGetValueAtIndex(outArray
, 0);
111 if(CFGetTypeID(*keyRef
) != SecKeyGetTypeID()) {
112 printf("***Unknown type returned after import\n");
120 /* import file as cert into specified keychain */
121 static int doImportCert(
122 const char *fileName
,
123 SecKeychainRef kcRef
,
124 SecCertificateRef
*certRef
) // RETURNED
126 unsigned char *item
= NULL
;
127 unsigned itemLen
= 0;
129 if(readFile(fileName
, &item
, &itemLen
)) {
130 printf("***Error reading %s. \n", fileName
);
133 CSSM_DATA certData
= {itemLen
, (uint8
*)item
};
134 OSStatus ortn
= SecCertificateCreateFromData(&certData
,
135 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, certRef
);
137 cssmPerror("SecCertificateCreateFromData", ortn
);
140 ortn
= SecCertificateAddToKeychain(*certRef
, kcRef
);
142 cssmPerror("SecCertificateAddToKeychain", ortn
);
149 * Verify specified attr does not exist
151 * make sure we get it back
154 SecKeychainItemRef itemRef
,
155 CFStringRef attrName
,
160 CFDataRef fetchedVal
= NULL
;
164 printf(" ...verifying attribute doesn't exist\n");
166 ortn
= SecKeychainItemCopyExtendedAttribute(itemRef
, attrName
, &fetchedVal
);
167 if(ortn
!= errSecNoSuchAttr
) {
168 printf("***First SecKeychainItemCopyExtendedAttribute returned %d, expected %d\n",
169 (int)ortn
, (int)errSecNoSuchAttr
);
174 printf(" ...setting attribute\n");
176 ortn
= SecKeychainItemSetExtendedAttribute(itemRef
, attrName
, attrVal
);
178 cssmPerror("SecKeychainItemSetExtendedAttribute", ortn
);
183 printf(" ...verify attribute\n");
185 ortn
= SecKeychainItemCopyExtendedAttribute(itemRef
, attrName
, &fetchedVal
);
187 cssmPerror("SecKeychainItemCopyExtendedAttribute", ortn
);
191 if(!CFEqual(fetchedVal
, attrVal
)) {
192 printf("***Mismatch in set and fetched attribute\n");
196 CFRELEASE(fetchedVal
);
201 * Set two distinct extended attributes;
202 * Ensure that each comes back via SecKeychainItemCopyExtendedAttribute();
203 * Ensure that both come back via SecKeychainItemCopyAllExtendedAttributes();
205 int doTest(SecKeychainItemRef itemRef
,
206 const ItemAttrs
&itemAttrs
,
209 CFDataRef attrVal1
= CFDataCreate(NULL
,
210 (const UInt8
*)itemAttrs
.attr1Value
, strlen(itemAttrs
.attr1Value
));
211 if(testOneAttr(itemRef
, itemAttrs
.attr1Name
, attrVal1
, quiet
)) {
214 CFDataRef attrVal2
= CFDataCreate(NULL
,
215 (const UInt8
*)itemAttrs
.attr2Value
, strlen(itemAttrs
.attr2Value
));
216 if(testOneAttr(itemRef
, itemAttrs
.attr2Name
, attrVal2
, quiet
)) {
221 printf(" ...verify both attributes via CopyAllExtendedAttributes()\n");
223 /* make sure they both come back in SecKeychainItemCopyAllExtendedAttributes */
224 CFArrayRef attrNames
= NULL
;
225 CFArrayRef attrValues
= NULL
;
226 OSStatus ortn
= SecKeychainItemCopyAllExtendedAttributes(itemRef
, &attrNames
, &attrValues
);
228 cssmPerror("SecKeychainItemCopyAllExtendedAttributes", ortn
);
231 CFIndex numNames
= CFArrayGetCount(attrNames
);
232 CFIndex numValues
= CFArrayGetCount(attrValues
);
233 if((numNames
!= 2) || (numValues
!= 2)) {
234 printf("***Bad array count after SecKeychainItemCopyAllExtendedAttributes\n");
235 printf(" numNames %ld numValues %ld; expected 2 for both\n",
236 (long)numNames
, (long)numValues
);
241 for(CFIndex dex
=0; dex
<numNames
; dex
++) {
242 CFStringRef attrName
= (CFStringRef
)CFArrayGetValueAtIndex(attrNames
, dex
);
243 CFDataRef valToCompare
= NULL
;
244 if(CFEqual(attrName
, itemAttrs
.attr1Name
)) {
246 valToCompare
= attrVal1
;
248 else if(CFEqual(attrName
, itemAttrs
.attr2Name
)) {
250 valToCompare
= attrVal2
;
253 printf("***Found unknown attribute name\n");
256 CFDataRef foundVal
= (CFDataRef
)CFArrayGetValueAtIndex(attrValues
, dex
);
257 if(!CFEqual(foundVal
, valToCompare
)) {
258 printf("***Attribute Value miscompare\n");
262 CFRelease(attrNames
);
263 CFRelease(attrValues
);
267 if(!found1
|| !found2
) {
268 printf("***wrote two attribute; found1 %s, found2 %s\n",
269 found1
? "true" : "false", found2
? "true" : "false");
276 /* delete two attrs, verify that none are left */
277 static int doDeleteTest(
278 SecKeychainItemRef itemRef
,
279 const ItemAttrs
&itemAttrs
,
283 printf(" ...deleting both attributes, verifying none are left\n");
286 OSStatus ortn
= SecKeychainItemSetExtendedAttribute(itemRef
, itemAttrs
.attr1Name
, NULL
);
288 cssmPerror("SecKeychainItemSetExtendedAttribute (NULL)", ortn
);
291 ortn
= SecKeychainItemSetExtendedAttribute(itemRef
, itemAttrs
.attr2Name
, NULL
);
293 cssmPerror("SecKeychainItemSetExtendedAttribute (NULL)", ortn
);
296 CFArrayRef attrNames
= NULL
;
297 CFArrayRef attrValues
= NULL
;
298 ortn
= SecKeychainItemCopyAllExtendedAttributes(itemRef
, &attrNames
, &attrValues
);
299 if(ortn
!= errSecNoSuchAttr
) {
300 printf("***Last SecKeychainItemCopyExtendedAttribute returned %d, expected %d\n",
301 (int)ortn
, (int)errSecNoSuchAttr
);
308 * Verify that SecKeychainItemDelete() also deletes extended attributes.
310 * Assuming empty keychain:
312 * Set two extended attributes, make sure they're there;
314 * Import the cert again;
315 * Verify that the new item has *no* extended attributes;
317 static int doDeleteItemTest(
318 SecKeychainRef kcRef
,
321 SecCertificateRef certRef
= NULL
;
323 if(doImportCert(CERT_FILE
, kcRef
, &certRef
)) {
327 printf("...testing cert\n");
329 if(doTest((SecKeychainItemRef
)certRef
, certAttrs
, quiet
)) {
333 /* doTest() verified that there are two extended attrs */
335 printf("...deleting cert\n");
337 OSStatus ortn
= SecKeychainItemDelete((SecKeychainItemRef
)certRef
);
339 cssmPerror("SecKeychainItemDelete", ortn
);
345 printf("...reimporting cert, verifying it has no extended attributes\n");
347 if(doImportCert(CERT_FILE
, kcRef
, &certRef
)) {
350 CFArrayRef attrNames
= NULL
;
351 ortn
= SecKeychainItemCopyAllExtendedAttributes((SecKeychainItemRef
)certRef
, &attrNames
,
353 if(ortn
!= errSecNoSuchAttr
) {
354 printf("***Deleted cert, re-imported it, and the new cert has extended attributes!\n");
361 int main(int argc
, char **argv
)
363 const char *kcName
= DEFAULT_KC_NAME
;
367 bool noDelete
= false;
369 while ((arg
= getopt(argc
, argv
, "k:qnh")) != -1) {
388 testStartBanner("extendAttrTest", argc
, argv
);
390 SecKeychainRef kcRef
= NULL
;
394 printf("Deleting possible existing keychain and creating %s...\n", kcName
);
397 /* delete possible existing keychain, then create it */
398 if (SecKeychainOpen(kcName
, &kcRef
) == noErr
)
400 SecKeychainDelete(kcRef
);
405 ortn
= SecKeychainCreate(kcName
,
406 strlen(DEFAULT_KC_NAME
), DEFAULT_KC_NAME
,
407 false, NULL
, &kcRef
);
409 cssmPerror("SecKeychainCreate", ortn
);
414 SecKeyRef pubKey
= NULL
;
415 SecKeyRef privKey
= NULL
;
417 printf("Importing %s to keychain...\n", PUB_KEY
);
419 if(doImportKey(PUB_KEY
, kSecFormatOpenSSL
, kSecItemTypePublicKey
, kcRef
, &pubKey
)) {
423 printf("Importing %s to keychain...\n", PRIV_KEY
);
425 if(doImportKey(PRIV_KEY
, kSecFormatOpenSSL
, kSecItemTypePrivateKey
, kcRef
, &privKey
)) {
430 printf("...testing public key\n");
432 if(doTest((SecKeychainItemRef
)pubKey
, pubKeyAttrs
, quiet
)) {
436 printf("...testing private key\n");
438 if(doTest((SecKeychainItemRef
)privKey
, privKeyAttrs
, quiet
)) {
443 * Those keys and their extended attrs are still in the keychain. Test a cert.
445 SecCertificateRef certRef
= NULL
;
446 if(doImportCert(CERT_FILE
, kcRef
, &certRef
)) {
450 printf("...testing cert\n");
452 if(doTest((SecKeychainItemRef
)certRef
, certAttrs
, quiet
)) {
456 /* leaving everything in place, test a generic password. */
457 SecKeychainItemRef pwdRef
= NULL
;
458 ortn
= SecKeychainAddGenericPassword(kcRef
,
459 strlen(PWD_SERVICE
), PWD_SERVICE
,
460 strlen(PWD_ACCOUNT
), PWD_ACCOUNT
,
461 strlen(PWD_PWD
), PWD_PWD
,
464 cssmPerror("SecKeychainAddGenericPassword", ortn
);
468 printf("...testing generic password\n");
470 if(doTest(pwdRef
, pwdAttrs
, quiet
)) {
478 /* delete extended attrs; make sure they really get deleted */
480 printf("...removing extended attributes from public key\n");
482 if(doDeleteTest((SecKeychainItemRef
)pubKey
, pubKeyAttrs
, quiet
)) {
486 printf("...removing extended attributes from private key\n");
488 if(doDeleteTest((SecKeychainItemRef
)privKey
, privKeyAttrs
, quiet
)) {
492 printf("...removing extended attributes from certificate\n");
494 if(doDeleteTest((SecKeychainItemRef
)certRef
, certAttrs
, quiet
)) {
498 printf("...removing extended attributes from generic password\n");
500 if(doDeleteTest(pwdRef
, pwdAttrs
, quiet
)) {
508 /* Verify that SecKeychainItemDelete() also deletes extended attributes */
509 ortn
= SecKeychainItemDelete((SecKeychainItemRef
)certRef
);
511 cssmPerror("SecKeychainItemDelete", ortn
);
515 if(doDeleteItemTest(kcRef
, quiet
)) {
519 SecKeychainDelete(kcRef
);
523 printf("...Success\n");