Skip to content

Commit cd1c747

Browse files
committed
The module should support AES gcm mode.
Closes #25
1 parent 8953ff7 commit cd1c747

3 files changed

+156
-24
lines changed

src/ngx_http_encrypted_session_cipher.c

+45-5
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,28 @@
2020
static uint64_t ngx_http_encrypted_session_ntohll(uint64_t n);
2121
static uint64_t ngx_http_encrypted_session_htonll(uint64_t n);
2222

23+
const EVP_CIPHER*
24+
ngx_http_encrypted_session_get_cipher(enum ngx_http_encrypted_session_mode mode)
25+
{
26+
if (mode == ngx_http_encrypted_session_mode_cbc)
27+
{
28+
return EVP_aes_256_cbc();
29+
}
30+
else if (mode == ngx_http_encrypted_session_mode_gcm)
31+
{
32+
return EVP_aes_256_gcm();
33+
}
34+
35+
return NULL;
36+
}
2337

2438
ngx_int_t
2539
ngx_http_encrypted_session_aes_mac_encrypt(
2640
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
2741
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
2842
size_t key_len, const u_char *in, size_t in_len, ngx_uint_t expires,
29-
u_char **dst, size_t *dst_len)
43+
enum ngx_http_encrypted_session_mode mode,
44+
u_char **dst, size_t *dst_len, u_char **tag)
3045
{
3146
const EVP_CIPHER *cipher;
3247
u_char *p, *data;
@@ -50,7 +65,10 @@ ngx_http_encrypted_session_aes_mac_encrypt(
5065
}
5166
}
5267

53-
cipher = EVP_aes_256_cbc();
68+
cipher = ngx_http_encrypted_session_get_cipher(mode);
69+
if (!cipher) {
70+
goto evp_error;
71+
}
5472

5573
block_size = EVP_CIPHER_block_size(cipher);
5674

@@ -107,6 +125,15 @@ ngx_http_encrypted_session_aes_mac_encrypt(
107125
p += len;
108126

109127
ret = EVP_EncryptFinal(emcf->session_ctx, p, &len);
128+
if (!ret) {
129+
goto evp_error;
130+
}
131+
132+
if (mode == ngx_http_encrypted_session_mode_gcm) {
133+
*tag = (u_char*)ngx_pcalloc(pool, ngx_http_encrypted_session_aes_tag_size);
134+
ret = EVP_CIPHER_CTX_ctrl(emcf->session_ctx, EVP_CTRL_GCM_GET_TAG,
135+
ngx_http_encrypted_session_aes_tag_size, *tag);
136+
}
110137

111138
emcf->reset_cipher_ctx(emcf->session_ctx);
112139

@@ -139,8 +166,10 @@ ngx_int_t
139166
ngx_http_encrypted_session_aes_mac_decrypt(
140167
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
141168
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
142-
size_t key_len, const u_char *in, size_t in_len, u_char **dst,
143-
size_t *dst_len)
169+
size_t key_len, const u_char *in, size_t in_len,
170+
enum ngx_http_encrypted_session_mode mode,
171+
u_char *tag,
172+
u_char **dst, size_t *dst_len)
144173
{
145174
const EVP_CIPHER *cipher;
146175
int ret;
@@ -171,7 +200,10 @@ ngx_http_encrypted_session_aes_mac_decrypt(
171200
}
172201
}
173202

174-
cipher = EVP_aes_256_cbc();
203+
cipher = ngx_http_encrypted_session_get_cipher(mode);
204+
if (!cipher) {
205+
goto evp_error;
206+
}
175207

