- Patch for TLS session resumption from Manabu Sonoda,

enable with tls-session-ticket-keys in unbound.conf.


git-svn-id: file:///svn/unbound/trunk@5059 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2019-01-23 09:35:52 +00:00
parent 4e59c8344f
commit 510606dd1c
20 changed files with 3328 additions and 3100 deletions

View file

@ -178,6 +178,9 @@
/* Define to 1 if you have the <event.h> header file. */
#undef HAVE_EVENT_H
/* Define to 1 if you have the `EVP_aes_256_cbc' function. */
#undef HAVE_EVP_AES_256_CBC
/* Define to 1 if you have the `EVP_cleanup' function. */
#undef HAVE_EVP_CLEANUP
@ -187,6 +190,9 @@
/* Define to 1 if you have the `EVP_dss1' function. */
#undef HAVE_EVP_DSS1
/* Define to 1 if you have the `EVP_EncryptInit_ex' function. */
#undef HAVE_EVP_ENCRYPTINIT_EX
/* Define to 1 if you have the `EVP_MD_CTX_new' function. */
#undef HAVE_EVP_MD_CTX_NEW
@ -259,6 +265,9 @@
/* Define to 1 if you have the <hiredis/hiredis.h> header file. */
#undef HAVE_HIREDIS_HIREDIS_H
/* Define to 1 if you have the `HMAC_Init_ex' function. */
#undef HAVE_HMAC_INIT_EX
/* If you have HMAC_Update */
#undef HAVE_HMAC_UPDATE
@ -457,6 +466,9 @@
/* Define to 1 if you have the `SSL_CTX_set_security_level' function. */
#undef HAVE_SSL_CTX_SET_SECURITY_LEVEL
/* Define to 1 if you have the `SSL_CTX_set_tlsext_ticket_key_cb' function. */
#undef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_CB
/* Define to 1 if you have the `SSL_get0_peername' function. */
#undef HAVE_SSL_GET0_PEERNAME

2
configure vendored
View file

@ -17993,7 +17993,7 @@ fi
done
for ac_func in OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify
for ac_func in OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_tlsext_ticket_key_cb EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

View file

@ -781,7 +781,7 @@ else
AC_MSG_RESULT([no])
fi
AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify])
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_tlsext_ticket_key_cb EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex])
# these check_funcs need -lssl
BAKLIBS="$LIBS"

View file

@ -973,6 +973,8 @@ print_ext(RES* ssl, struct ub_stats_info* s)
(unsigned long)s->svr.qtcp_outgoing)) return 0;
if(!ssl_printf(ssl, "num.query.tls"SQ"%lu\n",
(unsigned long)s->svr.qtls)) return 0;
if(!ssl_printf(ssl, "num.query.tls.resume"SQ"%lu\n",
(unsigned long)s->svr.qtls_resume)) return 0;
if(!ssl_printf(ssl, "num.query.ipv6"SQ"%lu\n",
(unsigned long)s->svr.qipv6)) return 0;
/* flags */

View file

@ -66,6 +66,9 @@
#ifdef CLIENT_SUBNET
#include "edns-subnet/subnetmod.h"
#endif
#ifdef HAVE_SSL
#include <openssl/ssl.h>
#endif
/** add timers and the values do not overflow or become negative */
static void
@ -414,6 +417,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
total->svr.qtcp += a->svr.qtcp;
total->svr.qtcp_outgoing += a->svr.qtcp_outgoing;
total->svr.qtls += a->svr.qtls;
total->svr.qtls_resume += a->svr.qtls_resume;
total->svr.qipv6 += a->svr.qipv6;
total->svr.qbit_QR += a->svr.qbit_QR;
total->svr.qbit_AA += a->svr.qbit_AA;
@ -470,8 +474,13 @@ void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
stats->qopcode[ LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ]++;
if(c->type != comm_udp) {
stats->qtcp++;
if(c->ssl != NULL)
if(c->ssl != NULL) {
stats->qtls++;
#ifdef HAVE_SSL
if(SSL_session_reused(c->ssl))
stats->qtls_resume++;
#endif
}
}
if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen))
stats->qipv6++;

View file

