bool encryptionEnabled(SecKeyRef privateKeyRef) { /* Since CSSM searching for attributes is an AND, not an OR, we need to get all identities then check each one for a good key usage. Note that for the CAC card, the "Email Encryption Private Key" only has the unwrap bit set (0x1A). Return true if this identity supports appropriate encryption. */ UInt32 tag[] = { kSecKeyEncrypt, kSecKeyDecrypt, kSecKeyDerive, kSecKeyWrap, kSecKeyUnwrap }; UInt32 format[] = { CSSM_DB_ATTRIBUTE_FORMAT_UINT32, CSSM_DB_ATTRIBUTE_FORMAT_UINT32, CSSM_DB_ATTRIBUTE_FORMAT_UINT32, CSSM_DB_ATTRIBUTE_FORMAT_UINT32, CSSM_DB_ATTRIBUTE_FORMAT_UINT32}; SecKeychainAttributeInfo info = { 5, tag, format }; // attrs to retrieve SecKeychainAttributeList *attrList = NULL; OSStatus status = SecKeychainItemCopyAttributesAndData((SecKeychainItemRef)privateKeyRef, &info, NULL, &attrList, 0, NULL); if (status || !attrList) return false; bool canEncrypt = false; for (uint32_t index = 0; index < attrList->count; ++index) { if (attrList->attr[index].length != sizeof(uint32_t) || !attrList->attr[index].data || 0 == *(uint32_t*)attrList->attr[index].data) continue; canEncrypt = true; break; } status = SecKeychainItemFreeAttributesAndData(attrList, NULL); return canEncrypt; }
/* * Determine if specified SecCertificateRef is a self-signed cert. * We do this by comparing the subject and issuerr names; no cryptographic * verification is performed. * * Returns true if the cert appears to be a root. */ static bool isCertRefRoot( SecCertificateRef certRef) { bool brtn = false; #if 0 /* just search for the two attrs we want */ UInt32 tags[2] = {kSecSubjectItemAttr, kSecIssuerItemAttr}; SecKeychainAttributeInfo attrInfo; attrInfo.count = 2; attrInfo.tag = tags; attrInfo.format = NULL; SecKeychainAttributeList *attrList = NULL; SecKeychainAttribute *attr1 = NULL; SecKeychainAttribute *attr2 = NULL; OSStatus ortn = SecKeychainItemCopyAttributesAndData( (SecKeychainItemRef)certRef, &attrInfo, NULL, // itemClass &attrList, NULL, // length - don't need the data NULL); // outData if(ortn) { cssmPerror("SecKeychainItemCopyAttributesAndData", ortn); /* may want to be a bit more robust here, but this should * never happen */ return false; } /* subsequent errors to errOut: */ if((attrList == NULL) || (attrList->count != 2)) { printf("***Unexpected result fetching label attr\n"); goto errOut; } /* rootness is just byte-for-byte compare of the two names */ attr1 = &attrList->attr[0]; attr2 = &attrList->attr[1]; if(attr1->length == attr2->length) { if(memcmp(attr1->data, attr2->data, attr1->length) == 0) { brtn = true; } } errOut: SecKeychainItemFreeAttributesAndData(attrList, NULL); #endif return brtn; }
OSStatus findCertificatePublicKeyHash(SecCertificateRef certificate, CFDataRef *label) { UInt32 tag[1] = { kSecPublicKeyHashItemAttr }; // kSecKeyLabel == hash public key [kSecPublicKeyHashItemAttr ??kSecKeyLabel] UInt32 format[1] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB }; SecKeychainAttributeInfo info = { 1, tag, format }; // attrs to retrieve SecKeychainAttributeList *attrList = NULL; OSStatus status = SecKeychainItemCopyAttributesAndData(SecKeychainItemRef(certificate), &info, NULL, &attrList, 0, NULL); if (status || !attrList || !attrList->count) return status; const uint32_t index = 0; if (attrList->attr[index].tag == kSecPublicKeyHashItemAttr) *label = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)attrList->attr[index].data, attrList->attr[index].length); SecKeychainItemFreeAttributesAndData(attrList, NULL); return noErr; }
static int getAttribute(SecKeychainItemRef itemRef, SecItemAttr item, SecKeychainAttributeList **attrs) { SecKeychainAttributeInfo attrInfo; uint32 attrFormat = 0; OSStatus ret; *attrs = NULL; attrInfo.count = 1; attrInfo.tag = &item; attrInfo.format = &attrFormat; ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, attrs, NULL, NULL); if (ret) return EINVAL; return 0; }
void genKeychainItem(const SecKeychainItemRef& item, QueryData& results) { Row r; // Create an info structure with 1 tag, then iterate over setting the tag // type to assure maximum compatibility with the various Keychain items. SecKeychainAttributeInfo info; UInt32 tags[1]; info.count = sizeof(tags) / sizeof(UInt32); info.tag = tags; info.format = nullptr; SecItemClass item_class = 0; SecKeychainAttributeList* attr_list = nullptr; // Any tag that does not exist for the item will prevent the entire result. for (const auto& attr_tag : kKeychainItemAttrs) { tags[0] = attr_tag.first; SecKeychainItemCopyAttributesAndData( item, &info, &item_class, &attr_list, 0, nullptr); if (attr_list != nullptr) { // Expect each specific tag to return string data. for (int i = 0; i < attr_list->count; ++i) { SecKeychainAttribute* attr = &attr_list->attr[i]; if (attr->length > 0) { r[attr_tag.second] = std::string((char*)attr->data, attr->length); } } SecKeychainItemFreeAttributesAndData(attr_list, nullptr); attr_list = nullptr; } } // The keychain item class is obtained each time and will be consistent. if (kKeychainItemClasses.count(item_class) > 0) { r["type"] = kKeychainItemClasses.at(item_class); } r["path"] = getKeychainPath(item); results.push_back(r); }
static VALUE rb_keychain_item_copy_password(VALUE self){ void *data; SecKeychainItemRef keychainItem=NULL; UInt32 dataLength; Data_Get_Struct(self, struct OpaqueSecKeychainItemRef, keychainItem); VALUE unsaved = rb_ivar_get(self, rb_intern("unsaved_password")); if(!NIL_P(unsaved)){ return unsaved; } else{ OSStatus result = SecKeychainItemCopyAttributesAndData(keychainItem, NULL , NULL, NULL, &dataLength, &data); CheckOSStatusOrRaise(result); VALUE rb_data = rb_enc_str_new(data, dataLength, rb_ascii8bit_encoding()); SecKeychainItemFreeAttributesAndData(NULL,data); return rb_data; } }
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; }
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; }
void P12Coder::addSecCert( SecCertificateRef certRef) { /* get the cert's attrs and data */ /* I don't know what the format field is for */ SecKeychainAttributeInfo attrInfo; attrInfo.count = 2; UInt32 tags[2] = {kSecLabelItemAttr, kSecPublicKeyHashItemAttr}; attrInfo.tag = tags; attrInfo.format = NULL; // ??? /* FIXME header says this is an IN/OUT param, but it's not */ SecKeychainAttributeList *attrList = NULL; UInt32 certLen; void *certData; OSStatus ortn = SecKeychainItemCopyAttributesAndData( (SecKeychainItemRef)certRef, &attrInfo, NULL, // itemClass &attrList, &certLen, &certData); if(ortn) { p12ErrorLog("addSecCert: SecKeychainItemCopyAttributesAndData " "error\n"); MacOSError::throwMe(ortn); } /* Snag the attrs, convert to something useful */ CFStringRef friendName = NULL; CFDataRef localKeyId = NULL; for(unsigned i=0; i<attrList->count; i++) { SecKeychainAttribute *attr = &attrList->attr[i]; switch(attr->tag) { case kSecPublicKeyHashItemAttr: localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length); break; case kSecLabelItemAttr: /* FIXME: always in UTF8? */ friendName = CFStringCreateWithBytes(NULL, (UInt8 *)attr->data, attr->length, kCFStringEncodingUTF8, false); break; default: p12ErrorLog("addSecCert: unexpected attr tag\n"); MacOSError::throwMe(errSecParam); } } /* Cook up a cert bag and save it */ CSSM_DATA cData = {certLen, (uint8 *)certData}; P12CertBag *certBag = new P12CertBag(CT_X509, cData, friendName, localKeyId, NULL, mCoder); addCert(certBag); SecKeychainItemFreeAttributesAndData(attrList, certData); if(friendName) { CFRelease(friendName); } if(localKeyId) { CFRelease(localKeyId); } }
void P12Coder::addSecKey( SecKeyRef keyRef) { /* get the cert's attrs (not data) */ /* * Convert the attr name strings we happen to know about to * unknowable name-as-int values. */ UInt32 printNameTag; OSStatus ortn = attrNameToInt(P12_KEY_ATTR_PRINT_NAME, &printNameTag); if(ortn) { p12ErrorLog("addSecKey: problem looking up key attr name\n"); MacOSError::throwMe(ortn); } UInt32 labelHashTag; ortn = attrNameToInt(P12_KEY_ATTR_LABEL_AND_HASH, &labelHashTag); if(ortn) { p12ErrorLog("addSecKey: problem looking up key attr name\n"); MacOSError::throwMe(ortn); } UInt32 tags[2]; tags[0] = printNameTag; tags[1] = labelHashTag; /* I don't know what the format field is for */ SecKeychainAttributeInfo attrInfo; attrInfo.count = 2; attrInfo.tag = tags; attrInfo.format = NULL; // ??? /* FIXME header says this is an IN/OUT param, but it's not */ SecKeychainAttributeList *attrList = NULL; ortn = SecKeychainItemCopyAttributesAndData( (SecKeychainItemRef)keyRef, &attrInfo, NULL, // itemClass &attrList, NULL, // don't need the data NULL); if(ortn) { p12ErrorLog("addSecKey: SecKeychainItemCopyAttributesAndData " "error\n"); MacOSError::throwMe(ortn); } /* Snag the attrs, convert to something useful */ CFStringRef friendName = NULL; CFDataRef localKeyId = NULL; for(unsigned i=0; i<attrList->count; i++) { SecKeychainAttribute *attr = &attrList->attr[i]; if(attr->tag == printNameTag) { friendName = CFStringCreateWithBytes(NULL, (UInt8 *)attr->data, attr->length, kCFStringEncodingUTF8, false); } else if(attr->tag == labelHashTag) { localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length); } else { p12ErrorLog("addSecKey: unexpected attr tag\n"); MacOSError::throwMe(errSecParam); } } /* * Infer the CSP associated with this key. * FIXME: this should be an attribute of the SecKeyRef itself, * not inferred from the keychain it happens to be living on * (SecKeyRefs should not have to be attached to Keychains at * this point). */ SecKeychainRef kcRef; ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef); if(ortn) { p12ErrorLog("addSecKey: SecKeychainItemCopyKeychain returned %d\n", (int)ortn); MacOSError::throwMe(ortn); } CSSM_CSP_HANDLE cspHand; ortn = SecKeychainGetCSPHandle(kcRef, &cspHand); if(ortn) { p12ErrorLog("addSecKey: SecKeychainGetCSPHandle returned %d\n", (int)ortn); MacOSError::throwMe(ortn); } CFRelease(kcRef); /* and the CSSM_KEY itself */ const CSSM_KEY *cssmKey; ortn = SecKeyGetCSSMKey(keyRef, &cssmKey); if(ortn) { p12ErrorLog("addSecKey: SecKeyGetCSSMKey returned %d\n", (int)ortn); MacOSError::throwMe(ortn); } /* Cook up a key bag and save it */ P12KeyBag *keyBag = new P12KeyBag(cssmKey, cspHand, friendName, localKeyId, NULL, // other attrs mCoder, keyRef); addKey(keyBag); SecKeychainItemFreeAttributesAndData(attrList, NULL); if(friendName) { CFRelease(friendName); } if(localKeyId) { CFRelease(localKeyId); } }
/* * Infer DescriptiveData (i.e., comment) from a SecKeyRef's PrintName * attribute. */ void impExpOpensshInferDescData( SecKeyRef keyRef, CssmOwnedData &descData) { OSStatus ortn; SecKeychainAttributeInfo attrInfo; SecKeychainAttrType attrType = kSecKeyPrintName; attrInfo.count = 1; attrInfo.tag = &attrType; attrInfo.format = NULL; SecKeychainAttributeList *attrList = NULL; ortn = SecKeychainItemCopyAttributesAndData( (SecKeychainItemRef)keyRef, &attrInfo, NULL, // itemClass &attrList, NULL, // don't need the data NULL); if(ortn) { SecSSHDbg("SecKeychainItemCopyAttributesAndData returned %ld", (unsigned long)ortn); return; } /* subsequent errors to errOut: */ SecKeychainAttribute *attr = attrList->attr; /* * On a previous import, we would have set this to something like * "OpenSSHv2 Public Key: comment". * We want to strip off everything up to the actual comment. */ unsigned toStrip = 0; /* min length of attribute value for this code to be meaningful */ unsigned len = strlen(SSHv2_PUB_KEY_NAME) + 1; char *printNameStr = NULL; if(len < attr->length) { printNameStr = (char *)malloc(attr->length + 1); memmove(printNameStr, attr->data, attr->length); printNameStr[attr->length] = '\0'; if(strstr(printNameStr, SSHv2_PUB_KEY_NAME) == printNameStr) { toStrip = strlen(SSHv2_PUB_KEY_NAME); } else if(strstr(printNameStr, SSHv1_PUB_KEY_NAME) == printNameStr) { toStrip = strlen(SSHv1_PUB_KEY_NAME); } else if(strstr(printNameStr, SSHv1_PRIV_KEY_NAME) == printNameStr) { toStrip = strlen(SSHv1_PRIV_KEY_NAME); } if(toStrip) { /* only strip if we have ": " after toStrip bytes */ if((printNameStr[toStrip] == ':') && (printNameStr[toStrip+1] == ' ')) { toStrip += 2; } } } if(printNameStr) { free(printNameStr); } len = attr->length; unsigned char *attrVal; if(len < toStrip) { SecSSHDbg("impExpOpensshInferDescData: string parse screwup"); goto errOut; } if(len > toStrip) { /* Normal case of stripping off leading header */ len -= toStrip; } else { /* * If equal, then the attr value *is* "OpenSSHv2 Public Key: " with * no comment. Not sure how that could happen, but let's be careful. */ toStrip = 0; } attrVal = ((unsigned char *)attr->data) + toStrip; descData.copy(attrVal, len); errOut: SecKeychainItemFreeAttributesAndData(attrList, NULL); return; }