176208
ret = EVP_DecryptInit(emcf->session_ctx, cipher, key, iv);
177209
if (!ret) {
@@ -200,6 +232,14 @@ ngx_http_encrypted_session_aes_mac_decrypt(
200232

201233
p += len;
202234

235+
if (mode == ngx_http_encrypted_session_mode_gcm) {
236+
ret = EVP_CIPHER_CTX_ctrl(emcf->session_ctx, EVP_CTRL_GCM_SET_TAG,
237+
ngx_http_encrypted_session_aes_tag_size, tag);
238+
if (!ret) {
239+
goto evp_error;
240+
}
241+
}
242+
203243
ret = EVP_DecryptFinal(emcf->session_ctx, p, &len);
204244

205245
emcf->reset_cipher_ctx(emcf->session_ctx);

src/ngx_http_encrypted_session_cipher.h

+13-4
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,30 @@ typedef struct {
1919

2020
enum {
2121
ngx_http_encrypted_session_key_length = 256 / 8,
22-
ngx_http_encrypted_session_iv_length = EVP_MAX_IV_LENGTH
22+
ngx_http_encrypted_session_iv_length = EVP_MAX_IV_LENGTH,
23+
ngx_http_encrypted_session_aes_tag_size = 16
2324
};
2425

26+
enum ngx_http_encrypted_session_mode {
27+
ngx_http_encrypted_session_mode_unknown = 0, // unknown / unset value.
28+
ngx_http_encrypted_session_mode_cbc = 1, // equivalent of setting cbc string in config or nothing at all.
29+
ngx_http_encrypted_session_mode_gcm = 2 // equivalent of explicitly setting gcm in nginx config.
30+
};
2531

2632
ngx_int_t ngx_http_encrypted_session_aes_mac_encrypt(
2733
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
2834
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
2935
size_t key_len, const u_char *in, size_t in_len,
30-
ngx_uint_t expires, u_char **dst, size_t *dst_len);
36+
ngx_uint_t expires, enum ngx_http_encrypted_session_mode mode,
37+
u_char **dst, size_t *dst_len, u_char **tag);
3138

3239
ngx_int_t ngx_http_encrypted_session_aes_mac_decrypt(
3340
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
3441
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
35-
size_t key_len, const u_char *in, size_t in_len, u_char **dst,
36-
size_t *dst_len);
42+
size_t key_len, const u_char *in, size_t in_len,
43+
enum ngx_http_encrypted_session_mode mode,
44+
u_char *tag,
45+
u_char **dst, size_t *dst_len);
3746

3847
unsigned char* ngx_http_encrypted_session_hmac(
3948
ngx_pool_t *pool,

src/ngx_http_encrypted_session_module.c

+98-15
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@ const size_t IV_LENGTH = 16;
2121
const size_t SIGNATURE_LENGTH = 32;
2222

2323
typedef struct {
24-
u_char *key;
25-
size_t key_len;
26-
u_char *iv;
27-
size_t iv_len;
28-
time_t expires;
29-
ngx_flag_t iv_in_content;
24+
u_char *key;
25+
size_t key_len;
26+
u_char *iv;
27+
size_t iv_len;
28+
time_t expires;
29+
ngx_flag_t iv_in_content;
30+
enum ngx_http_encrypted_session_mode encryption_mode;
3031
} ngx_http_encrypted_session_conf_t;
3132

3233
static ngx_int_t ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
@@ -43,6 +44,9 @@ static char *ngx_http_encrypted_session_key(ngx_conf_t *cf, ngx_command_t *cmd,
4344
static char *ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd,
4445
void *conf);
4546

47+
static char *ngx_http_encrypted_session_mode_set(ngx_conf_t *cf,
48+
ngx_command_t *cmd, void *conf);
49+
4650
static char *ngx_http_encrypted_session_expires(ngx_conf_t *cf,
4751
ngx_command_t *cmd, void *conf);
4852

@@ -93,6 +97,15 @@ static ngx_command_t ngx_http_encrypted_session_commands[] = {
9397
0,
9498
NULL
9599
},
100+
{
101+
ngx_string("encrypted_session_mode"),
102+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
103+
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
104+
ngx_http_encrypted_session_mode_set,
105+
NGX_HTTP_LOC_CONF_OFFSET,
106+
0,
107+
NULL
108+
},
96109
{
97110
ngx_string("encrypted_session_expires"),
98111
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
@@ -245,15 +258,31 @@ ngx_http_session_generate_signature(ngx_http_request_t *r,
245258

246259
static ngx_str_t*
247260
ngx_http_session_generate_response_with_iv(ngx_http_request_t *r,
248-
ngx_str_t *iv, ngx_str_t *key, ngx_str_t *content)
261+
ngx_str_t *iv, ngx_str_t *key, ngx_str_t *content,
262+
ngx_str_t *tag, enum ngx_http_encrypted_session_mode mode)
249263
{
250264
ngx_str_t *signature = ngx_http_session_generate_signature(r, iv, key, content);
251265

252-
size_t new_len = iv->len + content->len + signature->len;
266+
size_t new_len = iv->len + signature->len + content->len;
267+
268+
if (mode == ngx_http_encrypted_session_mode_gcm)
269+
{
270+
new_len += tag->len;
271+
}
272+
253273
u_char *new_content = (u_char*)ngx_pcalloc(r->pool, new_len + 1);
254274
ngx_memcpy(new_content, iv->data, iv->len);
255275
ngx_memcpy(new_content + iv->len, signature->data, signature->len);
256-
ngx_memcpy(new_content + iv->len + signature->len, content->data, content->len);
276+
277+
if (mode == ngx_http_encrypted_session_mode_gcm)
278+
{
279+
ngx_memcpy(new_content + iv->len + signature->len, tag->data, tag->len);
280+
ngx_memcpy(new_content + iv->len + signature->len + tag->len, content->data, content->len);
281+
}
282+
else
283+
{
284+
ngx_memcpy(new_content + iv->len + signature->len, content->data, content->len);
285+
}
257286

258287
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
259288
"encrypted_session: encrypted data len=%d", content->len);
@@ -314,9 +343,11 @@ ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
314343
content.data);
315344
}
316345

346+
u_char *tag;
317347
rc = ngx_http_encrypted_session_aes_mac_encrypt(emcf, r->pool,
318348
r->connection->log, iv.data, iv.len, key.data, key.len,
319-
content.data, content.len, (ngx_uint_t) conf->expires, &dst, &len);
349+
content.data, content.len,
350+
(ngx_uint_t) conf->expires, conf->encryption_mode, &dst, &len, &tag);
320351