@ -443,6 +443,11 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
}
}
#endif
if(cfg->tls_session_ticket_keys) {
if(!listen_sslctx_setup_ticket_keys(daemon->listen_sslctx, cfg->tls_session_ticket_keys)) {
fatal_exit("could not set session ticket SSL_CTX");
}
}
}
if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL,
cfg->tls_cert_bundle, cfg->tls_win_cert)))

View file

@ -4,6 +4,8 @@
- Fixes for the patch, and man page entry.
- Fix configure to detect SSL_CTX_set_ciphersuites, for better
library compatibility when compiling.
- Patch for TLS session resumption from Manabu Sonoda,
enable with tls-session-ticket-keys in unbound.conf.
22 January 2018: Wouter
- Fix space calculation for tcp req buffer size.

View file

@ -720,6 +720,14 @@ server:
# cipher setting for TLSv1.3
# tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
# Add the secret file for TLS Session Ticket.
# Secret file must be 80 bytes of random data.
# First key use to encrypt and decrypt TLS session tickets.
# Other keys use to decrypt only.
# requires restart to take effect.
# tls-session-ticket-keys: "path/to/secret_file1"
# tls-session-ticket-keys: "path/to/secret_file2"
# request upstream over TLS (with plain DNS inside the TLS stream).
# Default is no. Can be turned on and off with unbound-control.
# tls-upstream: no

View file

