Skip to content

Commit

Permalink
The module should support AES gcm mode.
Browse files Browse the repository at this point in the history
  • Loading branch information
rcosnita committed Nov 3, 2020
1 parent 8953ff7 commit c118d54
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 28 deletions.
50 changes: 45 additions & 5 deletions src/ngx_http_encrypted_session_cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,28 @@
static uint64_t ngx_http_encrypted_session_ntohll(uint64_t n);
static uint64_t ngx_http_encrypted_session_htonll(uint64_t n);

const EVP_CIPHER*
ngx_http_encrypted_session_get_cipher(enum ngx_http_encrypted_session_mode mode)
{
if (mode == ngx_http_encrypted_session_mode_cbc)
{
return EVP_aes_256_cbc();
}
else if (mode == ngx_http_encrypted_session_mode_gcm)
{
return EVP_aes_256_gcm();
}

return NULL;
}

ngx_int_t
ngx_http_encrypted_session_aes_mac_encrypt(
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
size_t key_len, const u_char *in, size_t in_len, ngx_uint_t expires,
u_char **dst, size_t *dst_len)
enum ngx_http_encrypted_session_mode mode,
u_char **dst, size_t *dst_len, u_char **tag)
{
const EVP_CIPHER *cipher;
u_char *p, *data;
Expand All @@ -50,7 +65,10 @@ ngx_http_encrypted_session_aes_mac_encrypt(
}
}

cipher = EVP_aes_256_cbc();
cipher = ngx_http_encrypted_session_get_cipher(mode);
if (!cipher) {
goto evp_error;
}

block_size = EVP_CIPHER_block_size(cipher);

Expand Down Expand Up @@ -107,6 +125,15 @@ ngx_http_encrypted_session_aes_mac_encrypt(
p += len;

ret = EVP_EncryptFinal(emcf->session_ctx, p, &len);
if (!ret) {
goto evp_error;
}

if (mode == ngx_http_encrypted_session_mode_gcm) {
*tag = (u_char*)ngx_pcalloc(pool, ngx_http_encrypted_session_aes_tag_size);
ret = EVP_CIPHER_CTX_ctrl(emcf->session_ctx, EVP_CTRL_GCM_GET_TAG,
ngx_http_encrypted_session_aes_tag_size, *tag);
}

emcf->reset_cipher_ctx(emcf->session_ctx);

Expand Down Expand Up @@ -139,8 +166,10 @@ ngx_int_t
ngx_http_encrypted_session_aes_mac_decrypt(
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
size_t key_len, const u_char *in, size_t in_len, u_char **dst,
size_t *dst_len)
size_t key_len, const u_char *in, size_t in_len,
enum ngx_http_encrypted_session_mode mode,
u_char *tag,
u_char **dst, size_t *dst_len)
{
const EVP_CIPHER *cipher;
int ret;
Expand Down Expand Up @@ -171,7 +200,10 @@ ngx_http_encrypted_session_aes_mac_decrypt(
}
}

cipher = EVP_aes_256_cbc();
cipher = ngx_http_encrypted_session_get_cipher(mode);
if (!cipher) {
goto evp_error;
}

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

p += len;

if (mode == ngx_http_encrypted_session_mode_gcm) {
ret = EVP_CIPHER_CTX_ctrl(emcf->session_ctx, EVP_CTRL_GCM_SET_TAG,
ngx_http_encrypted_session_aes_tag_size, tag);
if (!ret) {
goto evp_error;
}
}

ret = EVP_DecryptFinal(emcf->session_ctx, p, &len);

emcf->reset_cipher_ctx(emcf->session_ctx);
Expand Down
17 changes: 13 additions & 4 deletions src/ngx_http_encrypted_session_cipher.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,30 @@ typedef struct {

enum {
ngx_http_encrypted_session_key_length = 256 / 8,
ngx_http_encrypted_session_iv_length = EVP_MAX_IV_LENGTH
ngx_http_encrypted_session_iv_length = EVP_MAX_IV_LENGTH,
ngx_http_encrypted_session_aes_tag_size = 16
};

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

ngx_int_t ngx_http_encrypted_session_aes_mac_encrypt(
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
size_t key_len, const u_char *in, size_t in_len,
ngx_uint_t expires, u_char **dst, size_t *dst_len);
ngx_uint_t expires, enum ngx_http_encrypted_session_mode mode,
u_char **dst, size_t *dst_len, u_char **tag);

