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"
1920
2021typedef 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
2834static 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,
4248static 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
4654static ngx_int_t ngx_http_encrypted_session_init (ngx_conf_t * cf );
4755static 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);
5361static char * ngx_http_encrypted_session_merge_conf (ngx_conf_t * cf , void * parent ,
5462 void * child );
5563
56-
5764static 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
153167static 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 + 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+
174219static ngx_int_t
175220ngx_http_set_encode_encrypted_session (ngx_http_request_t * r ,
176221 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,
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+ 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+ }
201257
202258 rc = ngx_http_encrypted_session_aes_mac_encrypt (emcf , r -> pool ,
203259 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 );
205261
206262 if (rc != NGX_OK ) {
207263 dst = NULL ;
@@ -211,6 +267,33 @@ ngx_http_set_encode_encrypted_session(ngx_http_request_t *r,
211267 "encrypted_session: failed to encrypt" );
212268 }
213269
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+
214297 res -> data = dst ;
215298 res -> len = len ;
216299
@@ -240,18 +323,88 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,
240323 return NGX_ERROR ;
241324 }
242325
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+ }
245385
246386 rc = ngx_http_encrypted_session_aes_mac_decrypt (emcf , r -> pool ,
247387 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 );
249389
250390 if (rc != NGX_OK ) {
391+ ngx_log_error (NGX_LOG_WARN , r -> connection -> log , 0 ,
392+ "encrypted_session: failed to decrypt" );
251393 dst = NULL ;
252394 len = 0 ;
253395 }
254396
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+
255408 res -> data = dst ;
256409 res -> len = len ;
257410
@@ -273,7 +426,9 @@ ngx_http_encrypted_session_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
273426 value = cf -> args -> elts ;
274427
275428 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 );
277432 return NGX_CONF_OK ;
278433 }
279434
@@ -287,6 +442,7 @@ ngx_http_encrypted_session_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
287442 }
288443
289444 llcf -> key = value [1 ].data ;
445+ llcf -> key_len = value [1 ].len ;
290446
291447 return NGX_CONF_OK ;
292448}
@@ -307,6 +463,7 @@ ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
307463
308464 if (value [1 ].len > 1 && value [1 ].data [0 ] == '$' ) {
309465 llcf -> iv = & (value [1 ].data [1 ]);
466+ llcf -> iv_len = value [1 ].len - 1 ;
310467 return NGX_CONF_OK ;
311468 }
312469
@@ -320,6 +477,7 @@ ngx_http_encrypted_session_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
320477 }
321478
322479 llcf -> iv = ngx_pcalloc (cf -> pool , ngx_http_encrypted_session_iv_length );
480+ llcf -> iv_len = ngx_http_encrypted_session_iv_length ;
323481
324482 if (llcf -> iv == NULL ) {
325483 return NGX_CONF_ERROR ;
@@ -360,6 +518,13 @@ ngx_http_encrypted_session_expires(ngx_conf_t *cf, ngx_command_t *cmd,
360518 return NGX_CONF_OK ;
361519}
362520
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+ }
363528
364529static void
365530ngx_http_encrypted_session_free_cipher_ctx (void * data )
@@ -435,8 +600,11 @@ ngx_http_encrypted_session_create_conf(ngx_conf_t *cf)
435600 }
436601
437602 conf -> key = NGX_CONF_UNSET_PTR ;
603+ conf -> key_len = NGX_CONF_UNSET ;
438604 conf -> iv = NGX_CONF_UNSET_PTR ;
605+ conf -> iv_len = NGX_CONF_UNSET ;
439606 conf -> expires = NGX_CONF_UNSET ;
607+ conf -> iv_in_content = NGX_CONF_UNSET ;
440608
441609 return conf ;
442610}
@@ -449,12 +617,17 @@ ngx_http_encrypted_session_merge_conf(ngx_conf_t *cf, void *parent, void *child)
449617 ngx_http_encrypted_session_conf_t * conf = child ;
450618
451619 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 );
452622
453623 ngx_conf_merge_ptr_value (conf -> iv , prev -> iv ,
454624 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 );
455627
456628 ngx_conf_merge_value (conf -> expires , prev -> expires ,
457629 ngx_http_encrypted_session_default_expires );
630+ ngx_conf_merge_value (conf -> iv_in_content , prev -> iv_in_content , 0 );
458631
459632 return NGX_CONF_OK ;
460633}
0 commit comments