Skip to content

Commit

Permalink
hsts: add support for Strict-Transport-Security
Browse files Browse the repository at this point in the history
- enable in the build (configure)
- header parsing
- host name lookup
- unit tests for the above
- CI build
- CURL_VERSION_HSTS bit
- curl_version_info support
- curl -V output
- curl-config --features
- CURLOPT_HSTS_CTRL
- man page for CURLOPT_HSTS_CTRL
- curl --hsts (sets CURLOPT_HSTS_CTRL and works with --libcurl)
- man page for --hsts
- save cache to disk
- load cache from disk
- CURLOPT_HSTS
- man page for CURLOPT_HSTS
- added docs/HSTS.md
- fixed --version docs
- adjusted curl_easy_duphandle

Closes #5896
  • Loading branch information
bagder committed Nov 3, 2020
1 parent 9f43b28 commit 7385610
Show file tree
Hide file tree
Showing 38 changed files with 1,122 additions and 21 deletions.
28 changes: 28 additions & 0 deletions configure.ac
Expand Up @@ -4882,6 +4882,31 @@ AC_HELP_STRING([--disable-alt-svc],[Disable alt-svc support]),
AC_MSG_RESULT(no)
)

dnl ************************************************************
dnl switch on/off hsts
dnl
curl_hsts_msg="no (--enable-hsts)";
AC_MSG_CHECKING([whether to support HSTS])
AC_ARG_ENABLE(hsts,
AC_HELP_STRING([--enable-hsts],[Enable HSTS support])
AC_HELP_STRING([--disable-hsts],[Disable HSTS support]),
[ case "$enableval" in
no)
AC_MSG_RESULT(no)
;;
*) AC_MSG_RESULT(yes)
curl_hsts_msg="enabled";
enable_hsts="yes"
;;
esac ],
AC_MSG_RESULT(no)
)

if test "$enable_hsts" = "yes"; then
AC_DEFINE(USE_HSTS, 1, [to enable HSTS])
experimental="$experimental HSTS"
fi

dnl *************************************************************
dnl check whether ECH support, if desired, is actually available
dnl
Expand Down Expand Up @@ -4998,6 +5023,9 @@ fi
if test "x$enable_altsvc" = "xyes"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES alt-svc"
fi
if test "x$enable_hsts" = "xyes"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES HSTS"
fi