321352
if (rc != NGX_OK) {
322353
res->data = NULL;
@@ -332,8 +363,12 @@ ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
332363
encrypted_content.len = len;
333364
encrypted_content.data = dst;
334365

366+
ngx_str_t tag_content;
367+
tag_content.len = ngx_http_encrypted_session_aes_tag_size;
368+
tag_content.data = tag;
369+
335370
ngx_str_t *result = ngx_http_session_generate_response_with_iv(r, &iv,
336-
&key, &encrypted_content);
371+
&key, &encrypted_content, &tag_content, conf->encryption_mode);
337372
res->data = result->data;
338373
res->len = result->len;
339374

@@ -377,6 +412,8 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
377412

378413
ngx_str_t iv;
379414
ngx_str_t content;
415+
ngx_str_t tag;
416+
380417
content.data = v->data;
381418
content.len = v->len;
382419

@@ -405,10 +442,28 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
405442
u_char* signature = (u_char*)ngx_pcalloc(r->pool, SIGNATURE_LENGTH + 1);
406443
ngx_memcpy(signature, content.data + iv.len, SIGNATURE_LENGTH);
407444

445+
if (conf->encryption_mode == ngx_http_encrypted_session_mode_gcm)
446+
{
447+
tag.len = ngx_http_encrypted_session_aes_tag_size;
448+
tag.data = (u_char*)ngx_pcalloc(r->pool, tag.len);
449+
ngx_memcpy(tag.data, content.data + iv.len + SIGNATURE_LENGTH, tag.len);
450+
}
451+
408452
ngx_str_t encrypted_content;
409-
encrypted_content.len = content.len - iv.len - SIGNATURE_LENGTH;
410-
encrypted_content.data = (u_char*)ngx_pcalloc(r->pool, encrypted_content.len + 1);
411-
ngx_memcpy(encrypted_content.data, v->data + iv.len + SIGNATURE_LENGTH, encrypted_content.len);
453+
if (conf->encryption_mode == ngx_http_encrypted_session_mode_gcm)
454+
{
455+
encrypted_content.len = content.len - iv.len - SIGNATURE_LENGTH - tag.len;
456+
encrypted_content.data = (u_char*)ngx_pcalloc(r->pool, encrypted_content.len + 1);
457+
ngx_memcpy(encrypted_content.data,
458+
v->data + iv.len + SIGNATURE_LENGTH + tag.len,
459+
encrypted_content.len);
460+
}
461+
else
462+
{
463+
encrypted_content.len = content.len - iv.len - SIGNATURE_LENGTH;
464+
encrypted_content.data = (u_char*)ngx_pcalloc(r->pool, encrypted_content.len + 1);
465+
ngx_memcpy(encrypted_content.data, v->data + iv.len + SIGNATURE_LENGTH, encrypted_content.len);
466+
}
412467