ngx_int_t ngx_http_encrypted_session_aes_mac_decrypt(
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
size_t key_len, const u_char *in, size_t in_len, u_char **dst,
size_t *dst_len);
size_t key_len, const u_char *in, size_t in_len,
enum ngx_http_encrypted_session_mode mode,
u_char *tag,
u_char **dst, size_t *dst_len);

unsigned char* ngx_http_encrypted_session_hmac(
ngx_pool_t *pool,
Expand Down
138 changes: 119 additions & 19 deletions src/ngx_http_encrypted_session_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ const size_t IV_LENGTH = 16;
const size_t SIGNATURE_LENGTH = 32;

typedef struct {
u_char *key;
size_t key_len;
u_char *iv;
size_t iv_len;
time_t expires;
ngx_flag_t iv_in_content;
u_char *key;
size_t key_len;
u_char *iv;
size_t iv_len;
time_t expires;
ngx_flag_t iv_in_content;
enum ngx_http_encrypted_session_mode encryption_mode;
} ngx_http_encrypted_session_conf_t;

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

static char *ngx_http_encrypted_session_mode_set(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);

static char *ngx_http_encrypted_session_expires(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);

Expand Down Expand Up @@ -93,6 +97,15 @@ static ngx_command_t ngx_http_encrypted_session_commands[] = {
0,
NULL
},
{
ngx_string("encrypted_session_mode"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
ngx_http_encrypted_session_mode_set,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
},
{
ngx_string("encrypted_session_expires"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
Expand Down Expand Up @@ -216,12 +229,28 @@ ngx_http_session_encrypted_compute_hmac(ngx_http_request_t *r,

static ngx_str_t*
ngx_http_session_generate_signature(ngx_http_request_t *r,
ngx_str_t *iv, ngx_str_t *key, ngx_str_t *content)
ngx_str_t *iv, ngx_str_t *key, ngx_str_t *content,
ngx_str_t *tag, enum ngx_http_encrypted_session_mode mode)
{
size_t signature_content_len = iv->len + content->len;
if (mode == ngx_http_encrypted_session_mode_gcm)
{
signature_content_len += tag->len;
}

u_char* signature_content = (u_char*)ngx_pcalloc(r->pool, signature_content_len + 1);
ngx_memcpy(signature_content, iv->data, iv->len);
ngx_memcpy(signature_content + iv->len, content->data, content->len);

if (mode == ngx_http_encrypted_session_mode_gcm)
{
ngx_memcpy(signature_content + iv->len, tag->data, tag->len);
ngx_memcpy(signature_content + iv->len + tag->len,
content->data, content->len);
}
else
{
ngx_memcpy(signature_content + iv->len, content->data, content->len);
}

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

static ngx_str_t*
ngx_http_session_generate_response_with_iv(ngx_http_request_t *r,
ngx_str_t *iv, ngx_str_t *key, ngx_str_t *content)
ngx_str_t *iv, ngx_str_t *key, ngx_str_t *content,
ngx_str_t *tag, enum ngx_http_encrypted_session_mode mode)
{
ngx_str_t *signature = ngx_http_session_generate_signature(r, iv, key, content);
ngx_str_t *signature = ngx_http_session_generate_signature(r, iv, key,
content, tag, mode);

size_t new_len = iv->len + signature->len + content->len;

if (mode == ngx_http_encrypted_session_mode_gcm)
{
new_len += tag->len;
}

size_t new_len = iv->len + content->len + signature->len;
u_char *new_content = (u_char*)ngx_pcalloc(r->pool, new_len + 1);
ngx_memcpy(new_content, iv->data, iv->len);
ngx_memcpy(new_content + iv->len, signature->data, signature->len);
ngx_memcpy(new_content + iv->len + signature->len, content->data, content->len);

if (mode == ngx_http_encrypted_session_mode_gcm)
{
ngx_memcpy(new_content + iv->len + signature->len, tag->data, tag->len);
ngx_memcpy(new_content + iv->len + signature->len + tag->len, content->data, content->len);
}
else
{
ngx_memcpy(new_content + iv->len + signature->len, content->data, content->len);
}

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

u_char *tag;
rc = ngx_http_encrypted_session_aes_mac_encrypt(emcf, r->pool,
r->connection->log, iv.data, iv.len, key.data, key.len,
content.data, content.len, (ngx_uint_t) conf->expires, &dst, &len);
content.data, content.len,
(ngx_uint_t) conf->expires, conf->encryption_mode, &dst, &len, &tag);

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

ngx_str_t tag_content;
tag_content.len = ngx_http_encrypted_session_aes_tag_size;
tag_content.data = tag;

ngx_str_t *result = ngx_http_session_generate_response_with_iv(r, &iv,
&key, &encrypted_content);
&key, &encrypted_content, &tag_content, conf->encryption_mode);
res->data = result->data;
res->len = result->len;

Expand Down Expand Up @@ -377,6 +429,8 @@ ngx_http_set_decode_encrypted_session(ngx_http_request_t *r,

ngx_str_t iv;
ngx_str_t content;
ngx_str_t tag;

content.data = v->data;
content.len = v->len;

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

if (conf->encryption_mode == ngx_http_encrypted_session_mode_gcm)
{
tag.len = ngx_http_encrypted_session_aes_tag_size;
tag.data = (u_char*)ngx_pcalloc(r->pool, tag.len);
ngx_memcpy(tag.data, content.data + iv.len + SIGNATURE_LENGTH, tag.len);
}

ngx_str_t encrypted_content;
encrypted_content.len = content.len - iv.len - SIGNATURE_LENGTH;
encrypted_content.data = (u_char*)ngx_pcalloc(r->pool, encrypted_content.len + 1);
ngx_memcpy(encrypted_content.data, v->data + iv.len + SIGNATURE_LENGTH, encrypted_content.len);
if (conf->encryption_mode == ngx_http_encrypted_session_mode_gcm)
{
encrypted_content.len = content.len - iv.len - SIGNATURE_LENGTH - tag.len;
encrypted_content.data = (u_char*)ngx_pcalloc(r->pool, encrypted_content.len + 1);
ngx_memcpy(encrypted_content.data,
v->data + iv.len + SIGNATURE_LENGTH + tag.len,
encrypted_content.len);
}
else
{
encrypted_content.len = content.len - iv.len - SIGNATURE_LENGTH;
encrypted_content.data = (u_char*)ngx_pcalloc(r->pool, encrypted_content.len + 1);
ngx_memcpy(encrypted_content.data, v->data + iv.len + SIGNATURE_LENGTH, encrypted_content.len);
}

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

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

rc = ngx_http_encrypted_session_aes_mac_decrypt(emcf, r->pool,
r->connection->log, iv.data, iv.len, key.data, key.len,
content.data, content.len, &dst, &len);
content.data, content.len, conf->encryption_mode, tag.data,
&dst, &len);

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

static char *
ngx_http_encrypted_session_mode_set(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf)
{
ngx_str_t *value;
ngx_http_encrypted_session_conf_t *llcf = conf;

value = cf->args->elts;
if (value[1].len == 3 && strncmp("cbc", (char*)value[1].data, 3) == 0) {
llcf->encryption_mode = ngx_http_encrypted_session_mode_cbc;
}
else if (value[1].len == 3 && strncmp("gcm", (char*)value[1].data, 3) == 0) {
llcf->encryption_mode = ngx_http_encrypted_session_mode_gcm;
}

return NGX_CONF_OK;
}


static char *
ngx_http_encrypted_session_expires(ngx_conf_t *cf, ngx_command_t *cmd,
Expand Down Expand Up @@ -654,6 +745,7 @@ ngx_http_encrypted_session_create_conf(ngx_conf_t *cf)
conf->iv_len = NGX_CONF_UNSET;
conf->expires = NGX_CONF_UNSET;
conf->iv_in_content = NGX_CONF_UNSET;
conf->encryption_mode = ngx_http_encrypted_session_mode_unknown;

return conf;
}
Expand All @@ -678,5 +770,13 @@ ngx_http_encrypted_session_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_encrypted_session_default_expires);
ngx_conf_merge_value(conf->iv_in_content, prev->iv_in_content, 0);

if (conf->encryption_mode == ngx_http_encrypted_session_mode_unknown) {
conf->encryption_mode = prev->encryption_mode;
}

if (conf->encryption_mode == ngx_http_encrypted_session_mode_unknown) {
conf->encryption_mode = ngx_http_encrypted_session_mode_cbc;
}

return NGX_CONF_OK;
}

0 comments on commit c118d54

Please sign in to comment.