curl-library
Using PKCS12 certificate from memory
Date: Fri, 5 Aug 2016 10:32:41 +0200
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
Received on 2016-08-05