【问题标题】:EXC_BAD_ACCESS While trying to access OS X KeychainEXC_BAD_ACCESS 尝试访问 OS X 钥匙串时
【发布时间】:2020-03-16 20:31:47
【问题描述】:

我编写了一个示例代码(之前收到了help)来从 OS X 钥匙串中添加和检索密码。我能够成功添加密码,但是当我尝试检索它时,我得到一个 EXC_BAD_ACCESS(代码=EXC_I386_GPFLT)。我尝试了两种方法:

  1. 使用 SecItemCopyMatching API,该 API 使用基于查询的方法来访问钥匙串。
  2. 使用 SecKeychainFindGenericPassword。

BAD ACCESS 错误只发生在第一种方法中,第二种方法成功。我正在尝试使用第一种方法,以便确保在完成后使用 SecKeychainItemFreeContent 进行清理。

注意 - 这是一个示例代码,因此我没有对返回值进行任何检查。虽然我一直在调试器中密切关注它们,但没有发现任何错误。

#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>

int main(int argc, const char * argv[])
{
    char acc_name[20];
    char password[20];
    CFStringRef keys[3];

    printf("Enter account name - ");
    scanf("%s", acc_name);

    printf("\nEnter password - ");
    scanf("%s", password);

    keys[0] = kSecClass;
    keys[1] = kSecAttrAccount;
    keys[2] = kSecValueData;

    CFTypeRef values[3];
    values[0] = kSecClassGenericPassword;
    values[1] = CFStringCreateWithCString(kCFAllocatorDefault, acc_name, kCFStringEncodingUTF8);
    values[2] = CFStringCreateWithCString(kCFAllocatorDefault, password, kCFStringEncodingUTF8);

    CFDictionaryRef query;
    query = CFDictionaryCreate(kCFAllocatorDefault, (const void**) keys, (const void**) values, 3, NULL, NULL);

    OSStatus result = SecItemAdd(query, NULL);

    printf("%d\n", result);

    printf("Retrieve\n");

    SecKeychainItemRef pitem = NULL;
    SecKeychainItemRef kch_ref = NULL;
    CFStringRef qkeys[6];
    qkeys[0] = kSecClass;
    qkeys[1] = kSecAttrAccount;
    qkeys[2] = kSecMatchLimit;
    qkeys[3] = kSecReturnAttributes;
    qkeys[4] = kSecReturnData;
    qkeys[5] = kSecReturnRef;

    CFTypeRef qvalues[6];
    qvalues[0] = kSecClassGenericPassword;
    qvalues[1] = CFStringCreateWithCString(kCFAllocatorDefault, acc_name, kCFStringEncodingUTF8);
    qvalues[2] = kSecMatchLimitOne;
    qvalues[3] = kCFBooleanTrue;
    qvalues[4] = kCFBooleanTrue;
    qvalues[5] = kCFBooleanTrue;

    unsigned int plength = 0;
    char *pdata = NULL;

    unsigned int plength2 = 0;
    void *pdata2 = NULL;

    CFDictionaryRef extract_query = CFDictionaryCreate(kCFAllocatorDefault, (const void **)qkeys, (const void **)qvalues, 6, NULL, NULL);
    result = SecItemCopyMatching(extract_query, (CFTypeRef *)&kch_ref);
    SecKeychainItemCopyAttributesAndData(kch_ref, NULL, NULL, NULL, &plength2, &pdata2); // <-- EXC_BAD_ACCESS (code=EXC_I386_GPFLT) 

    //result = SecKeychainFindGenericPassword(NULL, 0, NULL, (uint32)strlen(acc_name), acc_name, &plength, (void **)&pdata, &pitem);
    if (result)
    {
        //return error;
    }

    printf("password - %s\n", pdata);

    return 0;
}

【问题讨论】:

    标签: c xcode macos security keychain


    【解决方案1】:

    您似乎向SecKeychainItemCopyAttributesAndData 传递了错误的参数。

    在查询字典中,您指定三种不同的返回类型:kSecReturnAttributeskSecReturnDatakSecReturnRefSecItemCopyMatching 的文档是这样说的:

    使用在项目返回结果键中找到的键来指示您是查找项目的属性、项目的数据、对数据的引用、对数据的持久引用,还是这些的组合。当您指定多个返回类型时,搜索将返回包含您请求的每种类型的字典。当您的搜索允许多个结果时,它们都会在一个项目数组中一起返回。

    因此,SecItemCopyMatching 返回的类型(因为您限制为一个结果)将是 CFDictionary,其中包含项目数据、项目属性和对项目的引用。

    然后你将它传递给SecKeychainItemCopyAttributesAndData,但是第一个参数的文档说:

    itemRef

    对您希望从中检索数据或属性的钥匙串项的引用。

    如果您修改查询字典以仅包含 kSecReturnRef 返回类型(删除 kSecReturnAttributeskSecReturnData),您的代码将正常工作。

    (或者,从 SecItemCopyMatching 返回的字典中提取引用并将 that 传递给 SecKeychainItemCopyAttributesAndData

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-21
      • 2014-08-25
      • 2018-05-14
      • 1970-01-01
      • 2020-06-20
      • 1970-01-01
      • 2014-08-12
      • 1970-01-01
      相关资源
      最近更新 更多