10
10
#include "ddebug.h"
11
11
12
12
#include <ndk.h>
13
+ #include <string.h>
13
14
#include "ngx_http_encrypted_session_cipher.h"
14
15
15
16
#define ngx_http_encrypted_session_default_iv (u_char *) "deadbeefdeadbeef"
19
20
20
21
typedef struct {
21
22
u_char * key ;
23
+ size_t key_len ;
22
24
u_char * iv ;
25
+ size_t iv_len ;
23
26
time_t expires ;
24
-
27
+ ngx_flag_t iv_in_content ;
25
28
} ngx_http_encrypted_session_conf_t ;
26
29
30
+ const char * PARTS_DELIMITER = ":" ;
31
+ const size_t PARTS_DELIMITER_LEN = 1 ;
32
+ const size_t NUM_OF_DELIMITERS = 2 ;
27
33
28
34
static ngx_int_t ngx_http_set_encode_encrypted_session (ngx_http_request_t * r ,
29
35
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,
42
48
static char * ngx_http_encrypted_session_expires (ngx_conf_t * cf ,
43
49
ngx_command_t * cmd , void * conf );
44
50
51
+ static char * ngx_http_encrypted_iv_in_content (ngx_conf_t * cf ,
52
+ ngx_command_t * cmd , void * conf );
45
53
46
54
static ngx_int_t ngx_http_encrypted_session_init (ngx_conf_t * cf );
47
55
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);
53
61
static char * ngx_http_encrypted_session_merge_conf (ngx_conf_t * cf , void * parent ,
54
62
void * child );
55
63
56
-
57
64
static ndk_set_var_t ngx_http_set_encode_encrypted_session_filter = {
58
65
NDK_SET_VAR_VALUE ,
59
66
(void * ) ngx_http_set_encode_encrypted_session ,
@@ -115,7 +122,14 @@ static ngx_command_t ngx_http_encrypted_session_commands[] = {
115
122
0 ,
116
123
& ngx_http_set_decode_encrypted_session_filter
117
124
},
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
+ },
119
133
ngx_null_command
120
134
};
121
135
@@ -151,14 +165,14 @@ ngx_module_t ngx_http_encrypted_session_module = {
151
165
};
152
166
153
167
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 )
155
169
{
156
170
ngx_http_variable_value_t * v ;
157
171
ngx_str_t name_str ;
158
172
name_str .data = name ;
159
- name_str .len = strlen (( const char * ) name ) ;
173
+ name_str .len = name_len ;
160
174
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 );
162
176
v = ngx_http_get_variable (r , & name_str , key );
163
177
164
178
if (v -> not_found ) {
@@ -171,6 +185,37 @@ static ngx_str_t ngx_http_get_variable_by_name(ngx_http_request_t *r,
171
185
return var_value ;
172
186
}
173
187
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 + 1 );
194
+ data = strncat (data , (char * )iv -> data , iv -> len );
195
+ data = strcat (data , PARTS_DELIMITER );
196
+ data = strncat (data , input , input_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 (r -> pool , 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
+ result -> data = signature ;
216
+ return result ;
217
+ }
218
+
174
219
static ngx_int_t
175
220
ngx_http_set_encode_encrypted_session (ngx_http_request_t * r ,
176
221
ngx_str_t * res , ngx_http_variable_value_t * v )
@@ -196,12 +241,23 @@ ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
196
241
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
197
242
"encrypted_session: expires=%T" , conf -> expires );
198
243
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
+ ngx_log_error (NGX_LOG_DEBUG , r -> connection -> log , 0 ,
253
+ "encrypted_session: content to encrypt=%s" ,
254
+ data );
255
+ v -> len = strlen (data );
256
+ }
201
257
202
258
rc = ngx_http_encrypted_session_aes_mac_encrypt (emcf , r -> pool ,
203
259
r -> connection -> log , iv .data , iv .len , key .data , key .len ,
204
- v -> data , v -> len , (ngx_uint_t ) conf -> expires , & dst , & len );
260
+ ( u_char * ) data , v -> len , (ngx_uint_t ) conf -> expires , & dst , & len );
205
261
206
262
if (rc != NGX_OK ) {
207
263
dst = NULL ;
@@ -211,6 +267,33 @@ ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
211
267
"encrypted_session: failed to encrypt" );
212
268
}
213
269
270
+ if (conf -> iv_in_content ) {
271
+ size_t signature_content_len = iv .len + len ;
272
+ char * signature_content = (char * )ngx_pcalloc (r -> pool , signature_content_len + 1 );
273
+ signature_content = strncat (signature_content , (char * )iv .data , iv .len );
274
+ signature_content = strncat (signature_content , (char * )dst , len );
275
+
276
+ ngx_str_t signature_input ;
277
+ signature_input .len = signature_content_len ;
278
+ signature_input .data = (u_char * )signature_content ;
279
+ ngx_str_t * signature = ngx_http_session_encrypted_compute_hmac (r , & key ,
280
+ & signature_input );
281
+
282
+ size_t new_len = iv .len + len + signature -> len + NUM_OF_DELIMITERS * PARTS_DELIMITER_LEN ;
283
+ char * new_content = (char * )ngx_pcalloc (r -> pool , new_len + 1 );
284
+ new_content = strncat (new_content , (char * )iv .data , iv .len );
285
+ new_content = strcat (new_content , PARTS_DELIMITER );
286
+ new_content = strncat (new_content , (char * )dst , len );
287
+ new_content = strcat (new_content , PARTS_DELIMITER );
288
+ new_content = strncat (new_content , (char * )signature -> data , signature -> len );
289
+ len = new_len ;
290
+ dst = (u_char * )new_content ;
291
+
292
+ ngx_log_error (NGX_LOG_DEBUG , r -> connection -> log , 0 ,
293
+ "encrypted_session: full response=%s" ,
294
+ dst );
295
+ }
296
+
214
297
res -> data = dst ;
215
298
res -> len = len ;
216
299
@@ -240,18 +323,88 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
240
323
return NGX_ERROR ;
241
324
}
242
325
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 );
326
+ ngx_str_t key = ngx_http_get_variable_by_name (r , conf -> key , conf -> key_len ,
327
+ conf );
328
+
329
+ ngx_str_t iv ;
330
+ char * data = (char * )v -> data ;
331
+ size_t data_len = v -> len ;
332
+
333
+
334
+ if (!conf -> iv_in_content )
335
+ {
336
+ iv = ngx_http_get_variable_by_name (r , conf -> iv , conf -> iv_len , conf );
337
+ }
338
+ else
339
+ {
340
+ ngx_log_error (NGX_LOG_DEBUG , r -> connection -> log , 0 ,
341
+ "encrypted_session: input to decrypt=%s" ,
342
+ data );
343
+ iv .len = strcspn (data , PARTS_DELIMITER );
344
+ iv .data = (u_char * )ngx_pcalloc (r -> pool , iv .len + 1 );
345
+ strncpy ((char * )iv .data , (char * )v -> data , iv .len );
346
+
347
+ ngx_log_error (NGX_LOG_DEBUG , r -> connection -> log , 0 ,
348
+ "encrypted_session: iv=%s" , iv .data );
349
+
350
+ size_t signature_start = iv .len + strcspn (& data [iv .len + 1 ], PARTS_DELIMITER ) + NUM_OF_DELIMITERS * PARTS_DELIMITER_LEN ;
351
+ size_t signature_len = v -> len - signature_start ;
352
+
353
+ u_char * signature = (u_char * )ngx_pcalloc (r -> pool , signature_len + 1 );
354
+ strncpy ((char * )signature , & data [data_len - signature_len ], signature_len );
355
+
356
+ ngx_log_error (NGX_LOG_DEBUG , r -> connection -> log , 0 ,
357
+ "encrypted_session: signature=%s" , signature );
358
+
359
+ data_len = v -> len - iv .len - signature_len - NUM_OF_DELIMITERS * PARTS_DELIMITER_LEN ;
360
+ data = (char * )ngx_pcalloc (r -> pool , data_len + 1 );
361
+ strncpy (data , (char * )(& v -> data [iv .len + 1 ]), data_len );
362
+
363
+ ngx_log_error (NGX_LOG_DEBUG , r -> connection -> log , 0 ,
364
+ "encrypted_session: data=%s" , data );
365
+
366
+ ngx_str_t signature_input ;
367
+ signature_input .len = iv .len + data_len ;
368
+ signature_input .data = (u_char * )ngx_pcalloc (r -> pool , signature_input .len + 1 );
369
+ strncat ((char * )signature_input .data , (char * )iv .data , iv .len );
370
+ strncat ((char * )signature_input .data , (char * )data , data_len );
371
+
372
+ ngx_str_t * computed_signature = ngx_http_session_encrypted_compute_hmac (r ,
373
+ & key , & signature_input );
374
+ if (signature_len != computed_signature -> len ||
375
+ strncmp ((char * )computed_signature -> data , (char * )signature , signature_len ) != 0 )
376
+ {
377
+ ngx_log_error (NGX_LOG_WARN , r -> connection -> log , 0 ,
378
+ "encrypted_session: signatures do not match" );
379
+ res -> data = NULL ;
380
+ res -> len = 0 ;
381
+
382
+ return NGX_OK ;
383
+ }
384
+ }
245
385
246
386
rc = ngx_http_encrypted_session_aes_mac_decrypt (emcf , r -> pool ,
247
387
r -> connection -> log , iv .data , iv .len , key .data , key .len ,
248
- v -> data , v -> len , & dst , & len );
388
+ ( u_char * ) data , data_len , & dst , & len );
249
389
250
390
if (rc != NGX_OK ) {
391
+ ngx_log_error (NGX_LOG_WARN , r -> connection -> log , 0 ,
392
+ "encrypted_session: failed to decrypt" );
251
393
dst = NULL ;
252
394
len = 0 ;
253
395
}
254
396
397
+ if (conf -> iv_in_content ) {
398
+ size_t payload_len = len - iv .len - 1 ;
399
+ u_char * result = ngx_pcalloc (r -> pool , payload_len + 1 );
400
+ memcpy (result , & dst [iv .len + 1 ], payload_len );
401
+ dst = result ;
402
+ len = payload_len ;
403
+ ngx_log_error (NGX_LOG_DEBUG , r -> connection -> log , 0 ,
404
+ "encrypted_session: decrypted content=%s" ,
405
+ dst );
406
+ }
407
+
255
408
res -> data = dst ;
256
409
res -> len = len ;
257
410
@@ -273,7 +426,9 @@ ngx_http_encrypted_session_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
273
426
value = cf -> args -> elts ;
274
427
275
428
if (value [1 ].len > 1 && value [1 ].data [0 ] == '$' ) {
276
- llcf -> key = & (value [1 ].data [1 ]);
429
+ llcf -> key_len = value [1 ].len - 1 ;
430
+ llcf -> key = (u_char * )ngx_pcalloc (cf -> pool , llcf -> key_len );
431
+ strncpy ((char * )llcf -> key , (char * )& (value [1 ].data [1 ]), llcf -> key_len );
277
432
return NGX_CONF_OK ;
278
433
}
279
434
@@ -287,6 +442,7 @@ ngx_http_encrypted_session_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
287
442
}
288
443
289
444
llcf -> key = value [1 ].data ;
445
+ llcf -> key_len = value [1 ].len ;
290
446
291
447
return NGX_CONF_OK ;
292
448
}
@@ -307,6 +463,7 @@ ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
307
463
308
464
if (value [1 ].len > 1 && value [1 ].data [0 ] == '$' ) {
309
465
llcf -> iv = & (value [1 ].data [1 ]);
466
+ llcf -> iv_len = value [1 ].len - 1 ;
310
467
return NGX_CONF_OK ;
311
468
}
312
469
@@ -320,6 +477,7 @@ ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
320
477
}
321
478
322
479
llcf -> iv = ngx_pcalloc (cf -> pool , ngx_http_encrypted_session_iv_length );
480
+ llcf -> iv_len = ngx_http_encrypted_session_iv_length ;
323
481
324
482
if (llcf -> iv == NULL ) {
325
483
return NGX_CONF_ERROR ;
@@ -360,6 +518,13 @@ ngx_http_encrypted_session_expires(ngx_conf_t *cf, ngx_command_t *cmd,
360
518
return NGX_CONF_OK ;
361
519
}
362
520
521
+ static char * ngx_http_encrypted_iv_in_content (ngx_conf_t * cf ,
522
+ ngx_command_t * cmd , void * conf )
523
+ {
524
+ ngx_http_encrypted_session_conf_t * llcf = conf ;
525
+ llcf -> iv_in_content = 1 ;
526
+ return NGX_CONF_OK ;
527
+ }
363
528
364
529
static void
365
530
ngx_http_encrypted_session_free_cipher_ctx (void * data )
@@ -435,8 +600,11 @@ ngx_http_encrypted_session_create_conf(ngx_conf_t *cf)
435
600
}
436
601
437
602
conf -> key = NGX_CONF_UNSET_PTR ;
603
+ conf -> key_len = NGX_CONF_UNSET ;
438
604
conf -> iv = NGX_CONF_UNSET_PTR ;
605
+ conf -> iv_len = NGX_CONF_UNSET ;
439
606
conf -> expires = NGX_CONF_UNSET ;
607
+ conf -> iv_in_content = NGX_CONF_UNSET ;
440
608
441
609
return conf ;
442
610
}
@@ -449,12 +617,17 @@ ngx_http_encrypted_session_merge_conf(ngx_conf_t *cf, void *parent, void *child)
449
617
ngx_http_encrypted_session_conf_t * conf = child ;
450
618
451
619
ngx_conf_merge_ptr_value (conf -> key , prev -> key , NULL );
620
+ ngx_conf_merge_size_value (conf -> key_len , prev -> key_len ,
621
+ (size_t )ngx_http_encrypted_session_key_length );
452
622
453
623
ngx_conf_merge_ptr_value (conf -> iv , prev -> iv ,
454
624
ngx_http_encrypted_session_default_iv );
625
+ ngx_conf_merge_size_value (conf -> iv_len , prev -> iv_len ,
626
+ (size_t )ngx_http_encrypted_session_iv_length );
455
627
456
628
ngx_conf_merge_value (conf -> expires , prev -> expires ,
457
629
ngx_http_encrypted_session_default_expires );
630
+ ngx_conf_merge_value (conf -> iv_in_content , prev -> iv_in_content , 0 );
458
631
459
632
return NGX_CONF_OK ;
460
633
}
0 commit comments