mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 23:58:49 -05:00
Add CURLOPT_CAINFO_PEM
This commit is contained in:
parent
4506607b44
commit
397e11bfa6
@ -702,6 +702,8 @@ set(CURL_CA_FALLBACK OFF CACHE BOOL
|
|||||||
"Set ON to use built-in CA store of TLS backend. Defaults to OFF")
|
"Set ON to use built-in CA store of TLS backend. Defaults to OFF")
|
||||||
set(CURL_CA_PATH "auto" CACHE STRING
|
set(CURL_CA_PATH "auto" CACHE STRING
|
||||||
"Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
|
"Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
|
||||||
|
set(CURL_CA_BUNDLE_PEM OFF CACHE BOOL
|
||||||
|
"Set ON to use built-in CACERT_PEM from generated cacert.h. Defaults to OFF")
|
||||||
|
|
||||||
if("${CURL_CA_BUNDLE}" STREQUAL "")
|
if("${CURL_CA_BUNDLE}" STREQUAL "")
|
||||||
message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.")
|
message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.")
|
||||||
|
18
acinclude.m4
18
acinclude.m4
@ -2306,6 +2306,24 @@ AC_HELP_STRING([--without-ca-fallback], [Don't use the built in CA store of the
|
|||||||
fi
|
fi
|
||||||
AC_DEFINE_UNQUOTED(CURL_CA_FALLBACK, 1, [define "1" to use built in CA store of SSL library ])
|
AC_DEFINE_UNQUOTED(CURL_CA_FALLBACK, 1, [define "1" to use built in CA store of SSL library ])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether to use built in CACERT_PEM from generated cacert.h])
|
||||||
|
AC_ARG_WITH(ca-built-in,
|
||||||
|
AC_HELP_STRING([--with-ca-built-in], [Use the built in CACERT_PEM from generated cacert.h])
|
||||||
|
AC_HELP_STRING([--without-ca-built-in], [Don't use the built in CACERT_PEM from generated cacert.h]),
|
||||||
|
[
|
||||||
|
if test "x$with_ca_built_in" != "xyes" -a "x$with_ca_built_in" != "xno"; then
|
||||||
|
AC_MSG_ERROR([--with-ca-built-in only allows yes or no as parameter])
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[ with_ca_fallback="no"])
|
||||||
|
AC_MSG_RESULT([$with_ca_built_in])
|
||||||
|
if test "x$with_ca_built_in" = "xyes"; then
|
||||||
|
if test "x$OPENSSL_ENABLED" != "x1"; then
|
||||||
|
AC_MSG_ERROR([--with-ca-built-in only works with OpenSSL])
|
||||||
|
fi
|
||||||
|
AC_DEFINE_UNQUOTED(CURL_CA_BUNDLE_PEM, 1, [define "1" to use built in CACERT_PEM from generated cacert.h ])
|
||||||
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
dnl CURL_CHECK_WIN32_LARGEFILE
|
dnl CURL_CHECK_WIN32_LARGEFILE
|
||||||
|
@ -4982,6 +4982,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
|
|||||||
ca cert bundle: ${ca}${ca_warning}
|
ca cert bundle: ${ca}${ca_warning}
|
||||||
ca cert path: ${capath}${capath_warning}
|
ca cert path: ${capath}${capath_warning}
|
||||||
ca fallback: ${with_ca_fallback}
|
ca fallback: ${with_ca_fallback}
|
||||||
|
ca built in: ${with_ca_built_in}
|
||||||
LDAP: ${curl_ldap_msg}
|
LDAP: ${curl_ldap_msg}
|
||||||
LDAPS: ${curl_ldaps_msg}
|
LDAPS: ${curl_ldaps_msg}
|
||||||
RTSP: ${curl_rtsp_msg}
|
RTSP: ${curl_rtsp_msg}
|
||||||
|
@ -1954,6 +1954,14 @@ typedef enum {
|
|||||||
/* allow RCPT TO command to fail for some recipients */
|
/* allow RCPT TO command to fail for some recipients */
|
||||||
CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290),
|
CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290),
|
||||||
|
|
||||||
|
/* The CAfile in memory as PEM used to validate the proxy certificate
|
||||||
|
this option is used only if PROXY_SSL_VERIFYPEER is true */
|
||||||
|
CURLOPT(CURLOPT_CAINFO_PEM, CURLOPTTYPE_STRINGPOINT, 291),
|
||||||
|
|
||||||
|
/* The CAfile in memory as PEM used to validate the proxy certificate
|
||||||
|
this option is used only if PROXY_SSL_VERIFYPEER is true */
|
||||||
|
CURLOPT(CURLOPT_PROXY_CAINFO_PEM, CURLOPTTYPE_STRINGPOINT, 292),
|
||||||
|
|
||||||
CURLOPT_LASTENTRY /* the last unused */
|
CURLOPT_LASTENTRY /* the last unused */
|
||||||
} CURLoption;
|
} CURLoption;
|
||||||
|
|
||||||
|
38
lib/cacert.h
Normal file
38
lib/cacert.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
*
|
||||||
|
* This software is licensed as described in the file COPYING, which
|
||||||
|
* you should have received as part of this distribution. The terms
|
||||||
|
* are also available at https://curl.haxx.se/docs/copyright.html.
|
||||||
|
*
|
||||||
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||||
|
* copies of the Software, and permit persons to whom the Software is
|
||||||
|
* furnished to do so, under the terms of the COPYING file.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
regenerate this file like so:
|
||||||
|
|
||||||
|
curl -Oz cacert.pem https://curl.haxx.se/ca/cacert.pem \
|
||||||
|
&& xxd -i -C cacert.pem | sed -r 's/(0x..)$/\1, 0x00/' > lib/cacert.h
|
||||||
|
|
||||||
|
unless CACERT_PEM is defined in here, there will be a compile error if
|
||||||
|
CURL_CA_BUNDLE_PEM is defined, CACERT_PEM must be a proper null-terminated
|
||||||
|
C string
|
||||||
|
|
||||||
|
unsigned char CACERT_PEM[] = {
|
||||||
|
0x62, 0x6f, 0x62, 0x0a, 0x00
|
||||||
|
};
|
||||||
|
unsigned int CACERT_PEM_LEN = 4;
|
||||||
|
*/
|
15
lib/setopt.c
15
lib/setopt.c
@ -1944,6 +1944,21 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
result = CURLE_NOT_BUILT_IN;
|
result = CURLE_NOT_BUILT_IN;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case CURLOPT_CAINFO_PEM:
|
||||||
|
/*
|
||||||
|
* Set CA info for SSL connection. Specify entire PEM of the CA certificate
|
||||||
|
*/
|
||||||
|
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PEM_ORIG],
|
||||||
|
va_arg(param, char *));
|
||||||
|
break;
|
||||||
|
case CURLOPT_PROXY_CAINFO_PEM:
|
||||||
|
/*
|
||||||
|
* Set CA info for SSL connection proxy.
|
||||||
|
* Specify entire PEM of the CA certificate
|
||||||
|
*/
|
||||||
|
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PEM_PROXY],
|
||||||
|
va_arg(param, char *));
|
||||||
|
break;
|
||||||
case CURLOPT_CRLFILE:
|
case CURLOPT_CRLFILE:
|
||||||
/*
|
/*
|
||||||
* Set CRL file info for SSL connection. Specify file name of the CRL
|
* Set CRL file info for SSL connection. Specify file name of the CRL
|
||||||
|
20
lib/url.c
20
lib/url.c
@ -127,6 +127,10 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
|
|||||||
#include "curl_memory.h"
|
#include "curl_memory.h"
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
#if defined(CURL_CA_BUNDLE_PEM)
|
||||||
|
#include "cacert.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static void conn_free(struct connectdata *conn);
|
static void conn_free(struct connectdata *conn);
|
||||||
static unsigned int get_protocol_family(unsigned int protocol);
|
static unsigned int get_protocol_family(unsigned int protocol);
|
||||||
|
|
||||||
@ -507,6 +511,18 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
|
|||||||
set->socks5_gssapi_nec = FALSE;
|
set->socks5_gssapi_nec = FALSE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CURL_CA_BUNDLE_PEM)
|
||||||
|
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PEM_ORIG],
|
||||||
|
(const char *) CACERT_PEM);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PEM_PROXY],
|
||||||
|
(const char *) CACERT_PEM);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set the default CA cert bundle/path detected/specified at build time.
|
/* Set the default CA cert bundle/path detected/specified at build time.
|
||||||
*
|
*
|
||||||
* If Schannel is the selected SSL backend then these locations are
|
* If Schannel is the selected SSL backend then these locations are
|
||||||
@ -3555,6 +3571,10 @@ static CURLcode create_conn(struct Curl_easy *data,
|
|||||||
data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
|
data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
|
||||||
data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG];
|
data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG];
|
||||||
data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
|
data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
|
||||||
|
data->set.ssl.primary.ca_file_pem =
|
||||||
|
data->set.str[STRING_SSL_CAFILE_PEM_ORIG];
|
||||||
|
data->set.proxy_ssl.primary.ca_file_pem =
|
||||||
|
data->set.str[STRING_SSL_CAFILE_PEM_PROXY];
|
||||||
data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
|
data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
|
||||||
data->set.proxy_ssl.primary.random_file =
|
data->set.proxy_ssl.primary.random_file =
|
||||||
data->set.str[STRING_SSL_RANDOM_FILE];
|
data->set.str[STRING_SSL_RANDOM_FILE];
|
||||||
|
@ -230,6 +230,7 @@ struct ssl_primary_config {
|
|||||||
char *cipher_list; /* list of ciphers to use */
|
char *cipher_list; /* list of ciphers to use */
|
||||||
char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
|
char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
|
||||||
char *pinned_key;
|
char *pinned_key;
|
||||||
|
char *ca_file_pem;
|
||||||
BIT(verifypeer); /* set TRUE if this is desired */
|
BIT(verifypeer); /* set TRUE if this is desired */
|
||||||
BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
|
BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
|
||||||
BIT(verifystatus); /* set TRUE if certificate status must be checked */
|
BIT(verifystatus); /* set TRUE if certificate status must be checked */
|
||||||
@ -1529,6 +1530,8 @@ enum dupstring {
|
|||||||
STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */
|
STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */
|
||||||
STRING_SSL_CAFILE_ORIG, /* certificate file to verify peer against */
|
STRING_SSL_CAFILE_ORIG, /* certificate file to verify peer against */
|
||||||
STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
|
STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
|
||||||
|
STRING_SSL_CAFILE_PEM_ORIG, /* PEM certificate to verify peer against */
|
||||||
|
STRING_SSL_CAFILE_PEM_PROXY, /* PEM certificate to verify peer against */
|
||||||
STRING_SSL_PINNEDPUBLICKEY_ORIG, /* public key file to verify peer against */
|
STRING_SSL_PINNEDPUBLICKEY_ORIG, /* public key file to verify peer against */
|
||||||
STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
|
STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
|
||||||
STRING_SSL_CIPHER_LIST_ORIG, /* list of ciphers to use */
|
STRING_SSL_CIPHER_LIST_ORIG, /* list of ciphers to use */
|
||||||
|
@ -2385,6 +2385,61 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
|
||||||
|
const char * const ca_file_pem)
|
||||||
|
{
|
||||||
|
/* these need freed at the end */
|
||||||
|
BIO *cbio = NULL;
|
||||||
|
STACK_OF(X509_INFO) *inf = NULL;
|
||||||
|
|
||||||
|
/* everything else is just a reference */
|
||||||
|
int i, count = 0;
|
||||||
|
X509_STORE *cts = NULL;
|
||||||
|
X509_INFO *itmp = NULL;
|
||||||
|
|
||||||
|
CURLcode result = CURLE_SSL_CACERT_BADFILE;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* casting strlen to int feels wrong, but what to do with this API? */
|
||||||
|
cbio = BIO_new_mem_buf(ca_file_pem, (int) strlen(ca_file_pem));
|
||||||
|
if(!cbio)
|
||||||
|
break;
|
||||||
|
|
||||||
|
cts = SSL_CTX_get_cert_store(ctx);
|
||||||
|
if(!cts)
|
||||||
|
break;
|
||||||
|
|
||||||
|
inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
|
||||||
|
if(!inf)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* add each entry from PEM file to x509_store */
|
||||||
|
for(i = 0; i < sk_X509_INFO_num(inf); ++i) {
|
||||||
|
itmp = sk_X509_INFO_value(inf, i);
|
||||||
|
if(itmp->x509) {
|
||||||
|
X509_STORE_add_cert(cts, itmp->x509);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
if(itmp->crl) {
|
||||||
|
X509_STORE_add_crl(cts, itmp->crl);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we didn't end up importing anything, treat that as an error */
|
||||||
|
if(count > 0)
|
||||||
|
result = CURLE_OK;
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
if(inf)
|
||||||
|
sk_X509_INFO_pop_free(inf, X509_INFO_free);
|
||||||
|
|
||||||
|
if(cbio)
|
||||||
|
BIO_free(cbio);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
|
static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
|
||||||
{
|
{
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
@ -2416,6 +2471,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
|
|||||||
const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
|
const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
|
||||||
const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
|
const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
|
||||||
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
|
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
|
||||||
|
const char * const ca_file_pem = SSL_CONN_CONFIG(ca_file_pem);
|
||||||
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
|
||||||
const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
|
const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
|
||||||
char error_buffer[256];
|
char error_buffer[256];
|
||||||
@ -2720,6 +2776,16 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if(ca_file_pem && load_cacert_from_memory(backend->ctx, ca_file_pem)) {
|
||||||
|
if(verifypeer) {
|
||||||
|
/* Fail if we insist on successfully verifying the server. */
|
||||||
|
failf(data, "error setting certificate from memory");
|
||||||
|
return CURLE_SSL_CACERT_BADFILE;
|
||||||
|
}
|
||||||
|
/* Continue with a warning if no certificate verification is required. */
|
||||||
|
infof(data, "error setting certificate file, continuing anyway\n");
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||||
/* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
|
/* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
|
||||||
if(ssl_cafile) {
|
if(ssl_cafile) {
|
||||||
|
@ -93,6 +93,7 @@ Curl_ssl_config_matches(struct ssl_primary_config* data,
|
|||||||
(data->verifystatus == needle->verifystatus) &&
|
(data->verifystatus == needle->verifystatus) &&
|
||||||
Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
|
Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
|
||||||
Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
|
Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
|
||||||
|
Curl_safe_strcasecompare(data->ca_file_pem, needle->ca_file_pem) &&
|
||||||
Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
|
Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
|
||||||
Curl_safe_strcasecompare(data->random_file, needle->random_file) &&
|
Curl_safe_strcasecompare(data->random_file, needle->random_file) &&
|
||||||
Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
|
Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
|
||||||
@ -117,6 +118,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
|
|||||||
|
|
||||||
CLONE_STRING(CApath);
|
CLONE_STRING(CApath);
|
||||||
CLONE_STRING(CAfile);
|
CLONE_STRING(CAfile);
|
||||||
|
CLONE_STRING(ca_file_pem);
|
||||||
CLONE_STRING(clientcert);
|
CLONE_STRING(clientcert);
|
||||||
CLONE_STRING(random_file);
|
CLONE_STRING(random_file);
|
||||||
CLONE_STRING(egdsocket);
|
CLONE_STRING(egdsocket);
|
||||||
@ -131,6 +133,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
|
|||||||
{
|
{
|
||||||
Curl_safefree(sslc->CApath);
|
Curl_safefree(sslc->CApath);
|
||||||
Curl_safefree(sslc->CAfile);
|
Curl_safefree(sslc->CAfile);
|
||||||
|
Curl_safefree(sslc->ca_file_pem);
|
||||||
Curl_safefree(sslc->clientcert);
|
Curl_safefree(sslc->clientcert);
|
||||||
Curl_safefree(sslc->random_file);
|
Curl_safefree(sslc->random_file);
|
||||||
Curl_safefree(sslc->egdsocket);
|
Curl_safefree(sslc->egdsocket);
|
||||||
|
Loading…
Reference in New Issue
Block a user