"Set ON to use built-in CA store of TLS backend. Defaults to OFF")
set(CURL_CA_PATH "auto" CACHE STRING
"Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
+ set(CURL_CA_EMBED "" CACHE STRING
+ "Path to the CA bundle to embed into the curl tool.")
if(CURL_CA_BUNDLE STREQUAL "")
message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.")
endif()
endif()
endif()
+
+ set(CURL_CA_EMBED_SET FALSE)
+ if(BUILD_CURL_EXE AND NOT CURL_CA_EMBED STREQUAL "")
+ if(EXISTS "${CURL_CA_EMBED}")
+ set(CURL_CA_EMBED_SET TRUE)
+ else()
+ message(FATAL_ERROR "CA bundle to embed is missing: '${CURL_CA_EMBED}'")
+ endif()
+ endif()
endif()
# Check for header files
_add_if("TrackMemory" ENABLE_CURLDEBUG)
_add_if("ECH" SSL_ENABLED AND HAVE_ECH)
_add_if("PSL" USE_LIBPSL)
+ _add_if("CAcert" CURL_CA_EMBED_SET)
if(_items)
if(NOT CMAKE_VERSION VERSION_LESS 3.13)
list(SORT _items CASE INSENSITIVE)
fi
])
+
+dnl CURL_CHECK_CA_EMBED
+dnl -------------------------------------------------
+dnl Check if a ca-bundle should be embedded
+
+AC_DEFUN([CURL_CHECK_CA_EMBED], [
+
+ AC_MSG_CHECKING([CA cert bundle path to embed])
+
+ AC_ARG_WITH(ca-embed,
+AS_HELP_STRING([--with-ca-embed=FILE],
+[Path to a file containing CA certificates (example: /etc/ca-bundle.crt)])
+AS_HELP_STRING([--without-ca-embed], [Don't embed a default CA bundle]),
+ [
+ want_ca_embed="$withval"
+ if test "x$want_ca_embed" = "xyes"; then
+ AC_MSG_ERROR([--with-ca-embed=FILE requires a path to the CA bundle])
+ fi
+ ],
+ [ want_ca_embed="unset" ])
+
+ CURL_CA_EMBED=''
+ if test "x$want_ca_embed" != "xno" -a "x$want_ca_embed" != "xunset" -a -f "$want_ca_embed"; then
+ CURL_CA_EMBED='"'$want_ca_embed'"'
+ AC_SUBST(CURL_CA_EMBED)
+ AC_MSG_RESULT([$want_ca_embed])
+ else
+ AC_MSG_RESULT([no])
+ fi
+])
+
dnl CURL_CHECK_WIN32_LARGEFILE
dnl -------------------------------------------------
dnl Check if curl's WIN32 large file will be used
if test -n "$check_for_ca_bundle"; then
CURL_CHECK_CA_BUNDLE
+ CURL_CHECK_CA_EMBED
fi
+AM_CONDITIONAL(CURL_CA_EMBED_SET, test "x$CURL_CA_EMBED" != "x")
+
dnl **********************************************************************
dnl Check for libpsl
dnl **********************************************************************
CURL_CHECK_NONBLOCKING_SOCKET
-if test "x$BUILD_DOCS" != "x0" -o "x$USE_MANUAL" != "x0"; then
+if test "x$BUILD_DOCS" != "x0" -o "x$USE_MANUAL" != "x0" -o "x$CURL_CA_EMBED" != "x"; then
AC_PATH_PROG( PERL, perl, ,
$PATH:/usr/local/bin/perl:/usr/bin/:/usr/local/bin )
AC_SUBST(PERL)
if test -z "$PERL"; then
- AC_MSG_ERROR([perl was not found, needed for docs and manual])
+ AC_MSG_ERROR([perl was not found, needed for docs, manual and CA embed])
fi
fi
if test "x$want_curldebug" = "xyes"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES TrackMemory"
fi
+if test "x$CURL_CA_EMBED" != "x"; then
+ SUPPORT_FEATURES="$SUPPORT_FEATURES CAcert"
+fi
dnl replace spaces with newlines
dnl sort the lines
doh-cert-status.md \
doh-insecure.md \
doh-url.md \
+ dump-ca-embed.md \
dump-header.md \
ech.md \
egd-file.md \
See-also:
- cacert
- capath
+ - dump-ca-embed
- insecure
Example:
- --ca-native $URL
Multi: single
See-also:
- capath
+ - dump-ca-embed
- insecure
Example:
- --cacert CA-file.txt $URL
Multi: single
See-also:
- cacert
+ - dump-ca-embed
- insecure
Example:
- --capath /local/directory $URL
--- /dev/null
+---
+c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+SPDX-License-Identifier: curl
+Long: dump-ca-embed
+Help: Write the embedded CA bundle to standard output
+Protocols: TLS
+Category: http proxy tls
+Added: 8.10.0
+Multi: single
+See-also:
+ - ca-native
+ - cacert
+ - capath
+ - proxy-ca-native
+ - proxy-cacert
+ - proxy-capath
+Example:
+ - --dump-ca-embed
+---
+
+# `--dump-ca-embed`
+
+Write the CA bundle embedded in curl to standard output, then quit.
+
+If curl was not built with a default CA bundle embedded, the output is empty.
See-also:
- cacert
- capath
+ - dump-ca-embed
- insecure
Example:
- --proxy-ca-native $URL
- proxy-capath
- cacert
- capath
+ - dump-ca-embed
- proxy
Example:
- --proxy-cacert CA-file.txt -x https://proxy $URL
- proxy-cacert
- proxy
- capath
+ - dump-ca-embed
Example:
- --proxy-capath /local/directory -x https://proxy $URL
---
--doh-cert-status 7.76.0
--doh-insecure 7.76.0
--doh-url 7.62.0
+--dump-ca-embed 8.10.0
--dump-header (-D) 5.7
--ech 8.8.0
--egd-file 7.7
if "%CHECK_SRC%" == "TRUE" (
rem Check the src directory
if exist %SRC_DIR%\src (
- for /f "delims=" %%i in ('dir "%SRC_DIR%\src\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\src" -Wtool_hugehelp.c "%%i"
+ for /f "delims=" %%i in ('dir "%SRC_DIR%\src\*.c.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\src" -Wtool_ca_embed.c -Wtool_hugehelp.c "%%i"
for /f "delims=" %%i in ('dir "%SRC_DIR%\src\*.h.*" /b 2^>NUL') do @perl "%SRC_DIR%\scripts\checksrc.pl" "-D%SRC_DIR%\src" "%%i"
)
)
curl_config.h
curl_config.h.in
stamp-h2
+tool_ca_embed.c
tool_hugehelp.c
tool_version.h.dist
transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
+if(CURL_CA_EMBED_SET)
+ if(PERL_FOUND)
+ add_definitions("-DCURL_CA_EMBED")
+ add_custom_command(
+ OUTPUT tool_ca_embed.c
+ COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mk-file-embed.pl" --var curl_ca_embed < "${CURL_CA_EMBED}" > tool_ca_embed.c
+ DEPENDS
+ "${CURL_CA_EMBED}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/mk-file-embed.pl"
+ VERBATIM)
+ list(APPEND CURL_CFILES tool_ca_embed.c)
+ else()
+ message(WARNING "Perl not found. Will not embed the CA bundle.")
+ endif()
+endif()
+
if(WIN32)
list(APPEND CURL_CFILES curl.rc)
endif()
# embedded text.
NROFF=env LC_ALL=C @NROFF@ @MANOPT@ 2>/dev/null # figured out by the configure script
-EXTRA_DIST = mkhelp.pl \
+EXTRA_DIST = mk-file-embed.pl mkhelp.pl \
Makefile.mk curl.rc Makefile.inc CMakeLists.txt .checksrc
# Use absolute directory to disable VPATH
echo '#include "tool_hugehelp.h"' >> $(HUGE)
endif
-# ignore tool_hugehelp.c since it is generated source code and it plays
-# by slightly different rules!
+CA_EMBED_CSOURCE = tool_ca_embed.c
+CURL_CFILES += $(CA_EMBED_CSOURCE)
+CLEANFILES += $(CA_EMBED_CSOURCE)
+if CURL_CA_EMBED_SET
+AM_CPPFLAGS += -DCURL_CA_EMBED
+MK_FILE_EMBED = $(top_srcdir)/src/mk-file-embed.pl
+$(CA_EMBED_CSOURCE): $(MK_FILE_EMBED)
+ $(PERL) $(MK_FILE_EMBED) --var curl_ca_embed < $(CURL_CA_EMBED) > $(CA_EMBED_CSOURCE)
+else
+$(CA_EMBED_CSOURCE):
+ echo 'extern const void *curl_ca_embed; const void *curl_ca_embed;' > $(CA_EMBED_CSOURCE)
+endif
+
+# ignore generated C files since they play by slightly different rules!
checksrc:
$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \
- -W$(srcdir)/tool_hugehelp.c $(srcdir)/*.[ch])
+ -W$(srcdir)/$(HUGE) \
+ -W$(srcdir)/$(CA_EMBED_CSOURCE) \
+ $(srcdir)/*.[ch])
if DEBUGBUILD
# for debug builds, we scan the sources on all regular make invokes
CURL_CFILES += $(notdir $(CURLX_CFILES))
+ifneq ($(CURL_CA_EMBED),)
+CPPFLAGS += -DCURL_CA_EMBED
+CURL_CFILES += tool_ca_embed.c
+endif
+
curl_OBJECTS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(strip $(CURL_CFILES)))
ifdef MAP
CURL_MAP := curl.map
### Rules
-ifneq ($(wildcard tool_hugehelp.c.cvs),)
PERL ?= perl
+
+ifneq ($(wildcard tool_hugehelp.c.cvs),)
NROFF ?= groff
TOCLEAN += tool_hugehelp.c
endif
endif
+ifneq ($(CURL_CA_EMBED),)
+TOCLEAN += tool_ca_embed.c
+tool_ca_embed.c: mk-file-embed.pl
+ $(PERL) mk-file-embed.pl --var curl_ca_embed < $(CURL_CA_EMBED) > $@
+endif
+
$(TARGETS): $(curl_OBJECTS) $(PROOT)/lib/libcurl.a
$(CC) $(LDFLAGS) -o $@ $(curl_OBJECTS) $(LIBS)
--- /dev/null
+#!/usr/bin/env perl
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
+#
+# Copyright (C) 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.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.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+
+my $varname = "var";
+if($ARGV[0] eq "--var") {
+ shift;
+ $varname = shift @ARGV;
+}
+
+print <<HEAD
+/*
+ * NEVER EVER edit this manually, fix the mk-file-embed.pl script instead!
+ */
+extern const unsigned char ${varname}[];
+const unsigned char ${varname}[] = {
+HEAD
+ ;
+
+while (<STDIN>) {
+ my $line = $_;
+ foreach my $n (split //, $line) {
+ my $ord = ord($n);
+ printf("%s,", $ord);
+ if($ord == 10) {
+ printf("\n");
+ }
+ }
+}
+
+print <<ENDLINE
+0
+};
+ENDLINE
+ ;
C_DOH_CERT_STATUS,
C_DOH_INSECURE,
C_DOH_URL,
+ C_DUMP_CA_EMBED,
C_DUMP_HEADER,
C_ECH,
C_EGD_FILE,
{"doh-cert-status", ARG_BOOL, ' ', C_DOH_CERT_STATUS},
{"doh-insecure", ARG_BOOL, ' ', C_DOH_INSECURE},
{"doh-url" , ARG_STRG, ' ', C_DOH_URL},
+ {"dump-ca-embed", ARG_NONE, ' ', C_DUMP_CA_EMBED},
{"dump-header", ARG_FILE, 'D', C_DUMP_HEADER},
{"ech", ARG_STRG, ' ', C_ECH},
{"egd-file", ARG_STRG, ' ', C_EGD_FILE},
case C_URL_QUERY: /* --url-query */
err = url_query(nextarg, global, config);
break;
+ case C_DUMP_CA_EMBED: /* --dump-ca-embed */
+ err = PARAM_CA_EMBED_REQUESTED;
+ break;
case C_DUMP_HEADER: /* --dump-header */
err = getstr(&config->headerfile, nextarg, DENY_BLANK);
break;
if(result && result != PARAM_HELP_REQUESTED &&
result != PARAM_MANUAL_REQUESTED &&
result != PARAM_VERSION_INFO_REQUESTED &&
- result != PARAM_ENGINES_REQUESTED) {
+ result != PARAM_ENGINES_REQUESTED &&
+ result != PARAM_CA_EMBED_REQUESTED) {
const char *reason = param2text(result);
if(orig_opt && strcmp(":", orig_opt))
PARAM_MANUAL_REQUESTED,
PARAM_VERSION_INFO_REQUESTED,
PARAM_ENGINES_REQUESTED,
+ PARAM_CA_EMBED_REQUESTED,
PARAM_GOT_EXTRA_PARAMETER,
PARAM_BAD_NUMERIC,
PARAM_NEGATIVE_NUMERIC,
puts(""); /* newline */
}
if(feature_names[0]) {
- printf("Features:");
- for(builtin = feature_names; *builtin; ++builtin)
- printf(" %s", *builtin);
- puts(""); /* newline */
+ const char **feat_ext;
+ size_t feat_ext_count = feature_count;
+#ifdef CURL_CA_EMBED
+ ++feat_ext_count;
+#endif
+ feat_ext = malloc(sizeof(*feature_names) * (feat_ext_count + 1));
+ if(feat_ext) {
+ memcpy((void *)feat_ext, feature_names,
+ sizeof(*feature_names) * feature_count);
+ feat_ext_count = feature_count;
+#ifdef CURL_CA_EMBED
+ feat_ext[feat_ext_count++] = "CAcert";
+#endif
+ feat_ext[feat_ext_count] = NULL;
+ qsort((void *)feat_ext, feat_ext_count, sizeof(*feat_ext),
+ struplocompare4sort);
+ printf("Features:");
+ for(builtin = feat_ext; *builtin; ++builtin)
+ printf(" %s", *builtin);
+ puts(""); /* newline */
+ free((void *)feat_ext);
+ }
}
if(strcmp(CURL_VERSION, curlinfo->version)) {
printf("WARNING: curl and libcurl versions do not match. "
static const char *fnames[sizeof(maybe_feature) / sizeof(maybe_feature[0])];
const char * const *feature_names = fnames;
+size_t feature_count;
/*
* libcurl_info_init: retrieves runtime information about libcurl,
*p->feature_presentp = TRUE;
break;
}
+ ++feature_count;
}
return CURLE_OK;
extern size_t proto_count;
extern const char * const *feature_names;
+extern size_t feature_count;
extern const char *proto_file;
extern const char *proto_ftp;
{" --doh-url <URL>",
"Resolve hostnames over DoH",
CURLHELP_DNS},
+ {" --dump-ca-embed",
+ "Write the embedded CA bundle to standard output",
+ CURLHELP_HTTP | CURLHELP_PROXY | CURLHELP_TLS},
{"-D, --dump-header <filename>",
"Write the received headers to <filename>",
CURLHELP_HTTP | CURLHELP_FTP},
#include "memdebug.h" /* keep this as LAST include */
+#ifdef CURL_CA_EMBED
+extern const unsigned char curl_ca_embed[];
+#endif
+
#ifndef O_BINARY
/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
source code but yet it does not ruin anything */
break;
}
+#ifdef CURL_CA_EMBED
+ if(!config->cacert && !config->capath) {
+ struct curl_blob blob;
+ blob.data = (void *)curl_ca_embed;
+ blob.len = strlen((const char *)curl_ca_embed);
+ blob.flags = CURL_BLOB_NOCOPY;
+ notef(config->global,
+ "Using embedded CA bundle (%zu bytes)",
+ blob.len);
+ result = curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob);
+ if(result == CURLE_NOT_BUILT_IN) {
+ warnf(global,
+ "ignoring embedded CA bundle, not supported by libcurl");
+ }
+ }
+ if(!config->proxy_cacert && !config->proxy_capath) {
+ struct curl_blob blob;
+ blob.data = (void *)curl_ca_embed;
+ blob.len = strlen((const char *)curl_ca_embed);
+ blob.flags = CURL_BLOB_NOCOPY;
+ notef(config->global,
+ "Using embedded CA bundle, for proxies (%zu bytes)",
+ blob.len);
+ result = curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO_BLOB, &blob);
+ if(result == CURLE_NOT_BUILT_IN) {
+ warnf(global,
+ "ignoring embedded CA bundle, not supported by libcurl");
+ }
+ }
+#endif
+
if(config->crlfile)
my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
if(config->proxy_crlfile)
/* Check if we were asked to list the SSL engines */
else if(res == PARAM_ENGINES_REQUESTED)
tool_list_engines();
+ /* Check if we were asked to dump the embedded CA bundle */
+ else if(res == PARAM_CA_EMBED_REQUESTED) {
+#ifdef CURL_CA_EMBED
+ printf("%s", curl_ca_embed);
+#endif
+ }
else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL)
result = CURLE_UNSUPPORTED_PROTOCOL;
else if(res == PARAM_READ_ERROR)
if(res != PARAM_HELP_REQUESTED &&
res != PARAM_MANUAL_REQUESTED &&
res != PARAM_VERSION_INFO_REQUESTED &&
- res != PARAM_ENGINES_REQUESTED) {
+ res != PARAM_ENGINES_REQUESTED &&
+ res != PARAM_CA_EMBED_REQUESTED) {
const char *reason = param2text(res);
errorf(operation->global, "%s:%d: '%s' %s",
filename, lineno, option, reason);