]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
curl: support embedding a CA bundle
authorViktor Szakats <commit@vsz.me>
Sat, 29 Jun 2024 01:30:14 +0000 (03:30 +0200)
committerViktor Szakats <commit@vsz.me>
Sat, 3 Aug 2024 07:22:26 +0000 (09:22 +0200)
Add the ability to embed a CA bundle into the curl binary. It is used
when no other runtime or build-time option set one.

This helps curl-for-win macOS and Linux builds to run standalone, and
also helps Windows builds to avoid picking up the CA bundle from an
arbitrary (possibly world-writable) location (though this behaviour is
not currently disablable).

Usage:
- cmake: `-DCURL_CA_EMBED=/path/to/curl-ca-bundle.crt`
- autotools: `--with-ca-embed=/path/to/curl-ca-bundle.crt`
- Makefile.mk: `CURL_CA_EMBED=/path/to/curl-ca-bundle.crt`

Also add new command-line option `--dump-ca-embed` to dump the embedded
CA bundle to standard output.

Closes #14059

26 files changed:
CMakeLists.txt
acinclude.m4
configure.ac
docs/cmdline-opts/Makefile.inc
docs/cmdline-opts/ca-native.md
docs/cmdline-opts/cacert.md
docs/cmdline-opts/capath.md
docs/cmdline-opts/dump-ca-embed.md [new file with mode: 0644]
docs/cmdline-opts/proxy-ca-native.md
docs/cmdline-opts/proxy-cacert.md
docs/cmdline-opts/proxy-capath.md
docs/options-in-versions
projects/checksrc.bat
src/.gitignore
src/CMakeLists.txt
src/Makefile.am
src/Makefile.mk
src/mk-file-embed.pl [new file with mode: 0755]
src/tool_getparam.c
src/tool_getparam.h
src/tool_help.c
src/tool_libinfo.c
src/tool_libinfo.h
src/tool_listhelp.c
src/tool_operate.c
src/tool_parsecfg.c

index 2b3663e9b002526c4dd530620fbe74a3596bc82f..12b96c3211e95544d7e91f3c6be8cb2b098aad84 100644 (file)
@@ -1133,6 +1133,8 @@ if(curl_ca_bundle_supported)
       "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.")
@@ -1196,6 +1198,15 @@ if(curl_ca_bundle_supported)
       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
@@ -1798,6 +1809,7 @@ if(NOT CURL_DISABLE_INSTALL)
   _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)
index 7a26ecedc15e806232f911a346cb7c816a8c187a..4ec37c6c21c7ce01edd49f48c9f37346be471de7 100644 (file)
@@ -1357,6 +1357,37 @@ AS_HELP_STRING([--without-ca-fallback], [Don't use the built in CA store of the
   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
index 3e8fece3cd2e2e0003ce946787c2b01c171c207d..f6c4e1602f0077712ecb1decaf0625c2151fa950 100644 (file)
@@ -2090,8 +2090,11 @@ dnl **********************************************************************
 
 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 **********************************************************************
@@ -3844,13 +3847,13 @@ AC_CHECK_DECL([fseeko],
 
 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
 
@@ -4866,6 +4869,9 @@ 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
index d69635e4950966646024e1066f06236ae00e3f79..75178b28a85df488ecdb46d620c11a86b1c22dcd 100644 (file)
@@ -89,6 +89,7 @@ DPAGES = \
   doh-cert-status.md \
   doh-insecure.md \
   doh-url.md \
+  dump-ca-embed.md \
   dump-header.md \
   ech.md \
   egd-file.md \
index a771a7a81334acf10a9063c2185f53628900c52d..3d773a8c4501e80f462016e4e6b16c87643389c6 100644 (file)
@@ -10,6 +10,7 @@ Multi: boolean
 See-also:
   - cacert
   - capath
+  - dump-ca-embed
   - insecure
 Example:
   - --ca-native $URL
index 3268f966defa46de82a7f2bbeddc7d0d2dbc2419..43a17aed7bb600f15cfc632ece3d490603411c12 100644 (file)
@@ -10,6 +10,7 @@ Added: 7.5
 Multi: single
 See-also:
   - capath
+  - dump-ca-embed
   - insecure
 Example:
   - --cacert CA-file.txt $URL
index 58919dd4ab1957b4355d64173137d084d192343e..51be39e29300c904841e24ba17541a9127c261f7 100644 (file)
@@ -10,6 +10,7 @@ Added: 7.9.8
 Multi: single
 See-also:
   - cacert
+  - dump-ca-embed
   - insecure
 Example:
   - --capath /local/directory $URL
diff --git a/docs/cmdline-opts/dump-ca-embed.md b/docs/cmdline-opts/dump-ca-embed.md
new file mode 100644 (file)
index 0000000..c5c2c00
--- /dev/null
@@ -0,0 +1,25 @@
+---
+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.
index fd78f12fbd1cb019eaef99461f110d7fef0b961a..e84dbd9601d4e85a98753c5c465efc2fd9a0673f 100644 (file)
@@ -10,6 +10,7 @@ Multi: boolean
 See-also:
   - cacert
   - capath
+  - dump-ca-embed
   - insecure
 Example:
   - --proxy-ca-native $URL
index 189ed390d2376281951595dc8378f7eb5b6becfa..682349a7e26011c9a623c0bf3b6cd804c43b6099 100644 (file)
@@ -11,6 +11,7 @@ See-also:
   - proxy-capath
   - cacert
   - capath
+  - dump-ca-embed
   - proxy
 Example:
   - --proxy-cacert CA-file.txt -x https://proxy $URL
index bc2c7b56f59218e4e5c2a973d09c5a6d9004a5c1..3a3aabf10eb35ff5f7d55b889a67f6fa16388ef6 100644 (file)
@@ -11,6 +11,7 @@ See-also:
   - proxy-cacert
   - proxy
   - capath
+  - dump-ca-embed
 Example:
   - --proxy-capath /local/directory -x https://proxy $URL
 ---
index e329f87230a1ecc5b9a420724e5b79ee1cd78c0a..e19965e6a41b60242541cb6846c68889e408ed92 100644 (file)
@@ -54,6 +54,7 @@
 --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
index 018dc5960533729de8a8e60754e760931b80c08d..69e3d8c4f1846ba222bc901ef717251ae08bd004 100644 (file)
@@ -115,7 +115,7 @@ rem ***************************************************************************
   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"
     )
   )
index c132010c4b4daa7c69f0e67dbe593e67a3a1abb8..b866dad63ea37991bda2c02bbe0405324b17087e 100644 (file)
@@ -10,5 +10,6 @@ curl
 curl_config.h
 curl_config.h.in
 stamp-h2
+tool_ca_embed.c
 tool_hugehelp.c
 tool_version.h.dist
index 4f3019c7bd5cdc14e8741607b99a1043300e1dd9..32355b545e3a00278f007a3ded52c75f9b5f40b0 100644 (file)
@@ -54,6 +54,22 @@ endif()
 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()
index 4ce83c92395e09e8043222bc5727a0c361985679..73fbe8068f079688d1fba7d985d3b5b43ae65d00 100644 (file)
@@ -88,7 +88,7 @@ CLEANFILES = tool_hugehelp.c
 # 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
@@ -135,11 +135,25 @@ $(HUGE):
        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
index 83dd65d16fc8cba55419a7a80a145dcf68fb3d84..24b4bd3a764d6ad5afb23559d3916a18705480c9 100644 (file)
@@ -45,6 +45,11 @@ TARGETS := curl$(BIN_EXT)
 
 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
@@ -57,8 +62,9 @@ TOCLEAN := $(curl_OBJECTS)
 
 ### Rules
 
-ifneq ($(wildcard tool_hugehelp.c.cvs),)
 PERL  ?= perl
+
+ifneq ($(wildcard tool_hugehelp.c.cvs),)
 NROFF ?= groff
 
 TOCLEAN += tool_hugehelp.c
@@ -84,6 +90,12 @@ 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)
 
