【问题标题】:How do I kill the popup?我如何杀死弹出窗口?
【发布时间】:2016-10-03 22:44:24
【问题描述】:

如果您编辑以下代码以获得有效的证书路径和需要客户端证书的 url,然后在 OS X 上使用 clang++ -lcurl curl.cpp 编译它(我使用的是 El Cap,但我认为 Mavericks 或更高版本的行为方式相同),然后运行可执行文件,您会从 OS X 收到一个弹出窗口(如下所示),询问您是否要允许可执行文件在您的钥匙串中使用私钥。这对于知道发生了什么的用户来说很烦人(OS X 上的内部 curl 使用 OS X 安全框架来加载客户端证书),但对于不知道发生了什么的用户来说却是可怕的,因为他们认为程序正在尝试访问他们钥匙串中的私钥(顺便说一句,这是 Apple 糟糕的用户体验的一个例子,因为弹出消息是一个完整的红鲱鱼)。

curl 命令行工具不会产生弹出窗口,因此要么我可以使用较低级别的 API,要么是因为可执行文件已签名。我尝试添加此功能的实际程序通常作为源代码分发,因此对可执行文件进行签名不是一种理想的方法,因为我无法分发签名密钥,否则它们将被撤销。有谁知道我如何以编程方式防止弹出窗口?

#include <curl/curl.h>
#include <string>

using namespace std;

static size_t receiveResponseBytes(void *buffer, size_t size, size_t nmemb, void *userData) {
  string *responseData = (string *) userData;
  responseData->append((const char *) buffer, size * nmemb);
  return size * nmemb;
}

void prepareCurlPOST(CURL *curl, string &bodyJsonString, string *responseData, struct curl_slist **chunk) {
  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
  curl_easy_setopt(curl, CURLOPT_URL, "https://example.dev/v1/check.json");
  curl_easy_setopt(curl, CURLOPT_HTTPGET, 0);
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bodyJsonString.c_str());
  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, bodyJsonString.length());
  *chunk = curl_slist_append(NULL, "Content-Type: application/json");
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *chunk);
  curl_easy_setopt(curl, CURLOPT_SSLCERT, "/path/to/client_cert.p12");
  curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "P12");
  curl_easy_setopt(curl, CURLOPT_SSLCERTPASSWD, "1234");
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveResponseBytes);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, responseData);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
  curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/ca.crt");
}

int main(){
  CURL* curl = curl_easy_init();
  struct curl_slist *chunk = NULL;
  string responseData;
  long responseCode;
  string bodyJsonString = "{\"version\": 1}";
  prepareCurlPOST(curl, bodyJsonString, &responseData, &chunk);
  fprintf(stderr,"%s\n",curl_easy_strerror(curl_easy_perform(curl)));
  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
  if (responseCode != 200) {
    fprintf(stderr, "HTTP %d %s\n", (int) responseCode, responseData.c_str());
  }
  curl_slist_free_all(chunk);
  curl_easy_cleanup(curl);
}

