[TODO] 支持TLS 1.2的PSK加密套件
- Dominant language
- C
- Stars
- 13.4k
- Forks
- 2.5k
- Avg merge
- 4h 39m
- Merged PRs (30d)
- 11
Description
```
diff -u -r nginx-1.15.10-ori/runtime/conf/nginx.conf nginx-1.15.10/runtime/conf/nginx.conf
--- nginx-1.15.10-ori/runtime/conf/nginx.conf 2019-04-12 10:07:45.219323855 +0800
+++ nginx-1.15.10/runtime/conf/nginx.conf 2019-04-12 11:31:03.655450661 +0800
@@ -33,8 +33,19 @@
#gzip on;
server {
- listen 80;
- server_name localhost;
+ listen 8443 ssl;
+ server_name _;
+
+ ssl_protocols TLSv1.2;
+ ssl_ciphers PSK;
+ ssl_certificate /home/cfsego/Downloads/projects/ca/server.crt;
+ ssl_certificate_key /home/cfsego/Downloads/projects/ca/server.key;
+ ssl_psk_hash_max_size 16;
+ ssl_psk_hash_bucket_size 16;
+ ssl_use_psk {
+ TEST 1a;
+ TEST1 2a;
+ }
#charset koi8-r;
diff -u -r nginx-1.15.10-ori/src/event/ngx_event_openssl.c nginx-1.15.10/src/event/ngx_event_openssl.c
--- nginx-1.15.10-ori/src/event/ngx_event_openssl.c 2019-03-26 22:06:55.000000000 +0800
+++ nginx-1.15.10/src/event/ngx_event_openssl.c 2019-04-12 11:21:51.503436654 +0800
@@ -134,6 +134,7 @@
int ngx_ssl_next_certificate_index;
int ngx_ssl_certificate_name_index;
int ngx_ssl_stapling_index;
+int ngx_ssl_psk_context_index;
ngx_int_t
@@ -245,6 +246,15 @@
return NGX_ERROR;
}
+ ngx_ssl_psk_context_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
+ NULL);
+
+ if (ngx_ssl_psk_context_index == -1) {
+ ngx_ssl_error(NGX_LOG_ALERT, log, 0,
+ "SSL_CTX_get_ex_new_index() failed");
+ return NGX_ERROR;
+ }
+
return NGX_OK;
}
@@ -1470,6 +1480,59 @@
}
+static unsigned int
+ngx_psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk,
+ unsigned int max_psk_len)
+{
+ size_t len;
+ u_char *low;
+ ngx_str_t *value;
+ ngx_uint_t key;
+ ngx_connection_t *c;
+ ngx_hash_combined_t *map;
+
+ map = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl), ngx_ssl_psk_context_index);
+ c = SSL_get_ex_data(ssl, ngx_ssl_connection_index);
+
+ len = ngx_strlen(identity);
+
+ if (len) {
+ low = ngx_pnalloc(c->pool, len);
+ if (low == NULL) {
+ return 0;
+ }
+
+ } else {
+ low = NULL;
+ }
+
+ key = ngx_hash_strlow(low, (u_char *) identity, len);
+
+ value = ngx_hash_find_combined(map, key, low, len);
+ if (value == NULL) {
+ return 0;
+ }
+
+ if (value->len > max_psk_len) {
+ return 0;
+ }
+
+ ngx_memcpy(psk, value->data, value->len);
+ return value->len;
+}
+
+
+ngx_int_t
+ngx_ssl_use_psk(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_hash_combined_t *psk_map)
+{
+ if (!SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_psk_context_index, psk_map)) {
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
ngx_int_t
ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable)
{
@@ -1509,6 +1572,7 @@
ngx_int_t
ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
{
+ void *use_psk;
ngx_ssl_connection_t *sc;
sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t));
@@ -1539,6 +1603,11 @@
return NGX_ERROR;
}
+ use_psk = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_psk_context_index);
+ if (use_psk) {
+ SSL_set_psk_server_callback(sc->connection, ngx_psk_server_callback);
+ }
+
if (flags & NGX_SSL_CLIENT) {
SSL_set_connect_state(sc->connection);
diff -u -r nginx-1.15.10-ori/src/event/ngx_event_openssl.h nginx-1.15.10/src/event/ngx_event_openssl.h
--- nginx-1.15.10-ori/src/event/ngx_event_openssl.h 2019-03-26 22:06:55.000000000 +0800
+++ nginx-1.15.10/src/event/ngx_event_openssl.h 2019-04-11 16:37:05.469724589 +0800
@@ -263,6 +263,8 @@
ngx_int_t ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
+ngx_int_t ngx_ssl_use_psk(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_hash_combined_t *psk_map);
ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size);
diff -u -r nginx-1.15.10-ori/src/http/modules/ngx_http_ssl_module.c nginx-1.15.10/src/http/modules/ngx_http_ssl_module.c
--- nginx-1.15.10-ori/src/http/modules/ngx_http_ssl_module.c 2019-03-26 22:06:55.000000000 +0800
+++ nginx-1.15.10/src/http/modules/ngx_http_ssl_module.c 2019-04-12 10:09:53.735327116 +0800
@@ -50,6 +50,9 @@
void *conf);
static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_ssl_psk_block(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_ssl_psk(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf);
@@ -249,6 +252,27 @@
offsetof(ngx_http_ssl_srv_conf_t, early_data),
NULL },
+ { ngx_string("ssl_use_psk"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
+ ngx_http_ssl_psk_block,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("ssl_psk_hash_max_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_ssl_srv_conf_t, psk_hash_max_size),
+ NULL },
+
+ { ngx_string("ssl_psk_hash_bucket_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_ssl_srv_conf_t, psk_hash_bucket_size),
+ NULL },
+
ngx_null_command
};
@@ -356,9 +380,170 @@
};
+typedef struct {
+ ngx_hash_keys_arrays_t keys;
+} ngx_http_ssl_psk_conf_ctx_t;
+
+
static ngx_str_t ngx_http_ssl_sess_id_ctx = ngx_string("HTTP");
+static char *
+ngx_http_ssl_psk_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_ssl_srv_conf_t *sscf = conf;
+
+ char *rv;
+ ngx_conf_t save;
+ ngx_pool_t *pool;
+ ngx_hash_init_t hash;
+ ngx_http_ssl_psk_conf_ctx_t ctx;
+
+ if (sscf->psk_hash_max_size == NGX_CONF_UNSET_UINT) {
+ sscf->psk_hash_max_size = 2048;
+ }
+
+ if (sscf->psk_hash_bucket_size == NGX_CONF_UNSET_UINT) {
+ sscf->psk_hash_bucket_size = ngx_cacheline_size;
+
+ } else {
+ sscf->psk_hash_bucket_size = ngx_align(sscf->psk_hash_bucket_size,
+ ngx_cacheline_size);
+ }
+
+ sscf->psk_map = ngx_pcalloc(cf->pool, sizeof(ngx_hash_combined_t));
+ if (sscf->psk_map == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
+ if (pool == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ctx.keys.pool = cf->pool;
+ ctx.keys.temp_pool = pool;
+
+ if (ngx_hash_keys_array_init(&ctx.keys, NGX_HASH_LARGE) != NGX_OK) {
+ ngx_destroy_pool(pool);
+ return NGX_CONF_ERROR;
+ }
+
+ save = *cf;
+ cf->pool = pool;
+ cf->ctx = &ctx;
+ cf->handler = ngx_http_ssl_psk;
+ cf->handler_conf = conf;
+
+ rv = ngx_conf_parse(cf, NULL);
+
+ *cf = save;
+
+ if (rv != NGX_CONF_OK) {
+ ngx_destroy_pool(pool);
+ return rv;
+ }
+
+ hash.key = ngx_hash_key_lc;
+ hash.max_size = sscf->psk_hash_max_size;
+ hash.bucket_size = sscf->psk_hash_bucket_size;
+ hash.name = "psk_hash";
+ hash.pool = cf->pool;
+
+ if (ctx.keys.keys.nelts) {
+ hash.hash = &sscf->psk_map->hash;
+ hash.temp_pool = NULL;
+
+ if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts)
+ != NGX_OK)
+ {
+ ngx_destroy_pool(pool);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ ngx_destroy_pool(pool);
+
+ return rv;
+}
+
+
+static ngx_int_t
+ngx_hexstr2buf(ngx_pool_t *pool, ngx_str_t *hex, ngx_str_t *buf)
+{
+ u_char *p, *p_buf;
+ ngx_int_t rc;
+
+ if (hex->len % 2 != 0) {
+ return NGX_ERROR;
+ }
+
+ buf->len = hex->len / 2;
+ p_buf = ngx_pnalloc(pool, buf->len);
+ if (p_buf == NULL) {
+ return NGX_ERROR;
+ }
+ buf->data = p_buf;
+
+ for (p = hex->data; p < hex->data + hex->len; p += 2) {
+ rc = ngx_hextoi(p, 2);
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+ *p_buf = (u_char) rc;
+ p_buf++;
+ }
+
+ return NGX_OK;
+}
+
+
+static char *
+ngx_http_ssl_psk(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
+{
+ ngx_int_t rv;
+ ngx_str_t *value;
+ ngx_http_ssl_psk_conf_ctx_t *ctx;
+ ngx_str_t *val;
+
+ ctx = cf->ctx;
+
+ value = cf->args->elts;
+
+ if (cf->args->nelts != 2) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid number of the map parameters");
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_strcmp(value[0].data, "include") == 0) {
+ return ngx_conf_include(cf, dummy, conf);
+ }
+
+ val = ngx_palloc(ctx->keys.pool, sizeof(ngx_str_t));
+ if (val == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_hexstr2buf(ctx->keys.pool, &value[1], val) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ rv = ngx_hash_add_key(&ctx->keys, &value[0], val, 0);
+
+ if (rv == NGX_OK) {
+ return NGX_CONF_OK;
+ }
+
+ if (rv == NGX_BUSY) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "conflicting parameter \"%V\"", &value[0]);
+ }
+
+ return NGX_CONF_ERROR;
+}
+
+
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
static int
@@ -563,6 +748,7 @@
* sscf->shm_zone = NULL;
* sscf->stapling_file = { 0, NULL };
* sscf->stapling_responder = { 0, NULL };
+ * sscf->psk_map = NULL;
*/
sscf->enable = NGX_CONF_UNSET;
@@ -580,6 +766,8 @@
sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;
sscf->stapling = NGX_CONF_UNSET;
sscf->stapling_verify = NGX_CONF_UNSET;
+ sscf->psk_hash_max_size = NGX_CONF_UNSET_UINT;
+ sscf->psk_hash_bucket_size = NGX_CONF_UNSET_UINT;
return sscf;
}
@@ -647,6 +835,10 @@
ngx_conf_merge_str_value(conf->stapling_responder,
prev->stapling_responder, "");
+ if (conf->psk_map == NULL) {
+ conf->psk_map = prev->psk_map;
+ }
+
conf->ssl.log = cf->log;
if (conf->enable) {
@@ -857,6 +1049,10 @@
return NGX_CONF_ERROR;
}
+ if (ngx_ssl_use_psk(cf, &conf->ssl, conf->psk_map) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
return NGX_CONF_OK;
}
diff -u -r nginx-1.15.10-ori/src/http/modules/ngx_http_ssl_module.h nginx-1.15.10/src/http/modules/ngx_http_ssl_module.h
--- nginx-1.15.10-ori/src/http/modules/ngx_http_ssl_module.h 2019-03-26 22:06:55.000000000 +0800
+++ nginx-1.15.10/src/http/modules/ngx_http_ssl_module.h 2019-04-11 16:35:17.421721848 +0800
@@ -61,6 +61,10 @@
u_char *file;
ngx_uint_t line;
+
+ ngx_uint_t psk_hash_max_size;
+ ngx_uint_t psk_hash_bucket_size;
+ ngx_hash_combined_t *psk_map;
} ngx_http_ssl_srv_conf_t;
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Review src/http/modules/ngx_http_ssl_module.c and src/event/ngx_event_openssl.c first, along with their headers, to understand the proposed PSK configuration and TLS callback flow. Build the relevant Tengine configuration and verify that TLS 1.2 PSK identities from ssl_use_psk are accepted without breaking existing SSL configuration.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- backend, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100