diff --git a/src/mk-file-embed.pl b/src/mk-file-embed.pl
new file mode 100755 (executable)
index 0000000..3447aa9
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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
+    ;
index b92a2038fe8a097199981f2fdb6431d639722a86..ae5dec9a16b71c2b315cbf29d5de85483b120e4d 100644 (file)
@@ -122,6 +122,7 @@ typedef enum {
   C_DOH_CERT_STATUS,
   C_DOH_INSECURE,
   C_DOH_URL,
+  C_DUMP_CA_EMBED,
   C_DUMP_HEADER,
   C_ECH,
   C_EGD_FILE,
@@ -408,6 +409,7 @@ static const struct LongShort aliases[]= {
   {"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},
@@ -2113,6 +2115,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
     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;
@@ -2984,7 +2989,8 @@ ParameterError parse_args(struct GlobalConfig *global, int argc,
   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))
index 12a971d0277206d92069373ab09860aac93b3527..8abf5787e9db0b49f47f04505ac5c5e16ffa621b 100644 (file)
@@ -35,6 +35,7 @@ typedef enum {
   PARAM_MANUAL_REQUESTED,
   PARAM_VERSION_INFO_REQUESTED,
   PARAM_ENGINES_REQUESTED,
+  PARAM_CA_EMBED_REQUESTED,
   PARAM_GOT_EXTRA_PARAMETER,
   PARAM_BAD_NUMERIC,
   PARAM_NEGATIVE_NUMERIC,
index a12626eff3ea3a64799c0914dff45aca7c1de35f..c570cb96c8e96b030b19a264110cc44aa71342ee 100644 (file)
@@ -244,10 +244,28 @@ void tool_version_info(void)
     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. "
index 2b74e4e5e16873c44242b2d0a4472d2da3b94092..8b006894fd9f82f21f57a6a2a052a41b9c29850e 100644 (file)
@@ -124,6 +124,7 @@ static struct feature_name_presentp {
 
 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,
@@ -182,6 +183,7 @@ CURLcode get_libcurl_info(void)
           *p->feature_presentp = TRUE;
         break;
       }
+    ++feature_count;
   }
 
   return CURLE_OK;
index e69f35829b64da0baf36a80835423bb5261e6b27..ad9c195dc056661b8257fe4bb53b898ea1ce6d75 100644 (file)
@@ -34,6 +34,7 @@ extern const char * const *built_in_protos;
 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;
index a825a03154d5a3a06cf4f3e5debe1739ae692cdf..4095d4aa3d49826177b5dd78ff2b3e67dd0b0154 100644 (file)
@@ -165,6 +165,9 @@ const struct helptxt helptext[] = {
   {"    --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},
index f6ae64dd3d5f44c578fb8713f0bc129fb32199ee..c56b950a4128bba39f03c1404a5501476b46cc55 100644 (file)
 
 #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 */
@@ -1657,6 +1661,37 @@ static CURLcode single_transfer(struct GlobalConfig *global,
             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)
@@ -2842,6 +2877,12 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[])
       /* 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)
index d0a3159f56d0afbaf43d1f7c5915c8dd3d59d614..ad67f540fcb68378ed62474d5ff20155ffde9094 100644 (file)
@@ -262,7 +262,8 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
         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);