Skip to content

Commit c118d54

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

3 files changed

+177
-28
lines changed

src/ngx_http_encrypted_session_cipher.c

Lines changed: 45 additions & 5 deletions
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

Lines changed: 13 additions & 4 deletions
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

Lines changed: 119 additions & 19 deletions
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
@@ -216,12 +229,28 @@ ngx_http_session_encrypted_compute_hmac(ngx_http_request_t *r,
216229

217230
static ngx_str_t*
218231
ngx_http_session_generate_signature(ngx_http_request_t *r,
219-
ngx_str_t *iv, ngx_str_t *key, ngx_str_t *content)
232+
ngx_str_t *iv, ngx_str_t *key, ngx_str_t *content,
233+
ngx_str_t *tag, enum ngx_http_encrypted_session_mode mode)
220234
{
221235
size_t signature_content_len = iv->len + content->len;
236+
if (mode == ngx_http_encrypted_session_mode_gcm)
237+
{
238+
signature_content_len += tag->len;
239+
}
240+
222241
u_char* signature_content = (u_char*)ngx_pcalloc(r->pool, signature_content_len + 1);
223242
ngx_memcpy(signature_content, iv->data, iv->len);
224-
ngx_memcpy(signature_content + iv->len, content->data, content->len);
243+
244+
if (mode == ngx_http_encrypted_session_mode_gcm)
245+
{
246+
ngx_memcpy(signature_content + iv->len, tag->data, tag->len);
247+
ngx_memcpy(signature_content + iv->len + tag->len,
248+
content->data, content->len);
249+
}
250+
else
251+
{
252+
ngx_memcpy(signature_content + iv->len, content->data, content->len);
253+
}
225254

226255
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
227256
"encrypted_session: signature content len=%d",
@@ -245,15 +274,32 @@ ngx_http_session_generate_signature(ngx_http_request_t *r,
245274

246275
static ngx_str_t*
247276
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)
277+
ngx_str_t *iv, ngx_str_t *key, ngx_str_t *content,
278+
ngx_str_t *tag, enum ngx_http_encrypted_session_mode mode)
249279
{
250-
ngx_str_t *signature = ngx_http_session_generate_signature(r, iv, key, content);
280+
ngx_str_t *signature = ngx_http_session_generate_signature(r, iv, key,
281+
content, tag, mode);
282+
283+
size_t new_len = iv->len + signature->len + content->len;
284+
285+
if (mode == ngx_http_encrypted_session_mode_gcm)
286+
{
287+
new_len += tag->len;
288+
}
251289

252-
size_t new_len = iv->len + content->len + signature->len;
253290
u_char *new_content = (u_char*)ngx_pcalloc(r->pool, new_len + 1);
254291
ngx_memcpy(new_content, iv->data, iv->len);
255292
ngx_memcpy(new_content + iv->len, signature->data, signature->len);
256-
ngx_memcpy(new_content + iv->len + signature->len, content->data, content->len);
293+
294+
if (mode == ngx_http_encrypted_session_mode_gcm)
295+
{
296+
ngx_memcpy(new_content + iv->len + signature->len, tag->data, tag->len);
297+
ngx_memcpy(new_content + iv->len + signature->len + tag->len, content->data, content->len);
298+
}
299+
else
300+
{
301+
ngx_memcpy(new_content + iv->len + signature->len, content->data, content->len);
302+
}
257303

258304
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
259305
"encrypted_session: encrypted data len=%d", content->len);
@@ -314,9 +360,11 @@ ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
314360
content.data);
315361
}
316362

363+
u_char *tag;
317364
rc = ngx_http_encrypted_session_aes_mac_encrypt(emcf, r->pool,
318365
r->connection->log, iv.data, iv.len, key.data, key.len,
319-
content.data, content.len, (ngx_uint_t) conf->expires, &dst, &len);
366+
content.data, content.len,
367+
(ngx_uint_t) conf->expires, conf->encryption_mode, &dst, &len, &tag);
320368

321369
if (rc != NGX_OK) {
322370
res->data = NULL;
@@ -332,8 +380,12 @@ ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
332380
encrypted_content.len = len;
333381
encrypted_content.data = dst;
334382

383+
ngx_str_t tag_content;
384+
tag_content.len = ngx_http_encrypted_session_aes_tag_size;
385+
tag_content.data = tag;
386+
335387
ngx_str_t *result = ngx_http_session_generate_response_with_iv(r, &iv,
336-
&key, &encrypted_content);
388+
&key, &encrypted_content, &tag_content, conf->encryption_mode);
337389
res->data = result->data;
338390
res->len = result->len;
339391

@@ -377,6 +429,8 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
377429

378430
ngx_str_t iv;
379431
ngx_str_t content;
432+
ngx_str_t tag;
433+
380434
content.data = v->data;
381435
content.len = v->len;
382436

