2016-09-20 12 views
1

有効な証明書パスとクライアント証明書が必要なURLを持つように編集し、OS Xでclang++ -lcurl curl.cpp(私はEl Capを使用していますが、Mavericks以降は同じように動作すると思います)でコンパイルすると実行可能ファイルを実行すると、実行可能ファイルがキーチェーン内の秘密鍵を使用できるようにするかどうかを尋ねるOS Xからのポップアップ(下記)が表示されます。これは、何が起こっているのかを知っているユーザにとっては迷惑なことです(OS Xの内部的なカールはOS Xのセキュリティフレームワークを使用してクライアント証明書を読み込みます)が、プログラムがアクセスしようとしていると思われるために何が起こっているのかわからないキーチェーン内の秘密鍵(これは、ポップアップメッセージが完全なレッドニシンなので、これはAppleの恐ろしいUXの例です)。ポップアップを削除するにはどうすればよいですか?

curlコマンドラインツールではポップアップが生成されないため、使用できる低レベルのAPIがあるか、実行可能ファイルが署名されているためです。この機能を追加しようとしている実際のプログラムはソースコードとして配布されることが多いので、署名鍵を配布できないか、取り消されるため、実行可能ファイルに署名するのは理想的な方法ではありません。誰も私はどのようにプログラムでポップアップを防ぐことができます知っていますか?

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

答えて

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(); 
} 
関連する問題