简体   繁体   English

我如何杀死弹出窗口?

[英]How do I kill the popup?

If you edit the following code to have valid certificate paths and a url that requires client certificates and then compile it with clang++ -lcurl curl.cpp on OS X (I'm using El Cap, but I think Mavericks or later behave the same way), and run the executable, you get a popup (shown below) from OS X asking if you want to allow the executable to use a private key in your keychain.如果您编辑以下代码以获得有效的证书路径和需要客户端证书的 url,然后在 OS X 上使用clang++ -lcurl curl.cpp编译它(我使用的是 El Cap,但我认为 Mavericks 或更高版本的行为方式相同),然后运行该可执行文件,您会从 OS X 收到一个弹出窗口(如下所示),询问您是否要允许该可执行文件在您的钥匙串中使用私钥。 This is annoying to users that know what's going on (internally curl on OS X uses the OS X security framework to load the client cert) but it's frightening for users who don't know what's happening because they think that the program is trying to access a private key in their keychain (as an aside this is an example of terrible UX from Apple as the popup message is a complete red herring).这对于知道发生了什么的用户来说很烦人(OS X 上的内部 curl 使用 OS X 安全框架来加载客户端证书),但对于不知道发生了什么的用户来说是可怕的,因为他们认为该程序正在尝试访问他们钥匙串中的私钥(顺便说一句,这是Apple糟糕的用户体验的一个例子,因为弹出消息是一个完整的红鲱鱼)。

The curl command line tool doesn't produce a popup, so either there is a lower level API I could use or it's because the executable is signed. curl 命令行工具不会产生弹出窗口,所以要么有我可以使用的较低级别的 API,要么是因为可执行文件已签名。 The real program I'm trying to add this feature to is often distributed as source code so signing the executable isn't an ideal approach, as I can't distribute the signing keys or they'll be revoked.我尝试添加此功能的真实程序通常作为源代码分发,因此对可执行文件进行签名并不是一种理想的方法,因为我无法分发签名密钥,否则它们将被撤销。 Does anyone know how I can prevent the popup programmatically?有谁知道我如何以编程方式防止弹出窗口?

带有警告文本的弹出窗口:a 想要使用钥匙串中的密钥“privateKey”进行签名。 “a”的真实性无法验证。您要允许访问此项目吗?以及允许、拒绝和始终允许的按钮

#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);
}

This is how I solved this problem (thanks to the Phusion folks for letting me tinker on this):这就是我解决这个问题的方法(感谢 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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM