static VALUE rb_keychain_status(VALUE self){ UInt32 status; SecKeychainRef keychain=NULL; Data_Get_Struct(self, struct OpaqueSecKeychainRef, keychain); OSStatus result = SecKeychainGetStatus(keychain, &status); CheckOSStatusOrRaise(result); return UINT2NUM(status); }
SecKeychainRef SROpenKeychain(char* path) { SecKeychainRef keychain = NULL; OSStatus status = SecKeychainOpen(path, &keychain); SecKeychainStatus keychainStatus = 0; status = SecKeychainGetStatus(keychain, &keychainStatus); if (status == 0) { } else { fprintf(stderr, "Unable to open keychain at path %s: ", path); SRHandleError(status, false); exit(EX_IOERR); } return keychain; }
/* * Returns true if we are to allow/trust the specified * cert as a PKINIT-only anchor. */ static bool tpCheckPkinitServerCert( TPCertGroup &certGroup) { /* * Basic requirement: exactly one cert, self-signed. * The numCerts == 1 requirement might change... */ unsigned numCerts = certGroup.numCerts(); if(numCerts != 1) { tpDebug("tpCheckPkinitServerCert: too many certs"); return false; } /* end of chain... */ TPCertInfo *theCert = certGroup.certAtIndex(numCerts - 1); if(!theCert->isSelfSigned()) { tpDebug("tpCheckPkinitServerCert: 1 cert, not self-signed"); return false; } const CSSM_DATA *subjectName = theCert->subjectName(); /* * Open the magic keychain. * We're going up and over the Sec layer here, not generally * kosher, but this is a temp hack. */ OSStatus ortn; SecKeychainRef kcRef = NULL; string fullPathName; const char *homeDir = getenv("HOME"); if (homeDir == NULL) { // If $HOME is unset get the current user's home directory // from the passwd file. uid_t uid = geteuid(); if (!uid) uid = getuid(); struct passwd *pw = getpwuid(uid); if (!pw) { return false; } homeDir = pw->pw_dir; } fullPathName = homeDir; fullPathName += "/Library/Application Support/PKINIT/TrustedServers.keychain"; ortn = SecKeychainOpen(fullPathName.c_str(), &kcRef); if(ortn) { tpDebug("tpCheckPkinitServerCert: keychain not found (1)"); return false; } /* subsequent errors to errOut: */ bool ourRtn = false; SecKeychainStatus kcStatus; CSSM_DATA_PTR subjSerial = NULL; CSSM_RETURN crtn; SecKeychainSearchRef srchRef = NULL; SecKeychainAttributeList attrList; SecKeychainAttribute attrs[2]; SecKeychainItemRef foundItem = NULL; ortn = SecKeychainGetStatus(kcRef, &kcStatus); if(ortn) { tpDebug("tpCheckPkinitServerCert: keychain not found (2)"); goto errOut; } /* * We already have this cert's normalized name; get its * serial number. */ crtn = theCert->fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial); if(crtn) { /* should never happen */ tpDebug("tpCheckPkinitServerCert: error fetching serial number"); goto errOut; } attrs[0].tag = kSecSubjectItemAttr; attrs[0].length = subjectName->Length; attrs[0].data = subjectName->Data; attrs[1].tag = kSecSerialNumberItemAttr; attrs[1].length = subjSerial->Length; attrs[1].data = subjSerial->Data; attrList.count = 2; attrList.attr = attrs; ortn = SecKeychainSearchCreateFromAttributes(kcRef, kSecCertificateItemClass, &attrList, &srchRef); if(ortn) { tpDebug("tpCheckPkinitServerCert: search failure"); goto errOut; } for(;;) { ortn = SecKeychainSearchCopyNext(srchRef, &foundItem); if(ortn) { tpDebug("tpCheckPkinitServerCert: end search"); break; } /* found a matching cert; do byte-for-byte compare */ CSSM_DATA certData; ortn = SecCertificateGetData((SecCertificateRef)foundItem, &certData); if(ortn) { tpDebug("tpCheckPkinitServerCert: SecCertificateGetData failure"); continue; } if(tpCompareCssmData(&certData, theCert->itemData())){ tpDebug("tpCheckPkinitServerCert: FOUND CERT"); ourRtn = true; break; } tpDebug("tpCheckPkinitServerCert: skipping matching cert"); CFRelease(foundItem); foundItem = NULL; } errOut: CFRELEASE(kcRef); CFRELEASE(srchRef); CFRELEASE(foundItem); if(subjSerial != NULL) { theCert->freeField(&CSSMOID_X509V1SerialNumber, subjSerial); } return ourRtn; }
/* * Given an open keychain, find a SecIdentityRef and munge it into * a CFArrayRef required by SSLSetCertificate(). */ CFArrayRef sslKcRefToCertArray( SecKeychainRef kcRef, bool encryptOnly, bool completeCertChain, const char *trustedAnchorFile) { /* quick check to make sure the keychain exists */ SecKeychainStatus kcStat; OSStatus ortn = SecKeychainGetStatus(kcRef, &kcStat); if(ortn) { printSslErrStr("SecKeychainGetStatus", ortn); printf("Can not open keychain. Aborting.\n"); return nil; } /* * Search for "any" identity matching specified key use; * in this app, we expect there to be exactly one. */ SecIdentitySearchRef srchRef = nil; ortn = SecIdentitySearchCreate(kcRef, encryptOnly ? CSSM_KEYUSE_DECRYPT : CSSM_KEYUSE_SIGN, &srchRef); if(ortn) { printf("SecIdentitySearchCreate returned %d.\n", (int)ortn); printf("Cannot find signing key in keychain. Aborting.\n"); return nil; } SecIdentityRef identity = nil; ortn = SecIdentitySearchCopyNext(srchRef, &identity); if(ortn) { printf("SecIdentitySearchCopyNext returned %d.\n", (int)ortn); printf("Cannot find signing key in keychain. Aborting.\n"); return nil; } if(CFGetTypeID(identity) != SecIdentityGetTypeID()) { printf("SecIdentitySearchCopyNext CFTypeID failure!\n"); return nil; } /* * Found one. */ if(completeCertChain) { /* * Place it and the other certs needed to verify it - * up to but not including the root - in a CFArray. */ SecCertificateRef anchorCert = NULL; if(trustedAnchorFile) { ortn = sslReadAnchor(trustedAnchorFile, &anchorCert); if(ortn) { printf("***Error reading anchor file\n"); } } CFArrayRef ca; ortn = sslCompleteCertChain(identity, anchorCert, false, &ca); if(anchorCert) { CFRelease(anchorCert); } return ca; } else { /* simple case, just this one identity */ CFArrayRef ca = CFArrayCreate(NULL, (const void **)&identity, 1, NULL); if(ca == nil) { printf("CFArrayCreate error\n"); } return ca; } }
static void tests(void) { char *home = getenv("HOME"); char kcname1[256], kcname2[256]; SecKeychainStatus status1, status2; if (!home || strlen(home) > 200) plan_skip_all("home too big"); sprintf(kcname1, "%s/kctests/kc1/kc1", home); SecKeychainRef kc1 = NULL, kc2 = NULL; kc1 = createNewKeychainAt(kcname1, "test"); ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status"); is(status1, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus, "status unlocked readable writable"); ok_status(SecKeychainLock(kc1), "SecKeychainLock kc1"); ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status"); TODO: { todo("<rdar://problem/2668794> KeychainImpl::status() returns " "incorrect status (always writable?)"); is(status1, kSecReadPermStatus|kSecWritePermStatus, "status (locked) readable writable"); } /* Make keychain non writable. */ char kcdir1[256]; sprintf(kcdir1, "%s/kctests/kc1", home); ok_unix(chmod(kcdir1, 0555), "chmod kcdir1 0555"); ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status"); is(status1, kSecReadPermStatus, "status (locked) readable"); ok_status(SecKeychainUnlock(kc1, 4, "test", TRUE), "SecKeychainLock kc1"); ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status"); TODO: { todo("<rdar://problem/2668794> KeychainImpl::status() returns " "incorrect status (always writable?)"); is(status1, kSecUnlockStateStatus|kSecReadPermStatus, "status unlocked readable"); } /* Reopen the keychain. */ CFRelease(kc1); ok_status(SecKeychainOpen(kcname1, &kc1), "SecKeychainOpen kc1"); ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status"); TODO: { todo("<rdar://problem/2668794> KeychainImpl::status() returns " "incorrect status (always writable?)"); is(status1, kSecUnlockStateStatus|kSecReadPermStatus, "status unlocked readable"); } sprintf(kcname2, "%s/kctests/kc2/kc2", home); kc2 = createNewKeychainAt(kcname2, "test"); ok_unix(chmod(kcname2, 0444), "chmod kc2 0444"); ok_status(SecKeychainGetStatus(kc2, &status2), "get kc2 status"); is(status2, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus, "status unlocked readable writable"); /* Reopen the keychain. */ CFRelease(kc2); ok_status(SecKeychainOpen(kcname2, &kc2), "SecKeychainOpen kc2"); ok_status(SecKeychainGetStatus(kc2, &status2), "get kc2 status"); is(status2, kSecUnlockStateStatus|kSecReadPermStatus|kSecWritePermStatus, "status unlocked readable writable"); /* Restore dir to writable so cleanup code will work ok. */ ok_unix(chmod(kcdir1, 0755), "chmod kcdir1 0755"); ok_status(SecKeychainDelete(kc1), "%s: SecKeychainDelete", testName); CFRelease(kc1); ok_status(SecKeychainDelete(kc2), "%s: SecKeychainDelete", testName); CFRelease(kc2); bool testWithFreshlyCreatedKeychain = true; SecKeychainRef keychain = createNewKeychain("test", "test"); ok_status(SecKeychainLock(keychain), "SecKeychainLock"); do { SecKeychainStatus keychainStatus = 0; is_status(SecKeychainUnlock(keychain, 0, NULL, true), -25293, "SecKeychainUnlock with NULL password (incorrect)"); ok_status(SecKeychainGetStatus(keychain, &keychainStatus), "SecKeychainGetStatus"); is( (keychainStatus & kSecUnlockStateStatus), 0, "Check it's not unlocked"); keychainStatus = 0; ok_status(SecKeychainUnlock(keychain, strlen("test"), "test", true), "SecKeychainUnlock with correct password"); ok_status(SecKeychainGetStatus(keychain, &keychainStatus), "SecKeychainGetStatus"); is( (keychainStatus & kSecUnlockStateStatus), kSecUnlockStateStatus, "Check it's unlocked"); ok_status(SecKeychainLock(keychain), "SecKeychainLock"); if (testWithFreshlyCreatedKeychain) { CFRelease(keychain); testWithFreshlyCreatedKeychain = false; ok_status(SecKeychainOpen("test", &keychain), "SecKeychainOpen"); } else { testWithFreshlyCreatedKeychain = true; ok_status(SecKeychainDelete(keychain), "%s: SecKeychainDelete", testName); CFReleaseNull(keychain); } } while(!testWithFreshlyCreatedKeychain); }