--- /dev/null
+/*
+ * Examine and test a keychain's identity
+ */
+#include <Security/Security.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
+#include <security_cdsa_utils/cuPrintCert.h>
+#include <utilLib/common.h>
+#include <utilLib/cspwrap.h>
+#include <clAppUtils/clutils.h>
+
+typedef enum {
+ KC_Nop,
+ KC_GetInfo,
+ KC_LockKC,
+ KC_UnlockKC,
+ KC_SignVfy,
+ KC_KeyCertInfo
+} KcOp;
+
+static void usage(char **argv)
+{
+ printf("Usage: %s keychain|- cmd [options]\n", argv[0]);
+ printf("Command:\n");
+ printf(" i get KC info\n");
+ printf(" k get key and cert info\n");
+ printf(" l lock\n");
+ printf(" u unlock\n");
+ printf(" s sign and verify\n");
+ printf("Options:\n");
+ printf(" p=passphrase\n");
+ printf("Specifying '-' for keychain means NULL, default\n");
+ exit(1);
+}
+
+static void showError(
+ OSStatus ortn,
+ const char *msg)
+{
+ const char *errStr = NULL;
+ switch(ortn) {
+ case errSecItemNotFound:
+ errStr = "errSecItemNotFound"; break;
+ case errSecNoSuchKeychain:
+ errStr = "errSecNoSuchKeychain"; break;
+ case errSecNotAvailable:
+ errStr = "errSecNotAvailable"; break;
+ /* more? */
+ default:
+ if(ortn < (CSSM_BASE_ERROR +
+ (CSSM_ERRORCODE_MODULE_EXTENT * 8))) {
+ /* assume CSSM error */
+ errStr = cssmErrToStr(ortn);
+ }
+ break;
+
+ }
+ if(errStr) {
+ printf("***Error on %s: %s\n", msg, errStr);
+ }
+ else {
+ printf("***Error on %s: %d(d)\n", msg, (int)ortn);
+ }
+}
+
+static void printDataAsHex(
+ const CSSM_DATA *d,
+ unsigned maxToPrint = 0) // optional, 0 means print it all
+{
+ unsigned i;
+ bool more = false;
+ uint32 len = d->Length;
+ uint8 *cp = d->Data;
+
+ if((maxToPrint != 0) && (len > maxToPrint)) {
+ len = maxToPrint;
+ more = true;
+ }
+ for(i=0; i<len; i++) {
+ printf("%02X ", ((unsigned char *)cp)[i]);
+ }
+ if(more) {
+ printf("...\n");
+ }
+ else {
+ printf("\n");
+ }
+}
+
+static void printKeyHeader(
+ const CSSM_KEYHEADER &hdr)
+{
+ printf(" Algorithm : ");
+ switch(hdr.AlgorithmId) {
+ case CSSM_ALGID_RSA:
+ printf("RSA\n");
+ break;
+ case CSSM_ALGID_DSA:
+ printf("DSA\n");
+ break;
+ case CSSM_ALGID_FEE:
+ printf("FEE\n");
+ break;
+ case CSSM_ALGID_DH:
+ printf("Diffie-Hellman\n");
+ break;
+ default:
+ printf("Unknown(%u(d), 0x%x)\n", (unsigned)hdr.AlgorithmId,
+ (unsigned)hdr.AlgorithmId);
+ }
+ printf(" Key Size : %u bits\n",
+ (unsigned)hdr.LogicalKeySizeInBits);
+ printf(" Key Use : ");
+ CSSM_KEYUSE usage = hdr.KeyUsage;
+ if(usage & CSSM_KEYUSE_ANY) {
+ printf("CSSM_KEYUSE_ANY ");
+ }
+ if(usage & CSSM_KEYUSE_ENCRYPT) {
+ printf("CSSM_KEYUSE_ENCRYPT ");
+ }
+ if(usage & CSSM_KEYUSE_DECRYPT) {
+ printf("CSSM_KEYUSE_DECRYPT ");
+ }
+ if(usage & CSSM_KEYUSE_SIGN) {
+ printf("CSSM_KEYUSE_SIGN ");
+ }
+ if(usage & CSSM_KEYUSE_VERIFY) {
+ printf("CSSM_KEYUSE_VERIFY ");
+ }
+ if(usage & CSSM_KEYUSE_SIGN_RECOVER) {
+ printf("CSSM_KEYUSE_SIGN_RECOVER ");
+ }
+ if(usage & CSSM_KEYUSE_VERIFY_RECOVER) {
+ printf("CSSM_KEYUSE_VERIFY_RECOVER ");
+ }
+ if(usage & CSSM_KEYUSE_WRAP) {
+ printf("CSSM_KEYUSE_WRAP ");
+ }
+ if(usage & CSSM_KEYUSE_UNWRAP) {
+ printf("CSSM_KEYUSE_UNWRAP ");
+ }
+ if(usage & CSSM_KEYUSE_DERIVE) {
+ printf("CSSM_KEYUSE_DERIVE ");
+ }
+ printf("\n");
+
+}
+
+static OSStatus getIdentity(
+ SecKeychainRef kcRef,
+ CSSM_KEYUSE keyUse,
+ SecIdentityRef &idRef)
+{
+ SecIdentitySearchRef srchRef = nil;
+ OSStatus ortn = SecIdentitySearchCreate(kcRef, keyUse, &srchRef);
+ if(ortn) {
+ showError(ortn, "SecIdentitySearchCreate");
+ return ortn;
+ }
+ ortn = SecIdentitySearchCopyNext(srchRef, &idRef);
+ if(ortn) {
+ showError(ortn, "SecIdentitySearchCopyNext");
+ return ortn;
+ }
+ if(CFGetTypeID(idRef) != SecIdentityGetTypeID()) {
+ printf("SecIdentitySearchCopyNext CFTypeID failure!\n");
+ return paramErr;
+ }
+ return noErr;
+}
+
+static OSStatus getKeyCertInfo(
+ SecCertificateRef certRef,
+ SecKeyRef keyRef,
+ CSSM_KEY_PTR cssmKey,
+ CSSM_CSP_HANDLE cspHand)
+{
+ /* display the private key */
+ if(cssmKey == NULL) {
+ printf(" ***malformed CSSM_KEY\n");
+ }
+ else {
+ printf("Private Key :\n");
+ printKeyHeader(cssmKey->KeyHeader);
+ printf(" Key Blob : ");
+ printDataAsHex(&cssmKey->KeyData, 8);
+ }
+
+ /* and the cert */
+ CSSM_DATA certData;
+ OSStatus ortn = SecCertificateGetData(certRef, &certData);
+ if(ortn) {
+ showError(ortn, "SecCertificateGetData");
+ return ortn;
+ }
+ printf("\nCertificate :\n");
+ printCert((unsigned char *)certData.Data, (unsigned)certData.Length,
+ CSSM_TRUE);
+ return noErr;
+}
+
+#define SIG_ALG CSSM_ALGID_SHA1WithRSA
+
+static OSStatus signVfy(
+ SecCertificateRef certRef,
+ SecKeyRef keyRef,
+ CSSM_KEY_PTR cssmKey,
+ CSSM_CSP_HANDLE cspHand)
+{
+ uint8 someData[] = {0,1,2,3,4,5,6,7,8};
+ CSSM_DATA ptext = {sizeof(someData), someData};
+ CSSM_DATA sig = {0, NULL};
+ CSSM_RETURN crtn;
+
+ /* sign with CSPDL */
+ crtn = cspSign(cspHand, SIG_ALG, cssmKey, &ptext, &sig);
+ if(crtn) {
+ printf("Error signing with private key\n");
+ return crtn;
+ }
+
+ /* attach to CL */
+ CSSM_CL_HANDLE clHand = clStartup();
+ if(clHand == 0) {
+ printf("***Error attaching to CL\n");
+ return ioErr;
+ }
+
+ /* get the public key from the cert */
+ CSSM_DATA certData;
+ OSStatus ortn = SecCertificateGetData(certRef, &certData);
+ if(ortn) {
+ showError(ortn, "SecCertificateGetData");
+ return ortn;
+ }
+ CSSM_KEY_PTR pubKey = NULL;
+ crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey);
+ if(crtn) {
+ printError("CSSM_CL_CertGetKeyInfo", crtn);
+ return crtn;
+ }
+
+ /* attach to raw CSP */
+ CSSM_CSP_HANDLE rawCspHand = cspStartup();
+ if(rawCspHand == 0) {
+ printf("***Error attaching to raw CSP\n");
+ return ioErr;
+ }
+
+ /* verify with raw CSP and raw public key */
+ crtn = cspSigVerify(rawCspHand, SIG_ALG, pubKey, &ptext,
+ &sig, CSSM_OK);
+ if(crtn) {
+ printf("Error verifying with public key\n");
+ return crtn;
+ }
+
+ /* free everything */
+ CSSM_ModuleDetach(rawCspHand);
+ CSSM_ModuleDetach(clHand);
+ printf("...sign with private key, vfy with cert OK\n");
+ return noErr;
+}
+
+/* get cert and private key (in Sec and CSSM form) from identity */
+static OSStatus getKeyCert(
+ SecIdentityRef idRef,
+ SecCertificateRef &certRef, // RETURNED
+ SecKeyRef &keyRef, // private key, RETURNED
+ CSSM_KEY_PTR &cssmKey) // private key, RETURNED
+{
+ OSStatus ortn = SecIdentityCopyCertificate(idRef, &certRef);
+ if(ortn) {
+ showError(ortn, "SecIdentityCopyCertificate");
+ return ortn;
+ }
+ ortn = SecIdentityCopyPrivateKey(idRef, &keyRef);
+ if(ortn) {
+ showError(ortn, "SecIdentityCopyPrivateKey");
+ return ortn;
+ }
+ ortn = SecKeyGetCSSMKey(keyRef, (const CSSM_KEY **)&cssmKey);
+ if(ortn) {
+ showError(ortn, "SecKeyGetCSSMKey");
+ }
+ return ortn;
+}
+
+int main(int argc, char **argv)
+{
+ SecKeychainRef kcRef = nil;
+ OSStatus ortn;
+ int arg;
+ char *argp;
+
+ /* user-spec'd variables */
+ KcOp op = KC_Nop;
+ char *pwd = NULL;
+ char *kcName;
+
+ if(argc < 3) {
+ usage(argv);
+ }
+ kcName = argv[1];
+ if(!strcmp("-", kcName)) {
+ /* null - no open */
+ kcName = NULL;
+ }
+ switch(argv[2][0]) {
+ case 'i':
+ op = KC_GetInfo; break;
+ case 'l':
+ op = KC_LockKC; break;
+ case 'u':
+ op = KC_UnlockKC; break;
+ case 's':
+ op = KC_SignVfy; break;
+ case 'k':
+ op = KC_KeyCertInfo; break;
+ default:
+ usage(argv);
+ }
+ for(arg=3; arg<argc; arg++) {
+ argp = argv[arg];
+ switch(argp[0]) {
+ case 'p':
+ pwd = &argp[2];
+ break;
+ default:
+ usage(argv);
+ }
+ }
+
+ if(kcName != NULL) {
+ ortn = SecKeychainOpen(kcName, &kcRef);
+ if(ortn) {
+ showError(ortn, "SecKeychainOpen");
+ printf("Cannot open keychain at %s. Aborting.\n", kcName);
+ exit(1);
+ }
+ }
+
+ /* handle trivial commands right now */
+ switch(op) {
+ case KC_LockKC:
+ ortn = SecKeychainLock(kcRef);
+ if(ortn) {
+ showError(ortn, "SecKeychainLock");
+ exit(1);
+ }
+ printf("...keychain %s locked.\n", argv[1]);
+ exit(0);
+
+ case KC_UnlockKC:
+ if(pwd == NULL) {
+ printf("***Warning: unlocking with no password\n");
+ }
+ ortn = SecKeychainUnlock(kcRef,
+ pwd ? strlen(pwd) : 0,
+ pwd,
+ pwd ? true : false); // usePassword
+ if(ortn) {
+ showError(ortn, "SecKeychainUnlock");
+ exit(1);
+ }
+ printf("...keychain %s unlocked.\n", argv[1]);
+ exit(0);
+
+ case KC_GetInfo:
+ {
+ SecKeychainStatus kcStat;
+ ortn = SecKeychainGetStatus(kcRef, &kcStat);
+ if(ortn) {
+ showError(ortn, "SecKeychainGetStatus");
+ exit(1);
+ }
+ printf("...SecKeychainStatus = %u ( ", (unsigned)kcStat);
+ if(kcStat & kSecUnlockStateStatus) {
+ printf("UnlockState ");
+ }
+ if(kcStat & kSecReadPermStatus) {
+ printf("RdPerm ");
+ }
+ if(kcStat & kSecWritePermStatus) {
+ printf("WrPerm ");
+ }
+ printf(")\n");
+ exit(0);
+ }
+
+ default:
+ /* more processing below */
+ break;
+ }
+
+ /* remaining cmds need an identity */
+ SecIdentityRef idRef;
+ ortn = getIdentity(kcRef, CSSM_KEYUSE_SIGN, idRef);
+ if(ortn) {
+ printf("***No identity found in keychain %s. Aborting.\n", kcName);
+ exit(1);
+ }
+
+ /* and a CSP */
+ CSSM_CSP_HANDLE cspHand;
+ ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
+ if(ortn) {
+ showError(ortn, "SecKeychainGetCSPHandle");
+ exit(1);
+ }
+
+ /* and the cert and keys */
+ SecCertificateRef certRef = nil;
+ SecKeyRef keyRef = nil;
+ CSSM_KEY_PTR privKey = NULL;
+ ortn = getKeyCert(idRef, certRef, keyRef, privKey);
+ if(ortn) {
+ printf("***Incomplete identity\n");
+ exit(1);
+ }
+
+ switch(op) {
+ case KC_KeyCertInfo:
+ ortn = getKeyCertInfo(certRef, keyRef, privKey, cspHand);
+ break;
+ case KC_SignVfy:
+ ortn = signVfy(certRef, keyRef, privKey, cspHand);
+ break;
+ default:
+ printf("BRRRZAP!\n");
+ exit(1);
+ }
+ CFRelease(idRef);
+ if(kcRef) {
+ CFRelease(kcRef);
+ }
+ return (int)ortn;
+}