Skip to content

Commit ade3dc5

Browse files
committed
An IV should be generated for each encryption
We now have the ability to decide if the IV is communicated to the client in a non forgeable manner or we only keep it on the server side. Closes #2
1 parent 99662f8 commit ade3dc5

3 files changed

+169
-13
lines changed

src/ngx_http_encrypted_session_cipher.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "ngx_http_encrypted_session_cipher.h"
1414
#include <openssl/evp.h>
15+
#include <openssl/hmac.h>
1516
#include <openssl/md5.h>
1617
#include <stdint.h>
1718

@@ -291,3 +292,16 @@ ngx_http_encrypted_session_htonll(uint64_t n)
291292
+ htonl((unsigned long) (n >> 32));
292293
#endif
293294
}
295+
296+
unsigned char*
297+
ngx_http_encrypted_session_hmac(const u_char *key, size_t key_len,
298+
const u_char *data, size_t data_len, u_char **dst, size_t *dst_len)
299+
{
300+
u_char *result = NULL;
301+
unsigned int len;
302+
*dst = HMAC(EVP_sha256(), key, key_len, data, data_len, result,
303+
&len);
304+
*dst_len = len;
305+
306+
return *dst;
307+
}

src/ngx_http_encrypted_session_cipher.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <ngx_core.h>
66
#include <ngx_http.h>
77
#include <openssl/evp.h>
8+
#include <openssl/hmac.h>
89

910

1011
typedef int (*cipher_ctx_reset_handle) (EVP_CIPHER_CTX *ctx);
@@ -34,6 +35,9 @@ ngx_int_t ngx_http_encrypted_session_aes_mac_decrypt(
3435
size_t key_len, const u_char *in, size_t in_len, u_char **dst,
3536
size_t *dst_len);
3637

38+
unsigned char* ngx_http_encrypted_session_hmac(
39+
const u_char *key, size_t key_len,
40+
const u_char *data, size_t data_len, u_char **dst, size_t *dst_len);
3741

3842
#endif /* NGX_HTTP_ENCRYPTED_SESSION_CIPHER_H */
3943

src/ngx_http_encrypted_session_module.c

Lines changed: 151 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "ddebug.h"
1111

1212
#include <ndk.h>
13+
#include <string.h>
1314
#include "ngx_http_encrypted_session_cipher.h"
1415

1516
#define ngx_http_encrypted_session_default_iv (u_char *) "deadbeefdeadbeef"
@@ -19,11 +20,16 @@
1920

2021
typedef struct {
2122
u_char *key;
23+
size_t key_len;
2224
u_char *iv;
25+
size_t iv_len;
2326
time_t expires;
24-
27+
ngx_flag_t iv_in_content;
2528
} ngx_http_encrypted_session_conf_t;
2629

30+
const char *PARTS_DELIMITER = ":";
31+
const size_t PARTS_DELIMITER_LEN = 1;
32+
const size_t NUM_OF_DELIMITERS = 2;
2733

2834
static ngx_int_t ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
2935
ngx_str_t *res, ngx_http_variable_value_t *v);
@@ -42,6 +48,8 @@ static char *ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd,
4248
static char *ngx_http_encrypted_session_expires(ngx_conf_t *cf,
4349
ngx_command_t *cmd, void *conf);
4450

51+
static char *ngx_http_encrypted_iv_in_content(ngx_conf_t *cf,
52+
ngx_command_t *cmd, void *conf);
4553

4654
static ngx_int_t ngx_http_encrypted_session_init(ngx_conf_t *cf);
4755
static void *ngx_http_encrypted_session_create_main_conf(ngx_conf_t *cf);
@@ -53,7 +61,6 @@ static void *ngx_http_encrypted_session_create_conf(ngx_conf_t *cf);
5361
static char *ngx_http_encrypted_session_merge_conf(ngx_conf_t *cf, void *parent,
5462
void *child);
5563

