diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2021-01-30 21:04:18 -0500 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2021-02-01 03:00:51 -0500 |
commit | 0936fe69052c72b204ad575df937a34551b94819 (patch) | |
tree | 5c210dadaeb06c33a7049dba170118844d7f78e1 /src/mod_gnutls.c | |
parent | 2d78182546d5c77a719764d22930e7eada55227e (diff) | |
download | lighttpd-git-0936fe69052c72b204ad575df937a34551b94819.tar.gz |
[mod_gnutls] fix acme-tls/1 challenge bootstrap
parse ALPN in GNUTLS_HOOK_PRE via gnutls_ext_raw_parse()
(does not appear to work when checking in GNUTLS_HOOK_POST)
Diffstat (limited to 'src/mod_gnutls.c')
-rw-r--r-- | src/mod_gnutls.c | 157 |
1 files changed, 80 insertions, 77 deletions
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c index 0732c7b7..82754cd2 100644 --- a/src/mod_gnutls.c +++ b/src/mod_gnutls.c @@ -1230,7 +1230,7 @@ mod_gnutls_acme_tls_1 (handler_ctx *hctx) /* check if acme-tls/1 protocol is enabled (path to dir of cert(s) is set)*/ if (buffer_string_is_empty(hctx->conf.ssl_acme_tls_1)) - return 0; /*(should not happen)*/ + return 0; /* check if SNI set server name (required for acme-tls/1 protocol) * and perform simple path checks for no '/' @@ -1313,6 +1313,7 @@ mod_gnutls_acme_tls_1 (handler_ctx *hctx) hctx->acme_tls_1_cred = ssl_cred; /*(save ptr and free later)*/ + gnutls_credentials_clear(hctx->ssl); rc = gnutls_credentials_set(hctx->ssl, GNUTLS_CRD_CERTIFICATE, ssl_cred); if (rc < 0) { elogf(hctx->r->conf.errh, __FILE__, __LINE__, rc, @@ -1321,6 +1322,9 @@ mod_gnutls_acme_tls_1 (handler_ctx *hctx) return rc; } + /*(acme-tls/1 is separate from certificate auth access to website)*/ + gnutls_certificate_server_set_request(hctx->ssl, GNUTLS_CERT_IGNORE); + return GNUTLS_E_SUCCESS; /* 0 */ } @@ -1333,67 +1337,61 @@ enum { }; +/* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids */ static int -mod_gnutls_alpn_select_cb (gnutls_session_t ssl, handler_ctx *hctx) -{ - const int i = 0; - uint8_t proto; - - gnutls_datum_t d = { NULL, 0 }; - if (gnutls_alpn_get_selected_protocol(ssl, &d) < 0) - return 0; /* ignore GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE */ - const char *in = (const char *)d.data; - const int n = (int)d.size; - - switch (n) { - case 2: /* "h2" */ - if (in[i] == 'h' && in[i+1] == '2') { - proto = MOD_GNUTLS_ALPN_H2; - hctx->r->http_version = HTTP_VERSION_2; - break; - } - return 0; - case 8: /* "http/1.1" "http/1.0" */ - if (0 == memcmp(in+i, "http/1.", 7)) { - if (in[i+7] == '1') { - proto = MOD_GNUTLS_ALPN_HTTP11; - break; +mod_gnutls_ALPN (handler_ctx * const hctx, const unsigned char * const in, const unsigned int inlen) +{ + /*(skip first two bytes which should match inlen-2)*/ + for (unsigned int i = 2, n; i < inlen; i += n) { + n = in[i++]; + if (i+n > inlen || 0 == n) break; + + switch (n) { + case 2: /* "h2" */ + if (in[i] == 'h' && in[i+1] == '2') { + if (!hctx->r->conf.h2proto) continue; + hctx->alpn = MOD_GNUTLS_ALPN_H2; + hctx->r->http_version = HTTP_VERSION_2; + return GNUTLS_E_SUCCESS; } - if (in[i+7] == '0') { - proto = MOD_GNUTLS_ALPN_HTTP10; - break; + continue; + case 8: /* "http/1.1" "http/1.0" */ + if (0 == memcmp(in+i, "http/1.", 7)) { + if (in[i+7] == '1') { + hctx->alpn = MOD_GNUTLS_ALPN_HTTP11; + return GNUTLS_E_SUCCESS; + } + if (in[i+7] == '0') { + hctx->alpn = MOD_GNUTLS_ALPN_HTTP10; + return GNUTLS_E_SUCCESS; + } } - } - return 0; - case 10: /* "acme-tls/1" */ - if (0 == memcmp(in+i, "acme-tls/1", 10)) { - int rc = mod_gnutls_acme_tls_1(hctx); - if (0 == rc) { - proto = MOD_GNUTLS_ALPN_ACME_TLS_1; - break; + continue; + case 10: /* "acme-tls/1" */ + if (0 == memcmp(in+i, "acme-tls/1", 10)) { + int rc = mod_gnutls_acme_tls_1(hctx); + if (0 == rc) { + hctx->alpn = MOD_GNUTLS_ALPN_ACME_TLS_1; + return GNUTLS_E_SUCCESS; + } + return rc; } - return rc; + continue; + default: + continue; } - return 0; - default: - return 0; } - hctx->alpn = proto; - return 0; + return GNUTLS_E_SUCCESS; } #endif /* GNUTLS_VERSION_NUMBER >= 0x030200 */ static int -mod_gnutls_SNI(void *ctx, unsigned int tls_id, +mod_gnutls_SNI(handler_ctx * const hctx, const unsigned char *servername, unsigned int len) { - if (tls_id != 0) return 0; - - /* server name */ - /* https://www.gnutls.org/manual/gnutls.html#Virtual-hosts-and-credentials * figure the advertized name - the following hack relies on the fact that * this extension only supports DNS names, and due to a protocol bug cannot @@ -1401,7 +1399,6 @@ mod_gnutls_SNI(void *ctx, unsigned int tls_id, if (len < 5) return 0; len -= 5; servername += 5; - handler_ctx * const hctx = (handler_ctx *) ctx; request_st * const r = hctx->r; buffer_copy_string(&r->uri.scheme, "https"); @@ -1436,21 +1433,20 @@ mod_gnutls_SNI(void *ctx, unsigned int tls_id, static int -mod_gnutls_client_hello_hook_post(gnutls_session_t ssl) -{ - #if GNUTLS_VERSION_NUMBER >= 0x030200 - handler_ctx * const hctx = gnutls_session_get_ptr(ssl); - int rc = mod_gnutls_alpn_select_cb(ssl, hctx); - if (rc < 0) - return rc; - - /* check if acme-tls/1 protocol is enabled (path to dir of cert(s) is set)*/ - if (hctx->alpn == MOD_GNUTLS_ALPN_ACME_TLS_1) { - /*(acme-tls/1 is separate from certificate auth access to website)*/ - gnutls_certificate_server_set_request(ssl, GNUTLS_CERT_IGNORE); - return GNUTLS_E_SUCCESS; /* 0 */ /*(skip further session config below)*/ +mod_gnutls_client_hello_ext_cb(void *ctx, unsigned int tls_id, + const unsigned char *data, unsigned int dlen) +{ + switch (tls_id) { + case 0: /* Server Name */ + return mod_gnutls_SNI((handler_ctx *)ctx, data, dlen); + #if GNUTLS_VERSION_NUMBER >= 0x030200 + case 16: /* ALPN */ + return mod_gnutls_ALPN((handler_ctx *)ctx, data, dlen); + #endif + /*case 35:*/ /* Session Ticket */ + default: + break; } - #endif return GNUTLS_E_SUCCESS; /* 0 */ } @@ -1462,17 +1458,25 @@ mod_gnutls_client_hello_hook(gnutls_session_t ssl, unsigned int htype, const gnutls_datum_t *msg) { /*assert(htype == GNUTLS_HANDSHAKE_CLIENT_HELLO);*/ + /*assert(when == GNUTLS_HOOK_PRE);*/ UNUSED(htype); + UNUSED(when); UNUSED(incoming); - if (when == GNUTLS_HOOK_POST) - return mod_gnutls_client_hello_hook_post(ssl); - handler_ctx * const hctx = gnutls_session_get_ptr(ssl); - #if GNUTLS_VERSION_NUMBER < 0x030600 - gnutls_dh_params_t dh_params = hctx->conf.dh_params; + #if GNUTLS_VERSION_NUMBER >= 0x030200 + /*(do not repeat if acme-tls/1 creds have been set + * and still in handshake (hctx->alpn not unset yet))*/ + if (hctx->alpn == MOD_GNUTLS_ALPN_ACME_TLS_1) + return GNUTLS_E_SUCCESS; /* 0 */ #endif - int rc = gnutls_ext_raw_parse(hctx, mod_gnutls_SNI, msg, + /* ??? why might this be called more than once ??? renegotiation? */ + void *existing_cred = NULL; + if (0 == gnutls_credentials_get(ssl, GNUTLS_CRD_CERTIFICATE, &existing_cred) + && existing_cred) + return GNUTLS_E_SUCCESS; /* 0 */ + + int rc = gnutls_ext_raw_parse(hctx, mod_gnutls_client_hello_ext_cb, msg, GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO); if (rc < 0) { log_error_st *errh = hctx->r->conf.errh; @@ -1501,17 +1505,16 @@ mod_gnutls_client_hello_hook(gnutls_session_t ssl, unsigned int htype, elog(errh, __FILE__, __LINE__, rc, "gnutls_alpn_set_protocols()"); return rc; } - #if 0 - /* XXX: might have to manually process client hello for ALPN "acme-tls/1" - * and handle here (GNUTLS_HOOK_PRE) before setting certificate */ - if (!buffer_string_is_empty(hctx->conf.ssl_acme_tls_1)) { - } - #endif + /*(skip below if creds already set for acme-tls/1 + * via mod_gnutls_client_hello_ext_cb())*/ + if (hctx->alpn == MOD_GNUTLS_ALPN_ACME_TLS_1) + return GNUTLS_E_SUCCESS; /* 0 */ #endif #if 0 /* must enable before GnuTLS client hello hook */ /* GnuTLS returns an error here if TLSv1.3 (? key already set ?) */ /* see mod_gnutls_handle_con_accept() */ + /* future: ? handle in mod_gnutls_client_hello_ext_cb() */ if (hctx->ssl_session_ticket && session_ticket_key.size) { /* XXX: NOT done: parse client hello for session ticket extension * and choose from among multiple keys */ @@ -1550,8 +1553,8 @@ mod_gnutls_client_hello_hook(gnutls_session_t ssl, unsigned int htype, gnutls_certificate_server_set_request(ssl, req); #if GNUTLS_VERSION_NUMBER < 0x030600 - if (dh_params) - gnutls_certificate_set_dh_params(ssl_cred, dh_params); + if (hctx->conf.dh_params) + gnutls_certificate_set_dh_params(ssl_cred, hctx->conf.dh_params); #if GNUTLS_VERSION_NUMBER >= 0x030506 else gnutls_certificate_set_known_dh_params(ssl_cred, GNUTLS_SEC_PARAM_HIGH); @@ -2537,7 +2540,7 @@ CONNECTION_FUNC(mod_gnutls_handle_con_accept) /* generic func replaces gnutls_handshake_set_post_client_hello_function()*/ gnutls_handshake_set_hook_function(hctx->ssl, GNUTLS_HANDSHAKE_CLIENT_HELLO, - GNUTLS_HOOK_BOTH, + GNUTLS_HOOK_PRE, mod_gnutls_client_hello_hook); gnutls_session_set_ptr(hctx->ssl, hctx); |