Commit d51371e8 authored by Geoff Simmons's avatar Geoff Simmons

Now a VMOD with a VFP for decryption.

The VFP passes the two "I am the walrus" tests from RFC 8188.

The key table is currently just a mockup.
parent a27102cf
......@@ -3,11 +3,67 @@ AUTOMAKE_OPTIONS = subdir-objects
AM_CFLAGS = $(VARNISHAPI_CFLAGS) @CRYPTO_CFLAGS@ -Wall -Werror -Wextra -std=c99
AM_LDFLAGS = $(VARNISHAPI_LIBS) @CRYPTO_LIBS@ -ldl
EXTRA_DIST = \
vmod_ece.vcc
vmod_LTLIBRARIES = libvmod_ece.la
libvmod_ece_la_SOURCES = \
vmod_ece.c \
rfc8188.c \
rfc8188.h \
vfp.c \
vfp.h \
foreign/vend.h \
keys.h
nodist_libvmod_ece_la_SOURCES = \
vcc_if.c \
vcc_if.h
vmod_ece.lo: $(nodist_libvmod_ece_la_SOURCES)
rfc8188.h: foreign/vend.h
vfp.c: rfc8188.h keys.h
vmod_ece.c: vfp.h
dist_man_MANS = vmod_ece.3
vcc_if.h vmod_ece.rst vmod_ece.man.rst: vcc_if.c
TESTS = rfc8188_test
vcc_if.c: vmod_ece.vcc
$(AM_V_VMODTOOL) $(PYTHON) $(VMODTOOL) -o vcc_if $(srcdir)/vmod_ece.vcc
vmod_ece.3: vmod_ece.man.rst
$(AM_V_GEN) $(RST2MAN) vmod_ece.man.rst vmod_ece.3
AM_TESTS_ENVIRONMENT = \
PATH="$(VMOD_TEST_PATH)" \
LD_LIBRARY_PATH="$(VARNISH_LIBRARY_PATH)"
TEST_EXTENSIONS = .vtc
VTC_LOG_COMPILER = varnishtest -v
AM_VTC_LOG_FLAGS = -Dvmod_ece="$(VMOD_ECE)"
TESTS = @VMOD_TESTS@
# To test an individual VTC test named test.vtc:
# $ cd src/
# $ make check TESTS=tests/test.vtc
check_PROGRAMS = rfc8188_test
rfc8188_test_SOURCES = rfc8188_test.c rfc8188.c rfc8188.h
rfc8188_test_SOURCES = rfc8188_test.c rfc8188.c rfc8188.h foreign/vend.h
# Stop automake from complaining about making rfc8188.o twice
rfc8188_test_CFLAGS = $(AM_CFLAGS)
TESTS += rfc8188_test
EXTRA_DIST = \
vmod_ece.vcc \
$(VMOD_TESTS)
CLEANFILES = \
$(builddir)/vcc_if.c \
$(builddir)/vcc_if.h \
$(builddir)/vmod_ece.rst \
$(builddir)/vmod_ece.man.rst \
$(builddir)/vmod_ece.3
/*-
* Copyright (c) 2003,2010 Poul-Henning Kamp <phk@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From:
* $FreeBSD: head/sys/sys/endian.h 121122 2003-10-15 20:05:57Z obrien $
*
* Endian conversion functions
*/
#ifndef VEND_H_INCLUDED
#define VEND_H_INCLUDED
/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
static __inline uint16_t
vbe16dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return ((p[0] << 8) | p[1]);
}
static __inline uint32_t
vbe32dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
}
static __inline uint64_t
vbe64dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return (((uint64_t)vbe32dec(p) << 32) | vbe32dec(p + 4));
}
#if 0
static __inline uint16_t
vle16dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return ((p[1] << 8) | p[0]);
}
#endif
static __inline uint32_t
vle32dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
}
#if 0
static __inline uint64_t
vle64dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return (((uint64_t)vle32dec(p + 4) << 32) | vle32dec(p));
}
#endif
static __inline void
vbe16enc(void *pp, uint16_t u)
{
uint8_t *p = (uint8_t *)pp;
p[0] = (u >> 8) & 0xff;
p[1] = u & 0xff;
}
static __inline void
vbe32enc(void *pp, uint32_t u)
{
uint8_t *p = (uint8_t *)pp;
p[0] = (u >> 24) & 0xff;
p[1] = (u >> 16) & 0xff;
p[2] = (u >> 8) & 0xff;
p[3] = u & 0xff;
}
static __inline void
vbe64enc(void *pp, uint64_t u)
{
uint8_t *p = (uint8_t *)pp;
vbe32enc(p, (uint32_t)(u >> 32));
vbe32enc(p + 4, (uint32_t)(u & 0xffffffffU));
}
static __inline void
vle16enc(void *pp, uint16_t u)
{
uint8_t *p = (uint8_t *)pp;
p[0] = u & 0xff;
p[1] = (u >> 8) & 0xff;
}
static __inline void
vle32enc(void *pp, uint32_t u)
{
uint8_t *p = (uint8_t *)pp;
p[0] = u & 0xff;
p[1] = (u >> 8) & 0xff;
p[2] = (u >> 16) & 0xff;
p[3] = (u >> 24) & 0xff;
}
#if 0
static __inline void
vle64enc(void *pp, uint64_t u)
{
uint8_t *p = (uint8_t *)pp;
vle32enc(p, (uint32_t)(u & 0xffffffffU));
vle32enc(p + 4, (uint32_t)(u >> 32));
}
#endif
#endif
/*-
* Copyright (c) 2019 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
/*
* XXX mockup for testing
* These are the keys in the two examples in chs 3.1 & 3.2 of RFC 8188.
*/
static struct key {
char *id;
const uint8_t idlen;
uint8_t key[16];
} key[] = {
{
"",
0,
{
0xca, 0xa7, 0x65, 0x67, 0xeb, 0x58, 0x7a, 0x67,
0xe8, 0x81, 0x29, 0xaf, 0xed, 0x6b, 0x39, 0x3d,
},
},
{
"a1",
2,
{
0x04, 0xed, 0xd9, 0x54, 0xfc, 0x54, 0x96, 0x72,
0xce, 0x45, 0xb5, 0x46, 0x32, 0x96, 0xd3, 0xd5,
},
},
{
NULL,
0,
{ 0 }
},
};
static inline uint8_t *
get_key(uint8_t *id, uint8_t idlen)
{
for (int i = 0; key[i].key != NULL; i++)
if (idlen != key[i].idlen)
continue;
else if (idlen == 0 && key[i].idlen == 0)
return key[i].key;
else if (memcmp(id, key[i].id, idlen) == 0)
return key[i].key;
return (NULL);
}
......@@ -33,6 +33,8 @@
#include <openssl/evp.h>
#include "foreign/vend.h"
#define AES128_KEYLEN 16
#define SALT_LEN 16
#define SHA256_LEN 32
......@@ -51,15 +53,6 @@
* MUST be allocated with the given size.
*/
/* copied from vend.h */
static inline uint32_t
be32dec(const void *pp)
{
uint8_t const *p = (uint8_t const *)pp;
return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
}
/*
* ch 2.1
* Input is hdr, outputs are rs and idlen. The salt is the first SALT_LEN
......@@ -72,7 +65,7 @@ be32dec(const void *pp)
static inline void
decode_header(uint8_t *hdr, uint32_t *rs, uint8_t *idlen)
{
*rs = be32dec(hdr + RS_OFF);
*rs = vbe32dec(hdr + RS_OFF);
*idlen = hdr[IDLEN_OFF];
}
......
# looks like -*- vcl -*-
varnishtest "vcl.use and .discard, and version strings"
varnish v1 -vcl {
import ${vmod_ece};
backend b { .host = "${bad_ip}"; }
} -start
varnish v1 -vcl {backend b { .host = "${bad_ip}"; }}
varnish v1 -cli "vcl.list"
varnish v1 -cli "vcl.use vcl1"
varnish v1 -cli "vcl.use vcl2"
varnish v1 -cli "vcl.use vcl1"
varnish v1 -cli "vcl.show vcl1"
varnish v1 -cli "vcl.use vcl2"
varnish v1 -cli "vcl.discard vcl1"
varnish v1 -cli "vcl.list"
varnish v1 -vcl {
import ${vmod_ece};
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.x-version = ece.version();
if (!resp.http.x-version) {
set resp.status = 500;
}
return(deliver);
}
}
client c1 {
txreq -url "/"
rxresp
expect resp.status == 200
expect resp.http.x-version ~ "^.+$"
} -run
# looks like -*- vcl -*-
varnishtest "standard decryption VFP"
# Test vectors from RFC 8188 ch 3.1 & 3.2
server s1 {
rxreq
txresp -nolen -hdr "Content-Encoding: aes128gcm" \
-hdr "Content-Length: 53"
sendhex "23 50 6c c6 d1 6d b6 5b f7 bb f3 a8 f7 8c 67 9b"
sendhex "00 00 10 00 00 f8 d0 15 b9 bd aa 16 00 44 b9 02"
sendhex "91 6a 9a 19 bb e2 31 90 8b da dc c1 01 d4 f0 fe"
sendhex "97 2f 13 86 38"
rxreq
txresp -nolen -hdr "Content-Encoding: aes128gcm" \
-hdr "Content-Length: 73"
sendhex "b8 d0 a4 5a 23 58 cc a4 e7 04 df 63 8b 7f aa 58"
sendhex "00 00 00 19 02 61 31 ce 1b c7 21 cf f8 27 be 03"
sendhex "aa 74 66 28 bf 1c a3 ba a4 72 24 58 c4 0f 2a 05"
sendhex "d4 5b e4 8f a8 50 3d d3 c7 23 9d 4e 11 42 84 a6"
sendhex "0c f7 4a c2 d6 22 a4 bf b8"
} -start
varnish v1 -arg "-p vsl_mask=+VfpAcct" -vcl+backend {
import ${vmod_ece};
sub vcl_backend_response {
set beresp.filters = "ece_decrypt";
set beresp.uncacheable = true;
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.Content-Encoding == <undef>
expect resp.bodylen == 15
expect resp.body == "I am the walrus"
txreq
rxresp
expect resp.status == 200
expect resp.http.Content-Encoding == <undef>
expect resp.bodylen == 15
expect resp.body == "I am the walrus"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VfpAcct" {
expect 0 * Begin bereq
expect * = VfpAcct {^ece_decrypt \d+ 15$}
expect * = End
expect 0 * Begin bereq
expect * = VfpAcct {^ece_decrypt \d+ 15$}
expect * = End
} -run
/*-
* Copyright (c) 2019 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "cache/cache.h"
/* XXX grr */
#undef ZERO_OBJ
#define ZERO_OBJ(to, sz) (void)memset(to, 0, sz)
#include "rfc8188.h"
#include "vfp.h"
#include "keys.h"
#define HDR_PREFIX_LEN (SALT_LEN + 4 + 1)
#define ID_LEN 255
#define ERR_DEC(ctx, msg) \
VFP_Error((ctx), "ece decrypt: " msg)
#define VERR_DEC(ctx, fmt, ...) \
VFP_Error((ctx), "ece decrypt: " fmt, __VA_ARGS__)
struct ece_crypto {
unsigned magic;
#define ECE_CRYPTO_MAGIC 0xe7f66e91
unsigned char cek[AES128_KEYLEN];
unsigned char prenonce[NONCE_LEN];
};
struct ece {
unsigned magic;
#define ECE_MAGIC 0x2b066cec
struct ece_crypto *crypto;
EVP_CIPHER_CTX *ectx;
uint8_t *buf;
uint64_t seq_lo;
uint32_t seq_hi;
uint32_t rs;
};
static enum vfp_status
suck_bytes(struct vfp_ctx *ctx, void *ptr, size_t *lenp)
{
size_t len, off;
ssize_t l;
enum vfp_status vp = VFP_OK;
CHECK_OBJ_NOTNULL(ctx, VFP_CTX_MAGIC);
AN(ptr);
AN(lenp);
len = *lenp;
for (off = 0, l = len; vp == VFP_OK && off < len; l = len - l) {
vp = VFP_Suck(ctx, ptr + off, &l);
assert(l >= 0);
assert(vp >= VFP_ERROR && vp < VFP_NULL);
if (vp == VFP_ERROR)
return (vp);
assert((size_t) l <= len - off);
off += l;
}
*lenp = off;
return (vp);
}
/*
* RFC8188 ch 2: "The final encoding consists of a header ... and zero or
* more fixed-size encrypted records ..."
* So we reject an empty body, but accept a header with no records. The
* latter results in a zero-length decryption.
*/
static enum vfp_status
decrypt_init(struct ece *ece, struct vfp_ctx *ctx)
{
size_t len;
uint8_t idlen, *key, hdr[HDR_PREFIX_LEN], id[ID_LEN], prk[SHA256_LEN],
cek[SHA256_LEN];
char errmsg[ERRMSG_LEN];
enum vfp_status vp;
CHECK_OBJ_NOTNULL(ece, ECE_MAGIC);
CHECK_OBJ_NOTNULL(ece->crypto, ECE_CRYPTO_MAGIC);
CHECK_OBJ_NOTNULL(ctx, VFP_CTX_MAGIC);
AZ(ece->rs);
AZ(ece->seq_hi);
AZ(ece->seq_lo);
len = HDR_PREFIX_LEN;
vp = suck_bytes(ctx, hdr, &len);
if (vp == VFP_ERROR)
return (vp);
if (vp == VFP_END) {
if (len == 0)
return (ERR_DEC(ctx, "empty body"));
else
return (ERR_DEC(ctx, "truncated header"));
}
decode_header(hdr, &ece->rs, &idlen);
if (ece->rs < 18)
return(VERR_DEC(ctx, "invalid record size %u", ece->rs));
errno = 0;
ece->buf = malloc(ece->rs);
if (ece->buf == NULL)
return (VERR_DEC(ctx, "buffer allocation failed: %s",
strerror(errno)));
len = idlen;
vp = suck_bytes(ctx, id, &len);
if (vp == VFP_ERROR)
return (vp);
if (vp == VFP_END) {
if (len == idlen)
/* Empty decryption */
return (vp);
else
return (ERR_DEC(ctx, "truncated header"));
}
/* XXX rdlock key table */
key = get_key(id, idlen);
if (key == NULL)
vp = VERR_DEC(ctx, "unknown key %.*s", idlen, id);
else if (derive_prk(hdr, key, prk, errmsg) != 0)
vp = VERR_DEC(ctx, "%s", errmsg);
/* XXX rdunlock key table */
if (vp == VFP_ERROR)
return (vp);
if (derive_cek(prk, cek, errmsg) != 0
|| derive_prenonce(prk, ece->crypto->prenonce, errmsg) != 0)
return (VERR_DEC(ctx, "%s", errmsg));
memcpy(ece->crypto->cek, cek, AES128_KEYLEN);
return (VFP_OK);
}
static inline void
seq_inc(struct ece *ece)
{
CHECK_OBJ_NOTNULL(ece, ECE_MAGIC);
if (ece->seq_lo < UINT64_MAX)
ece->seq_lo++;
else {
assert(ece->seq_hi != UINT32_MAX);
ece->seq_hi++;
ece->seq_lo = 0;
}
}
static inline void
nonce_xor_seq(struct ece *ece, uint8_t *nonce)
{
uint8_t seq[NONCE_LEN];
CHECK_OBJ_NOTNULL(ece, ECE_MAGIC);
CHECK_OBJ_NOTNULL(ece->crypto, ECE_CRYPTO_MAGIC);
vbe32enc(seq, ece->seq_hi);
vbe64enc(seq + 4, ece->seq_lo);
for (int i = 0; i < NONCE_LEN; i++)
nonce[i] = ece->crypto->prenonce[i] ^ seq[i];
}
#if 0
static inline void
nonce_xor_seq(struct ece *ece, uint8_t *nonce)
{
uint32_t *nonce_hi, *prenonce_hi;
uint64_t *nonce_lo, *prenonce_lo;
CHECK_OBJ_NOTNULL(ece, ECE_MAGIC);
CHECK_OBJ_NOTNULL(ece->crypto, ECE_CRYPTO_MAGIC);
nonce_hi = (uint32_t *)nonce;
prenonce_hi = (uint32_t *)ece->crypto->prenonce;
nonce_lo = (uint64_t *)(nonce + 4);
prenonce_lo = (uint64_t *)(ece->crypto->prenonce + 4);
*nonce_hi = *prenonce_hi ^ ece->seq_hi;
*nonce_lo = *prenonce_lo ^ ece->seq_lo;
}
#endif
static enum vfp_status
decrypt(struct ece *ece, struct vfp_ctx *ctx, unsigned char *plaintext,
size_t *lenp, enum vfp_status vp)
{
ssize_t ciphertext_len, plaintext_len;
unsigned char nonce[NONCE_LEN], *tag;
char errmsg[ERRMSG_LEN];
int last;
CHECK_OBJ_NOTNULL(ece, ECE_MAGIC);
CHECK_OBJ_NOTNULL(ece->crypto, ECE_CRYPTO_MAGIC);
if (*lenp < 18)
return (ERR_DEC(ctx, "record truncated"));
ciphertext_len = *lenp - TAG_LEN;
tag = ece->buf + ciphertext_len;
nonce_xor_seq(ece, nonce);
plaintext_len = decrypt_record(ece->ectx, ece->buf, ciphertext_len,
tag, ece->crypto->cek, nonce, plaintext,
&last, errmsg);
if (plaintext_len < 0)
return (VERR_DEC(ctx, "%s", errmsg));
if (last && vp != VFP_END)
return (ERR_DEC(ctx, "premature last record"));
if (!last && vp == VFP_END)
return (ERR_DEC(ctx, "message truncated"));
if (!last && *lenp < ece->rs)
return (ERR_DEC(ctx, "record smaller than record size"));
seq_inc(ece);
*lenp = plaintext_len;
return (vp);
}
/* VFP interface */
static enum vfp_status v_matchproto_(vfp_init_f)
vfp_decrypt_init(struct vfp_ctx *ctx, struct vfp_entry *ent)
{
struct ece *ece;
struct ece_crypto *crypto;
char errmsg[ERRMSG_LEN];
CHECK_OBJ_NOTNULL(ctx, VFP_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ent, VFP_ENTRY_MAGIC);
AN(ent->vfp);
/* XXX implement me */
if (http_GetStatus(ctx->resp) == 206)
return (VFP_NULL);
if (!http_HdrIs(ctx->resp, H_Content_Encoding, "aes128gcm"))
return (VFP_NULL);
errno = 0;
ALLOC_OBJ(ece, ECE_MAGIC);
if (ece == NULL)
return (VERR_DEC(ctx, "allocation in init: %s",
strerror(errno)));
ece->ectx = cipher_ctx_init(0, errmsg);
if (ece->ectx == NULL) {
FREE_OBJ(ece);
return (VERR_DEC(ctx, "initializing cipher context: %s",
errmsg));
}
ALLOC_OBJ(crypto, ECE_CRYPTO_MAGIC);
if (crypto == NULL) {
FREE_OBJ(ece);
return (VERR_DEC(ctx, "allocation in init: %s",
strerror(errno)));
}
ece->crypto = crypto;
ent->priv1 = ece;
http_Unset(ctx->resp, H_Content_Encoding);
http_Unset(ctx->resp, H_Content_Length);
RFC2616_Weaken_Etag(ctx->resp);
ctx->obj_flags |= OF_CHGCE;
return (VFP_OK);
}
static void v_matchproto_(vfp_fini_f)
vfp_decrypt_fini(struct vfp_ctx *ctx, struct vfp_entry *ent)
{
struct ece *ece;
CHECK_OBJ_NOTNULL(ctx, VFP_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ent, VFP_ENTRY_MAGIC);
if (ent->priv1 == NULL)
return;
CAST_OBJ(ece, ent->priv1, ECE_MAGIC);
if (ece->ectx != NULL)
cipher_ctx_fini(ece->ectx);
if (ece->buf != NULL)
free(ece->buf);
if (ece->crypto == NULL)
return;
CHECK_OBJ(ece->crypto, ECE_CRYPTO_MAGIC);
FREE_OBJ(ece->crypto);
}
static enum vfp_status v_matchproto_(vfp_pull_f)
vfp_decrypt_pull(struct vfp_ctx *ctx, struct vfp_entry *ent, void *ptr,
ssize_t *lenp)
{
struct ece *ece;
size_t len;
enum vfp_status vp;
CHECK_OBJ_NOTNULL(ctx, VFP_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ent, VFP_ENTRY_MAGIC);
CAST_OBJ_NOTNULL(ece, ent->priv1, ECE_MAGIC);
AN(ptr);
AN(lenp);
*lenp = 0;
if (ece->rs == 0)
if ((vp = decrypt_init(ece, ctx)) != VFP_OK)
return (vp);
AN(ece->rs);
AN(ece->buf);
len = ece->rs;
vp = suck_bytes(ctx, ece->buf, &len);
assert(len <= ece->rs);
if (vp == VFP_ERROR)
return (vp);
vp = decrypt(ece, ctx, ptr, &len, vp);
*lenp = len;
return (vp);
}
const struct vfp vfp_decrypt = {
.name = "ece_decrypt",
.init = vfp_decrypt_init,
.pull = vfp_decrypt_pull,
.fini = vfp_decrypt_fini,
};
/*-
* Copyright (c) 2019 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "cache/cache_filter.h"
extern const struct vfp vfp_decrypt;
/*-
* Copyright (c) 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config.h"
#include "cache/cache.h"
#include "vcc_if.h"
#include "vfp.h"
/* Event function */
int
VPFX(event)(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
{
ASSERT_CLI();
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(priv);
switch(e) {
case VCL_EVENT_LOAD:
VRT_AddVFP(ctx, &vfp_decrypt);
return (0);
case VCL_EVENT_DISCARD:
VRT_RemoveVFP(ctx, &vfp_decrypt);
return (0);
case VCL_EVENT_WARM:
case VCL_EVENT_COLD:
return (0);
default:
WRONG("illegal event enum");
}
NEEDLESS(return (0));
}
VCL_STRING
vmod_version(VRT_CTX)
{
(void) ctx;
return VERSION;
}
#-
# Copyright (c) 2019 UPLEX Nils Goroll Systemoptimierung
# All rights reserved
#
# Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
#
# See LICENSE
#
.. _RFC 8188: https://tools.ietf.org/html/rfc8188
$Module ece 3 "Varnish Module for encrypted Content-Encoding per RFC 8188"
$ABI vrt
$Synopsis manual
SYNOPSIS
========
::
import ece;
# The built-in "ece_decrypt" filter decrypts backend responses.
sub vcl_backend_response {
if (beresp.http.Content-Encoding == "aes128gc") {
set beresp.filters = "ece_decrypt";
}
}
# VMOD version
STRING ece.version()
DESCRIPTION
===========
VMOD ece is a Varnish module that supports the use of encrypted
content encoding. It enables configurations that implement and
interpret Content-Encoding ``aes128gcm``, by providing these
resources:
* a Varnish Fetch Processor (VFP) to decrypt backend responses
* XXX
Encrypted Content-Encoding for HTTP is specified in `RFC
8188`_. Details of the encoding are beyond the scope of this manual;
users of this library are advised to consult the RFC as well, to fully
understand how to use it properly and securely.
XXX ...
Encryption and HTTP
--------------------
XXX ...
$Function STRING version()
Return the version string for this VMOD.
Example::
std.log("Using VMOD ece version: " + ece.version());
STATISTICS
==========
XXX ...
SECURITY
========
XXX ...
ERRORS
======
XXX ...
REQUIREMENTS
============
The VMOD currently requires the Varnish master branch. It also
requires the ``libcrypto`` library, and has been tested with
OpenSSL version 1.1.1c.
XXX ...
INSTALLATION
============
See `INSTALL.rst <INSTALL.rst>`_ in the source repository.
LIMITATIONS
===========
XXX ...
SEE ALSO
========
* varnishd(1)
* vcl(7)
* `RFC 8188`_
$Event event
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