Hello, I've an application which need use a PKCS12 client side certificate from memory buffer. Unfortunately, there is no natural way to do it with libcurl.
Below, I show my method with 1) DarwinSSL (the Apple system SSL library for iOS and MacOSX) : I had to modify curl/lib/vtls/darwinssl.c source, and I put a string containing the certificate with "base64:" prefix in CURLOPT_SSLCERT parameter 2) OpenSSL : I don't need modify curl source, using an OpenSSL specific callback My suggestion : giving a way to use a certificate from memory buffer in the different SSL layer. I think "base64:*" as filename, like my darwinssl patch is the more easy way. (If we do that, it can be also useful to create a Curl_base64_encode function without struct Curl_easy * parameter) Here are my modification against darwinssl from libcurl 7.50.[0/1] (I also put on http://gvollant.free.fr/darwinssl_mod_75.c ) *** W:\patchclient\src\PatchClient\curl\lib\vtls\darwinssl.c Wed Aug 03 11:03:15 2016 --- W:\patchclient\src\PatchClient\darwinssl_mod_75.c Thu Jul 21 11:55:27 2016 *************** *** 935,942 **** 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; --- 935,941 ---- SecIdentityRef *out_cert_and_key) { OSStatus status = errSecItemNotFound; ! CFURLRef pkcs_url = NULL; CFStringRef password = cPassword ? CFStringCreateWithCString(NULL, cPassword, kCFStringEncodingUTF8) : NULL; CFDataRef pkcs_data = NULL; *************** *** 945,952 **** /* These constants are documented as having first appeared in 10.6 but they raise linker errors when used on that cat for some reason. */ #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS ! if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data, ! NULL, NULL, &status)) { const void *cKeys[] = {kSecImportExportPassphrase}; const void *cValues[] = {password}; CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues, --- 944,979 ---- /* These constants are documented as having first appeared in 10.6 but they raise linker errors when used on that cat for some reason. */ #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS ! ! Boolean isBase64 = false; ! Boolean resource_imported; ! ! isBase64 = ((cPath!=NULL) && (strlen(cPath)>7) && (memcmp(cPath,"base64:",7)==0)); ! if (isBase64) ! { ! ! char *outptr=NULL; ! size_t outlen=0; ! if (Curl_base64_decode(cPath+7,&outptr,&outlen) == CURLE_OK) ! { ! pkcs_data=CFDataCreate( ! kCFAllocatorDefault, ! (const unsigned char *)outptr, ! outlen); ! status=errSecSuccess; ! resource_imported=true; ! free(outptr); ! } ! } ! else ! { ! pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL, ! (const UInt8 *)cPath, strlen(cPath), false); ! resource_imported = CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data, ! NULL, NULL, &status); ! } ! ! if(resource_imported) { const void *cKeys[] = {kSecImportExportPassphrase}; const void *cValues[] = {password}; CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues, *************** *** 973,979 **** #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ if(password) CFRelease(password); ! CFRelease(pkcs_url); return status; } --- 1000,1007 ---- #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ if(password) CFRelease(password); ! if (pkcs_url!=NULL) ! CFRelease(pkcs_url); return status; } *************** *** 990,995 **** --- 1018,1027 ---- if(filename == NULL) return false; + + if(strlen(filename)>7) + if (memcmp(filename,"base64:",7)==0) + return true; if(stat(filename, &st) == 0) return S_ISREG(st.st_mode); For using it, I put in char* base64Certif a string with "base64:" prefix then the certificate encoded as base64 curl_easy_setopt(curl_handle, CURLOPT_SSLCERTTYPE, "P12"); curl_easy_setopt(curl_handle, CURLOPT_SSLKEYPASSWD, certificatePassword); curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, base64Certif); For openssl, in the main function which uses libcurl, with certificate binary data in memory (pointer certificateData, size certificateSize, handle curl_handle) CertColl certColl; certColl.pkey=NULL; certColl.cert=NULL; certColl.ca = NULL; certColl.p12=NULL; BIO*bp=BIO_new_mem_buf((void*)certificateData,(int)certificateSize); certColl.p12 = d2i_PKCS12_bio(bp,NULL); BIO_free(bp); curl_easy_setopt(curl_handle,CURLOPT_SSL_CTX_FUNCTION, *sslctx_p12_function); curl_easy_setopt(curl_handle,CURLOPT_SSL_CTX_DATA,&certColl); And, I defined before in the source file typedef struct { EVP_PKEY *pkey ; X509 *cert ; STACK_OF(X509) *ca ; PKCS12 *p12; } CertColl; static CURLcode sslctx_p12_function(CURL * curl, void * sslctx, void * parm) { CertColl *certColl=(CertColl *)parm; SSL_CTX* ctx=(SSL_CTX*)sslctx; /* get a pointer to the X509 certificate store (which may be empty!) */ if(SSL_CTX_use_certificate(ctx, certColl->cert) != 1) { return CURLE_FAILED_INIT; } if(SSL_CTX_use_PrivateKey(ctx, certColl->pkey) != 1) { return CURLE_FAILED_INIT; } /* all set to go */ return CURLE_OK ; } ------------------------------------------------------------------- List admin: https://cool.haxx.se/list/listinfo/curl-library Etiquette: https://curl.haxx.se/mail/etiquette.html