@@ -405,10 +459,28 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
405459
u_char* signature = (u_char*)ngx_pcalloc(r->pool, SIGNATURE_LENGTH + 1);
406460
ngx_memcpy(signature, content.data + iv.len, SIGNATURE_LENGTH);
407461

462+
if (conf->encryption_mode == ngx_http_encrypted_session_mode_gcm)
463+
{
464+
tag.len = ngx_http_encrypted_session_aes_tag_size;
465+
tag.data = (u_char*)ngx_pcalloc(r->pool, tag.len);
466+
ngx_memcpy(tag.data, content.data + iv.len + SIGNATURE_LENGTH, tag.len);
467+
}
468+
408469
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);
470+
if (conf->encryption_mode == ngx_http_encrypted_session_mode_gcm)
471+
{
472+
encrypted_content.len = content.len - iv.len - SIGNATURE_LENGTH - tag.len;
473+
encrypted_content.data = (u_char*)ngx_pcalloc(r->pool, encrypted_content.len + 1);
474+
ngx_memcpy(encrypted_content.data,
475+
v->data + iv.len + SIGNATURE_LENGTH + tag.len,
476+
encrypted_content.len);
477+
}
478+
else
479+
{
480+
encrypted_content.len = content.len - iv.len - SIGNATURE_LENGTH;
481+
encrypted_content.data = (u_char*)ngx_pcalloc(r->pool, encrypted_content.len + 1);
482+
ngx_memcpy(encrypted_content.data, v->data + iv.len + SIGNATURE_LENGTH, encrypted_content.len);
483+
}
412484

413485
content.data = encrypted_content.data;
414486
content.len = encrypted_content.len;
@@ -417,7 +489,7 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
417489
"encrypted_session: data len=%d", content.len);
418490

419491
ngx_str_t *computed_signature = ngx_http_session_generate_signature(r,
420-
&iv, &key, &encrypted_content);
492+
&iv, &key, &encrypted_content, &tag, conf->encryption_mode);
421493
if (SIGNATURE_LENGTH != computed_signature->len ||
422494
ngx_memcmp(computed_signature->data, signature, SIGNATURE_LENGTH) != 0)
423495
{
@@ -432,7 +504,8 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
432504

433505
rc = ngx_http_encrypted_session_aes_mac_decrypt(emcf, r->pool,
434506
r->connection->log, iv.data, iv.len, key.data, key.len,
435-
content.data, content.len, &dst, &len);
507+
content.data, content.len, conf->encryption_mode, tag.data,
508+
&dst, &len);
436509

437510
if (rc != NGX_OK) {
438511
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
@@ -542,6 +615,24 @@ ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
542615
return NGX_CONF_OK;
543616
}
544617

618+
static char *
619+
ngx_http_encrypted_session_mode_set(ngx_conf_t *cf,
620+
ngx_command_t *cmd, void *conf)
621+
{
622+
ngx_str_t *value;
623+
ngx_http_encrypted_session_conf_t *llcf = conf;
624+
625+
value = cf->args->elts;
626+
if (value[1].len == 3 && strncmp("cbc", (char*)value[1].data, 3) == 0) {
627+
llcf->encryption_mode = ngx_http_encrypted_session_mode_cbc;
628+
}
629+
else if (value[1].len == 3 && strncmp("gcm", (char*)value[1].data, 3) == 0) {
630+
llcf->encryption_mode = ngx_http_encrypted_session_mode_gcm;
631+
}
632+
633+
return NGX_CONF_OK;
634+
}
635+
545636

546637
static char *
547638
ngx_http_encrypted_session_expires(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -654,6 +745,7 @@ ngx_http_encrypted_session_create_conf(ngx_conf_t *cf)
654745
conf->iv_len = NGX_CONF_UNSET;
655746
conf->expires = NGX_CONF_UNSET;
656747
conf->iv_in_content = NGX_CONF_UNSET;
748+
conf->encryption_mode = ngx_http_encrypted_session_mode_unknown;
657749

658750
return conf;
659751
}
@@ -678,5 +770,13 @@ ngx_http_encrypted_session_merge_conf(ngx_conf_t *cf, void *parent, void *child)
678770
ngx_http_encrypted_session_default_expires);
679771
ngx_conf_merge_value(conf->iv_in_content, prev->iv_in_content, 0);
680772

773+
if (conf->encryption_mode == ngx_http_encrypted_session_mode_unknown) {
774+
conf->encryption_mode = prev->encryption_mode;
775+
}
776+
777+
if (conf->encryption_mode == ngx_http_encrypted_session_mode_unknown) {
778+
conf->encryption_mode = ngx_http_encrypted_session_mode_cbc;
779+
}
780+
681781
return NGX_CONF_OK;
682782
}

0 commit comments

Comments
 (0)