56-
5764
static ndk_set_var_t ngx_http_set_encode_encrypted_session_filter = {
5865
NDK_SET_VAR_VALUE,
5966
(void *) ngx_http_set_encode_encrypted_session,
@@ -115,7 +122,14 @@ static ngx_command_t ngx_http_encrypted_session_commands[] = {
115122
0,
116123
&ngx_http_set_decode_encrypted_session_filter
117124
},
118-
125+
{ ngx_string("include_iv_in_encrypted_payload"),
126+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
127+
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
128+
ngx_http_encrypted_iv_in_content,
129+
NGX_HTTP_LOC_CONF_OFFSET,
130+
0,
131+
NULL
132+
},
119133
ngx_null_command
120134
};
121135

@@ -151,14 +165,14 @@ ngx_module_t ngx_http_encrypted_session_module = {
151165
};
152166

153167
static ngx_str_t ngx_http_get_variable_by_name(ngx_http_request_t *r,
154-
unsigned char *name, ngx_http_encrypted_session_conf_t *conf)
168+
unsigned char *name, size_t name_len, ngx_http_encrypted_session_conf_t *conf)
155169
{
156170
ngx_http_variable_value_t *v;
157171
ngx_str_t name_str;
158172
name_str.data = name;
159-
name_str.len = strlen((const char *)name);
173+
name_str.len = name_len;
160174

161-
ngx_uint_t key = ngx_hash_strlow(name, name, name_str.len);
175+
ngx_uint_t key = ngx_hash_strlow(name, name, name_len);
162176
v = ngx_http_get_variable(r, &name_str, key);
163177

164178
if (v->not_found) {
@@ -171,6 +185,37 @@ static ngx_str_t ngx_http_get_variable_by_name(ngx_http_request_t *r,
171185
return var_value;
172186
}
173187

188+
static char*
189+
ngx_http_encrypted_session_build_payload(ngx_http_request_t *r,
190+
char *input, size_t input_len, ngx_str_t *iv)
191+
{
192+
size_t new_len = input_len + iv->len + PARTS_DELIMITER_LEN;
193+
char *data = (char *)ngx_pcalloc(r->pool, new_len);
194+
data = strncat(data, input, input_len);
195+
data = strcat(data, PARTS_DELIMITER);
196+
data = strncat(data, (char *)iv->data, iv->len);
197+
198+
return data;
199+
}
200+
201+
static ngx_str_t*
202+
ngx_http_session_encrypted_compute_hmac(ngx_http_request_t *r,
203+
ngx_str_t *key, ngx_str_t *content)
204+
{
205+
size_t signature_len;
206+
u_char* signature;
207+
208+
ngx_http_encrypted_session_hmac(key->data, key->len,
209+
content->data, content->len,
210+
&signature, &signature_len);
211+
212+
ngx_str_t *result = (ngx_str_t*)ngx_pcalloc(r->pool, sizeof(ngx_str_t));
213+
result->len = signature_len;
214+
result->data = (u_char*)ngx_pcalloc(r->pool, signature_len + 1);
215+
memcpy(result->data, signature, signature_len);
216+
return result;
217+
}
218+
174219
static ngx_int_t
175220
ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
176221
ngx_str_t *res, ngx_http_variable_value_t *v)
@@ -196,12 +241,19 @@ ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
196241
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
197242
"encrypted_session: expires=%T", conf->expires);
198243

199-
ngx_str_t iv = ngx_http_get_variable_by_name(r, conf->iv, conf);
200-
ngx_str_t key = ngx_http_get_variable_by_name(r, conf->key, conf);
244+
ngx_str_t iv = ngx_http_get_variable_by_name(r, conf->iv, conf->iv_len,
245+
conf);
246+
ngx_str_t key = ngx_http_get_variable_by_name(r, conf->key, conf->key_len,
247+
conf);
248+
249+
char *data = (char *)v->data;
250+
if (conf->iv_in_content) {
251+
data = ngx_http_encrypted_session_build_payload(r, data, v->len, &iv);
252+
}
201253

202254
rc = ngx_http_encrypted_session_aes_mac_encrypt(emcf, r->pool,
203255
r->connection->log, iv.data, iv.len, key.data, key.len,
204-
v->data, v->len, (ngx_uint_t) conf->expires, &dst, &len);
256+
(u_char*)data, v->len, (ngx_uint_t) conf->expires, &dst, &len);
205257

