mirror of
https://github.com/curl/curl.git
synced 2026-08-25 00:13:34 +03:00
vtls: feature ssls-export for SSL session im-/export
Adds the experimental feature `ssls-export` to libcurl and curl for importing and exporting SSL sessions from/to a file. * add functions to libcurl API * add command line option `--ssl-sessions <filename>` to curl * add documenation * add support in configure * add support in cmake + add pytest case Closes #15924
This commit is contained in:
parent
8a1ee2b47d
commit
515a21f350
48 changed files with 1662 additions and 125 deletions
|
|
@ -32,12 +32,14 @@
|
|||
# libcurl sources to include in curltool lib we use for test binaries
|
||||
CURLTOOL_LIBCURL_CFILES = \
|
||||
../lib/base64.c \
|
||||
../lib/dynbuf.c
|
||||
../lib/dynbuf.c \
|
||||
../lib/curl_get_line.c
|
||||
|
||||
# libcurl has sources that provide functions named curlx_* that are not part of
|
||||
# the official API, but we reuse the code here to avoid duplication.
|
||||
CURLX_CFILES = \
|
||||
../lib/base64.c \
|
||||
../lib/curl_get_line.c \
|
||||
../lib/curl_multibyte.c \
|
||||
../lib/dynbuf.c \
|
||||
../lib/nonblock.c \
|
||||
|
|
@ -48,6 +50,7 @@ CURLX_CFILES = \
|
|||
|
||||
CURLX_HFILES = \
|
||||
../lib/curl_ctype.h \
|
||||
../lib/curl_get_line.h \
|
||||
../lib/curl_multibyte.h \
|
||||
../lib/curl_setup.h \
|
||||
../lib/dynbuf.h \
|
||||
|
|
@ -92,6 +95,7 @@ CURL_CFILES = \
|
|||
tool_progress.c \
|
||||
tool_setopt.c \
|
||||
tool_sleep.c \
|
||||
tool_ssls.c \
|
||||
tool_stderr.c \
|
||||
tool_strdup.c \
|
||||
tool_urlglob.c \
|
||||
|
|
@ -139,6 +143,7 @@ CURL_HFILES = \
|
|||
tool_setopt.h \
|
||||
tool_setup.h \
|
||||
tool_sleep.h \
|
||||
tool_ssls.h \
|
||||
tool_stderr.h \
|
||||
tool_strdup.h \
|
||||
tool_urlglob.h \
|
||||
|
|
|
|||
|
|
@ -330,6 +330,7 @@ struct GlobalConfig {
|
|||
bool styled_output; /* enable fancy output style detection */
|
||||
long ms_per_transfer; /* start next transfer after (at least) this
|
||||
many milliseconds */
|
||||
char *ssl_sessions; /* file to load/save SSL session tickets */
|
||||
#ifdef DEBUGBUILD
|
||||
bool test_duphandle;
|
||||
bool test_event_based;
|
||||
|
|
|
|||
|
|
@ -300,6 +300,7 @@ static const struct LongShort aliases[]= {
|
|||
{"ssl-no-revoke", ARG_BOOL, ' ', C_SSL_NO_REVOKE},
|
||||
{"ssl-reqd", ARG_BOOL, ' ', C_SSL_REQD},
|
||||
{"ssl-revoke-best-effort", ARG_BOOL, ' ', C_SSL_REVOKE_BEST_EFFORT},
|
||||
{"ssl-sessions", ARG_FILE, ' ', C_SSL_SESSIONS},
|
||||
{"sslv2", ARG_NONE, '2', C_SSLV2},
|
||||
{"sslv3", ARG_NONE, '3', C_SSLV3},
|
||||
{"stderr", ARG_FILE, ' ', C_STDERR},
|
||||
|
|
@ -2470,6 +2471,12 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
|
|||
if(feature_ssl)
|
||||
config->ssl_revoke_best_effort = TRUE;
|
||||
break;
|
||||
case C_SSL_SESSIONS: /* --ssl-sessions */
|
||||
if(feature_ssls_export)
|
||||
err = getstr(&global->ssl_sessions, nextarg, DENY_BLANK);
|
||||
else
|
||||
err = PARAM_LIBCURL_DOESNT_SUPPORT;
|
||||
break;
|
||||
case C_TCP_FASTOPEN: /* --tcp-fastopen */
|
||||
config->tcp_fastopen = TRUE;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@ typedef enum {
|
|||
C_SSL_NO_REVOKE,
|
||||
C_SSL_REQD,
|
||||
C_SSL_REVOKE_BEST_EFFORT,
|
||||
C_SSL_SESSIONS,
|
||||
C_SSLV2,
|
||||
C_SSLV3,
|
||||
C_STDERR,
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ bool feature_ssl = FALSE;
|
|||
bool feature_tls_srp = FALSE;
|
||||
bool feature_zstd = FALSE;
|
||||
bool feature_ech = FALSE;
|
||||
bool feature_ssls_export = FALSE;
|
||||
|
||||
static struct feature_name_presentp {
|
||||
const char *feature_name;
|
||||
|
|
@ -115,6 +116,7 @@ static struct feature_name_presentp {
|
|||
{"SPNEGO", &feature_spnego, CURL_VERSION_SPNEGO},
|
||||
{"SSL", &feature_ssl, CURL_VERSION_SSL},
|
||||
{"SSPI", NULL, CURL_VERSION_SSPI},
|
||||
{"SSLS-EXPORT", &feature_ssls_export, 0},
|
||||
{"threadsafe", NULL, CURL_VERSION_THREADSAFE},
|
||||
{"TLS-SRP", &feature_tls_srp, CURL_VERSION_TLSAUTH_SRP},
|
||||
{"TrackMemory", NULL, CURL_VERSION_CURLDEBUG},
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ extern bool feature_ssl;
|
|||
extern bool feature_tls_srp;
|
||||
extern bool feature_zstd;
|
||||
extern bool feature_ech;
|
||||
extern bool feature_ssls_export;
|
||||
|
||||
CURLcode get_libcurl_info(void);
|
||||
const char *proto_token(const char *proto);
|
||||
|
|
|
|||
|
|
@ -715,6 +715,9 @@ const struct helptxt helptext[] = {
|
|||
{" --ssl-revoke-best-effort",
|
||||
"Ignore missing cert CRL dist points",
|
||||
CURLHELP_TLS},
|
||||
{" --ssl-sessions <filename>",
|
||||
"Load/save SSL session tickets from/to this file",
|
||||
CURLHELP_TLS},
|
||||
{"-2, --sslv2",
|
||||
"SSLv2",
|
||||
CURLHELP_DEPRECATED},
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@
|
|||
#include "tool_parsecfg.h"
|
||||
#include "tool_setopt.h"
|
||||
#include "tool_sleep.h"
|
||||
#include "tool_ssls.h"
|
||||
#include "tool_urlglob.h"
|
||||
#include "tool_util.h"
|
||||
#include "tool_writeout.h"
|
||||
|
|
@ -3232,18 +3233,31 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[])
|
|||
curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL);
|
||||
curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_HSTS);
|
||||
|
||||
/* Get the required arguments for each operation */
|
||||
do {
|
||||
result = get_args(operation, count++);
|
||||
if(global->ssl_sessions && feature_ssls_export)
|
||||
result = tool_ssls_load(global, global->first, share,
|
||||
global->ssl_sessions);
|
||||
|
||||
operation = operation->next;
|
||||
} while(!result && operation);
|
||||
if(!result) {
|
||||
/* Get the required arguments for each operation */
|
||||
do {
|
||||
result = get_args(operation, count++);
|
||||
|
||||
/* Set the current operation pointer */
|
||||
global->current = global->first;
|
||||
operation = operation->next;
|
||||
} while(!result && operation);
|
||||
|
||||
/* now run! */
|
||||
result = run_all_transfers(global, share, result);
|
||||
/* Set the current operation pointer */
|
||||
global->current = global->first;
|
||||
|
||||
/* now run! */
|
||||
result = run_all_transfers(global, share, result);
|
||||
|
||||
if(global->ssl_sessions && feature_ssls_export) {
|
||||
CURLcode r2 = tool_ssls_save(global, global->first, share,
|
||||
global->ssl_sessions);
|
||||
if(r2 && !result)
|
||||
result = r2;
|
||||
}
|
||||
}
|
||||
|
||||
curl_share_cleanup(share);
|
||||
if(global->libcurl) {
|
||||
|
|
|
|||
222
src/tool_ssls.c
Normal file
222
src/tool_ssls.c
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "curlx.h"
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_cb_dbg.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_setopt.h"
|
||||
#include "tool_ssls.h"
|
||||
#include "dynbuf.h"
|
||||
#include "curl_base64.h"
|
||||
#include "curl_get_line.h"
|
||||
|
||||
/* The maximum line length for an ecoded session ticket */
|
||||
#define MAX_SSLS_LINE (64 * 1024)
|
||||
|
||||
|
||||
static CURLcode tool_ssls_easy(struct GlobalConfig *global,
|
||||
struct OperationConfig *config,
|
||||
CURLSH *share, CURL **peasy)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
*peasy = curl_easy_init();
|
||||
if(!*peasy)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
result = curl_easy_setopt(*peasy, CURLOPT_SHARE, share);
|
||||
if(global->tracetype != TRACE_NONE) {
|
||||
my_setopt(*peasy, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
|
||||
my_setopt(*peasy, CURLOPT_DEBUGDATA, config);
|
||||
my_setopt(*peasy, CURLOPT_VERBOSE, 1L);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode tool_ssls_load(struct GlobalConfig *global,
|
||||
struct OperationConfig *config,
|
||||
CURLSH *share, const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
CURL *easy = NULL;
|
||||
struct dynbuf buf;
|
||||
unsigned char *shmac = NULL, *sdata = NULL;
|
||||
char *c, *line, *end;
|
||||
size_t shmac_len, sdata_len;
|
||||
CURLcode r = CURLE_OK;
|
||||
int i, imported;
|
||||
|
||||
curlx_dyn_init(&buf, MAX_SSLS_LINE);
|
||||
fp = fopen(filename, FOPEN_READTEXT);
|
||||
if(!fp) { /* ok if it does not exist */
|
||||
notef(global, "SSL session file does not exist (yet?): %s", filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = tool_ssls_easy(global, config, share, &easy);
|
||||
if(r)
|
||||
goto out;
|
||||
|
||||
i = imported = 0;
|
||||
while(Curl_get_line(&buf, fp)) {
|
||||
++i;
|
||||
curl_free(shmac);
|
||||
curl_free(sdata);
|
||||
line = Curl_dyn_ptr(&buf);
|
||||
while(*line && ISBLANK(*line))
|
||||
line++;
|
||||
if(*line == '#')
|
||||
/* skip commented lines */
|
||||
continue;
|
||||
|
||||
c = memchr(line, ':', strlen(line));
|
||||
if(!c) {
|
||||
warnf(global, "unrecognized line %d in ssl session file %s",
|
||||
i, filename);
|
||||
continue;
|
||||
}
|
||||
*c = '\0';
|
||||
r = curlx_base64_decode(line, &shmac, &shmac_len);
|
||||
if(r) {
|
||||
warnf(global, "invalid shmax base64 encoding in line %d", i);
|
||||
continue;
|
||||
}
|
||||
line = c + 1;
|
||||
end = line + strlen(line) - 1;
|
||||
while((end > line) && (*end == '\n' || *end == '\r' || ISBLANK(*line))) {
|
||||
*end = '\0';
|
||||
--end;
|
||||
}
|
||||
r = curlx_base64_decode(line, &sdata, &sdata_len);
|
||||
if(r) {
|
||||
warnf(global, "invalid sdata base64 encoding in line %d: %s", i, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = curl_easy_ssls_import(easy, NULL, shmac, shmac_len, sdata, sdata_len);
|
||||
if(r) {
|
||||
warnf(global, "import of session from line %d rejected(%d)", i, r);
|
||||
continue;
|
||||
}
|
||||
++imported;
|
||||
}
|
||||
r = CURLE_OK;
|
||||
|
||||
out:
|
||||
if(easy)
|
||||
curl_easy_cleanup(easy);
|
||||
if(fp)
|
||||
fclose(fp);
|
||||
curlx_dyn_free(&buf);
|
||||
curl_free(shmac);
|
||||
curl_free(sdata);
|
||||
return r;
|
||||
}
|
||||
|
||||
struct tool_ssls_ctx {
|
||||
struct GlobalConfig *global;
|
||||
FILE *fp;
|
||||
int exported;
|
||||
};
|
||||
|
||||
static CURLcode tool_ssls_exp(CURL *easy, void *userptr,
|
||||
const char *session_key,
|
||||
const unsigned char *shmac, size_t shmac_len,
|
||||
const unsigned char *sdata, size_t sdata_len,
|
||||
curl_off_t valid_until, int ietf_tls_id,
|
||||
const char *alpn, size_t earlydata_max)
|
||||
{
|
||||
struct tool_ssls_ctx *ctx = userptr;
|
||||
char *enc = NULL;
|
||||
size_t enc_len;
|
||||
CURLcode r;
|
||||
|
||||
(void)easy;
|
||||
(void)valid_until;
|
||||
(void)ietf_tls_id;
|
||||
(void)alpn;
|
||||
(void)earlydata_max;
|
||||
if(!ctx->exported)
|
||||
fputs("# Your SSL session cache. https://curl.se/docs/ssl-sessions.html\n"
|
||||
"# This file was generated by libcurl! Edit at your own risk.\n",
|
||||
ctx->fp);
|
||||
|
||||
r = curlx_base64_encode((const char *)shmac, shmac_len, &enc, &enc_len);
|
||||
if(r)
|
||||
goto out;
|
||||
r = CURLE_WRITE_ERROR;
|
||||
if(enc_len != fwrite(enc, 1, enc_len, ctx->fp))
|
||||
goto out;
|
||||
if(EOF == fputc(':', ctx->fp))
|
||||
goto out;
|
||||
curl_free(enc);
|
||||
r = curlx_base64_encode((const char *)sdata, sdata_len, &enc, &enc_len);
|
||||
if(r)
|
||||
goto out;
|
||||
r = CURLE_WRITE_ERROR;
|
||||
if(enc_len != fwrite(enc, 1, enc_len, ctx->fp))
|
||||
goto out;
|
||||
if(EOF == fputc('\n', ctx->fp))
|
||||
goto out;
|
||||
r = CURLE_OK;
|
||||
ctx->exported++;
|
||||
out:
|
||||
if(r)
|
||||
warnf(ctx->global, "Warning: error saving SSL session for '%s': %d",
|
||||
session_key, r);
|
||||
curl_free(enc);
|
||||
return r;
|
||||
}
|
||||
|
||||
CURLcode tool_ssls_save(struct GlobalConfig *global,
|
||||
struct OperationConfig *config,
|
||||
CURLSH *share, const char *filename)
|
||||
{
|
||||
struct tool_ssls_ctx ctx;
|
||||
CURL *easy = NULL;
|
||||
CURLcode r = CURLE_OK;
|
||||
|
||||
ctx.global = global;
|
||||
ctx.exported = 0;
|
||||
ctx.fp = fopen(filename, FOPEN_WRITETEXT);
|
||||
if(!ctx.fp) {
|
||||
warnf(global, "Warning: Failed to create SSL session file %s", filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = tool_ssls_easy(global, config, share, &easy);
|
||||
if(r)
|
||||
goto out;
|
||||
|
||||
r = curl_easy_ssls_export(easy, tool_ssls_exp, &ctx);
|
||||
|
||||
out:
|
||||
if(easy)
|
||||
curl_easy_cleanup(easy);
|
||||
if(ctx.fp)
|
||||
fclose(ctx.fp);
|
||||
return r;
|
||||
}
|
||||
37
src/tool_ssls.h
Normal file
37
src/tool_ssls.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef HEADER_CURL_TOOL_SSLS_H
|
||||
#define HEADER_CURL_TOOL_SSLS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_operate.h"
|
||||
|
||||
|
||||
CURLcode tool_ssls_load(struct GlobalConfig *global,
|
||||
struct OperationConfig *config,
|
||||
CURLSH *share, const char *filename);
|
||||
CURLcode tool_ssls_save(struct GlobalConfig *global,
|
||||
struct OperationConfig *config,
|
||||
CURLSH *share, const char *filename);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_SSLS_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue