2016-09-20 2 views
1

Wenn Sie den folgenden Code bearbeiten, um gültige Zertifikatpfade und eine URL zu haben, die Clientzertifikate erfordert und kompilieren Sie sie dann mit clang++ -lcurl curl.cpp auf OS X (ich benutze El Cap, aber ich denke Mavericks oder später verhalten sich genauso) und Wenn Sie die ausführbare Datei ausführen, erhalten Sie ein Popup (siehe unten) von OS X mit der Frage, ob Sie der ausführbaren Datei erlauben möchten, einen privaten Schlüssel in Ihrem Schlüsselbund zu verwenden. Dies ist ärgerlich für Benutzer, die wissen, was vor sich geht (intern unter OS X benutzt das OS X Sicherheitsframework, um das Client-Zertifikat zu laden), aber es ist erschreckend für Benutzer, die nicht wissen, was passiert, weil sie glauben, dass das Programm versucht, darauf zuzugreifen ein privater Schlüssel in ihrem Schlüsselbund (nebenbei ist dies ein Beispiel für schreckliche UX von Apple, da die Popup-Nachricht ein kompletter Ablenkungsmanöver ist).Wie kann ich das Popup beenden?

Das Befehlszeilenprogramm curl erzeugt kein Popup, also gibt es entweder eine niedrigere API, die ich verwenden könnte, oder die ausführbare Datei ist signiert. Das eigentliche Programm, dem ich diese Funktion hinzufügen möchte, wird oft als Quellcode verteilt. Daher ist das Signieren der ausführbaren Datei kein idealer Ansatz, da ich die Signaturschlüssel nicht verteilen kann oder sie widerrufen werden. Weiß jemand wie ich das Popup programmatisch verhindern kann?

Popup with warning text: a wants to sign using key "privateKey" in your keychain. The authenticity of "a" cannot be verified. Do you want to allow access to this item? and buttons for Allow, Deny, and Always Allow

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

Antwort

1

Dies ist, wie ich dieses Problem (dank der Phusion Leute, dass Sie mich auf diese bastel) gelöst:

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