if test "x$CURL_DISABLE_CRYPTO_AUTH" != "x1" -a \
\( "x$HAVE_GSSAPI" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" \); then
Expand Down
2 changes: 2 additions & 0 deletions docs/EXPERIMENTAL.md
Expand Up @@ -20,3 +20,5 @@ Experimental support in curl means:

- HTTP/3 support and options
- CURLSSLOPT_NATIVE_CA (No configure option, feature built in when supported)
- HSTS support and options

44 changes: 44 additions & 0 deletions docs/HSTS.md
@@ -0,0 +1,44 @@
# HSTS support

curl features **EXPERIMENTAL** support for the Strict-Transport-Security: HTTP
header. Added in curl 7.74.0

## Standard

[HTTP Strict Transport Security](https://tools.ietf.org/html/rfc6797)

## Behavior

libcurl features an in-memory cache for HSTS hosts, so that subsequent
HTTP-only requests to a host name present in the cache will get internally
"redirected" to the HTTPS version.

## `curl_easy_setopt()` options:

- `CURLOPT_HSTS_CTRL` - enable HSTS for this easy handle
- `CURLOPT_HSTS` - specify file name where to store the HSTS cache on close
(and possibly read from at startup)

## curl cmdline options

- `--hsts [filename]` - enable HSTS, use the file as HSTS cache. If filename
is `""` (no length) then no file will be used, only in-memory cache.

## HSTS cache file format

Lines starting with `#` are ignored.

For each hsts entry:

[host name] "YYYYMMDD HH:MM:SS"

The `[host name]` is dot-prefixed if it is a includeSubDomain.

The time stamp is when the entry expires.

I considered using wget's file format for the HSTS cache. However, they store the time stamp as the epoch (number of seconds since 1970) and I strongly disagree with using that format. Instead I opted to use a format similar to the curl alt-svc cache file format.

## Possible future additions

- `CURLOPT_HSTS_PRELOAD` - provide a set of preloaded HSTS host names
- ability to save to something else than a file
1 change: 1 addition & 0 deletions docs/Makefile.am
Expand Up @@ -63,6 +63,7 @@ EXTRA_DIST = \
GOVERNANCE.md \
HELP-US.md \
HISTORY.md \
HSTS.md \
HTTP-COOKIES.md \
HTTP2.md \
HTTP3.md \
Expand Down
1 change: 1 addition & 0 deletions docs/cmdline-opts/Makefile.inc
Expand Up @@ -85,6 +85,7 @@ DPAGES = \
head.d header.d \
help.d \
hostpubmd5.d \
hsts.d \
http0.9.d \
http1.0.d \
http1.1.d http2.d \
Expand Down
18 changes: 18 additions & 0 deletions docs/cmdline-opts/hsts.d
@@ -0,0 +1,18 @@
Long: hsts
Arg: <file name>
Protocols: HTTPS
Help: Enable HSTS with this cache file
Added: 7.74.0
Category: http
---
WARNING: this option is experimental. Do not use in production.

This option enables HSTS for the transfer. If the file name points to an
existing HSTS cache file, that will be used. After a completed transfer, the
cache will be saved to the file name again if it has been modified.

Specify a "" file name (zero length) to avoid loading/saving and make curl
just handle HSTS in memory.

If this option is used several times, curl will load contents from all the
files but the last one will be used for saving.
2 changes: 2 additions & 0 deletions docs/cmdline-opts/version.d
Expand Up @@ -28,6 +28,8 @@ This curl uses a libcurl built with Debug. This enables more error-tracking
and memory debugging etc. For curl-developers only!
.IP "GSS-API"
GSS-API is supported.
.IP "HSTS"
HSTS support is present.
.IP "HTTP2"
HTTP/2 support has been built-in.
.IP "HTTP3"
Expand Down
4 changes: 4 additions & 0 deletions docs/libcurl/curl_easy_setopt.3
Expand Up @@ -319,6 +319,10 @@ Add or control cookies. See \fICURLOPT_COOKIELIST(3)\fP
Specify the Alt-Svc: cache file name. See \fICURLOPT_ALTSVC(3)\fP
.IP CURLOPT_ALTSVC_CTRL
Enable and configure Alt-Svc: treatment. See \fICURLOPT_ALTSVC_CTRL(3)\fP
.IP CURLOPT_HSTS
Set HSTS cache file. See \fICURLOPT_HSTS(3)\fP
.IP CURLOPT_HSTS_CTRL
Enable HSTS. See \fICURLOPT_HSTS_CTRL(3)\fP
.IP CURLOPT_HTTPGET
Do an HTTP GET request. See \fICURLOPT_HTTPGET(3)\fP
.IP CURLOPT_REQUEST_TARGET
Expand Down
3 changes: 3 additions & 0 deletions docs/libcurl/curl_version_info.3
Expand Up @@ -143,6 +143,9 @@ to use the current user credentials without the app having to pass them on.
(Added in 7.38.0)
.IP CURL_VERSION_GSSNEGOTIATE
supports HTTP GSS-Negotiate (added in 7.10.6)
.IP CURL_VERSION_HSTS
libcurl was built with support for HSTS (HTTP Strict Transport Security)
(Added in 7.74.0)
.IP CURL_VERSION_HTTPS_PROXY
libcurl was built with support for HTTPS-proxy.
(Added in 7.52.0)
Expand Down
66 changes: 66 additions & 0 deletions docs/libcurl/opts/CURLOPT_HSTS.3
@@ -0,0 +1,66 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 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.
.\" *
.\" **************************************************************************
.\"
.TH CURLOPT_HSTS 3 "5 Feb 2019" "libcurl 7.74.0" "curl_easy_setopt options"
.SH NAME
CURLOPT_HSTS \- set HSTS cache file name
.SH SYNOPSIS
.nf
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HSTS, char *filename);
.fi
.SH EXPERIMENTAL
Warning: this feature is early code and is marked as experimental. It can only
be enabled by explicitly telling configure with \fB--enable-hsts\fP. You are
advised to not ship this in production before the experimental label is
removed.
.SH DESCRIPTION
Make the \fIfilename\fP point to a file name to load an existing HSTS cache
from, and to store the cache in when the easy handle is closed. Setting a file
name with this option will also enable HSTS for this handle (the equivalent of
setting \fICURLHSTS_ENABLE\fP with \fICURLOPT_HSTS_CTRL(3)\fP).

If the given file does not exist or contains no HSTS entries at startup, the
HSTS cache will simply start empty. Setting the file name to NULL or "" will
only enable HSTS without reading from or writing to any file.

If this option is set multiple times, libcurl will load cache entries from
each given file but will only store the last used name for later writing.
.SH DEFAULT
NULL, no file name
.SH PROTOCOLS
HTTPS and HTTP
.SH EXAMPLE
.nf
CURL *curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_HSTS, "/home/user/.hsts-cache");
curl_easy_perform(curl);
}
.fi
.SH AVAILABILITY
Added in 7.74.0
.SH RETURN VALUE
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
.SH "SEE ALSO"
.BR CURLOPT_HSTS_CTRL "(3), " CURLOPT_ALTSVC "(3), " CURLOPT_RESOLVE "(3), "
73 changes: 73 additions & 0 deletions docs/libcurl/opts/CURLOPT_HSTS_CTRL.3
@@ -0,0 +1,73 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 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.
.\" *
.\" **************************************************************************
.\"
.TH CURLOPT_HSTS_CTRL 3 "4 Sep 2020" "libcurl 7.74.0" "curl_easy_setopt options"
.SH NAME
CURLOPT_HSTS_CTRL \- control HSTS behavior
.SH SYNOPSIS
.nf
#include <curl/curl.h>