206258
if (rc != NGX_OK) {
207259
dst = NULL;
@@ -211,6 +263,29 @@ ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
211263
"encrypted_session: failed to encrypt");
212264
}
213265

266+
if (conf->iv_in_content) {
267+
size_t signature_content_len = iv.len + len;
268+
char* signature_content = (char*)ngx_pcalloc(r->pool, signature_content_len + 1);
269+
signature_content = strncat(signature_content, (char*)iv.data, iv.len);
270+
signature_content = strncat(signature_content, (char*)dst, len);
271+
272+
ngx_str_t signature_input;
273+
signature_input.len = signature_content_len;
274+
signature_input.data = (u_char*)signature_content;
275+
ngx_str_t *signature = ngx_http_session_encrypted_compute_hmac(r, &key,
276+
&signature_input);
277+
278+
size_t new_len = iv.len + len + signature->len + NUM_OF_DELIMITERS * PARTS_DELIMITER_LEN;
279+
char *new_content = (char*)ngx_pcalloc(r->pool, new_len + 1);
280+
new_content = strncat(new_content, (char*)iv.data, iv.len);
281+
new_content = strcat(new_content, PARTS_DELIMITER);
282+
new_content = strncat(new_content, (char*)dst, len);
283+
new_content = strcat(new_content, PARTS_DELIMITER);
284+
new_content = strncat(new_content, (char*)signature->data, signature->len);
285+
len = new_len;
286+
dst = (u_char*)new_content;
287+
}
288+
214289
res->data = dst;
215290
res->len = len;
216291

@@ -240,12 +315,55 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
240315
return NGX_ERROR;
241316
}
242317

243-
ngx_str_t iv = ngx_http_get_variable_by_name(r, conf->iv, conf);
244-
ngx_str_t key = ngx_http_get_variable_by_name(r, conf->key, conf);
318+
ngx_str_t key = ngx_http_get_variable_by_name(r, conf->key, conf->key_len,
319+
conf);
320+
321+
ngx_str_t iv;
322+
char *data = (char*)v->data;
323+
size_t data_len = v->len;
324+
325+
326+
if (!conf->iv_in_content)
327+
{
328+
iv = ngx_http_get_variable_by_name(r, conf->iv, conf->iv_len, conf);
329+
}
330+
else
331+
{
332+
iv.len = strcspn(data, PARTS_DELIMITER);
333+
iv.data = (u_char*)ngx_pcalloc(r->pool, iv.len + 1);
334+
strncpy((char*)iv.data, (char*)v->data, iv.len);
335+
336+
size_t signature_start = iv.len + strcspn(&data[iv.len + 1], PARTS_DELIMITER) + NUM_OF_DELIMITERS * PARTS_DELIMITER_LEN;
337+
size_t signature_len = v->len - signature_start;
338+
339+
u_char* signature = (u_char*)ngx_pcalloc(r->pool, signature_len + 1);
340+
strncpy((char*)signature, &data[data_len - signature_len], signature_len);
341+
342+
data_len = v->len - iv.len - signature_len - NUM_OF_DELIMITERS * PARTS_DELIMITER_LEN;
343+
data = (char*)ngx_pcalloc(r->pool, data_len + 1);
344+
strncpy(data, (char*)(&v->data[iv.len + 1]), data_len);
345+
346+
ngx_str_t signature_input;
347+
signature_input.len = iv.len + data_len;
348+
signature_input.data = (u_char*)ngx_pcalloc(r->pool, signature_input.len + 1);
349+
strncat((char*)signature_input.data, (char*)iv.data, iv.len);
350+
strncat((char*)signature_input.data, (char*)data, data_len);
351+
352+
ngx_str_t *computed_signature = ngx_http_session_encrypted_compute_hmac(r,
353+
&key, &signature_input);
354+
if (signature_len != computed_signature->len ||
355+
strncmp((char*)computed_signature->data, (char*)signature, signature_len) != 0)
356+
{
357+
res->data = NULL;
358+
res->len = 0;
359+
360+
return NGX_OK;
361+
}
362+
}
245363