413468
content.data = encrypted_content.data;
414469
content.len = encrypted_content.len;
@@ -432,7 +487,8 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
432487

433488
rc = ngx_http_encrypted_session_aes_mac_decrypt(emcf, r->pool,
434489
r->connection->log, iv.data, iv.len, key.data, key.len,
435-
content.data, content.len, &dst, &len);
490+
content.data, content.len, conf->encryption_mode, tag.data,
491+
&dst, &len);
436492

437493
if (rc != NGX_OK) {
438494
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
@@ -542,6 +598,24 @@ ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
542598
return NGX_CONF_OK;
543599
}
544600

601+
static char *
602+
ngx_http_encrypted_session_mode_set(ngx_conf_t *cf,
603+
ngx_command_t *cmd, void *conf)
604+
{
605+
ngx_str_t *value;
606+
ngx_http_encrypted_session_conf_t *llcf = conf;
607+
608+
value = cf->args->elts;
609+
if (value[1].len == 3 && strncmp("cbc", (char*)value[1].data, 3) == 0) {
610+
llcf->encryption_mode = ngx_http_encrypted_session_mode_cbc;
611+
}
612+
else if (value[1].len == 3 && strncmp("gcm", (char*)value[1].data, 3) == 0) {
613+
llcf->encryption_mode = ngx_http_encrypted_session_mode_gcm;
614+
}
615+
616+
return NGX_CONF_OK;
617+
}
618+
545619

546620
static char *
547621
ngx_http_encrypted_session_expires(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -654,6 +728,7 @@ ngx_http_encrypted_session_create_conf(ngx_conf_t *cf)
654728
conf->iv_len = NGX_CONF_UNSET;
655729
conf->expires = NGX_CONF_UNSET;
656730
conf->iv_in_content = NGX_CONF_UNSET;
731+
conf->encryption_mode = ngx_http_encrypted_session_mode_unknown;
657732

658733
return conf;
659734
}
@@ -678,5 +753,13 @@ ngx_http_encrypted_session_merge_conf(ngx_conf_t *cf, void *parent, void *child)
678753
ngx_http_encrypted_session_default_expires);
679754
ngx_conf_merge_value(conf->iv_in_content, prev->iv_in_content, 0);
680755

756+
if (conf->encryption_mode == ngx_http_encrypted_session_mode_unknown) {
757+
conf->encryption_mode = prev->encryption_mode;
758+
}
759+
760+
if (conf->encryption_mode == ngx_http_encrypted_session_mode_unknown) {
761+
conf->encryption_mode = ngx_http_encrypted_session_mode_cbc;
762+
}
763+
681764
return NGX_CONF_OK;
682765
}

0 commit comments

Comments
 (0)