#define CURLHSTS_ENABLE (1<<0)
#define CURLHSTS_READONLYFILE (1<<1)

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HSTS_CTRL, long bitmask);
.fi
.SH EXPERIMENTAL
Warning: this feature is early code and is marked as experimental. It can only
be enabled by explicitly telling configure with \fB--enable-hsts\fP. You are
advised to not ship this in production before the experimental label is
removed.
.SH DESCRIPTION
HSTS (HTTP Strict Transport Security) means that an HTTPS server can instruct
the client to not contact it again over clear-text HTTP for a certain period
into the future. libcurl will then automatically redirect HTTP attempts to
such hosts to instead use HTTPS. This is done by libcurl retaining this
knowledge in an in-memory cache.

Populate the long \fIbitmask\fP with the correct set of features to instruct
libcurl how to handle HSTS for the transfers using this handle.
.SH BITS
.IP "CURLHSTS_ENABLE"
Enable the in-memory HSTS cache for this handle.
.IP "CURLHSTS_READONLYFILE"
Make the HSTS file (if specified) read-only - makes libcurl not save the cache
to the file when closing the handle.
.SH DEFAULT
0. HSTS is disabled by default.
.SH PROTOCOLS
HTTPS and HTTP
.SH EXAMPLE
.nf
CURL *curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_HSTS_CTRL, CURLHSTS_ENABLE);
curl_easy_perform(curl);
}
.fi
.SH AVAILABILITY
Added in 7.74.0
.SH RETURN VALUE
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
.SH "SEE ALSO"
.BR CURLOPT_HSTS "(3), " CURLOPT_CONNECT_TO "(3), " CURLOPT_RESOLVE "(3), "
.BR CURLOPT_ALTSVC "(3), "
2 changes: 2 additions & 0 deletions docs/libcurl/opts/Makefile.inc
Expand Up @@ -180,6 +180,8 @@ man_MANS = \
CURLOPT_HEADERDATA.3 \
CURLOPT_HEADERFUNCTION.3 \
CURLOPT_HEADEROPT.3 \
CURLOPT_HSTS.3 \
CURLOPT_HSTS_CTRL.3 \
CURLOPT_HTTP09_ALLOWED.3 \
CURLOPT_HTTP200ALIASES.3 \
CURLOPT_HTTPAUTH.3 \
Expand Down
5 changes: 5 additions & 0 deletions docs/libcurl/symbols-in-versions
Expand Up @@ -213,6 +213,8 @@ CURLGSSAPI_DELEGATION_NONE 7.22.0
CURLGSSAPI_DELEGATION_POLICY_FLAG 7.22.0
CURLHEADER_SEPARATE 7.37.0
CURLHEADER_UNIFIED 7.37.0
CURLHSTS_ENABLE 7.74.0
CURLHSTS_READONLYFILE 7.74.0
CURLINFO_ACTIVESOCKET 7.45.0
CURLINFO_APPCONNECT_TIME 7.19.0
CURLINFO_APPCONNECT_TIME_T 7.61.0
Expand Down Expand Up @@ -443,6 +445,8 @@ CURLOPT_HEADER 7.1
CURLOPT_HEADERDATA 7.10
CURLOPT_HEADERFUNCTION 7.7.2
CURLOPT_HEADEROPT 7.37.0
CURLOPT_HSTS 7.74.0
CURLOPT_HSTS_CTRL 7.74.0
CURLOPT_HTTP09_ALLOWED 7.64.0
CURLOPT_HTTP200ALIASES 7.10.3
CURLOPT_HTTPAUTH 7.10.6
Expand Down Expand Up @@ -1001,6 +1005,7 @@ CURL_VERSION_CURLDEBUG 7.19.6
CURL_VERSION_DEBUG 7.10.6
CURL_VERSION_GSSAPI 7.38.0
CURL_VERSION_GSSNEGOTIATE 7.10.6 7.38.0
CURL_VERSION_HSTS 7.74.0
CURL_VERSION_HTTP2 7.33.0
CURL_VERSION_HTTP3 7.66.0
CURL_VERSION_HTTPS_PROXY 7.52.0
Expand Down
1 change: 1 addition & 0 deletions docs/options-in-versions
Expand Up @@ -79,6 +79,7 @@
--header (-H) 5.0
--help (-h) 4.0
--hostpubmd5 7.17.1
--hsts 7.74.0
--http0.9 7.64.0
--http1.0 (-0) 7.9.1
--http1.1 7.33.0
Expand Down
10 changes: 10 additions & 0 deletions include/curl/curl.h
Expand Up @@ -954,6 +954,10 @@ typedef enum {
#define CURLALTSVC_H2 (1<<4)
#define CURLALTSVC_H3 (1<<5)

/* CURLHSTS_* are bits for the CURLOPT_HSTS option */
#define CURLHSTS_ENABLE (long)(1<<0)
#define CURLHSTS_READONLYFILE (long)(1<<1)

/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
#define CURLPROTO_HTTP (1<<0)
#define CURLPROTO_HTTPS (1<<1)
Expand Down Expand Up @@ -2029,6 +2033,11 @@ typedef enum {
*/
CURLOPT(CURLOPT_SSL_EC_CURVES, CURLOPTTYPE_STRINGPOINT, 298),

/* HSTS bitmask */
CURLOPT(CURLOPT_HSTS_CTRL, CURLOPTTYPE_LONG, 299),
/* HSTS file name */
CURLOPT(CURLOPT_HSTS, CURLOPTTYPE_STRINGPOINT, 300),

CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

Expand Down Expand Up @@ -2900,6 +2909,7 @@ typedef struct curl_version_info_data curl_version_info_data;
#define CURL_VERSION_HTTP3 (1<<25) /* HTTP3 support built-in */
#define CURL_VERSION_ZSTD (1<<26) /* zstd features are present */
#define CURL_VERSION_UNICODE (1<<27) /* Unicode support on Windows */
#define CURL_VERSION_HSTS (1<<28) /* HSTS is supported */

/*
* NAME curl_version_info()
Expand Down
4 changes: 2 additions & 2 deletions lib/Makefile.inc
Expand Up @@ -61,7 +61,7 @@ LIB_CFILES = altsvc.c amigaos.c asyn-ares.c asyn-thread.c base64.c \
socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c strdup.c \
strerror.c strtok.c strtoofft.c system_win32.c telnet.c tftp.c timeval.c \
transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c dynbuf.c \
version_win32.c easyoptions.c easygetopt.c
version_win32.c easyoptions.c easygetopt.c hsts.c

LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h \
content_encoding.h cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h \
Expand All @@ -80,7 +80,7 @@ LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h \
smb.h smtp.h sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \
strdup.h strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h \
timeval.h transfer.h urlapi-int.h urldata.h warnless.h wildcard.h \
x509asn1.h dynbuf.h version_win32.h easyoptions.h
x509asn1.h dynbuf.h version_win32.h easyoptions.h hsts.h

LIB_RCFILES = libcurl.rc

Expand Down

0 comments on commit 7385610

Please sign in to comment.