246364
rc = ngx_http_encrypted_session_aes_mac_decrypt(emcf, r->pool,
247365
r->connection->log, iv.data, iv.len, key.data, key.len,
248-
v->data, v->len, &dst, &len);
366+
(u_char*)data, data_len, &dst, &len);
249367

250368
if (rc != NGX_OK) {
251369
dst = NULL;
@@ -273,7 +391,9 @@ ngx_http_encrypted_session_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
273391
value = cf->args->elts;
274392

275393
if (value[1].len > 1 && value[1].data[0] == '$') {
276-
llcf->key = &(value[1].data[1]);
394+
llcf->key_len = value[1].len - 1;
395+
llcf->key = (u_char*)ngx_pcalloc(cf->pool, llcf->key_len);
396+
strncpy((char*)llcf->key, (char*)&(value[1].data[1]), llcf->key_len);
277397
return NGX_CONF_OK;
278398
}
279399

@@ -287,6 +407,7 @@ ngx_http_encrypted_session_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
287407
}
288408

289409
llcf->key = value[1].data;
410+
llcf->key_len = value[1].len;
290411

291412
return NGX_CONF_OK;
292413
}
@@ -307,6 +428,7 @@ ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
307428

308429
if (value[1].len > 1 && value[1].data[0] == '$') {
309430
llcf->iv = &(value[1].data[1]);
431+
llcf->iv_len = value[1].len - 1;
310432
return NGX_CONF_OK;
311433
}
312434

@@ -320,6 +442,7 @@ ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
320442
}
321443

322444
llcf->iv = ngx_pcalloc(cf->pool, ngx_http_encrypted_session_iv_length);
445+
llcf->iv_len = ngx_http_encrypted_session_iv_length;
323446

324447
if (llcf->iv == NULL) {
325448
return NGX_CONF_ERROR;
@@ -360,6 +483,13 @@ ngx_http_encrypted_session_expires(ngx_conf_t *cf, ngx_command_t *cmd,
360483
return NGX_CONF_OK;
361484
}
362485

486+
static char *ngx_http_encrypted_iv_in_content(ngx_conf_t *cf,
487+
ngx_command_t *cmd, void *conf)
488+
{
489+
ngx_http_encrypted_session_conf_t *llcf = conf;
490+
llcf->iv_in_content = 1;
491+
return NGX_CONF_OK;
492+
}
363493

364494
static void
365495
ngx_http_encrypted_session_free_cipher_ctx(void *data)
@@ -435,8 +565,11 @@ ngx_http_encrypted_session_create_conf(ngx_conf_t *cf)
435565
}
436566

437567
conf->key = NGX_CONF_UNSET_PTR;
568+
conf->key_len = NGX_CONF_UNSET;
438569
conf->iv = NGX_CONF_UNSET_PTR;
570+
conf->iv_len = NGX_CONF_UNSET;
439571
conf->expires = NGX_CONF_UNSET;
572+
conf->iv_in_content = NGX_CONF_UNSET;
440573

441574
return conf;
442575
}
@@ -449,12 +582,17 @@ ngx_http_encrypted_session_merge_conf(ngx_conf_t *cf, void *parent, void *child)
449582
ngx_http_encrypted_session_conf_t *conf = child;
450583

451584
ngx_conf_merge_ptr_value(conf->key, prev->key, NULL);
585+
ngx_conf_merge_size_value(conf->key_len, prev->key_len,
586+
(size_t)ngx_http_encrypted_session_key_length);
452587

453588
ngx_conf_merge_ptr_value(conf->iv, prev->iv,
454589
ngx_http_encrypted_session_default_iv);
590+
ngx_conf_merge_size_value(conf->iv_len, prev->iv_len,
591+
(size_t)ngx_http_encrypted_session_iv_length);
455592

456593
ngx_conf_merge_value(conf->expires, prev->expires,
457594
ngx_http_encrypted_session_default_expires);
595+
ngx_conf_merge_value(conf->iv_in_content, prev->iv_in_content, 0);
458596

459597
return NGX_CONF_OK;
460598
}

0 commit comments

Comments
 (0)