#include "identPicker.h"
#include "sslAppUtils.h"
#include <sys/param.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
void getString(
char *buf,
unsigned bufSize)
{
unsigned dex;
char c;
char *cp = buf;
for(dex=0; dex<bufSize-1; dex++) {
c = getchar();
if(!isprint(c)) {
break;
}
switch(c) {
case '\n':
case '\r':
goto done;
default:
*cp++ = c;
}
}
done:
*cp = '\0';
}
char *kcItemPrintableName(
SecKeychainItemRef itemRef)
{
char *crtn = NULL;
UInt32 tag = kSecLabelItemAttr;
SecKeychainAttributeInfo attrInfo;
attrInfo.count = 1;
attrInfo.tag = &tag;
attrInfo.format = NULL;
SecKeychainAttributeList *attrList = NULL;
SecKeychainAttribute *attr = NULL;
OSStatus ortn = SecKeychainItemCopyAttributesAndData(
itemRef,
&attrInfo,
NULL, &attrList,
NULL, NULL); if(ortn) {
cssmPerror("SecKeychainItemCopyAttributesAndData", ortn);
return strdup("Unnamed KeychainItem");
}
if((attrList == NULL) || (attrList->count != 1)) {
printf("***Unexpected result fetching label attr\n");
crtn = strdup("Unnamed KeychainItem");
goto errOut;
}
attr = attrList->attr;
crtn = (char *)malloc(attr->length + 1);
memmove(crtn, attr->data, attr->length);
crtn[attr->length] = '\0';
errOut:
SecKeychainItemFreeAttributesAndData(attrList, NULL);
return crtn;
}
char *kcFileName(
SecKeychainRef kcRef)
{
char fullPath[MAXPATHLEN + 1];
OSStatus ortn;
UInt32 pathLen = MAXPATHLEN;
ortn = SecKeychainGetPath(kcRef, &pathLen, fullPath);
if(ortn) {
cssmPerror("SecKeychainGetPath", ortn);
return strdup("orphan keychain");
}
fullPath[pathLen] = '\0';
char *lastSlash = NULL;
char *thisSlash = fullPath;
do {
thisSlash = strchr(thisSlash, '/');
if(thisSlash == NULL) {
break;
}
thisSlash++;
lastSlash = thisSlash;
} while(thisSlash != NULL);
if(lastSlash == NULL) {
return strdup(fullPath);
}
else {
return strdup(lastSlash);
}
}
char *kcItemKcFileName(SecKeychainItemRef itemRef)
{
OSStatus ortn;
SecKeychainRef kcRef = NULL;
ortn = SecKeychainItemCopyKeychain(itemRef, &kcRef);
if(ortn) {
return NULL;
}
char *rtnStr = kcFileName(kcRef);
CFRelease(kcRef);
return rtnStr;
}
static CFIndex pickIdent(
CFArrayRef idArray)
{
CFIndex count = CFArrayGetCount(idArray);
CFIndex dex;
OSStatus ortn;
if(count == 0) {
printf("***sslIdentPicker screwup: no identities found\n");
return -1;
}
for(dex=0; dex<count; dex++) {
SecIdentityRef idRef = (SecIdentityRef)CFArrayGetValueAtIndex(idArray, dex);
SecCertificateRef certRef;
ortn = SecIdentityCopyCertificate(idRef, &certRef);
if(ortn) {
cssmPerror("SecIdentityCopyCertificate", ortn);
return -1;
}
char *certLabel = kcItemPrintableName((SecKeychainItemRef)certRef);
SecKeychainRef kcRef;
char *kcLabel;
ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)certRef, &kcRef);
if(ortn) {
cssmPerror("SecKeychainItemCopyKeychain", ortn);
kcLabel = (char *)"Unnamed keychain";
}
else {
kcLabel = kcFileName(kcRef);
}
printf("[%ld] keychain : %s\n", dex, kcLabel);
printf(" cert : %s\n", certLabel);
free(certLabel);
if(ortn == noErr) {
free(kcLabel);
}
CFRelease(certRef);
}
while(1) {
fpurge(stdin);
printf("\nEnter Certificate number or CR to quit : ");
fflush(stdout);
char resp[64];
getString(resp, sizeof(resp));
if(resp[0] == '\0') {
return -1;
}
int ires = atoi(resp);
if((ires >= 0) && (ires < count)) {
return (CFIndex)ires;
}
printf("***Invalid entry. Type a number between 0 and %ld\n",
count-1);
}
return -1;
}
OSStatus sslSimpleIdentPicker(
SecKeychainRef kcRef, SecIdentityRef *ident) {
OSStatus ortn;
CFMutableArrayRef idArray = NULL;
*ident = NULL;
SecIdentitySearchRef srchRef = nil;
ortn = SecIdentitySearchCreate(kcRef,
0, &srchRef);
if(ortn) {
cssmPerror("SecIdentitySearchCreate", (CSSM_RETURN)ortn);
printf("Cannot find signing key in keychain.\n");
return ortn;
}
SecIdentityRef identity = nil;
idArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
do {
ortn = SecIdentitySearchCopyNext(srchRef, &identity);
if(ortn != noErr) {
break;
}
CFArrayAppendValue(idArray, identity);
CFRelease(identity);
} while(ortn == noErr);
CFRelease(srchRef);
switch(ortn) {
case errSecItemNotFound:
if(CFArrayGetCount(idArray) == 0) {
printf("No signing keys found in keychain.\n");
return errSecItemNotFound;
}
else {
break;
}
default:
cssmPerror("SecIdentitySearchCopyNext", (CSSM_RETURN)ortn);
printf("Cannot find signing key in keychain.\n");
return ortn;
}
CFIndex whichId;
if(CFArrayGetCount(idArray) == 1) {
whichId = 0;
}
else {
whichId = pickIdent(idArray);
if(whichId < 0) {
return CSSMERR_CSSM_USER_CANCELED;
}
}
identity = (SecIdentityRef)CFArrayGetValueAtIndex(idArray, whichId);
CFRetain(identity);
CFRelease(idArray);
*ident = identity;
return noErr;
}
OSStatus sslIdentPicker(
SecKeychainRef kcRef, SecCertificateRef trustedAnchor, bool includeRoot, const CSSM_OID *vfyPolicy, CFArrayRef *outArray) {
OSStatus ortn;
SecIdentityRef identity;
ortn = sslSimpleIdentPicker(kcRef, &identity);
if(ortn) {
return ortn;
}
return sslCompleteCertChain(identity, trustedAnchor, includeRoot,
vfyPolicy, outArray);
}