Commit fe3cd1b4 authored by Geoff Simmons's avatar Geoff Simmons

Re-work and bugfix the concurrent use of symmetric cipher handles.

The previous implementation was not thread safe.
Now use pthread keys to create a handle for each object in each
thread, and then retrieve them in the same thread.
parent 3f9cbef7
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <gcrypt.h> #include <gcrypt.h>
#include <string.h> #include <string.h>
#include <pthread.h>
#include <errno.h>
#include "vcl.h" #include "vcl.h"
#include "cache/cache.h" #include "cache/cache.h"
...@@ -63,11 +65,14 @@ ...@@ -63,11 +65,14 @@
struct vmod_gcrypt_symmetric { struct vmod_gcrypt_symmetric {
unsigned magic; unsigned magic;
#define VMOD_GCRYPT_SYMMETRIC_MAGIC 0x82c7ffe2 #define VMOD_GCRYPT_SYMMETRIC_MAGIC 0x82c7ffe2
gcry_cipher_hd_t hd; pthread_key_t hdk;
char *vcl_name; char *vcl_name;
size_t blocklen; void *key;
size_t keylen;
enum padding padding; enum padding padding;
int algo;
int mode; int mode;
unsigned int flags;
}; };
static const char *gcrypt_version = NULL; static const char *gcrypt_version = NULL;
...@@ -215,6 +220,18 @@ vmod_init(VRT_CTX, VCL_ENUM cmd, VCL_BYTES n) ...@@ -215,6 +220,18 @@ vmod_init(VRT_CTX, VCL_ENUM cmd, VCL_BYTES n)
/* Object symmetric */ /* Object symmetric */
/* Destructor function for cipher handles pointed to by pthread keys */
static void
hdk_fini(void *p)
{
gcry_cipher_hd_t *hd;
AN(p);
hd = (gcry_cipher_hd_t *)p;
gcry_cipher_close(*hd);
free(p);
}
VCL_VOID VCL_VOID
vmod_symmetric__init(VRT_CTX, struct vmod_gcrypt_symmetric **symmetricp, vmod_symmetric__init(VRT_CTX, struct vmod_gcrypt_symmetric **symmetricp,
const char *vcl_name, VCL_ENUM ciphers, VCL_ENUM modes, const char *vcl_name, VCL_ENUM ciphers, VCL_ENUM modes,
...@@ -228,6 +245,7 @@ vmod_symmetric__init(VRT_CTX, struct vmod_gcrypt_symmetric **symmetricp, ...@@ -228,6 +245,7 @@ vmod_symmetric__init(VRT_CTX, struct vmod_gcrypt_symmetric **symmetricp,
enum padding padding = _MAX_PADDING; enum padding padding = _MAX_PADDING;
gcry_error_t err = GPG_ERR_NO_ERROR; gcry_error_t err = GPG_ERR_NO_ERROR;
size_t len; size_t len;
pthread_key_t hdk;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(symmetricp); AN(symmetricp);
...@@ -269,7 +287,7 @@ vmod_symmetric__init(VRT_CTX, struct vmod_gcrypt_symmetric **symmetricp, ...@@ -269,7 +287,7 @@ vmod_symmetric__init(VRT_CTX, struct vmod_gcrypt_symmetric **symmetricp,
len, ciphers, vcl_name); len, ciphers, vcl_name);
return; return;
} }
if ((len = gcry_cipher_get_algo_blklen(algo)) == 0) { if (gcry_cipher_get_algo_blklen(algo) == 0) {
VERR(ctx, "Cannot determine block length for %s cipher in %s " VERR(ctx, "Cannot determine block length for %s cipher in %s "
"constructor", ciphers, vcl_name); "constructor", ciphers, vcl_name);
return; return;
...@@ -294,28 +312,58 @@ vmod_symmetric__init(VRT_CTX, struct vmod_gcrypt_symmetric **symmetricp, ...@@ -294,28 +312,58 @@ vmod_symmetric__init(VRT_CTX, struct vmod_gcrypt_symmetric **symmetricp,
if (cbc_cts) if (cbc_cts)
flags |= GCRY_CIPHER_CBC_CTS; flags |= GCRY_CIPHER_CBC_CTS;
/* Create a handle to test for errors */
if ((err = gcry_cipher_open(&hd, algo, mode, flags)) if ((err = gcry_cipher_open(&hd, algo, mode, flags))
!= GPG_ERR_NO_ERROR) { != GPG_ERR_NO_ERROR) {
VERR(ctx, "Cannot open cipher in %s constructor: %s/%s", VERR(ctx, "Cannot open cipher in %s constructor: %s/%s",
vcl_name, gcry_strsource(err), gcry_strerror(err)); vcl_name, gcry_strsource(err), gcry_strerror(err));
return; return;
} }
if ((err = gcry_cipher_setkey(hd, key->priv, key->len)) err = gcry_cipher_setkey(hd, key->priv, key->len);
!= GPG_ERR_NO_ERROR) { gcry_cipher_close(hd);
if (err != GPG_ERR_NO_ERROR) {
VERR(ctx, "Cannot set key in %s constructor: %s/%s", VERR(ctx, "Cannot set key in %s constructor: %s/%s",
vcl_name, gcry_strsource(err), gcry_strerror(err)); vcl_name, gcry_strsource(err), gcry_strerror(err));
return; return;
} }
if (pthread_key_create(&hdk, hdk_fini) != 0) {
if (errno == EAGAIN)
VERR(ctx, "pthread key allocation exhausted "
"(PTHREAD_KEYS_MAX=%d) in %s constructor, "
"discard old VCL instances or restart Varnish",
PTHREAD_KEYS_MAX, vcl_name);
else
VERR(ctx, "unknown error creating pthread key in %s "
"constructor (errno=%d, %s)", vcl_name, errno,
strerror(errno));
return;
}
ALLOC_OBJ(symmetric, VMOD_GCRYPT_SYMMETRIC_MAGIC); ALLOC_OBJ(symmetric, VMOD_GCRYPT_SYMMETRIC_MAGIC);
AN(symmetric); AN(symmetric);
*symmetricp = symmetric; *symmetricp = symmetric;
memcpy(&symmetric->hd, &hd, sizeof(hd)); symmetric->hdk = hdk;
if (secure)
symmetric->key = gcry_malloc_secure(key->len);
else
symmetric->key = malloc(key->len);
if (symmetric->key == NULL) {
VERRNOMEM(ctx, "copying key in %s constructor", vcl_name);
return;
}
symmetric->vcl_name = strdup(vcl_name); symmetric->vcl_name = strdup(vcl_name);
AN(symmetric->vcl_name); if (symmetric->vcl_name == NULL) {
symmetric->blocklen = len; VERRNOMEM(ctx, "copying object name in %s constructor",
vcl_name);
return;
}
memcpy(symmetric->key, key->priv, key->len);
symmetric->keylen = key->len;
symmetric->padding = padding; symmetric->padding = padding;
symmetric->algo = algo;
symmetric->mode = mode; symmetric->mode = mode;
symmetric->flags = flags;
} }
VCL_VOID VCL_VOID
...@@ -323,28 +371,77 @@ vmod_symmetric__fini(struct vmod_gcrypt_symmetric **symmetricp) ...@@ -323,28 +371,77 @@ vmod_symmetric__fini(struct vmod_gcrypt_symmetric **symmetricp)
{ {
struct vmod_gcrypt_symmetric *symmetric; struct vmod_gcrypt_symmetric *symmetric;
if (symmetricp == NULL) if (symmetricp == NULL || *symmetricp == NULL)
return; return;
symmetric = *symmetricp; symmetric = *symmetricp;
if (symmetric == NULL)
return;
CHECK_OBJ(symmetric, VMOD_GCRYPT_SYMMETRIC_MAGIC); CHECK_OBJ(symmetric, VMOD_GCRYPT_SYMMETRIC_MAGIC);
if (symmetric->key != NULL) {
if (symmetric->flags & GCRY_CIPHER_SECURE)
gcry_free(symmetric->key);
else
free(symmetric->key);
}
if (symmetric->vcl_name != NULL) if (symmetric->vcl_name != NULL)
free(symmetric->vcl_name); free(symmetric->vcl_name);
gcry_cipher_close(symmetric->hd); AZ(pthread_key_delete(symmetric->hdk));
FREE_OBJ(symmetric); FREE_OBJ(symmetric);
} }
static gcry_cipher_hd_t *
get_symmetric_hd(VRT_CTX,
const struct vmod_gcrypt_symmetric * const restrict symmetric,
const char * const restrict caller)
{
void *p;
gcry_cipher_hd_t *hd;
gcry_error_t err = GPG_ERR_NO_ERROR;
p = pthread_getspecific(symmetric->hdk);
if (p != NULL) {
hd = (gcry_cipher_hd_t *)p;
if ((err = gcry_cipher_reset(*hd)) != GPG_ERR_NO_ERROR) {
VERR(ctx, "Cannot reset cipher handle in %s.%s(): "
"%s/%s", symmetric->vcl_name, caller,
gcry_strsource(err), gcry_strerror(err));
return NULL;
}
return hd;
}
hd = malloc(sizeof(hd));
if (hd == NULL) {
VERRNOMEM(ctx, "Allocating cipher handle in %s.%s()",
symmetric->vcl_name, caller);
return NULL;
}
if ((err = gcry_cipher_open(hd, symmetric->algo, symmetric->mode,
symmetric->flags)) != GPG_ERR_NO_ERROR) {
VERR(ctx, "Cannot open cipher in %s.%s(): %s/%s",
symmetric->vcl_name, caller, gcry_strsource(err),
gcry_strerror(err));
return NULL;
}
if ((err = gcry_cipher_setkey(*hd, symmetric->key, symmetric->keylen))
!= GPG_ERR_NO_ERROR) {
VERR(ctx, "Cannot set key in %s.%s(): %s/%s",
symmetric->vcl_name, caller, gcry_strsource(err),
gcry_strerror(err));
return NULL;
}
pthread_setspecific(symmetric->hdk, (void *)hd);
return hd;
}
VCL_BLOB VCL_BLOB
vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
VCL_BLOB plainblob, VCL_BLOB iv, VCL_BLOB ctr) VCL_BLOB plainblob, VCL_BLOB iv, VCL_BLOB ctr)
{ {
size_t len; size_t len, blocklen;
uintptr_t snap; uintptr_t snap;
void *plaintext; void *plaintext;
struct vmod_priv *ciphertext; struct vmod_priv *ciphertext;
gcry_error_t err = GPG_ERR_NO_ERROR; gcry_error_t err = GPG_ERR_NO_ERROR;
gcry_cipher_hd_t hd; gcry_cipher_hd_t *hd;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(symmetric, VMOD_GCRYPT_SYMMETRIC_MAGIC); CHECK_OBJ_NOTNULL(symmetric, VMOD_GCRYPT_SYMMETRIC_MAGIC);
...@@ -360,10 +457,11 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -360,10 +457,11 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
symmetric->vcl_name); symmetric->vcl_name);
return NULL; return NULL;
} }
blocklen = gcry_cipher_get_algo_blklen(symmetric->algo);
AN(blocklen);
if (symmetric->padding != NONE) { if (symmetric->padding != NONE) {
plaintext = (padf[symmetric->padding])(ctx->ws, plainblob->priv, plaintext = (padf[symmetric->padding])(ctx->ws, plainblob->priv,
plainblob->len, plainblob->len, blocklen,
symmetric->blocklen,
&len); &len);
if (plaintext == NULL) { if (plaintext == NULL) {
VERRNOMEM(ctx, "Allocating padded plaintext in " VERRNOMEM(ctx, "Allocating padded plaintext in "
...@@ -383,7 +481,11 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -383,7 +481,11 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
return NULL; return NULL;
} }
memcpy(&hd, &symmetric->hd, sizeof(hd)); hd = get_symmetric_hd(ctx, symmetric, "encrypt");
if (hd == NULL) {
WS_Reset(ctx->ws, snap);
return NULL;
}
if (need_iv[symmetric->mode]) { if (need_iv[symmetric->mode]) {
if (iv == NULL) { if (iv == NULL) {
VERR(ctx, "Required initialization vector is NULL in " VERR(ctx, "Required initialization vector is NULL in "
...@@ -395,7 +497,7 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -395,7 +497,7 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
/* A NULL iv of length 0 is permitted. */ /* A NULL iv of length 0 is permitted. */
if (iv->priv == NULL) if (iv->priv == NULL)
assert(iv->len == 0); assert(iv->len == 0);
if ((err = gcry_cipher_setiv(hd, iv->priv, iv->len)) if ((err = gcry_cipher_setiv(*hd, iv->priv, iv->len))
!= GPG_ERR_NO_ERROR) { != GPG_ERR_NO_ERROR) {
VERR(ctx, "Cannot set initialization vector in " VERR(ctx, "Cannot set initialization vector in "
"%s.encrypt(): %s/%s", symmetric->vcl_name, "%s.encrypt(): %s/%s", symmetric->vcl_name,
...@@ -412,7 +514,7 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -412,7 +514,7 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
return NULL; return NULL;
} }
assert(ctr->len >= 0); assert(ctr->len >= 0);
if ((err = gcry_cipher_setctr(hd, ctr->priv, ctr->len)) if ((err = gcry_cipher_setctr(*hd, ctr->priv, ctr->len))
!= GPG_ERR_NO_ERROR) { != GPG_ERR_NO_ERROR) {
VERR(ctx, "Cannot set counter vector in %s.encrypt(): " VERR(ctx, "Cannot set counter vector in %s.encrypt(): "
"%s/%s", symmetric->vcl_name, gcry_strsource(err), "%s/%s", symmetric->vcl_name, gcry_strsource(err),
...@@ -421,7 +523,7 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -421,7 +523,7 @@ vmod_symmetric_encrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
return NULL; return NULL;
} }
} }
if ((err = gcry_cipher_encrypt(hd, ciphertext->priv, len, plaintext, if ((err = gcry_cipher_encrypt(*hd, ciphertext->priv, len, plaintext,
len)) len))
!= GPG_ERR_NO_ERROR) { != GPG_ERR_NO_ERROR) {
VERR(ctx, "in %s.encrypt(): %s/%s", symmetric->vcl_name, VERR(ctx, "in %s.encrypt(): %s/%s", symmetric->vcl_name,
...@@ -441,7 +543,8 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -441,7 +543,8 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
uintptr_t snap; uintptr_t snap;
struct vmod_priv *plaintext; struct vmod_priv *plaintext;
gcry_error_t err = GPG_ERR_NO_ERROR; gcry_error_t err = GPG_ERR_NO_ERROR;
gcry_cipher_hd_t hd; gcry_cipher_hd_t *hd;
size_t blocklen;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(symmetric, VMOD_GCRYPT_SYMMETRIC_MAGIC); CHECK_OBJ_NOTNULL(symmetric, VMOD_GCRYPT_SYMMETRIC_MAGIC);
...@@ -467,7 +570,9 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -467,7 +570,9 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
return NULL; return NULL;
} }
memcpy(&hd, &symmetric->hd, sizeof(hd)); hd = get_symmetric_hd(ctx, symmetric, "decrypt");
if (hd == NULL)
goto fail;
if (need_iv[symmetric->mode]) { if (need_iv[symmetric->mode]) {
if (iv == NULL) { if (iv == NULL) {
VERR(ctx, "Required initialization vector is NULL in " VERR(ctx, "Required initialization vector is NULL in "
...@@ -478,7 +583,7 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -478,7 +583,7 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
/* A NULL iv of length 0 is permitted. */ /* A NULL iv of length 0 is permitted. */
if (iv->priv == NULL) if (iv->priv == NULL)
assert(iv->len == 0); assert(iv->len == 0);
if ((err = gcry_cipher_setiv(hd, iv->priv, iv->len)) if ((err = gcry_cipher_setiv(*hd, iv->priv, iv->len))
!= GPG_ERR_NO_ERROR) { != GPG_ERR_NO_ERROR) {
VERR(ctx, "Cannot set initialization vector in " VERR(ctx, "Cannot set initialization vector in "
"%s.decrypt(): %s/%s", symmetric->vcl_name, "%s.decrypt(): %s/%s", symmetric->vcl_name,
...@@ -493,7 +598,7 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -493,7 +598,7 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
goto fail; goto fail;
} }
assert(ctr->len >= 0); assert(ctr->len >= 0);
if ((err = gcry_cipher_setctr(hd, ctr->priv, ctr->len)) if ((err = gcry_cipher_setctr(*hd, ctr->priv, ctr->len))
!= GPG_ERR_NO_ERROR) { != GPG_ERR_NO_ERROR) {
VERR(ctx, "Cannot set counter vector in %s.decrypt(): " VERR(ctx, "Cannot set counter vector in %s.decrypt(): "
"%s/%s", symmetric->vcl_name, gcry_strsource(err), "%s/%s", symmetric->vcl_name, gcry_strsource(err),
...@@ -501,7 +606,7 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -501,7 +606,7 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
goto fail; goto fail;
} }
} }
if ((err = gcry_cipher_decrypt(hd, plaintext->priv, ciphertext->len, if ((err = gcry_cipher_decrypt(*hd, plaintext->priv, ciphertext->len,
ciphertext->priv, ciphertext->len)) ciphertext->priv, ciphertext->len))
!= GPG_ERR_NO_ERROR) { != GPG_ERR_NO_ERROR) {
VERR(ctx, "in %s.decrypt(): %s/%s", symmetric->vcl_name, VERR(ctx, "in %s.decrypt(): %s/%s", symmetric->vcl_name,
...@@ -509,18 +614,20 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric, ...@@ -509,18 +614,20 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
goto fail; goto fail;
} }
plaintext->len = ciphertext->len; plaintext->len = ciphertext->len;
blocklen = gcry_cipher_get_algo_blklen(symmetric->algo);
AN(blocklen);
if (symmetric->padding != NONE) { if (symmetric->padding != NONE) {
if (plaintext->len % symmetric->blocklen != 0) { if (plaintext->len % blocklen != 0) {
VERR(ctx, "in %s.decrypt(): padding is required, but " VERR(ctx, "in %s.decrypt(): padding is required, but "
"plaintext length %d is not a multiple of block " "plaintext length %d is not a multiple of block "
"length %d", symmetric->vcl_name, plaintext->len, "length %d", symmetric->vcl_name, plaintext->len,
symmetric->blocklen); blocklen);
goto fail; goto fail;
} }
plaintext->len = plaintext->len =
(unpadlenf[symmetric->padding])(plaintext->priv, (unpadlenf[symmetric->padding])(plaintext->priv,
ciphertext->len, ciphertext->len,
symmetric->blocklen); blocklen);
if (plaintext->len < 0) { if (plaintext->len < 0) {
VERR(ctx, "in %s.decrypt(): incorrect padding", VERR(ctx, "in %s.decrypt(): incorrect padding",
symmetric->vcl_name); symmetric->vcl_name);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment