extendAttrTest.cpp [plain text]
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
#include <Security/SecKeychainItemExtendedAttributes.h>
#include <Security/Security.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <utilLib/common.h>
#define DEFAULT_KC_NAME "extendAttr.keychain"
static void usage(char **argv)
{
printf("usage: %s [options]\n", argv[0]);
printf("Options:\n");
printf(" -k keychain -- default is %s\n", DEFAULT_KC_NAME);
printf(" -n -- don't delete attributes or keychain\n");
printf(" -q -- quiet\n");
exit(1);
}
#define PUB_KEY "rsakey_pub.der"
#define PRIV_KEY "rsakey_priv.der"
#define CERT_FILE "amazon_v3.100.cer"
#define PWD_SERVICE "some service"
#define PWD_ACCOUNT "some account"
#define PWD_PWD "some password"
typedef struct {
CFStringRef attr1Name;
const char *attr1Value;
CFStringRef attr2Name;
const char *attr2Value;
} ItemAttrs;
static const ItemAttrs pubKeyAttrs = {
CFSTR("one pub key Attribute"),
"some pub key value",
CFSTR("another pub key Attribute"),
"another pub key value"
};
static const ItemAttrs privKeyAttrs = {
CFSTR("one priv key Attribute"),
"some priv key value",
CFSTR("another priv key Attribute"),
"another priv key value"
};
static const ItemAttrs certAttrs = {
CFSTR("one cert Attribute"),
"some cert value",
CFSTR("another cert Attribute"),
"another cert value"
};
static const ItemAttrs pwdAttrs = {
CFSTR("one pwd Attribute"),
"some pwd value",
CFSTR("another pwd Attribute"),
"another pwd value"
};
#define CFRELEASE(cf) if(cf) { CFRelease(cf); }
static int doImportKey(
const char *fileName,
SecExternalFormat format,
SecExternalItemType itemType,
SecKeychainRef kcRef,
SecKeyRef *keyRef) {
unsigned char *item = NULL;
unsigned itemLen = 0;
if(readFile(fileName, &item, &itemLen)) {
printf("***Error reading %s. \n", fileName);
}
CFDataRef cfd = CFDataCreate(NULL, (const UInt8 *)item, itemLen);
free(item);
SecKeyImportExportParameters params;
memset(¶ms, 0, sizeof(params));
params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
params.keyUsage = CSSM_KEYUSE_ANY;
params.keyAttributes = CSSM_KEYATTR_PERMANENT;
if(itemType == kSecItemTypePrivateKey) {
params.keyAttributes |= CSSM_KEYATTR_SENSITIVE;
}
CFArrayRef outArray = NULL;
OSStatus ortn;
ortn = SecKeychainItemImport(cfd, NULL, &format, &itemType, 0, ¶ms, kcRef, &outArray);
if(ortn) {
cssmPerror("SecKeychainItemImport", ortn);
}
CFRelease(cfd);
if(ortn) {
return -1;
}
if((outArray == NULL) || (CFArrayGetCount(outArray) == 0)) {
printf("SecKeychainItemImport succeeded, but no returned items\n");
return -1;
}
*keyRef = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
if(CFGetTypeID(*keyRef) != SecKeyGetTypeID()) {
printf("***Unknown type returned after import\n");
return -1;
}
CFRetain(*keyRef);
CFRelease(outArray);
return 0;
}
static int doImportCert(
const char *fileName,
SecKeychainRef kcRef,
SecCertificateRef *certRef) {
unsigned char *item = NULL;
unsigned itemLen = 0;
if(readFile(fileName, &item, &itemLen)) {
printf("***Error reading %s. \n", fileName);
return -1;
}
CSSM_DATA certData = {itemLen, (uint8 *)item};
OSStatus ortn = SecCertificateCreateFromData(&certData,
CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, certRef);
if(ortn) {
cssmPerror("SecCertificateCreateFromData", ortn);
return -1;
}
ortn = SecCertificateAddToKeychain(*certRef, kcRef);
if(ortn) {
cssmPerror("SecCertificateAddToKeychain", ortn);
return -1;
}
return 0;
}
int testOneAttr(
SecKeychainItemRef itemRef,
CFStringRef attrName,
CFDataRef attrVal,
bool quiet)
{
OSStatus ortn;
CFDataRef fetchedVal = NULL;
int ourRtn = 0;
if(!quiet) {
printf(" ...verifying attribute doesn't exist\n");
}
ortn = SecKeychainItemCopyExtendedAttribute(itemRef, attrName, &fetchedVal);
if(ortn != errSecNoSuchAttr) {
printf("***First SecKeychainItemCopyExtendedAttribute returned %d, expected %d\n",
(int)ortn, (int)errSecNoSuchAttr);
ourRtn = -1;
goto errOut;
}
if(!quiet) {
printf(" ...setting attribute\n");
}
ortn = SecKeychainItemSetExtendedAttribute(itemRef, attrName, attrVal);
if(ortn) {
cssmPerror("SecKeychainItemSetExtendedAttribute", ortn);
ourRtn = -1;
goto errOut;
}
if(!quiet) {
printf(" ...verify attribute\n");
}
ortn = SecKeychainItemCopyExtendedAttribute(itemRef, attrName, &fetchedVal);
if(ortn) {
cssmPerror("SecKeychainItemCopyExtendedAttribute", ortn);
ourRtn = -1;
goto errOut;
}
if(!CFEqual(fetchedVal, attrVal)) {
printf("***Mismatch in set and fetched attribute\n");
ourRtn = -1;
}
errOut:
CFRELEASE(fetchedVal);
return ourRtn;
}
int doTest(SecKeychainItemRef itemRef,
const ItemAttrs &itemAttrs,
bool quiet)
{
CFDataRef attrVal1 = CFDataCreate(NULL,
(const UInt8 *)itemAttrs.attr1Value, strlen(itemAttrs.attr1Value));
if(testOneAttr(itemRef, itemAttrs.attr1Name, attrVal1, quiet)) {
return -1;
}
CFDataRef attrVal2 = CFDataCreate(NULL,
(const UInt8 *)itemAttrs.attr2Value, strlen(itemAttrs.attr2Value));
if(testOneAttr(itemRef, itemAttrs.attr2Name, attrVal2, quiet)) {
return -1;
}
if(!quiet) {
printf(" ...verify both attributes via CopyAllExtendedAttributes()\n");
}
CFArrayRef attrNames = NULL;
CFArrayRef attrValues = NULL;
OSStatus ortn = SecKeychainItemCopyAllExtendedAttributes(itemRef, &attrNames, &attrValues);
if(ortn) {
cssmPerror("SecKeychainItemCopyAllExtendedAttributes", ortn);
return -1;
}
CFIndex numNames = CFArrayGetCount(attrNames);
CFIndex numValues = CFArrayGetCount(attrValues);
if((numNames != 2) || (numValues != 2)) {
printf("***Bad array count after SecKeychainItemCopyAllExtendedAttributes\n");
printf(" numNames %ld numValues %ld; expected 2 for both\n",
(long)numNames, (long)numValues);
return -1;
}
bool found1 = false;
bool found2 = false;
for(CFIndex dex=0; dex<numNames; dex++) {
CFStringRef attrName = (CFStringRef)CFArrayGetValueAtIndex(attrNames, dex);
CFDataRef valToCompare = NULL;
if(CFEqual(attrName, itemAttrs.attr1Name)) {
found1 = true;
valToCompare = attrVal1;
}
else if(CFEqual(attrName, itemAttrs.attr2Name)) {
found2 = true;
valToCompare = attrVal2;
}
else {
printf("***Found unknown attribute name\n");
return -1;
}
CFDataRef foundVal = (CFDataRef)CFArrayGetValueAtIndex(attrValues, dex);
if(!CFEqual(foundVal, valToCompare)) {
printf("***Attribute Value miscompare\n");
return -1;
}
}
CFRelease(attrNames);
CFRelease(attrValues);
CFRelease(attrVal1);
CFRelease(attrVal2);
if(!found1 || !found2) {
printf("***wrote two attribute; found1 %s, found2 %s\n",
found1 ? "true" : "false", found2 ? "true" : "false");
return 1;
}
return 0;
}
static int doDeleteTest(
SecKeychainItemRef itemRef,
const ItemAttrs &itemAttrs,
bool quiet)
{
if(!quiet) {
printf(" ...deleting both attributes, verifying none are left\n");
}
OSStatus ortn = SecKeychainItemSetExtendedAttribute(itemRef, itemAttrs.attr1Name, NULL);
if(ortn) {
cssmPerror("SecKeychainItemSetExtendedAttribute (NULL)", ortn);
return -1;
}
ortn = SecKeychainItemSetExtendedAttribute(itemRef, itemAttrs.attr2Name, NULL);
if(ortn) {
cssmPerror("SecKeychainItemSetExtendedAttribute (NULL)", ortn);
return -1;
}
CFArrayRef attrNames = NULL;
CFArrayRef attrValues = NULL;
ortn = SecKeychainItemCopyAllExtendedAttributes(itemRef, &attrNames, &attrValues);
if(ortn != errSecNoSuchAttr) {
printf("***Last SecKeychainItemCopyExtendedAttribute returned %d, expected %d\n",
(int)ortn, (int)errSecNoSuchAttr);
return -1;
}
return 0;
}
static int doDeleteItemTest(
SecKeychainRef kcRef,
bool quiet)
{
SecCertificateRef certRef = NULL;
if(doImportCert(CERT_FILE, kcRef, &certRef)) {
return 1;
}
if(!quiet) {
printf("...testing cert\n");
}
if(doTest((SecKeychainItemRef)certRef, certAttrs, quiet)) {
return -1;
}
if(!quiet) {
printf("...deleting cert\n");
}
OSStatus ortn = SecKeychainItemDelete((SecKeychainItemRef)certRef);
if(ortn) {
cssmPerror("SecKeychainItemDelete", ortn);
return -1;
}
CFRelease(certRef);
if(!quiet) {
printf("...reimporting cert, verifying it has no extended attributes\n");
}
if(doImportCert(CERT_FILE, kcRef, &certRef)) {
return 1;
}
CFArrayRef attrNames = NULL;
ortn = SecKeychainItemCopyAllExtendedAttributes((SecKeychainItemRef)certRef, &attrNames,
NULL);
if(ortn != errSecNoSuchAttr) {
printf("***Deleted cert, re-imported it, and the new cert has extended attributes!\n");
return -1;
}
CFRelease(certRef);
return 0;
}
int main(int argc, char **argv)
{
const char *kcName = DEFAULT_KC_NAME;
extern char *optarg;
int arg;
bool quiet = false;
bool noDelete = false;
while ((arg = getopt(argc, argv, "k:qnh")) != -1) {
switch (arg) {
case 'k':
kcName = optarg;
break;
case 'n':
noDelete = true;
break;
case 'q':
quiet = true;
break;
case 'h':
usage(argv);
}
}
if(optind != argc) {
usage(argv);
}
testStartBanner("extendAttrTest", argc, argv);
SecKeychainRef kcRef = NULL;
OSStatus ortn;
if(!quiet) {
printf("Deleting possible existing keychain and creating %s...\n", kcName);
}
if (SecKeychainOpen(kcName, &kcRef) == noErr)
{
SecKeychainDelete(kcRef);
CFRelease(kcRef);
}
kcRef = NULL;
ortn = SecKeychainCreate(kcName,
strlen(DEFAULT_KC_NAME), DEFAULT_KC_NAME,
false, NULL, &kcRef);
if(ortn) {
cssmPerror("SecKeychainCreate", ortn);
exit(1);
}
SecKeyRef pubKey = NULL;
SecKeyRef privKey = NULL;
if(!quiet) {
printf("Importing %s to keychain...\n", PUB_KEY);
}
if(doImportKey(PUB_KEY, kSecFormatOpenSSL, kSecItemTypePublicKey, kcRef, &pubKey)) {
exit(1);
}
if(!quiet) {
printf("Importing %s to keychain...\n", PRIV_KEY);
}
if(doImportKey(PRIV_KEY, kSecFormatOpenSSL, kSecItemTypePrivateKey, kcRef, &privKey)) {
exit(1);
}
if(!quiet) {
printf("...testing public key\n");
}
if(doTest((SecKeychainItemRef)pubKey, pubKeyAttrs, quiet)) {
return -1;
}
if(!quiet) {
printf("...testing private key\n");
}
if(doTest((SecKeychainItemRef)privKey, privKeyAttrs, quiet)) {
return -1;
}
SecCertificateRef certRef = NULL;
if(doImportCert(CERT_FILE, kcRef, &certRef)) {
exit(1);
}
if(!quiet) {
printf("...testing cert\n");
}
if(doTest((SecKeychainItemRef)certRef, certAttrs, quiet)) {
return -1;
}
SecKeychainItemRef pwdRef = NULL;
ortn = SecKeychainAddGenericPassword(kcRef,
strlen(PWD_SERVICE), PWD_SERVICE,
strlen(PWD_ACCOUNT), PWD_ACCOUNT,
strlen(PWD_PWD), PWD_PWD,
&pwdRef);
if(ortn) {
cssmPerror("SecKeychainAddGenericPassword", ortn);
exit(1);
}
if(!quiet) {
printf("...testing generic password\n");
}
if(doTest(pwdRef, pwdAttrs, quiet)) {
return -1;
}
if(noDelete) {
goto done;
}
if(!quiet) {
printf("...removing extended attributes from public key\n");
}
if(doDeleteTest((SecKeychainItemRef)pubKey, pubKeyAttrs, quiet)) {
exit(1);
}
if(!quiet) {
printf("...removing extended attributes from private key\n");
}
if(doDeleteTest((SecKeychainItemRef)privKey, privKeyAttrs, quiet)) {
exit(1);
}
if(!quiet) {
printf("...removing extended attributes from certificate\n");
}
if(doDeleteTest((SecKeychainItemRef)certRef, certAttrs, quiet)) {
exit(1);
}
if(!quiet) {
printf("...removing extended attributes from generic password\n");
}
if(doDeleteTest(pwdRef, pwdAttrs, quiet)) {
exit(1);
}
CFRelease(pubKey);
CFRelease(privKey);
CFRelease(pwdRef);
ortn = SecKeychainItemDelete((SecKeychainItemRef)certRef);
if(ortn) {
cssmPerror("SecKeychainItemDelete", ortn);
exit(1);
}
CFRelease(certRef);
if(doDeleteItemTest(kcRef, quiet)) {
exit(1);
}
SecKeychainDelete(kcRef);
CFRelease(kcRef);
done:
if(!quiet) {
printf("...Success\n");
}
return 0;
}