【问题讨论】:

    标签: c++ macos libcurl


    【解决方案1】:

    这就是我解决这个问题的方法(感谢 Phusion 的人让我对此进行修改):

    #include <curl/curl.h>
    #include <string>
    
    #include <CoreFoundation/CoreFoundation.h>
    #include <Security/Security.h>
    
    using namespace std;
    
    const char* cert_label = "Name of the certificate as it appears in keychain access";
    const char* domain = "https://example.dev/v1/check.json";
    const char* ca_path = "/path/to/ca.crt";
    const char* cert_path = "/path/to/client_cert.p12";
    const char* cert_pw = "1234";
    
    static OSStatus LookupKeychainItem(const char *label,
                                       SecIdentityRef *out_cert_and_key)
    {
      OSStatus status = errSecItemNotFound;
    
      if(kSecClassIdentity != NULL) {
        CFTypeRef keys[4];
        CFTypeRef values[4];
        CFDictionaryRef query_dict;
        CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
                                                         kCFStringEncodingUTF8);
    
        /* Set up our search criteria and expected results: */
        values[0] = kSecClassIdentity; /* we want a certificate and a key */
        keys[0] = kSecClass;
        values[1] = kCFBooleanTrue;    /* we need a reference */
        keys[1] = kSecReturnRef;
        values[2] = kSecMatchLimitOne; /* one is enough, thanks */
        keys[2] = kSecMatchLimit;
        /* identity searches need a SecPolicyRef in order to work */
        values[3] = SecPolicyCreateSSL(false, label_cf);
        keys[3] = kSecMatchPolicy;
        query_dict = CFDictionaryCreate(NULL, (const void **)keys,
                                        (const void **)values, 4L,
                                        &kCFCopyStringDictionaryKeyCallBacks,
                                        &kCFTypeDictionaryValueCallBacks);
        CFRelease(values[3]);
        CFRelease(label_cf);
    
        /* Do we have a match? */
        status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key);
        CFRelease(query_dict);
      }
    
      return status;
    }
    
    SecAccessRef createAccess()
    {
      SecAccessRef access=NULL;
      if (SecAccessCreate(CFStringCreateWithCString(NULL, cert_label, kCFStringEncodingUTF8), NULL, &access)){
        printf("SecAccessCreate failed\n");
        return NULL;
      }
      return access;
    }
    
    static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
                                               const char *cPassword,
                                               SecIdentityRef *out_cert_and_key)
    {
      OSStatus status = errSecItemNotFound;
      CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL,
                                                                  (const UInt8 *)cPath, strlen(cPath), false);
      CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
                                                                   cPassword, kCFStringEncodingUTF8) : NULL;
      CFDataRef pkcs_data = NULL;
    
      if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
                                                  NULL, NULL, &status)) {
        SecAccessRef access = createAccess();
        const void *cKeys[] = {kSecImportExportPassphrase,kSecImportExportAccess};
        //kSecTrustSettingsKeyUseAny
        const void *cValues[] = {password,access};
        CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
                                                     2L, NULL, NULL);
        CFArrayRef items = NULL;
    
        /* Here we go: */
        status = SecPKCS12Import(pkcs_data, options, &items);
    
        if(items)
          CFRelease(items);
        CFRelease(options);
        CFRelease(pkcs_data);
      }
    
      if(password)
        CFRelease(password);
      CFRelease(pkcs_url);
      return status;
    }
    
    static size_t receiveResponseBytes(void *buffer, size_t size, size_t nmemb, void *userData) {
      string *responseData = (string *) userData;
      responseData->append((const char *) buffer, size * nmemb);
      return size * nmemb;
    }
    
    void prepareCurlPOST(CURL *curl, string &bodyJsonString, string *responseData, struct curl_slist **chunk) {
      curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
      curl_easy_setopt(curl, CURLOPT_URL, domain);
      curl_easy_setopt(curl, CURLOPT_HTTPGET, 0);
      curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bodyJsonString.c_str());
      curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, bodyJsonString.length());
      *chunk = curl_slist_append(NULL, "Content-Type: application/json");
      curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *chunk);
      curl_easy_setopt(curl, CURLOPT_SSLCERT, cert_label);
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveResponseBytes);
      curl_easy_setopt(curl, CURLOPT_WRITEDATA, responseData);
      curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
      curl_easy_setopt(curl, CURLOPT_CAINFO, ca_path);
    }
    
    void killKey(){
        SecIdentityRef id = NULL;
        if (LookupKeychainItem(cert_label,&id) != errSecItemNotFound){
    
            CFArrayRef itemList = CFArrayCreate(NULL, (const void **)&id, 1, NULL);
            const void *keys2[]   = { kSecClass,  kSecMatchItemList,  kSecMatchLimit };
            const void *values2[] = { kSecClassIdentity, itemList, kSecMatchLimitAll };
    
            CFDictionaryRef dict = CFDictionaryCreate(NULL, keys2, values2, 3, NULL, NULL);
            OSStatus oserr = SecItemDelete(dict);
            if (oserr) {
                CFStringRef str = SecCopyErrorMessageString(oserr, NULL);
                printf("Removing Passenger Cert from keychain failed: %s Please remove the private key from the certificate labeled %s in your keychain.", CFStringGetCStringPtr(str,kCFStringEncodingUTF8), cert_label);
                CFRelease(str);
            }
            CFRelease(dict);
            CFRelease(itemList);
    
        }
    }
    
    void preAuthKey(){
      SecIdentityRef id = NULL;
      if(LookupKeychainItem(cert_label,&id) == errSecItemNotFound){
        OSStatus status = SecKeychainSetUserInteractionAllowed(false);
        if(status != errSecSuccess){
          printf("%s\n",CFStringGetCStringPtr(SecCopyErrorMessageString(status,NULL),kCFStringEncodingUTF8));
        }
        CopyIdentityFromPKCS12File("/path/to/client_cert.p12","1234",&id);
        status = SecKeychainSetUserInteractionAllowed(true);
        if(status != errSecSuccess){
          printf("%s\n",CFStringGetCStringPtr(SecCopyErrorMessageString(status,NULL),kCFStringEncodingUTF8));
        }
      }
    }
    
    int main(){
      preAuthKey();
      CURL* curl = curl_easy_init();
      struct curl_slist *chunk = NULL;
      string responseData;
      long responseCode;
      string bodyJsonString = "{\"version\": 1}";
      prepareCurlPOST(curl, bodyJsonString, &responseData, &chunk);
      fprintf(stderr,"%s\n",curl_easy_strerror(curl_easy_perform(curl)));
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
      if (responseCode != 200) {
        fprintf(stderr, "HTTP %d %s\n", (int) responseCode, responseData.c_str());
      }
      curl_slist_free_all(chunk);
      curl_easy_cleanup(curl);
      killKey();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-03
      • 1970-01-01
      • 1970-01-01
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多