void tests(void) { SecKeychainRef keychain; ok_status(SecKeychainCreate("test", 4, "test", FALSE, NULL, &keychain), "create keychain"); SecKeyRef pub_crypt = NULL, prv_crypt = NULL; ok_status(SecKeyCreatePair(keychain, CSSM_ALGID_RSA, 256, 0 /* contextHandle */, CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP, CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE, CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP, CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_SENSITIVE, NULL /* initialAccess */, &pub_crypt, &prv_crypt), "generate encryption keypair"); SecKeyRef pub_sign = NULL, prv_sign = NULL; ok_status(SecKeyCreatePair(keychain, CSSM_ALGID_RSA, 256, 0 /* contextHandle */, CSSM_KEYUSE_VERIFY, CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE, CSSM_KEYUSE_SIGN, CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_SENSITIVE, NULL /* initialAccess */, &pub_sign, &prv_sign), "generate signing keypair"); uint32 btrue = 1; uint32 bfalse = 0; /* uint32 prv_class = CSSM_KEYCLASS_PRIVATE_KEY; */ SecKeychainAttribute attrs[] = { { kSecKeyDecrypt, sizeof(uint32), &btrue }, { kSecKeyEncrypt, sizeof(uint32), &bfalse }, /* { kSecKeyKeyClass, sizeof(uint32), &prv_class } */ }; SecKeychainAttributeList attrList = { sizeof(attrs) / sizeof(*attrs), attrs }; SecKeychainSearchRef search; OSStatus result; SecKeychainItemRef item; ok_status((result = SecKeychainSearchCreateFromAttributes(keychain, CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &search)), "create key search"); if (result == noErr) { ok_status(SecKeychainSearchCopyNext(search, &item), "get first key"); cmp_ok((intptr_t)prv_crypt, ==, (intptr_t)item, "is key found the right one?"); CFRelease(item); item = NULL; is_status(SecKeychainSearchCopyNext(search, &item), errSecItemNotFound, "get next key"); is((intptr_t)item, 0, "no item returned"); CFRelease(search); }
static int do_keychain_dump_class(FILE *stream, CFTypeRef keychainOrArray, SecItemClass itemClass, Boolean show_data, Boolean show_raw_data, Boolean show_acl, Boolean interactive) { SecKeychainItemRef item; SecKeychainSearchRef search = NULL; int result = 0; OSStatus status; status = SecKeychainSearchCreateFromAttributes(keychainOrArray, itemClass, NULL, &search); if (status) { sec_perror("SecKeychainSearchCreateFromAttributes", status); result = 1; goto cleanup; } while ((status = SecKeychainSearchCopyNext(search, &item)) == 0) { print_keychain_item_attributes(stream, item, show_data, show_raw_data, show_acl, interactive); CFRelease(item); } if (status != errSecItemNotFound) { sec_perror("SecKeychainSearchCopyNext", status); result = 1; goto cleanup; } cleanup: if (search) CFRelease(search); return result; }
SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray, char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win) { SecItemClass itemClass = kSecCertificateItemClass; SecKeychainSearchRef searchRef; SecKeychainItemRef itemRef = NULL; OSStatus status; SecKeychainAttribute attrs[1]; const char *serialNumber = "12345678"; // const SecKeychainAttributeList attrList; #if 0 attrs[1].tag = kSecLabelItemAttr; attrs[1].length = strlen(nickname)+1; attrs[1].data = nickname; #else attrs[1].tag = kSecSerialNumberItemAttr; attrs[1].length = (UInt32)strlen(serialNumber)+1; attrs[1].data = (uint8 *)serialNumber; #endif SecKeychainAttributeList attrList = { 0, attrs }; // 12 34 56 78 status = SecKeychainSearchCreateFromAttributes(keychainOrArray,itemClass,&attrList,&searchRef); if (status) { printf("CERT_FindUserCertByUsage: SecKeychainSearchCreateFromAttributes:%d",(int)status); return NULL; } status = SecKeychainSearchCopyNext(searchRef,&itemRef); if (status) printf("CERT_FindUserCertByUsage: SecKeychainSearchCopyNext:%d",(int)status); CFRelease(searchRef); return (SecCertificateRef)itemRef; }
/* find all the certs that represent the appropriate object (cert, priv key, or * pub key) in the cert store. */ static PRUint32 collect_class( CK_OBJECT_CLASS objClass, SecItemClass itemClass, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, ckmkInternalObject ***listp, PRUint32 *sizep, PRUint32 count, CK_RV *pError ) { ckmkInternalObject *next = NULL; SecKeychainSearchRef searchRef = 0; SecKeychainItemRef itemRef = 0; OSStatus error; /* future, build the attribute list based on the template * so we can refine the search */ error = SecKeychainSearchCreateFromAttributes( NULL, itemClass, NULL, &searchRef); while (noErr == SecKeychainSearchCopyNext(searchRef, &itemRef)) { /* if we don't have an internal object structure, get one */ if ((ckmkInternalObject *)NULL == next) { next = nss_ZNEW(NULL, ckmkInternalObject); if ((ckmkInternalObject *)NULL == next) { *pError = CKR_HOST_MEMORY; goto loser; } } /* fill in the relevant object data */ next->type = ckmkItem; next->objClass = objClass; next->u.item.itemRef = itemRef; next->u.item.itemClass = itemClass; /* see if this is one of the objects we are looking for */ if( CK_TRUE == ckmk_match(pTemplate, ulAttributeCount, next) ) { /* yes, put it on the list */ PUT_OBJECT(next, *pError, *sizep, count, *listp); next = NULL; /* this one is on the list, need to allocate a new one now */ } else { /* no , release the current item and clear out the structure for reuse */ CFRelease(itemRef); /* don't cache the values we just loaded */ nsslibc_memset(next, 0, sizeof(*next)); } } loser: if (searchRef) { CFRelease(searchRef); } nss_ZFreeIf(next); return count; }
/* * Add all of the roots in a given KC to SSL ctx's trusted anchors. */ OSStatus sslAddTrustedRoots( SSLContextRef ctx, SecKeychainRef keychain, bool *foundOne) // RETURNED, true if we found // at least one root cert { OSStatus ortn; SecCertificateRef secCert; SecKeychainSearchRef srch; *foundOne = false; ortn = SecKeychainSearchCreateFromAttributes(keychain, kSecCertificateItemClass, NULL, // any attrs &srch); if(ortn) { printSslErrStr("SecKeychainSearchCreateFromAttributes", ortn); return ortn; } /* * Only use root certs. Not an error if we don't find any. */ do { ortn = SecKeychainSearchCopyNext(srch, (SecKeychainItemRef *)&secCert); if(ortn) { break; } /* see if it's a root */ if(!isCertRoot(secCert)) { continue; } /* Tell Secure Transport to trust this one. */ ortn = addTrustedSecCert(ctx, secCert, false); if(ortn) { /* fatal */ printSslErrStr("addTrustedSecCert", ortn); return ortn; } CFRelease(secCert); *foundOne = true; } while(ortn == errSecSuccess); CFRelease(srch); return errSecSuccess; }
/* * Add all itmes of specified class from a keychain to an array. * Item class are things like kSecCertificateItemClass, and * CSSM_DL_DB_RECORD_PRIVATE_KEY. Identities are searched separately. */ static OSStatus addKcItems( SecKeychainRef kcRef, SecItemClass itemClass, // kSecCertificateItemClass CFMutableArrayRef outArray, unsigned *numItems) // UPDATED on return { OSStatus ortn; SecKeychainSearchRef srchRef; ortn = SecKeychainSearchCreateFromAttributes(kcRef, itemClass, NULL, // no attrs &srchRef); if(ortn) { sec_perror("SecKeychainSearchCreateFromAttributes", ortn); return ortn; } for(;;) { SecKeychainItemRef itemRef; ortn = SecKeychainSearchCopyNext(srchRef, &itemRef); if(ortn) { if(ortn == errSecItemNotFound) { /* normal search end */ ortn = noErr; } else { sec_perror("SecIdentitySearchCopyNext", ortn); } break; } CFArrayAppendValue(outArray, itemRef); CFRelease(itemRef); // array owns the item (*numItems)++; } CFRelease(srchRef); return ortn; }
// find_first_generic_password // // Returns a SecKeychainItemRef for the first item // which matches the specified attributes. Caller is // responsible for releasing the item (with CFRelease). // SecKeychainItemRef find_first_generic_password(CFTypeRef keychainOrArray, FourCharCode itemCreator, FourCharCode itemType, const char *kind, const char *value, const char *comment, const char *label, const char *serviceName, const char *accountName) { OSStatus status = noErr; SecKeychainSearchRef searchRef = NULL; SecKeychainItemRef itemRef = NULL; SecKeychainAttribute attrs[8]; // maximum number of searchable attributes SecKeychainAttributeList attrList = { 0, attrs }; // the primary key for a generic password item (i.e. the combination of // attributes which determine whether the item is unique) consists of: // { kSecAccountItemAttr, kSecServiceItemAttr } // // if we have a primary key, we don't need to search on other attributes // (and we don't want to, if non-primary attributes are being updated) Boolean primaryKey = (accountName && serviceName); // build the attribute list for searching if ((UInt32)itemCreator != 0 && !primaryKey) { attrs[attrList.count].tag = kSecCreatorItemAttr; attrs[attrList.count].length = sizeof(FourCharCode); attrs[attrList.count].data = (FourCharCode *)&itemCreator; attrList.count++; } if ((UInt32)itemType != 0 && !primaryKey) { attrs[attrList.count].tag = kSecTypeItemAttr; attrs[attrList.count].length = sizeof(FourCharCode); attrs[attrList.count].data = (FourCharCode *)&itemType; attrList.count++; } if (kind != NULL && !primaryKey) { attrs[attrList.count].tag = kSecDescriptionItemAttr; attrs[attrList.count].length = strlen(kind); attrs[attrList.count].data = (void*)kind; attrList.count++; } if (value != NULL && !primaryKey) { attrs[attrList.count].tag = kSecGenericItemAttr; attrs[attrList.count].length = strlen(value); attrs[attrList.count].data = (void*)value; attrList.count++; } if (comment != NULL && !primaryKey) { attrs[attrList.count].tag = kSecCommentItemAttr; attrs[attrList.count].length = strlen(comment); attrs[attrList.count].data = (void*)comment; attrList.count++; } if (label != NULL && !primaryKey) { attrs[attrList.count].tag = kSecLabelItemAttr; attrs[attrList.count].length = strlen(label); attrs[attrList.count].data = (void*)label; attrList.count++; } if (serviceName != NULL) { attrs[attrList.count].tag = kSecServiceItemAttr; attrs[attrList.count].length = strlen(serviceName); attrs[attrList.count].data = (void*)serviceName; attrList.count++; } if (accountName != NULL) { attrs[attrList.count].tag = kSecAccountItemAttr; attrs[attrList.count].length = strlen(accountName); attrs[attrList.count].data = (void*)accountName; attrList.count++; } status = SecKeychainSearchCreateFromAttributes(keychainOrArray, kSecGenericPasswordItemClass, &attrList, &searchRef); if (status) { sec_perror("SecKeychainSearchCreateFromAttributes", status); goto cleanup; } // we're only interested in the first match, if there is a match at all status = SecKeychainSearchCopyNext(searchRef, &itemRef); if (status) { itemRef = NULL; } cleanup: if (searchRef) CFRelease(searchRef); return itemRef; }
// find_unique_certificate // // Returns a SecKeychainItemRef for the certificate // in the specified keychain (or keychain list) // which is a unique match for either the specified name // or SHA-1 hash. If more than one match exists, the // certificate is not unique and none are returned. Caller is // responsible for releasing the item (with CFRelease). // SecKeychainItemRef find_unique_certificate(CFTypeRef keychainOrArray, const char *name, const char *hash) { OSStatus status = noErr; SecKeychainSearchRef searchRef = NULL; SecKeychainItemRef uniqueItemRef = NULL; status = SecKeychainSearchCreateFromAttributes(keychainOrArray, kSecCertificateItemClass, NULL, &searchRef); if (status) { return uniqueItemRef; } // check input hash string and convert to data CSSM_DATA hashData = { 0, NULL }; if (hash) { CSSM_SIZE len = strlen(hash)/2; hashData.Length = len; hashData.Data = (uint8 *)malloc(hashData.Length); fromHex(hash, &hashData); } // filter candidates against the hash (or the name, if no hash provided) CFStringRef matchRef = (name) ? CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8) : NULL; Boolean exactMatch = FALSE; CSSM_DATA certData = { 0, NULL }; SecKeychainItemRef candidate = NULL; while (SecKeychainSearchCopyNext(searchRef, &candidate) == noErr) { SecCertificateRef cert = (SecCertificateRef)candidate; if (SecCertificateGetData(cert, &certData) != noErr) { safe_CFRelease(&candidate); continue; } if (hash) { uint8 candidate_sha1_hash[20]; CSSM_DATA digest; digest.Length = sizeof(candidate_sha1_hash); digest.Data = candidate_sha1_hash; if ((SecDigestGetData(CSSM_ALGID_SHA1, &digest, &certData) == CSSM_OK) && (hashData.Length == digest.Length) && (!memcmp(hashData.Data, digest.Data, digest.Length))) { exactMatch = TRUE; uniqueItemRef = candidate; // currently retained break; // we're done - can't get more exact than this } } else { // copy certificate name CFStringRef nameRef = NULL; if ((SecCertificateCopyCommonName(cert, &nameRef) != noErr) || nameRef == NULL) { safe_CFRelease(&candidate); continue; // no name, so no match is possible } CFIndex nameLen = CFStringGetLength(nameRef); CFIndex bufLen = 1 + CFStringGetMaximumSizeForEncoding(nameLen, kCFStringEncodingUTF8); char *nameBuf = (char *)malloc(bufLen); if (!CFStringGetCString(nameRef, nameBuf, bufLen-1, kCFStringEncodingUTF8)) nameBuf[0]=0; CFRange find = { kCFNotFound, 0 }; if (nameRef && matchRef) find = CFStringFind(nameRef, matchRef, kCFCompareCaseInsensitive | kCFCompareNonliteral); Boolean isExact = (find.location == 0 && find.length == nameLen); if (find.location == kCFNotFound) { free(nameBuf); safe_CFRelease(&nameRef); safe_CFRelease(&candidate); continue; // no match } if (uniqueItemRef) { // got two matches if (exactMatch && !isExact) { // prior is better; ignore this one free(nameBuf); safe_CFRelease(&nameRef); safe_CFRelease(&candidate); continue; } if (exactMatch == isExact) { // same class of match if (CFEqual(uniqueItemRef, candidate)) { // same certificate free(nameBuf); safe_CFRelease(&nameRef); safe_CFRelease(&candidate); continue; } // ambiguity - must fail sec_error("\"%s\" is ambiguous, matches more than one certificate", name); free(nameBuf); safe_CFRelease(&nameRef); safe_CFRelease(&candidate); safe_CFRelease(&uniqueItemRef); break; } safe_CFRelease(&uniqueItemRef); // about to replace with this one } uniqueItemRef = candidate; // currently retained exactMatch = isExact; free(nameBuf); safe_CFRelease(&nameRef); } } safe_CFRelease(&searchRef); safe_CFRelease(&matchRef); if (hashData.Data) { free(hashData.Data); } return uniqueItemRef; }
// find_first_internet_password // // Returns a SecKeychainItemRef for the first item // which matches the specified attributes. Caller is // responsible for releasing the item (with CFRelease). // SecKeychainItemRef find_first_internet_password(CFTypeRef keychainOrArray, FourCharCode itemCreator, FourCharCode itemType, const char *kind, const char *comment, const char *label, const char *serverName, const char *securityDomain, const char *accountName, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType) { OSStatus status = noErr; SecKeychainSearchRef searchRef = NULL; SecKeychainItemRef itemRef = NULL; SecKeychainAttribute attrs[12]; // maximum number of searchable attributes SecKeychainAttributeList attrList = { 0, attrs }; // the primary key for an internet password item (i.e. the combination of // attributes which determine whether the item is unique) consists of: // { kSecAccountItemAttr, kSecSecurityDomainItemAttr, kSecServerItemAttr, // kSecProtocolItemAttr, kSecAuthenticationTypeItemAttr, // kSecPortItemAttr, kSecPathItemAttr } // // if we have a primary key, we don't need to search on other attributes. // (and we don't want to, if non-primary attributes are being updated) Boolean primaryKey = (accountName && securityDomain && serverName && protocol && authenticationType && port && path); // build the attribute list for searching if ((UInt32)itemCreator != 0 && !primaryKey) { attrs[attrList.count].tag = kSecCreatorItemAttr; attrs[attrList.count].length = sizeof(FourCharCode); attrs[attrList.count].data = (FourCharCode *)&itemCreator; attrList.count++; } if ((UInt32)itemType != 0 && !primaryKey) { attrs[attrList.count].tag = kSecTypeItemAttr; attrs[attrList.count].length = sizeof(FourCharCode); attrs[attrList.count].data = (FourCharCode *)&itemType; attrList.count++; } if (kind != NULL && !primaryKey) { attrs[attrList.count].tag = kSecDescriptionItemAttr; attrs[attrList.count].length = strlen(kind); attrs[attrList.count].data = (void*)kind; attrList.count++; } if (comment != NULL && !primaryKey) { attrs[attrList.count].tag = kSecCommentItemAttr; attrs[attrList.count].length = strlen(comment); attrs[attrList.count].data = (void*)comment; attrList.count++; } if (label != NULL && !primaryKey) { attrs[attrList.count].tag = kSecLabelItemAttr; attrs[attrList.count].length = strlen(label); attrs[attrList.count].data = (void*)label; attrList.count++; } if (serverName != NULL) { attrs[attrList.count].tag = kSecServerItemAttr; attrs[attrList.count].length = strlen(serverName); attrs[attrList.count].data = (void*)serverName; attrList.count++; } if (securityDomain != NULL) { attrs[attrList.count].tag = kSecSecurityDomainItemAttr; attrs[attrList.count].length = strlen(securityDomain); attrs[attrList.count].data = (void *)securityDomain; attrList.count++; } if (accountName != NULL) { attrs[attrList.count].tag = kSecAccountItemAttr; attrs[attrList.count].length = strlen(accountName); attrs[attrList.count].data = (void *)accountName; attrList.count++; } if (path != NULL) { attrs[attrList.count].tag = kSecPathItemAttr; attrs[attrList.count].length = strlen(path); attrs[attrList.count].data = (void *)path; attrList.count++; } if (port != 0) { attrs[attrList.count].tag = kSecPortItemAttr; attrs[attrList.count].length = sizeof(UInt16); attrs[attrList.count].data = (UInt16 *)&port; attrList.count++; } if ((UInt32)protocol != 0) { attrs[attrList.count].tag = kSecProtocolItemAttr; attrs[attrList.count].length = sizeof(SecProtocolType); attrs[attrList.count].data = (SecProtocolType *)&protocol; attrList.count++; } if ((UInt32)authenticationType != 0) { attrs[attrList.count].tag = kSecAuthenticationTypeItemAttr; attrs[attrList.count].length = sizeof(SecAuthenticationType); attrs[attrList.count].data = (SecAuthenticationType *)&authenticationType; attrList.count++; } status = SecKeychainSearchCreateFromAttributes(keychainOrArray, kSecInternetPasswordItemClass, &attrList, &searchRef); if (status) { sec_perror("SecKeychainSearchCreateFromAttributes", status); goto cleanup; } // we're only interested in the first match, if there is a match at all status = SecKeychainSearchCopyNext(searchRef, &itemRef); if (status) { itemRef = NULL; } cleanup: if (searchRef) CFRelease(searchRef); return itemRef; }
/* * 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; }
static int keychain_iter(hx509_context context, hx509_certs certs, void *data, void *cursor, hx509_cert *cert) { SecKeychainAttributeList *attrs = NULL; SecKeychainAttributeInfo attrInfo; uint32 attrFormat[1] = { 0 }; SecKeychainItemRef itemRef; SecItemAttr item[1]; struct iter *iter = cursor; OSStatus ret; UInt32 len; void *ptr = NULL; if (iter->certs) return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert); *cert = NULL; ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef); if (ret == errSecItemNotFound) return 0; else if (ret != 0) return EINVAL; /* * Pick out certificate and matching "keyid" */ item[0] = kSecPublicKeyHashItemAttr; attrInfo.count = 1; attrInfo.tag = item; attrInfo.format = attrFormat; ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrs, &len, &ptr); if (ret) return EINVAL; ret = hx509_cert_init_data(context, ptr, len, cert); if (ret) goto out; /* * Find related private key if there is one by looking at * kSecPublicKeyHashItemAttr == kSecKeyLabel */ { SecKeychainSearchRef search; SecKeychainAttribute attrKeyid; SecKeychainAttributeList attrList; attrKeyid.tag = kSecKeyLabel; attrKeyid.length = attrs->attr[0].length; attrKeyid.data = attrs->attr[0].data; attrList.count = 1; attrList.attr = &attrKeyid; ret = SecKeychainSearchCreateFromAttributes(NULL, CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &search); if (ret) { ret = 0; goto out; } ret = SecKeychainSearchCopyNext(search, &itemRef); CFRelease(search); if (ret == errSecItemNotFound) { ret = 0; goto out; } else if (ret) { ret = EINVAL; goto out; } set_private_key(context, itemRef, *cert); } out: SecKeychainItemFreeAttributesAndData(attrs, ptr); return ret; }
static void tls_get_cert_from_keychain( char *host ) { /* Cert info is kept in the global options. */ struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); if ( !lo ) return; /* If the server identity option is set, don't need to do anything * as the certificate will get set in the SSL context during context * initialization. */ if (lo->ldo_tls_server_ident_ref_name) { return; } /* If the cert is set in the options, don't override it. */ if ( lo->ldo_tls_cacertfile || lo->ldo_tls_certfile ) { Debug( LDAP_DEBUG_ANY, "TLS: not reading certificate from keychain, option %s is set\n", lo->ldo_tls_cacertfile ? "cacertfile" : "certfile", 0, 0 ); return; } SecKeychainRef keychainRef = NULL; OSStatus status = SecKeychainOpen( SYSTEM_KEYCHAIN_PATH, &keychainRef ); if ( status != errSecSuccess ) { Debug( LDAP_DEBUG_ANY, "TLS: SecKeychainOpen failed for keychain %s: %d", SYSTEM_KEYCHAIN_PATH, (int)status, 0 ); syslog( LOG_ERR, "TLS: SecKeychainOpen failed for keychain %s: %d", SYSTEM_KEYCHAIN_PATH, (int)status, 0 ); cssmPerror( "SecKeychainOpen", status ); return; } SecKeychainSearchRef searchRef = NULL; status = SecKeychainSearchCreateFromAttributes( keychainRef, kSecCertificateItemClass, NULL, &searchRef ); if ( status != errSecSuccess ) { Debug( LDAP_DEBUG_ANY, "TLS: SecKeychainSearchCreateFromAttributes failed: %d", (int)status, 0, 0 ); syslog( LOG_ERR, "TLS: SecKeychainSearchCreateFromAttributes failed: %d", (int)status ); cssmPerror( "SecKeychainSearchCreateFromAttributes", status ); } while ( status == errSecSuccess ) { SecCertificateRef certificateRef = NULL; status = SecKeychainSearchCopyNext( searchRef, (SecKeychainItemRef*)&certificateRef ); /* Bail on any error. */ if ( status != errSecSuccess ) { /* Only complain if the error is something other than * the normal search end. */ if ( status != errSecItemNotFound ) { Debug( LDAP_DEBUG_ANY, "TLS: SecKeychainSearchCopyNext failed: %d", (int)status, 0, 0 ); syslog( LOG_ERR, "SecKeychainSearchCopyNext failed: %d", (int)status ); cssmPerror( "SecKeychainSearchCopyNext", status ); } break; } /* Extract the name from the certificate. Will check against the host * name passed in. */ CFStringRef commonName = NULL; status = SecCertificateCopyCommonName( certificateRef, &commonName ); if ( status != errSecSuccess || !commonName ) { Debug( LDAP_DEBUG_ANY, "TLS: SecCertificateCopyCommonName failed: %d", (int)status, 0, 0 ); cssmPerror( "SecCertificateCopyCommonName", status ); /* Reset 'status' to allow the loop to continue. No need to * stop just because we can't get the name from one of the * certs. */ status = errSecSuccess; } else { /* If the common name in the certificate matches the host name, save * the certificate reference in the options data for later use. */ char commonNameCStr[PATH_MAX]; if ( !CFStringGetCString( commonName, commonNameCStr, sizeof(commonNameCStr), kCFStringEncodingUTF8 ) ) { Debug( LDAP_DEBUG_ANY, "TLS: Unable to convert certificate common name CFString into C String", 0, 0, 0); } CFRelease( commonName ); if ( commonNameCStr && strcmp( commonNameCStr, host ) == 0 ) { if ( lo->ldo_tls_cert_ref ) { CFRelease( lo->ldo_tls_cert_ref ); } lo->ldo_tls_cert_ref = certificateRef; status = !errSecSuccess; /* cert found - terminate the loop */ } } /* Only release the ref if we don't care about it. Refs we care * about get released later (when the connection is closed). */ if ( lo->ldo_tls_cert_ref != certificateRef ) { CFRelease( certificateRef ); } } if ( searchRef ) { CFRelease( searchRef ); } CFRelease( keychainRef ); Debug( LDAP_DEBUG_ANY, "TLS: %s certificate in keychain for host \"%s\"\n", lo->ldo_tls_cert_ref ? "found" : "did not find", host, 0 ); }
bool getCredentialsFromKeychain(const URI &uri, ClientRequest::ptr priorRequest, std::string &scheme, std::string &realm, std::string &username, std::string &password, size_t attempts) { if (attempts != 1) return false; bool proxy = priorRequest->response().status.status == PROXY_AUTHENTICATION_REQUIRED; const ChallengeList &challengeList = proxy ? priorRequest->response().response.proxyAuthenticate : priorRequest->response().response.wwwAuthenticate; if (isAcceptable(challengeList, "Basic")) scheme = "Basic"; else if (isAcceptable(challengeList, "Digest")) scheme = "Digest"; else return false; std::vector<SecKeychainAttribute> attrVector; std::string host = uri.authority.host(); attrVector.push_back((SecKeychainAttribute){kSecServerItemAttr, host.size(), (void *)host.c_str()}); UInt32 port = 0; if (uri.authority.portDefined()) { port = uri.authority.port(); attrVector.push_back((SecKeychainAttribute){kSecPortItemAttr, sizeof(UInt32), &port}); } SecProtocolType protocol; if (proxy && priorRequest->request().requestLine.method == CONNECT) protocol = kSecProtocolTypeHTTPSProxy; else if (proxy) protocol = kSecProtocolTypeHTTPProxy; else if (uri.scheme() == "https") protocol = kSecProtocolTypeHTTPS; else if (uri.scheme() == "http") protocol = kSecProtocolTypeHTTP; else MORDOR_NOTREACHED(); attrVector.push_back((SecKeychainAttribute){kSecProtocolItemAttr, sizeof(SecProtocolType), &protocol}); ScopedCFRef<SecKeychainSearchRef> search; SecKeychainAttributeList attrList; attrList.count = (UInt32)attrVector.size(); attrList.attr = &attrVector[0]; OSStatus status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, &attrList, &search); if (status != 0) return false; ScopedCFRef<SecKeychainItemRef> item; status = SecKeychainSearchCopyNext(search, &item); if (status != 0) return false; SecKeychainAttributeInfo info; SecKeychainAttrType tag = kSecAccountItemAttr; CSSM_DB_ATTRIBUTE_FORMAT format = CSSM_DB_ATTRIBUTE_FORMAT_STRING; info.count = 1; info.tag = (UInt32 *)&tag; info.format = (UInt32 *)&format; SecKeychainAttributeList *attrs; UInt32 passwordLength = 0; void *passwordBytes = NULL; status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attrs, &passwordLength, &passwordBytes); if (status != 0) return false; try { username.assign((const char *)attrs->attr[0].data, attrs->attr[0].length); password.assign((const char *)passwordBytes, passwordLength); } catch (...) { SecKeychainItemFreeContent(attrs, passwordBytes); throw; } SecKeychainItemFreeContent(attrs, passwordBytes); return true; }
static int do_keychain_find_certificate(CFTypeRef keychainOrArray, const char *name, const char *emailAddress, Boolean print_hash, Boolean output_pem, Boolean find_all, Boolean print_email) { OSStatus result = noErr; SecCertificateRef certificateRef = NULL; SecKeychainSearchRef searchRef = NULL; CFStringRef matchRef = (name) ? CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8) : NULL; if (find_all && emailAddress) { result = SecKeychainSearchCreateForCertificateByEmail(keychainOrArray, emailAddress, &searchRef); if (result) { sec_perror("SecKeychainSearchCreateForCertificateByEmail", result); goto cleanup; } } else { result = SecKeychainSearchCreateFromAttributes(keychainOrArray, kSecCertificateItemClass, NULL, &searchRef); if (result) { sec_perror("SecKeychainSearchCreateFromAttributes", result); goto cleanup; } } do { if (find_all) { SecKeychainItemRef itemRef = NULL; result = SecKeychainSearchCopyNext(searchRef, &itemRef); if (result == errSecItemNotFound) { result = 0; break; } else if (result) { sec_perror("SecKeychainSearchCopyNext", result); goto cleanup; } if (!emailAddress && name) { // match name in common name CFStringRef nameRef = NULL; if (SecCertificateCopyCommonName((SecCertificateRef)itemRef, &nameRef) != noErr) { safe_CFRelease(&itemRef); continue; // no name, so no match is possible } CFRange find = { kCFNotFound, 0 }; if (nameRef && matchRef) find = CFStringFind(nameRef, matchRef, kCFCompareCaseInsensitive | kCFCompareNonliteral); if (find.location == kCFNotFound) { safe_CFRelease(&nameRef); safe_CFRelease(&itemRef); continue; // no match } safe_CFRelease(&nameRef); } safe_CFRelease(&certificateRef); certificateRef = (SecCertificateRef) itemRef; } else { // only want the first match if (emailAddress) { result = SecCertificateFindByEmail(keychainOrArray, emailAddress, &certificateRef); if (result) { sec_perror("SecCertificateFindByEmail", result); goto cleanup; } } else { SecKeychainItemRef itemRef = NULL; while ((result = SecKeychainSearchCopyNext(searchRef, &itemRef)) != errSecItemNotFound) { if (name) { // match name in common name CFStringRef nameRef = NULL; if (SecCertificateCopyCommonName((SecCertificateRef)itemRef, &nameRef) != noErr) { safe_CFRelease(&itemRef); continue; // no name, so no match is possible } CFRange find = { kCFNotFound, 0 }; if (nameRef && matchRef) find = CFStringFind(nameRef, matchRef, kCFCompareCaseInsensitive | kCFCompareNonliteral); if (find.location == kCFNotFound) { safe_CFRelease(&nameRef); safe_CFRelease(&itemRef); continue; // no match } safe_CFRelease(&nameRef); } break; // we have a match! } if (result == errSecItemNotFound) { sec_perror("SecKeychainSearchCopyNext", result); goto cleanup; } certificateRef = (SecCertificateRef) itemRef; } } // process the found certificate if (print_hash) { uint8 sha1_hash[20]; CSSM_DATA data; CSSM_DATA digest; digest.Length = sizeof(sha1_hash); digest.Data = sha1_hash; if ((SecCertificateGetData(certificateRef, &data) == noErr) && (SecDigestGetData(CSSM_ALGID_SHA1, &digest, &data) == CSSM_OK)) { unsigned int i; uint32 len = digest.Length; uint8 *cp = digest.Data; fprintf(stdout, "SHA-1 hash: "); for(i=0; i<len; i++) { fprintf(stdout, "%02X", ((unsigned char *)cp)[i]); } fprintf(stdout, "\n"); } } if (print_email) { CFArrayRef emailAddresses = NULL; CFIndex ix, count; result = SecCertificateCopyEmailAddresses(certificateRef, &emailAddresses); if (result) { sec_perror("SecCertificateCopyEmailAddresses", result); goto cleanup; } count = CFArrayGetCount(emailAddresses); fputs("email addresses: ", stdout); for (ix = 0; ix < count; ++ix) { CFStringRef emailAddress = (CFStringRef)CFArrayGetValueAtIndex(emailAddresses, ix); const char *addr; char buffer[256]; if (ix) fputs(", ", stdout); addr = CFStringGetCStringPtr(emailAddress, kCFStringEncodingUTF8); if (!addr) { if (CFStringGetCString(emailAddress, buffer, sizeof(buffer), kCFStringEncodingUTF8)) addr = buffer; } fprintf(stdout, "%s", addr); } fputc('\n', stdout); CFRelease(emailAddresses); } if (output_pem) { CSSM_DATA certData = {}; result = SecCertificateGetData(certificateRef, &certData); if (result) { sec_perror("SecCertificateGetData", result); goto cleanup; } print_buffer_pem(stdout, "CERTIFICATE", certData.Length, certData.Data); } else { print_keychain_item_attributes(stdout, (SecKeychainItemRef)certificateRef, FALSE, FALSE, FALSE, FALSE); } } while (find_all); cleanup: safe_CFRelease(&searchRef); safe_CFRelease(&certificateRef); safe_CFRelease(&matchRef); return result; }
CFDataRef decodePrivateKeyHeader(SecKeychainRef keychain, const FVPrivateKeyHeader &inHeader) { // kSecKeyLabel is defined in libsecurity_keychain/lib/SecKey.h SecKeychainAttribute attrs[] = { { 6 /* kSecKeyLabel */, inHeader.publicKeyHashSize, const_cast<uint8 *>(inHeader.publicKeyHash) } }; SecKeychainAttributeList attrList = { sizeof(attrs) / sizeof(SecKeychainAttribute), attrs }; CSSM_CSP_HANDLE cspHandle = 0; const CSSM_KEY *cssmKey = NULL; const CSSM_ACCESS_CREDENTIALS *accessCred = NULL; CSSM_CC_HANDLE cc = 0; SecKeychainSearchRef _searchRef; throwIfError(SecKeychainSearchCreateFromAttributes(keychain, (SecItemClass) CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &_searchRef)); CFRef<SecKeychainSearchRef> searchRef(_searchRef); SecKeychainItemRef _item; if (SecKeychainSearchCopyNext(searchRef, &_item) != 0) { return NULL; // XXX possibly should throw here? } CFRef<SecKeyRef> keyItem(reinterpret_cast<SecKeyRef>(_item)); throwIfError(SecKeyGetCSPHandle(keyItem, &cspHandle)); throwIfError(SecKeyGetCSSMKey(keyItem, &cssmKey)); throwIfError(SecKeyGetCredentials(keyItem, CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault, &accessCred)); throwIfError(CSSM_CSP_CreateAsymmetricContext(cspHandle, cssmKey->KeyHeader.AlgorithmId, accessCred, cssmKey, CSSM_PADDING_PKCS1, &cc)); CFDataRef result; try { CssmMemoryFunctions memFuncs; throwIfError(CSSM_GetAPIMemoryFunctions(cspHandle, &memFuncs)); CssmMemoryFunctionsAllocator allocator(memFuncs); const CssmData cipherBuf(const_cast<uint8 *>(inHeader.encryptedBlob), inHeader.encryptedBlobSize); CssmAutoData clearBuf(allocator); CssmAutoData remData(allocator); size_t bytesDecrypted; CSSM_RETURN crx = CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get()); secinfo("FDERecovery", "decodePrivateKeyHeader: CSSM_DecryptData result: %d", crx); throwIfError(crx); // throwIfError(CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get())); clearBuf.length(bytesDecrypted); // rawKey.copy(clearBuf.get()); result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)clearBuf.get().data(), clearBuf.get().length()); // result = parseKeyBlob(clearBuf.get()); } catch(...) { CSSM_DeleteContext(cc); throw; } throwIfError(CSSM_DeleteContext(cc)); return result; }
OSStatus OTMacKeychain::SearchCopyNext(SecKeychainSearchRef searchRef, SecKeychainItemRef* itemRef) const { return SecKeychainSearchCopyNext(searchRef, itemRef); }
int main(int argc, char **argv) { if(argc < 2) { usage(argv); } bool print_cert = false; bool allCerts = false; const char *emailAddress = NULL; bool addToKC = false; extern int optind; optind = 1; if(argv[1][0] != '-') { /* normal case, email address specified */ emailAddress = argv[1]; optind++; } extern char *optarg; int arg; while ((arg = getopt(argc, argv, "aphA")) != -1) { switch (arg) { case 'p': print_cert = true; break; case 'a': allCerts = true; break; case 'A': addToKC = true; break; case 'h': default: usage(argv); } } if(optind != argc) { usage(argv); } if(!allCerts && (emailAddress == NULL)) { printf("***You must specify either an email address or the -a option.\n"); exit(1); } OSStatus ortn; SecKeychainSearchRef srch; SecKeychainAttributeList attrList; SecKeychainAttribute attr; unsigned numCerts = 0; if(emailAddress) { attr.tag = kSecAlias; // i.e., email address attr.length = strlen(emailAddress); attr.data = (void *)emailAddress; attrList.count = 1; attrList.attr = &attr; } else { attrList.count = 0; attrList.attr = NULL; } ortn = SecKeychainSearchCreateFromAttributes(NULL, // default search list kSecCertificateItemClass, &attrList, &srch); if(ortn) { cssmPerror("SecKeychainSearchCreateFromAttributes", ortn); exit(1); } do { SecCertificateRef certRef = NULL; CSSM_DATA certData; ortn = SecKeychainSearchCopyNext(srch, (SecKeychainItemRef *)&certRef); if(ortn) { break; } ortn = SecCertificateGetData(certRef, &certData); if(ortn) { cssmPerror("SecCertificateGetData", ortn); continue; } printf("=== Cert %u ===\n", numCerts); printCertName(certData.Data, certData.Length, NameBoth); if(print_cert) { printCert(certData.Data, certData.Length, CSSM_FALSE); } if(addToKC) { /* * Can't call SecCertificateAddToKeychain directly since this * cert already has a keychain. */ SecCertificateRef newCertRef = NULL; ortn = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &newCertRef); if(ortn) { cssmPerror("SecCertificateCreateFromData", ortn); printf("***Error adding this cert to default keychain.\n"); } else { ortn = SecCertificateAddToKeychain(newCertRef, NULL); if(ortn) { cssmPerror("SecCertificateAddToKeychain", ortn); printf("***Error adding this cert to default keychain.\n"); } else { printf("...cert added to default keychain.\n"); } CFRelease(newCertRef); } } CFRelease(certRef); numCerts++; } while(ortn == noErr); printf("...%u certs found matching email address \'%s\'\n", numCerts, emailAddress ? emailAddress : "<any>"); CFRelease(srch); return 0; }