@ -682,6 +682,8 @@ struct ub_server_stats {
long long qtcp_outgoing;
/** number of queries over (DNS over) TLS */
long long qtls;
/** number of TLS connection resume */
long long qtls_resume;
/** number of queries over IPv6 */
long long qipv6;
/** number of queries with QR bit */

View file

@ -330,6 +330,7 @@ static void print_extended(struct ub_stats_info* s)
PR_UL("num.query.tcp", s->svr.qtcp);
PR_UL("num.query.tcpout", s->svr.qtcp_outgoing);
PR_UL("num.query.tls", s->svr.qtls);
PR_UL("num.query.tls_resume", s->svr.qtls_resume);
PR_UL("num.query.ipv6", s->svr.qipv6);
/* flags */

View file

@ -13,7 +13,8 @@ server:
ssl-port: @SERVPORT@
ssl-service-key: "unbound_server.key"
ssl-service-pem: "unbound_server.pem"
tls-session-ticket-keys: "ticket1.dat"
tls-session-ticket-keys: "ticket2.dat"
# no other queries should reach here.
forward-zone:
name: "."

View file

@ -487,6 +487,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STRLIST("additional-tls-port:", tls_additional_port)
else S_STRLIST("tls-additional-ports:", tls_additional_port)
else S_STRLIST("tls-additional-port:", tls_additional_port)
else S_STRLIST("tls-session-ticket-keys:", tls_session_ticket_keys)
else S_STR("tls-ciphers:", tls_ciphers)
else S_STR("tls-ciphersuites:", tls_ciphersuites)
else S_YNO("interface-automatic:", if_automatic)
@ -926,6 +927,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_STR(opt, "tls-cert-bundle", tls_cert_bundle)
else O_YNO(opt, "tls-win-cert", tls_win_cert)
else O_LST(opt, "tls-additional-port", tls_additional_port)
else O_LST(opt, "tls-session-ticket-keys", tls_session_ticket_keys)
else O_STR(opt, "tls-ciphers", tls_ciphers)
else O_STR(opt, "tls-ciphersuites", tls_ciphersuites)
else O_YNO(opt, "use-systemd", use_systemd)
@ -1362,6 +1364,7 @@ config_delete(struct config_file* cfg)
free(cfg->ssl_service_pem);
free(cfg->tls_cert_bundle);
config_delstrlist(cfg->tls_additional_port);
config_delstrlist(cfg->tls_session_ticket_keys);
free(cfg->tls_ciphers);
free(cfg->tls_ciphersuites);
free(cfg->log_identity);

View file

@ -120,6 +120,8 @@ struct config_file {
int tls_win_cert;
/** additional tls ports */
struct config_strlist* tls_additional_port;
/** secret key used to encrypt and decrypt TLS session ticket -**/
struct config_strlist* tls_session_ticket_keys;
/** TLS ciphers */
char* tls_ciphers;
/** TLS chiphersuites (TLSv1.3) */

File diff suppressed because it is too large Load diff

View file

@ -245,6 +245,7 @@ additional-ssl-port{COLON} { YDVAR(1, VAR_TLS_ADDITIONAL_PORT) }
additional-tls-port{COLON} { YDVAR(1, VAR_TLS_ADDITIONAL_PORT) }
tls-additional-ports{COLON} { YDVAR(1, VAR_TLS_ADDITIONAL_PORT) }
tls-additional-port{COLON} { YDVAR(1, VAR_TLS_ADDITIONAL_PORT) }
tls-session-ticket-keys{COLON} { YDVAR(1, VAR_TLS_SESSION_TICKET_KEYS) }
tls-ciphers{COLON} { YDVAR(1, VAR_TLS_CIPHERS) }
tls-ciphersuites{COLON} { YDVAR(1, VAR_TLS_CIPHERSUITES) }
use-systemd{COLON} { YDVAR(1, VAR_USE_SYSTEMD) }

File diff suppressed because it is too large Load diff

View file

@ -307,7 +307,8 @@ extern int yydebug;
VAR_LOG_TAG_QUERYREPLY = 517,
VAR_STREAM_WAIT_SIZE = 518,
VAR_TLS_CIPHERS = 519,
VAR_TLS_CIPHERSUITES = 520
VAR_TLS_CIPHERSUITES = 520,
VAR_TLS_SESSION_TICKET_KEYS = 521
};
#endif
/* Tokens. */
@ -574,6 +575,7 @@ extern int yydebug;
#define VAR_STREAM_WAIT_SIZE 518
#define VAR_TLS_CIPHERS 519
#define VAR_TLS_CIPHERSUITES 520
#define VAR_TLS_SESSION_TICKET_KEYS 521
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@ -584,7 +586,7 @@ union YYSTYPE
char* str;
#line 588 "util/configparser.h" /* yacc.c:1909 */
#line 590 "util/configparser.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;

View file

@ -166,6 +166,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY
%token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY
%token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES
%token VAR_TLS_SESSION_TICKET_KEYS
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -265,7 +266,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_fast_server_permil | server_fast_server_num | server_tls_win_cert |
server_tcp_connection_limit | server_log_servfail | server_deny_any |
server_unknown_server_time_limit | server_log_tag_queryreply |
server_stream_wait_size | server_tls_ciphers | server_tls_ciphersuites
server_stream_wait_size | server_tls_ciphers |
server_tls_ciphersuites | server_tls_session_ticket_keys
;
stubstart: VAR_STUB_ZONE
{
@ -834,6 +836,14 @@ server_tls_ciphersuites: VAR_TLS_CIPHERSUITES STRING_ARG
cfg_parser->cfg->tls_ciphersuites = $2;
}
;
server_tls_session_ticket_keys: VAR_TLS_SESSION_TICKET_KEYS STRING_ARG
{
OUTYY(("P(server_tls_session_ticket_keys:%s)\n", $2));
if(!cfg_strlist_insert(&cfg_parser->cfg->tls_session_ticket_keys,
$2))
yyerror("out of memory");
}
;
server_use_systemd: VAR_USE_SYSTEMD STRING_ARG
{
OUTYY(("P(server_use_systemd:%s)\n", $2));

View file

@ -48,6 +48,7 @@
#include <fcntl.h>
#ifdef HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
#include <openssl/evp.h>
#endif
#ifdef HAVE_OPENSSL_ERR_H
#include <openssl/err.h>
@ -70,6 +71,12 @@ int RRSET_ROUNDROBIN = 0;
/** log tag queries with name instead of 'info' for filtering */
int LOG_TAG_QUERYREPLY = 0;
static struct tls_session_ticket_key {
unsigned char *key_name;
unsigned char *aes_key;
unsigned char *hmac_key;
} *ticket_keys;
/* returns true is string addr is an ip6 specced address */
int
str_is_ip6(const char* str)
@ -1090,3 +1097,106 @@ void ub_openssl_lock_delete(void)
#endif /* OPENSSL_THREADS */
}
int listen_sslctx_setup_ticket_keys(void* sslctx, struct config_strlist* tls_session_ticket_keys) {
#ifdef HAVE_SSL
int s = 1;
struct config_strlist* p;
struct tls_session_ticket_key *keys;
for(p = tls_session_ticket_keys; p; p = p->next) {
s++;
}
keys = calloc(s, sizeof(struct tls_session_ticket_key));
memset(keys, 0, sizeof(keys));
ticket_keys = keys;
for(p = tls_session_ticket_keys; p; p = p->next) {
unsigned char *data = (unsigned char *)malloc(80);
FILE *f = fopen(p->str, "r");
if(!f) {
log_err("could not read tls-session-ticket-key %s: %s", p->str, strerror(errno));
return 0;
}
int n = fread(data, 1, 80, f);
fclose(f);
if(n != 80) {
log_err("tls-session-ticket-key %s is %d bytes, must be 80 bytes", p->str, n);
return 0;
}
verbose(VERB_OPS, "read tls-session-ticket-key: %s", p->str);
keys->key_name = data;
keys->aes_key = data + 16;
keys->hmac_key = data + 48;
keys++;
}
keys->key_name = NULL;
if(SSL_CTX_set_tlsext_ticket_key_cb(sslctx, tls_session_ticket_key_cb) == 0) {
log_err("not support TLS session ticket");
return 0;
}
return 1;
#else
return 0;
#endif
}
int tls_session_ticket_key_cb(void *sslctx, unsigned char* key_name,unsigned char* iv, void *evp_sctx, void *hmac_ctx, int enc)
{
#ifdef HAVE_SSL
const EVP_MD *digest;
const EVP_CIPHER *cipher;
int evp_chiper_length;
digest = EVP_sha256();
cipher = EVP_aes_256_cbc();
evp_chiper_length = EVP_CIPHER_iv_length(cipher);
if( enc == 1 ) {
// encrypt
verbose(VERB_CLIENT, "start session encrypt");
memcpy(key_name, ticket_keys->key_name, 16);
if (RAND_bytes(iv, evp_chiper_length) != 1) {
verbose(VERB_CLIENT, "RAND_bytes failed");
return -1;
}
if (EVP_EncryptInit_ex(evp_sctx, cipher, NULL, ticket_keys->aes_key, iv) != 1) {
verbose(VERB_CLIENT, "EVP_EncryptInit_ex failed");
return -1;
}
if (HMAC_Init_ex(hmac_ctx, ticket_keys->hmac_key, 32, digest, NULL) != 1) {
verbose(VERB_CLIENT, "HMAC_Init_ex failed");
return -1;
}
return 1;
} else if (enc == 0) {
//decrypt
verbose(VERB_CLIENT, "start session decrypt");
struct tls_session_ticket_key *key;
for(key = ticket_keys; key->key_name != NULL; key++) {
if (!memcmp(key_name, key->key_name, 16)) {
verbose(VERB_CLIENT, "Found session_key");
break;
}
}
if(key->key_name == NULL) {
verbose(VERB_CLIENT, "Not found session_key");
return 0;
}
if (HMAC_Init_ex(hmac_ctx, key->hmac_key, 32, digest, NULL) != 1) {
verbose(VERB_CLIENT, "HMAC_Init_ex failed");
return -1;
}
if (EVP_DecryptInit_ex(evp_sctx, cipher, NULL, key->aes_key, iv) != 1) {
log_err("EVP_DecryptInit_ex failed");
return -1;
}
return (key == ticket_keys) ? 1 : 2;
}
return -1;
#else
return 0;
#endif
}

View file

@ -42,6 +42,7 @@
#ifndef NET_HELP_H
#define NET_HELP_H
#include "util/log.h"
#include "util/config_file.h"
struct sock_list;
struct regional;
@ -437,4 +438,24 @@ int ub_openssl_lock_init(void);
*/
void ub_openssl_lock_delete(void);
/**
* setup TLS session ticket
* @param sslctx: the SSL_CTX to use (from connect_sslctx_create())
* @param tls_session_ticket_keys: TLS ticket secret filenames
* @return false on failure (alloc failure).
*/
int listen_sslctx_setup_ticket_keys(void* sslctx, struct config_strlist* tls_session_ticket_keys);
/**
* callback TLS session ticket encrypt and decrypt
* @param s: the SSL_CTX to use (from connect_sslctx_create())
* @param key_name: secret name
* @param iv:
* @param evp_ctx:
* @param hmac_ctx:
* @param enc: 1 is encrypt, 0 is decrypt
* @return false on failure (alloc failure).
*/
int tls_session_ticket_key_cb(void *s, unsigned char* key_name,unsigned char* iv, void *evp_ctx, void *hmac_ctx, int enc);
#endif /* NET_HELP_H */