├── .gitignore ├── .travis.yml ├── CHANGES.rst ├── LICENSE ├── Makefile.am ├── README.rst ├── autogen.sh ├── configure.ac ├── m4 └── PLACEHOLDER └── src ├── Makefile.am ├── tests ├── test01.vtc ├── test02.vtc ├── test03.vtc ├── test_hash.vtc ├── test_hex.vtc └── test_nullstring.vtc ├── vmod_digest.c └── vmod_digest.vcc /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | .deps/ 4 | .libs/ 5 | *.o 6 | *.lo 7 | *.la 8 | *~ 9 | 10 | /aclocal.m4 11 | /autom4te.cache/ 12 | /compile 13 | /config.guess 14 | /config.h 15 | /config.h.in 16 | /config.log 17 | /config.status 18 | /config.sub 19 | /configure 20 | /depcomp 21 | /install-sh 22 | /libtool 23 | /ltmain.sh 24 | /missing 25 | /stamp-h1 26 | /m4/ 27 | 28 | /src/vcc_if.c 29 | /src/vcc_if.h 30 | /src/vmod_*rst 31 | /vmod_digest.3 32 | 33 | libvmod-digest-*.gz 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: c 3 | compiler: 4 | - clang 5 | - gcc 6 | before_install: 7 | - sudo apt-get update -q 8 | - sudo apt-get install -qq apt-transport-https libmhash-dev python-docutils 9 | - curl -s https://packagecloud.io/install/repositories/varnishcache/varnish60lts/script.deb.sh | sudo bash 10 | - sudo apt-get -q update 11 | - sudo apt-get install varnish varnish-dev 12 | - ./autogen.sh 13 | script: 14 | - ./configure && make CFLAGS="-Wall -Wextra" && 15 | make check VERBOSE=1 16 | -------------------------------------------------------------------------------- /CHANGES.rst: -------------------------------------------------------------------------------- 1 | This is a running log of changes to libvmod-digest. 2 | 3 | libvmod-digest 1.0.2 (2017-03-07) 4 | --------------------------------- 5 | 6 | * Small docs and compilation fixes. 7 | 8 | * Added compatibility with Varnish Cache 6.0 9 | 10 | This release was tested with Varnish Cache 4.1.9 and trunk (2018-03-07) 11 | 12 | 13 | libvmod-digest 1.0.1 (2016-03-15) 14 | --------------------------------- 15 | 16 | Changes since 1.0.0: 17 | 18 | * Fix overread in base64_encode() 19 | * is_hex() stylistic cleanups. 20 | 21 | This release was tested with Varnish Cache 4.1.2. 22 | 23 | 24 | libvmod-digest 1.0.0 (2016-03-14) 25 | --------------------------------- 26 | 27 | This is libvmod-digest, allowing use of libmhash (cryptographic functions) 28 | in Varnish VCL. 29 | 30 | Changes since last release: 31 | 32 | * Semantic versioning introduced. 33 | 34 | * Packaging files moved out of tree. 35 | 36 | This release was tested with Varnish Cache 4.1.2. 37 | 38 | List of changes was not kept for previous versions. 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions 3 | are met: 4 | 1. Redistributions of source code must retain the above copyright 5 | notice, this list of conditions and the following disclaimer. 6 | 2. Redistributions in binary form must reproduce the above copyright 7 | notice, this list of conditions and the following disclaimer in the 8 | documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 11 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 12 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 13 | ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 14 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 15 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 16 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 17 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 18 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 19 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 20 | SUCH DAMAGE. 21 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 -I ${LIBVARNISHAPI_DATAROOTDIR}/aclocal 2 | 3 | SUBDIRS = src 4 | 5 | DISTCHECK_CONFIGURE_FLAGS = \ 6 | VMOD_DIR='$${libdir}/varnish/vmods' 7 | 8 | EXTRA_DIST = README.rst LICENSE CHANGES.rst 9 | 10 | doc_DATA = README.rst LICENSE 11 | 12 | dist_man_MANS = vmod_digest.3 13 | MAINTAINERCLEANFILES = $(dist_man_MANS) 14 | 15 | vmod_digest.3: README.rst 16 | 17 | %.1 %.2 %.3 %.4 %.5 %.6 %.7 %.8 %.9: 18 | if HAVE_RST2MAN 19 | ${RST2MAN} $< $@ 20 | else 21 | @echo "========================================" 22 | @echo "You need rst2man installed to make dist" 23 | @echo "========================================" 24 | @false 25 | endif 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | vmod_digest 3 | =========== 4 | 5 | --------------------- 6 | Varnish Digest Module 7 | --------------------- 8 | 9 | :Manual section: 3 10 | :Author: Kristian Lyngstøl 11 | :Date: 2016-03-16 12 | :Version: 1.0.3 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | :: 18 | 19 | import digest; 20 | 21 | digest.hmac_md5(,); 22 | digest.hmac_sha1(, ); 23 | digest.hmac_sha256(, ); 26 | digest.base64url(); 27 | digest.base64url_nopad(); 28 | digest.base64_hex(); 29 | digest.base64url_hex(); 30 | digest.base64url_nopad_hex(); 31 | digest.base64_decode(); 32 | digest.base64url_decode(); 33 | digest.base64url_nopad_decode(); 34 | 35 | digest.version() 36 | 37 | digest.hash_sha1(); 38 | digest.hash_sha224(); 39 | digest.hash_sha256(); 40 | digest.hash_sha384(); 41 | digest.hash_sha512(); 42 | digest.hash_gost(); 43 | digest.hash_md2(); 44 | digest.hash_md4(); 45 | digest.hash_md5(); 46 | digest.hash_crc32(); 47 | digest.hash_crc32b(); 48 | digest.hash_adler32(); 49 | digest.hash_haval128(); 50 | digest.hash_haval160(); 51 | digest.hash_haval192(); 52 | digest.hash_haval224(); 53 | digest.hash_haval256(); 54 | digest.hash_ripemd128(); 55 | digest.hash_ripemd160(); 56 | digest.hash_ripemd256(); 57 | digest.hash_ripemd320(); 58 | digest.hash_tiger(); 59 | digest.hash_tiger128(); 60 | digest.hash_tiger160(); 61 | digest.hash_snefru128(); 62 | digest.hash_snefru256(); 63 | 64 | DESCRIPTION 65 | =========== 66 | 67 | Varnish Module (vmod) for computing HMAC, message digests and working with 68 | base64. 69 | 70 | All HMAC- and hash-functionality is provided by libmhash, while base64 is 71 | implemented locally. 72 | 73 | FUNCTIONS 74 | ========= 75 | 76 | Example VCL:: 77 | 78 | backend foo { ... }; 79 | 80 | import digest; 81 | 82 | sub vcl_recv { 83 | if (digest.hmac_sha256("key",req.http.x-data) != req.http.x-data-sig) 84 | { 85 | return (synth(401, "Naughty user!")); 86 | } 87 | } 88 | 89 | 90 | hmac_(hash) 91 | ----------- 92 | 93 | Prototype 94 | :: 95 | 96 | digest.hmac_md5(,); 97 | digest.hmac_sha1(, ); 98 | digest.hmac_sha256(, ); 117 | digest.base64url(); 118 | digest.base64url_nopad(); 119 | Returns 120 | String 121 | Description 122 | Returns the base64-encoded version of the input-string. The 123 | base64url-variant uses base64 url-encoding (+/ replaced by -_) and 124 | the base64url_nopad does the same, but avoids adding padding. The 125 | latter is more commonly used, though an (allowed) exception to the 126 | RFC4648. 127 | Example 128 | :: 129 | 130 | set resp.http.x-data-sig = 131 | digest.base64({"content with 132 | newline in it"}); 133 | 134 | base64_hex, base64url_hex, base64url_nopad_hex 135 | ----------------------------------------------- 136 | 137 | Prototype 138 | :: 139 | 140 | digest.base64_hex(); 141 | digest.base64url_hex(); 142 | digest.base64url_nopad_hex(); 143 | Returns 144 | String 145 | Description 146 | Returns the base64-encoded version of the hex encoded input-string. The 147 | input-string can start with an optional 0x. Input is hex-decoded into binary 148 | and the encoding is identical to base64, base64url, and base64url_nopad. 149 | Example 150 | :: 151 | 152 | set resp.http.x-data-sig = 153 | digest.base64_hex("0xdd26bfddf122c1055d4c"); 154 | 155 | hash_(algorithm) 156 | ---------------- 157 | 158 | Prototype 159 | :: 160 | 161 | digest.hash_sha1(); 162 | digest.hash_sha224(); 163 | digest.hash_sha256(); 164 | digest.hash_sha384(); 165 | digest.hash_sha512(); 166 | digest.hash_gost(); 167 | digest.hash_md2(); 168 | digest.hash_md4(); 169 | digest.hash_md5(); 170 | digest.hash_crc32(); 171 | digest.hash_crc32b(); 172 | digest.hash_adler32(); 173 | digest.hash_haval128(); 174 | digest.hash_haval160(); 175 | digest.hash_haval192(); 176 | digest.hash_haval224(); 177 | digest.hash_haval256(); 178 | digest.hash_ripemd128(); 179 | digest.hash_ripemd160(); 180 | digest.hash_ripemd256(); 181 | digest.hash_ripemd320(); 182 | digest.hash_tiger(); 183 | digest.hash_tiger128(); 184 | digest.hash_tiger160(); 185 | digest.hash_snefru128(); 186 | digest.hash_snefru256(); 187 | Returns 188 | String 189 | Description 190 | Computes the digest/hash of the supplied, using the specified hash 191 | algorithm. If in doubt as to which to pick, use SHA256. For 192 | detailed discussions, see The Internet. 193 | Example 194 | :: 195 | 196 | set resp.http.x-data-md5 = 197 | digest.hash_md5(resp.http.x-data); 198 | 199 | base64_decode, base64url_decode, base64url_nopad_decode 200 | ------------------------------------------------------- 201 | 202 | Prototype 203 | :: 204 | 205 | digest.base64_decode(); 206 | digest.base64url_decode(); 207 | digest.base64url_nopad_decode(); 208 | Returns 209 | String 210 | Description 211 | Decodes the bas64 and base64url-encoded strings. All functions 212 | treat padding the same, meaning base64url_decode and 213 | base64url_nopad_decode are identical, but available for consistency 214 | and practicality. 215 | Example 216 | :: 217 | synthetic(digest.base64_decode(req.http.x-parrot)); 218 | 219 | version 220 | ------- 221 | 222 | Prototype 223 | :: 224 | 225 | digest.version() 226 | Returns 227 | string 228 | Description 229 | Returns the string constant version-number of the digest vmod. 230 | Example 231 | :: 232 | 233 | set resp.http.X-digest-version = digest.version(); 234 | 235 | 236 | INSTALLATION 237 | ============ 238 | 239 | The source tree is based on autotools to configure the building, and 240 | does also have the necessary bits in place to do functional unit tests 241 | using the ``varnishtest`` tool. 242 | 243 | Building requires the Varnish header files and uses pkg-config to find 244 | the necessary paths. 245 | 246 | Usage:: 247 | 248 | ./autogen.sh 249 | ./configure 250 | 251 | If you have installed Varnish to a non-standard directory, call 252 | ``autogen.sh`` and ``configure`` with ``PKG_CONFIG_PATH`` pointing to 253 | the appropriate path. For example, when varnishd configure was called 254 | with ``--prefix=$PREFIX``, use 255 | 256 | PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig 257 | export PKG_CONFIG_PATH 258 | 259 | Make targets: 260 | 261 | * make - builds the vmod. 262 | * make install - installs your vmod. 263 | * make check - runs the unit tests in ``src/tests/*.vtc`` 264 | * make distcheck - run check and prepare a tarball of the vmod. 265 | 266 | 267 | AUTHOR 268 | ====== 269 | 270 | Original author: Kristian Lyngstøl . 271 | 272 | This Vmod was written for Media Norge, Schibsted and others. 273 | 274 | The bulk of the functionality is acquired through libmhash. 275 | 276 | 277 | BUGS 278 | ==== 279 | 280 | No bugs at all! 281 | 282 | If the key is NULL for hmac-functions, the function will fail and return 283 | NULL itself, and do no hmac-computation at all. This should be used as an 284 | indication of some greater flaw in your software/VCL. (I.e.: Your key 285 | should be under your control, not user-supplied without verification). 286 | 287 | The `base64url_nopad_decode()` and `base64url_decode()` functions do not 288 | differ much. The exception is that nopad_decode() does not know about 289 | padding at all, and might get confused if the input actually is padded. 290 | 291 | SEE ALSO 292 | ======== 293 | 294 | * libmhash 295 | * varnishd(1) 296 | * vcl(7) 297 | * https://github.com/varnish/libvmod-digest 298 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | warn() { 4 | echo "WARNING: $@" 1>&2 5 | } 6 | 7 | case `uname -s` in 8 | Darwin) 9 | LIBTOOLIZE=glibtoolize 10 | ;; 11 | FreeBSD) 12 | LIBTOOLIZE=libtoolize 13 | ;; 14 | Linux) 15 | LIBTOOLIZE=libtoolize 16 | ;; 17 | SunOS) 18 | LIBTOOLIZE=libtoolize 19 | ;; 20 | *) 21 | warn "unrecognized platform:" `uname -s` 22 | LIBTOOLIZE=libtoolize 23 | esac 24 | 25 | automake_version=`automake --version | tr ' ' '\n' | egrep '^[0-9]\.[0-9a-z.-]+'` 26 | if [ -z "$automake_version" ] ; then 27 | warn "unable to determine automake version" 28 | else 29 | case $automake_version in 30 | 0.*|1.[0-8]|1.[0-8][.-]*) 31 | warn "automake ($automake_version) detected; 1.9 or newer recommended" 32 | ;; 33 | *) 34 | ;; 35 | esac 36 | fi 37 | 38 | # check for varnishapi.m4 in custom paths 39 | dataroot=$(pkg-config --variable=datarootdir varnishapi 2>/dev/null) 40 | if [ -z "$dataroot" ] ; then 41 | cat >&2 <<'EOF' 42 | Package varnishapi was not found in the pkg-config search path. 43 | Perhaps you should add the directory containing `varnishapi.pc' 44 | to the PKG_CONFIG_PATH environment variable 45 | EOF 46 | exit 1 47 | fi 48 | set -ex 49 | aclocal -I m4 -I ${dataroot}/aclocal 50 | $LIBTOOLIZE --copy --force 51 | autoheader 52 | automake --add-missing --copy --foreign 53 | autoconf 54 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.59) 2 | AC_COPYRIGHT([Copyright (c) 2011-2019 Varnish Software]) 3 | AC_INIT([libvmod-digest], [1.0.3]) 4 | AC_CONFIG_MACRO_DIR([m4]) 5 | m4_ifndef([VARNISH_VMOD_INCLUDES], AC_MSG_ERROR([Need varnish.m4])) 6 | AC_CONFIG_SRCDIR(src/vmod_digest.vcc) 7 | AM_CONFIG_HEADER(config.h) 8 | 9 | AC_CANONICAL_SYSTEM 10 | AC_LANG(C) 11 | 12 | AM_INIT_AUTOMAKE([foreign]) 13 | 14 | AC_GNU_SOURCE 15 | AC_PROG_CC 16 | AC_PROG_CC_STDC 17 | if test "x$ac_cv_prog_cc_c99" = xno; then 18 | AC_MSG_ERROR([Could not find a C99 compatible compiler]) 19 | fi 20 | AC_PROG_CPP 21 | 22 | AC_PROG_INSTALL 23 | AC_PROG_LIBTOOL 24 | AC_PROG_MAKE_SET 25 | 26 | AC_CHECK_LIB(mhash, mhash_count, [AC_DEFINE([HAVE_MHASH],[1],[Define we have mhash])], 27 | [AC_MSG_ERROR([libvmod-digest requires libmhash.])]) 28 | # Check for rst utilities 29 | AC_CHECK_PROGS(RST2MAN, [rst2man rst2man.py], "no") 30 | if test "x$RST2MAN" = "xno"; then 31 | AC_MSG_WARN([rst2man not found - not building man pages]) 32 | fi 33 | AM_CONDITIONAL(HAVE_RST2MAN, [test "x$RST2MAN" != "xno"]) 34 | 35 | # Checks for header files. 36 | AC_HEADER_STDC 37 | AC_CHECK_HEADERS([sys/stdlib.h]) 38 | 39 | # backwards compat with older pkg-config 40 | # - pull in AC_DEFUN from pkg.m4 41 | m4_ifndef([PKG_CHECK_VAR], [ 42 | # PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, 43 | # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) 44 | # ------------------------------------------- 45 | # Retrieves the value of the pkg-config variable for the given module. 46 | AC_DEFUN([PKG_CHECK_VAR], 47 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 48 | AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl 49 | 50 | _PKG_CONFIG([$1], [variable="][$3]["], [$2]) 51 | AS_VAR_COPY([$1], [pkg_cv_][$1]) 52 | 53 | AS_VAR_IF([$1], [""], [$5], [$4])dnl 54 | ])# PKG_CHECK_VAR 55 | ]) 56 | 57 | PKG_CHECK_MODULES([libvarnishapi], [varnishapi]) 58 | PKG_CHECK_VAR([LIBVARNISHAPI_DATAROOTDIR], [varnishapi], [datarootdir]) 59 | PKG_CHECK_VAR([LIBVARNISHAPI_BINDIR], [varnishapi], [bindir]) 60 | PKG_CHECK_VAR([LIBVARNISHAPI_SBINDIR], [varnishapi], [sbindir]) 61 | AC_SUBST([LIBVARNISHAPI_DATAROOTDIR]) 62 | 63 | # Varnish include files tree 64 | VARNISH_VMOD_INCLUDES 65 | VARNISH_VMOD_DIR 66 | VARNISH_VMODTOOL 67 | 68 | AC_PATH_PROG([VARNISHTEST], [varnishtest], [], 69 | [$LIBVARNISHAPI_BINDIR:$LIBVARNISHAPI_SBINDIR:$PATH]) 70 | AC_PATH_PROG([VARNISHD], [varnishd], [], 71 | [$LIBVARNISHAPI_SBINDIR:$LIBVARNISHAPI_BINDIR:$PATH]) 72 | 73 | 74 | AC_CONFIG_FILES([ 75 | Makefile 76 | src/Makefile 77 | ]) 78 | AC_OUTPUT 79 | -------------------------------------------------------------------------------- /m4/PLACEHOLDER: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/varnish/libvmod-digest/e745761469b55e83e1fca21dd0cb8eca8022935d/m4/PLACEHOLDER -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = @VMOD_INCLUDES@ -Wall -Wextra -Werror 2 | 3 | vmoddir = @VMOD_DIR@ 4 | vmod_LTLIBRARIES = libvmod_digest.la 5 | 6 | libvmod_digest_la_LDFLAGS = -module -export-dynamic -avoid-version -shared -lmhash 7 | 8 | libvmod_digest_la_SOURCES = \ 9 | vmod_digest.c 10 | 11 | nodist_libvmod_digest_la_SOURCES = \ 12 | vcc_if.c \ 13 | vcc_if.h 14 | 15 | vmod_digest.lo: vcc_if.c vcc_if.h 16 | 17 | vcc_if.c: vcc_if.h 18 | 19 | vcc_if.h: @VMODTOOL@ $(top_srcdir)/src/vmod_digest.vcc 20 | @VMODTOOL@ $(top_srcdir)/src/vmod_digest.vcc 21 | 22 | VMOD_TESTS = $(top_srcdir)/src/tests/*.vtc 23 | .PHONY: $(VMOD_TESTS) 24 | 25 | $(top_srcdir)/src/tests/*.vtc: libvmod_digest.la 26 | @VARNISHTEST@ -Dvarnishd=@VARNISHD@ -Dvmod_topbuild=$(abs_top_builddir) $@ 27 | 28 | check: $(VMOD_TESTS) 29 | 30 | EXTRA_DIST = \ 31 | vmod_digest.vcc \ 32 | $(VMOD_TESTS) 33 | 34 | CLEANFILES = \ 35 | $(builddir)/vcc_if.c \ 36 | $(builddir)/vcc_if.h \ 37 | $(builddir)/vmod_digest.man.rst \ 38 | $(builddir)/vmod_digest.rst 39 | -------------------------------------------------------------------------------- /src/tests/test01.vtc: -------------------------------------------------------------------------------- 1 | varnishtest "Test digest vmod" 2 | 3 | # Test vectors borrowed from wikipedia (which is in turn borrowed from 4 | # rfc2104) 5 | 6 | server s1 { 7 | rxreq 8 | txresp 9 | } -start 10 | 11 | varnish v1 -vcl+backend { 12 | import digest from "${vmod_topbuild}/src/.libs/libvmod_digest.so"; 13 | 14 | sub vcl_deliver { 15 | set resp.http.sha256 = digest.hmac_sha256("key", "The quick brown fox jumps over the lazy dog"); 16 | set resp.http.sha1 = digest.hmac_sha1("key", "The quick brown fox jumps over the lazy dog"); 17 | set resp.http.md5 = digest.hmac_md5("key", "The quick brown fox jumps over the lazy dog"); 18 | set resp.http.sha256_b64 = digest.base64(digest.hmac_sha256("key", "The quick brown fox jumps over the lazy dog")); 19 | set resp.http.sha1_b64 = digest.base64(digest.hmac_sha1("key", "The quick brown fox jumps over the lazy dog")); 20 | set resp.http.md5_b64 = digest.base64(digest.hmac_md5("key", "The quick brown fox jumps over the lazy dog")); 21 | set resp.http.sha256_clean = digest.base64_decode(resp.http.sha256_b64); 22 | set resp.http.sha1_clean = digest.base64_decode(resp.http.sha1_b64); 23 | set resp.http.md5_clean = digest.base64_decode(resp.http.md5_b64); 24 | set resp.http.md5_b64url_nopad = digest.base64url_nopad("0x80070713463e7749b90c2dc24911e275"); 25 | set resp.http.clean_nopad = digest.base64url_decode("MHg4MDA3MDcxMzQ2M2U3NzQ5YjkwYzJkYzI0OTExZTI3NQ"); 26 | 27 | # Used to test +/ vs -_. The decoded variant is russian (I 28 | # think) 29 | set resp.http.ruski = digest.base64_decode("zprOsc67z47PgiDOv8+Bzq/Pg86xz4TOtQ=="); 30 | set resp.http.ruski_b64 = "zprOsc67z47PgiDOv8+Bzq/Pg86xz4TOtQ=="; 31 | set resp.http.ruski_url = digest.base64url_nopad(resp.http.ruski); 32 | 33 | set resp.http.hash_md5 = digest.hash_md5("foobar"); 34 | } 35 | } -start 36 | 37 | client c1 { 38 | txreq -url "/" 39 | rxresp 40 | expect resp.http.sha256 == "0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8" 41 | expect resp.http.sha1 == "0xde7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" 42 | expect resp.http.md5 == "0x80070713463e7749b90c2dc24911e275" 43 | 44 | expect resp.http.sha256_b64 == "MHhmN2JjODNmNDMwNTM4NDI0YjEzMjk4ZTZhYTZmYjE0M2VmNGQ1OWExNDk0NjE3NTk5NzQ3OWRiYzJkMWEzY2Q4" 45 | expect resp.http.sha1_b64 == "MHhkZTdjOWI4NWI4Yjc4YWE2YmM4YTdhMzZmNzBhOTA3MDFjOWRiNGQ5" 46 | expect resp.http.md5_b64 == "MHg4MDA3MDcxMzQ2M2U3NzQ5YjkwYzJkYzI0OTExZTI3NQ==" 47 | 48 | expect resp.http.sha256_clean == "0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8" 49 | expect resp.http.sha1_clean == "0xde7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" 50 | expect resp.http.md5_clean == "0x80070713463e7749b90c2dc24911e275" 51 | 52 | expect resp.http.clean_nopad == "0x80070713463e7749b90c2dc24911e275" 53 | expect resp.http.md5_b64url_nopad == "MHg4MDA3MDcxMzQ2M2U3NzQ5YjkwYzJkYzI0OTExZTI3NQ" 54 | expect resp.http.ruski_url == "zprOsc67z47PgiDOv8-Bzq_Pg86xz4TOtQ" 55 | 56 | expect resp.http.hash_md5 == "3858f62230ac3c915f300c664312c63f" 57 | } 58 | 59 | client c1 -run 60 | -------------------------------------------------------------------------------- /src/tests/test02.vtc: -------------------------------------------------------------------------------- 1 | varnishtest "Test digest vmod out of workspace" 2 | 3 | server s1 { } -start 4 | 5 | varnish v1 -vcl+backend { 6 | import digest from "${vmod_topbuild}/src/.libs/libvmod_digest.so"; 7 | import vtc; 8 | 9 | sub vcl_recv { 10 | vtc.workspace_alloc(client, -5); 11 | if (req.url == "/hmac_sha256") { 12 | set req.http.hmac_sha256 = digest.hmac_sha256("key", "The quick brown fox jumps over the lazy dog"); 13 | } 14 | 15 | if (req.url == "/hmac_sha1") { 16 | set req.http.hmac_sha1 = digest.hmac_sha1("key", "The quick brown fox jumps over the lazy dog"); 17 | } 18 | 19 | if (req.url == "/hmac_md5") { 20 | set req.http.md5 = digest.hmac_md5("key", "The quick brown fox jumps over the lazy dog"); 21 | } 22 | 23 | if (req.url == "/base64") { 24 | set req.http.base64 = digest.base64("TeSTTeSTTeST"); 25 | } 26 | 27 | if (req.url == "/base64_hex") { 28 | set req.http.base64_hex = digest.base64_hex("0x54655354"); 29 | } 30 | 31 | if (req.url == "/base64_decode") { 32 | set req.http.base64_decode = digest.base64_decode("zprOsc67z47PgiDOv8+Bzq/Pg86xz4TOtQ=="); 33 | } 34 | 35 | if (req.url == "/base64url") { 36 | set req.http.base64url = digest.base64url("Interesting!"); 37 | } 38 | 39 | if (req.url == "/base64url_hex") { 40 | set req.http.base64url = digest.base64url("496E746572657374696E6721"); 41 | } 42 | 43 | if (req.url == "/base64url_decode") { 44 | set req.http.base64url_decode = digest.base64url_decode("MHg4MDA3MDcxMzQ2M2U3NzQ5YjkwYzJkYzI0OTExZTI3NQ"); 45 | } 46 | 47 | if (req.url == "/hash_sha1") { 48 | set req.http.hash_sha1 = digest.hash_sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 49 | } 50 | 51 | if (req.url == "/hash_md4") { 52 | set req.http.hash_md4 = digest.hash_md4("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 53 | } 54 | 55 | if (req.url == "/hash_whirlpool") { 56 | set req.http.hash_whirlpool = digest.hash_whirlpool("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 57 | } 58 | } 59 | 60 | } -start 61 | 62 | logexpect l1 -v v1 -i VCL_Error { 63 | expect * * * "digest.hmac_generic() Error: Out of Workspace" 64 | expect * * * "digest.hmac_generic() Error: Out of Workspace" 65 | expect * * * "digest.hmac_generic() Error: Out of Workspace" 66 | expect * * * "digest.base64_generic() Error: Out of Workspace" 67 | expect * * * "digest.base64_generic() Error: Out of Workspace" 68 | expect * * * "digest.base64_decode_generic() Error: Out of Workspace" 69 | expect * * * "digest.base64_decode_generic() Error: Out of Workspace" 70 | expect * * * "digest.hash_generic() Error: Out of Workspace" 71 | expect * * * "digest.hash_generic() Error: Out of Workspace" 72 | expect * * * "digest.hash_generic() Error: Out of Workspace" 73 | } -start 74 | 75 | client c1 { 76 | txreq -url "/hmac_sha256" 77 | rxresp 78 | expect resp.status == 503 79 | } -run 80 | 81 | client c1 { 82 | txreq -url "/hmac_sha1" 83 | rxresp 84 | expect resp.status == 503 85 | } -run 86 | 87 | client c1 { 88 | txreq -url "/hmac_md5" 89 | rxresp 90 | expect resp.status == 503 91 | } -run 92 | 93 | client c1 { 94 | txreq -url "/base64" 95 | rxresp 96 | expect resp.status == 503 97 | } -run 98 | 99 | client c1 { 100 | txreq -url "/base64_hex" 101 | rxresp 102 | expect resp.status == 503 103 | } -run 104 | 105 | client c1 { 106 | txreq -url "/base64_decode" 107 | rxresp 108 | expect resp.status == 503 109 | } -run 110 | 111 | client c1 { 112 | txreq -url "/base64url_decode" 113 | rxresp 114 | expect resp.status == 503 115 | } -run 116 | 117 | client c1 { 118 | txreq -url "/hash_sha1" 119 | rxresp 120 | expect resp.status == 503 121 | } -run 122 | 123 | client c1 { 124 | txreq -url "/hash_md4" 125 | rxresp 126 | expect resp.status == 503 127 | } -run 128 | 129 | client c1 { 130 | txreq -url "/hash_whirlpool" 131 | rxresp 132 | expect resp.status == 503 133 | } -run 134 | 135 | logexpect l1 -wait 136 | -------------------------------------------------------------------------------- /src/tests/test03.vtc: -------------------------------------------------------------------------------- 1 | varnishtest "Test invalid data in digest vmod" 2 | 3 | server s1 { 4 | rxreq 5 | txresp 6 | } -start 7 | 8 | varnish v1 -vcl+backend { 9 | import digest from "${vmod_topbuild}/src/.libs/libvmod_digest.so"; 10 | 11 | sub vcl_deliver { 12 | # Test invalid base64 13 | set resp.http.invalid1 = digest.base64_decode(req.http.invalid1); 14 | } 15 | } -start 16 | 17 | logexpect l1 -v v1 -g request { 18 | expect * * VCL_Error "digest: Base64 input contains invalid characters" 19 | } -start 20 | 21 | client c1 { 22 | txreq -url "/" -hdr "invalid1: \xff" 23 | rxresp 24 | expect resp.http.invalid1 == "" 25 | } -run 26 | 27 | logexpect l1 -wait 28 | -------------------------------------------------------------------------------- /src/tests/test_hash.vtc: -------------------------------------------------------------------------------- 1 | varnishtest "Test various hashes" 2 | 3 | # Test vectors borrowed from mhash2's test suite. 4 | # Had to split the test to avoid hitting maxhdr too easily. 5 | 6 | server s1 { 7 | rxreq 8 | txresp 9 | rxreq 10 | txresp 11 | rxreq 12 | txresp 13 | rxreq 14 | txresp 15 | } -start 16 | 17 | varnish v1 -vcl+backend { 18 | import digest from "${vmod_topbuild}/src/.libs/libvmod_digest.so"; 19 | 20 | sub vcl_deliver { 21 | if (req.url == "/1") { 22 | set resp.http.CRC32_1 = digest.hash_crc32("checksum"); 23 | set resp.http.CRC32B_2 = digest.hash_crc32b("checksum"); 24 | set resp.http.GOST_66 = digest.hash_gost("This is message, length=32 bytes"); 25 | set resp.http.GOST_67 = digest.hash_gost("Suppose the original message has length = 50 bytes"); 26 | set resp.http.HAVAL128_17 = digest.hash_haval128(""); 27 | set resp.http.HAVAL160_16 = digest.hash_haval160("a"); 28 | set resp.http.HAVAL192_15 = digest.hash_haval192("HAVAL"); 29 | set resp.http.HAVAL224_14 = digest.hash_haval224("0123456789"); 30 | set resp.http.HAVAL256_12 = digest.hash_haval256("abcdefghijklmnopqrstuvwxyz"); 31 | set resp.http.HAVAL256_13 = digest.hash_haval256("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 32 | set resp.http.MD2_101 = digest.hash_md2(""); 33 | set resp.http.MD2_102 = digest.hash_md2("a"); 34 | set resp.http.MD2_103 = digest.hash_md2("abc"); 35 | set resp.http.MD2_104 = digest.hash_md2("message digest"); 36 | set resp.http.MD2_105 = digest.hash_md2("abcdefghijklmnopqrstuvwxyz"); 37 | set resp.http.MD2_106 = digest.hash_md2("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 38 | set resp.http.MD2_107 = digest.hash_md2("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 39 | set resp.http.MD4_68 = digest.hash_md4(""); 40 | set resp.http.MD4_69 = digest.hash_md4("a"); 41 | set resp.http.MD4_70 = digest.hash_md4("abc"); 42 | set resp.http.MD4_71 = digest.hash_md4("message digest"); 43 | set resp.http.MD4_72 = digest.hash_md4("abcdefghijklmnopqrstuvwxyz"); 44 | set resp.http.MD4_73 = digest.hash_md4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 45 | set resp.http.MD4_74 = digest.hash_md4("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 46 | set resp.http.MD5_3 = digest.hash_md5(""); 47 | set resp.http.MD5_4 = digest.hash_md5("a"); 48 | set resp.http.MD5_5 = digest.hash_md5("abc"); 49 | set resp.http.MD5_6 = digest.hash_md5("message digest"); 50 | set resp.http.MD5_7 = digest.hash_md5("abcdefghijklmnopqrstuvwxyz"); 51 | set resp.http.MD5_8 = digest.hash_md5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 52 | set resp.http.MD5_9 = digest.hash_md5("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 53 | } elsif(req.url == "/2") { 54 | set resp.http.RIPEMD128_18 = digest.hash_ripemd128(""); 55 | set resp.http.RIPEMD128_19 = digest.hash_ripemd128("a"); 56 | set resp.http.RIPEMD128_20 = digest.hash_ripemd128("abc"); 57 | set resp.http.RIPEMD128_21 = digest.hash_ripemd128("message digest"); 58 | set resp.http.RIPEMD128_22 = digest.hash_ripemd128("abcdefghijklmnopqrstuvwxyz"); 59 | set resp.http.RIPEMD128_23 = digest.hash_ripemd128("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 60 | set resp.http.RIPEMD128_24 = digest.hash_ripemd128("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 61 | set resp.http.RIPEMD128_25 = digest.hash_ripemd128("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 62 | set resp.http.RIPEMD160_26 = digest.hash_ripemd160(""); 63 | set resp.http.RIPEMD160_27 = digest.hash_ripemd160("a"); 64 | set resp.http.RIPEMD160_28 = digest.hash_ripemd160("abc"); 65 | set resp.http.RIPEMD160_29 = digest.hash_ripemd160("message digest"); 66 | set resp.http.RIPEMD160_30 = digest.hash_ripemd160("abcdefghijklmnopqrstuvwxyz"); 67 | set resp.http.RIPEMD160_31 = digest.hash_ripemd160("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 68 | set resp.http.RIPEMD160_32 = digest.hash_ripemd160("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 69 | set resp.http.RIPEMD160_33 = digest.hash_ripemd160("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 70 | set resp.http.RIPEMD256_34 = digest.hash_ripemd256(""); 71 | set resp.http.RIPEMD256_35 = digest.hash_ripemd256("a"); 72 | set resp.http.RIPEMD256_36 = digest.hash_ripemd256("abc"); 73 | set resp.http.RIPEMD256_37 = digest.hash_ripemd256("message digest"); 74 | set resp.http.RIPEMD256_38 = digest.hash_ripemd256("abcdefghijklmnopqrstuvwxyz"); 75 | set resp.http.RIPEMD256_39 = digest.hash_ripemd256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 76 | set resp.http.RIPEMD256_40 = digest.hash_ripemd256("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 77 | } elsif(req.url == "/3") { 78 | set resp.http.RIPEMD256_41 = digest.hash_ripemd256("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 79 | set resp.http.RIPEMD320_42 = digest.hash_ripemd320(""); 80 | set resp.http.RIPEMD320_43 = digest.hash_ripemd320("a"); 81 | set resp.http.RIPEMD320_44 = digest.hash_ripemd320("abc"); 82 | set resp.http.RIPEMD320_45 = digest.hash_ripemd320("message digest"); 83 | set resp.http.RIPEMD320_46 = digest.hash_ripemd320("abcdefghijklmnopqrstuvwxyz"); 84 | set resp.http.RIPEMD320_47 = digest.hash_ripemd320("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 85 | set resp.http.RIPEMD320_48 = digest.hash_ripemd320("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 86 | set resp.http.RIPEMD320_49 = digest.hash_ripemd320("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 87 | set resp.http.SHA1_10 = digest.hash_sha1("abc"); 88 | set resp.http.SHA1_11 = digest.hash_sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 89 | set resp.http.SHA224_78 = digest.hash_sha224("abc"); 90 | set resp.http.SHA224_79 = digest.hash_sha224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 91 | set resp.http.SHA256_75 = digest.hash_sha256("abc"); 92 | set resp.http.SHA256_76 = digest.hash_sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 93 | set resp.http.SHA256_77 = digest.hash_sha256("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); 94 | set resp.http.SHA384_82 = digest.hash_sha384("abc"); 95 | set resp.http.SHA384_83 = digest.hash_sha384("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); 96 | set resp.http.SHA512_80 = digest.hash_sha512("abc"); 97 | set resp.http.SHA512_81 = digest.hash_sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); 98 | } elsif (req.url == "/4") { 99 | set resp.http.SNEFRU128_92 = digest.hash_snefru128("abc"); 100 | set resp.http.SNEFRU128_93 = digest.hash_snefru128("abcdefghijklmnopqrstuvwxyz"); 101 | set resp.http.SNEFRU128_94 = digest.hash_snefru128("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 102 | set resp.http.SNEFRU128_95 = digest.hash_snefru128("Test message for buffer workflow test(47 bytes)"); 103 | set resp.http.SNEFRU128_96 = digest.hash_snefru128("Test message for buffer workflow test(48 bytes)."); 104 | set resp.http.SNEFRU128_97 = digest.hash_snefru128("Test message for buffer workflow test(49 bytes).."); 105 | set resp.http.SNEFRU256_100 = digest.hash_snefru256("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 106 | set resp.http.SNEFRU256_98 = digest.hash_snefru256("abc"); 107 | set resp.http.SNEFRU256_99 = digest.hash_snefru256("abcdefghijklmnopqrstuvwxyz"); 108 | set resp.http.TIGER128_63 = digest.hash_tiger128(""); 109 | set resp.http.TIGER128_64 = digest.hash_tiger128("abc"); 110 | set resp.http.TIGER128_65 = digest.hash_tiger128("Tiger"); 111 | set resp.http.TIGER160_58 = digest.hash_tiger160(""); 112 | set resp.http.TIGER160_59 = digest.hash_tiger160("abc"); 113 | set resp.http.TIGER160_60 = digest.hash_tiger160("Tiger"); 114 | set resp.http.TIGER160_61 = digest.hash_tiger160("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"); 115 | set resp.http.TIGER160_62 = digest.hash_tiger160("ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789"); 116 | set resp.http.TIGER_50 = digest.hash_tiger(""); 117 | set resp.http.TIGER_51 = digest.hash_tiger("abc"); 118 | set resp.http.TIGER_52 = digest.hash_tiger("Tiger"); 119 | set resp.http.TIGER_53 = digest.hash_tiger("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"); 120 | set resp.http.TIGER_54 = digest.hash_tiger("ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789"); 121 | set resp.http.TIGER_55 = digest.hash_tiger("Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham"); 122 | set resp.http.TIGER_56 = digest.hash_tiger("Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge."); 123 | set resp.http.TIGER_57 = digest.hash_tiger("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"); 124 | set resp.http.WHIRLPOOL_84 = digest.hash_whirlpool(""); 125 | set resp.http.WHIRLPOOL_85 = digest.hash_whirlpool("a"); 126 | set resp.http.WHIRLPOOL_86 = digest.hash_whirlpool("abc"); 127 | set resp.http.WHIRLPOOL_87 = digest.hash_whirlpool("message digest"); 128 | set resp.http.WHIRLPOOL_88 = digest.hash_whirlpool("abcdefghijklmnopqrstuvwxyz"); 129 | set resp.http.WHIRLPOOL_89 = digest.hash_whirlpool("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 130 | set resp.http.WHIRLPOOL_90 = digest.hash_whirlpool("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 131 | set resp.http.WHIRLPOOL_91 = digest.hash_whirlpool("abcdbcdecdefdefgefghfghighijhijk"); 132 | } 133 | } 134 | } -start 135 | 136 | client c1 { 137 | txreq -url "/1" 138 | rxresp 139 | expect resp.http.CRC32_1 == "7fbeb02e" 140 | expect resp.http.CRC32B_2 == "9adf6fde" 141 | expect resp.http.GOST_66 == "b1c466d37519b82e8319819ff32595e047a28cb6f83eff1c6916a815a637fffa" 142 | expect resp.http.GOST_67 == "471aba57a60a770d3a76130635c1fbea4ef14de51f78b4ae57dd893b62f55208" 143 | expect resp.http.HAVAL128_17 == "c68f39913f901f3ddf44c707357a7d70" 144 | expect resp.http.HAVAL160_16 == "4da08f514a7275dbc4cece4a347385983983a830" 145 | expect resp.http.HAVAL192_15 == "8da26ddab4317b392b22b638998fe65b0fbe4610d345cf89" 146 | expect resp.http.HAVAL224_14 == "ee345c97a58190bf0f38bf7ce890231aa5fcf9862bf8e7bebbf76789" 147 | expect resp.http.HAVAL256_12 == "72fad4bde1da8c8332fb60561a780e7f504f21547b98686824fc33fc796afa76" 148 | expect resp.http.HAVAL256_13 == "899397d96489281e9e76d5e65abab751f312e06c06c07c9c1d42abd31bb6a404" 149 | expect resp.http.MD2_101 == "8350e5a3e24c153df2275c9f80692773" 150 | expect resp.http.MD2_102 == "32ec01ec4a6dac72c0ab96fb34c0b5d1" 151 | expect resp.http.MD2_103 == "da853b0d3f88d99b30283a69e6ded6bb" 152 | expect resp.http.MD2_104 == "ab4f496bfb2a530b219ff33031fe06b0" 153 | expect resp.http.MD2_105 == "4e8ddff3650292ab5a4108c3aa47940b" 154 | expect resp.http.MD2_106 == "da33def2a42df13975352846c30338cd" 155 | expect resp.http.MD2_107 == "d5976f79d83d3a0dc9806c3c66f3efd8" 156 | expect resp.http.MD4_68 == "31d6cfe0d16ae931b73c59d7e0c089c0" 157 | expect resp.http.MD4_69 == "bde52cb31de33e46245e05fbdbd6fb24" 158 | expect resp.http.MD4_70 == "a448017aaf21d8525fc10ae87aa6729d" 159 | expect resp.http.MD4_71 == "d9130a8164549fe818874806e1c7014b" 160 | expect resp.http.MD4_72 == "d79e1c308aa5bbcdeea8ed63df412da9" 161 | expect resp.http.MD4_73 == "043f8582f241db351ce627e153e7f0e4" 162 | expect resp.http.MD4_74 == "e33b4ddc9c38f2199c3e7b164fcc0536" 163 | expect resp.http.MD5_3 == "d41d8cd98f00b204e9800998ecf8427e" 164 | expect resp.http.MD5_4 == "0cc175b9c0f1b6a831c399e269772661" 165 | expect resp.http.MD5_5 == "900150983cd24fb0d6963f7d28e17f72" 166 | expect resp.http.MD5_6 == "f96b697d7cb7938d525a2f31aaf161d0" 167 | expect resp.http.MD5_7 == "c3fcd3d76192e4007dfb496cca67e13b" 168 | expect resp.http.MD5_8 == "d174ab98d277d9f5a5611c2c9f419d9f" 169 | expect resp.http.MD5_9 == "57edf4a22be3c955ac49da2e2107b67a" 170 | txreq -url "/2" 171 | rxresp 172 | expect resp.http.RIPEMD128_18 == "cdf26213a150dc3ecb610f18f6b38b46" 173 | expect resp.http.RIPEMD128_19 == "86be7afa339d0fc7cfc785e72f578d33" 174 | expect resp.http.RIPEMD128_20 == "c14a12199c66e4ba84636b0f69144c77" 175 | expect resp.http.RIPEMD128_21 == "9e327b3d6e523062afc1132d7df9d1b8" 176 | expect resp.http.RIPEMD128_22 == "fd2aa607f71dc8f510714922b371834e" 177 | expect resp.http.RIPEMD128_23 == "a1aa0689d0fafa2ddc22e88b49133a06" 178 | expect resp.http.RIPEMD128_24 == "d1e959eb179c911faea4624c60c5c702" 179 | expect resp.http.RIPEMD128_25 == "3f45ef194732c2dbb2c4a2c769795fa3" 180 | expect resp.http.RIPEMD160_26 == "9c1185a5c5e9fc54612808977ee8f548b2258d31" 181 | expect resp.http.RIPEMD160_27 == "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe" 182 | expect resp.http.RIPEMD160_28 == "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc" 183 | expect resp.http.RIPEMD160_29 == "5d0689ef49d2fae572b881b123a85ffa21595f36" 184 | expect resp.http.RIPEMD160_30 == "f71c27109c692c1b56bbdceb5b9d2865b3708dbc" 185 | expect resp.http.RIPEMD160_31 == "12a053384a9c0c88e405a06c27dcf49ada62eb2b" 186 | expect resp.http.RIPEMD160_32 == "b0e20b6e3116640286ed3a87a5713079b21f5189" 187 | expect resp.http.RIPEMD160_33 == "9b752e45573d4b39f4dbd3323cab82bf63326bfb" 188 | expect resp.http.RIPEMD256_34 == "02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d" 189 | expect resp.http.RIPEMD256_35 == "f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925" 190 | expect resp.http.RIPEMD256_36 == "afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65" 191 | expect resp.http.RIPEMD256_37 == "87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e" 192 | expect resp.http.RIPEMD256_38 == "649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133" 193 | expect resp.http.RIPEMD256_39 == "3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f" 194 | expect resp.http.RIPEMD256_40 == "5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8" 195 | txreq -url "/3" 196 | rxresp 197 | expect resp.http.RIPEMD256_41 == "06fdcc7a409548aaf91368c06a6275b553e3f099bf0ea4edfd6778df89a890dd" 198 | expect resp.http.RIPEMD320_42 == "22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8" 199 | expect resp.http.RIPEMD320_43 == "ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d" 200 | expect resp.http.RIPEMD320_44 == "de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d" 201 | expect resp.http.RIPEMD320_45 == "3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197" 202 | expect resp.http.RIPEMD320_46 == "cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009" 203 | expect resp.http.RIPEMD320_47 == "d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac" 204 | expect resp.http.RIPEMD320_48 == "ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4" 205 | expect resp.http.RIPEMD320_49 == "557888af5f6d8ed62ab66945c6d2a0a47ecd5341e915eb8fea1d0524955f825dc717e4a008ab2d42" 206 | expect resp.http.SHA1_10 == "a9993e364706816aba3e25717850c26c9cd0d89d" 207 | expect resp.http.SHA1_11 == "84983e441c3bd26ebaae4aa1f95129e5e54670f1" 208 | expect resp.http.SHA224_78 == "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" 209 | expect resp.http.SHA224_79 == "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" 210 | expect resp.http.SHA256_75 == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" 211 | expect resp.http.SHA256_76 == "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" 212 | expect resp.http.SHA256_77 == "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1" 213 | expect resp.http.SHA384_82 == "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7" 214 | expect resp.http.SHA384_83 == "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039" 215 | expect resp.http.SHA512_80 == "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" 216 | expect resp.http.SHA512_81 == "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" 217 | txreq -url "/4" 218 | rxresp 219 | expect resp.http.SNEFRU128_92 == "553d0648928299a0f22a275a02c83b10" 220 | expect resp.http.SNEFRU128_93 == "7840148a66b91c219c36f127a0929606" 221 | expect resp.http.SNEFRU128_94 == "d9204ed80bb8430c0b9c244fe485814a" 222 | expect resp.http.SNEFRU128_95 == "dd0d1ab288c3c36671044f41c5077ad6" 223 | expect resp.http.SNEFRU128_96 == "e7054f05bd72d7e86a052153a17c741d" 224 | expect resp.http.SNEFRU128_97 == "9b34204833422df13c83e10a0c6d080a" 225 | expect resp.http.SNEFRU256_100 == "d5fce38a152a2d9b83ab44c29306ee45ab0aed0e38c957ec431dab6ed6bb71b8" 226 | expect resp.http.SNEFRU256_98 == "7d033205647a2af3dc8339f6cb25643c33ebc622d32979c4b612b02c4903031b" 227 | expect resp.http.SNEFRU256_99 == "9304bb2f876d9c4f54546cf7ec59e0a006bead745f08c642f25a7c808e0bf86e" 228 | expect resp.http.TIGER128_63 == "24f0130c63ac933216166e76b1bb925f" 229 | expect resp.http.TIGER128_64 == "f258c1e88414ab2a527ab541ffc5b8bf" 230 | expect resp.http.TIGER128_65 == "9f00f599072300dd276abb38c8eb6dec" 231 | expect resp.http.TIGER160_58 == "24f0130c63ac933216166e76b1bb925ff373de2d" 232 | expect resp.http.TIGER160_59 == "f258c1e88414ab2a527ab541ffc5b8bf935f7b95" 233 | expect resp.http.TIGER160_60 == "9f00f599072300dd276abb38c8eb6dec37790c11" 234 | expect resp.http.TIGER160_61 == "87fb2a9083851cf7470d2cf810e6df9eb5864450" 235 | expect resp.http.TIGER160_62 == "467db80863ebce488df1cd1261655de957896565" 236 | expect resp.http.TIGER_50 == "24f0130c63ac933216166e76b1bb925ff373de2d49584e7a" 237 | expect resp.http.TIGER_51 == "f258c1e88414ab2a527ab541ffc5b8bf935f7b951c132951" 238 | expect resp.http.TIGER_52 == "9f00f599072300dd276abb38c8eb6dec37790c116f9d2bdf" 239 | expect resp.http.TIGER_53 == "87fb2a9083851cf7470d2cf810e6df9eb586445034a5a386" 240 | expect resp.http.TIGER_54 == "467db80863ebce488df1cd1261655de957896565975f9197" 241 | expect resp.http.TIGER_55 == "0c410a042968868a1671da5a3fd29a725ec1e457d3cdb303" 242 | expect resp.http.TIGER_56 == "ebf591d5afa655ce7f22894ff87f54ac89c811b6b0da3193" 243 | expect resp.http.TIGER_57 == "00b83eb4e53440c576ac6aaee0a7485825fd15e70a59ffe4" 244 | expect resp.http.WHIRLPOOL_84 == "19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3" 245 | expect resp.http.WHIRLPOOL_85 == "8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a" 246 | expect resp.http.WHIRLPOOL_86 == "4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5" 247 | expect resp.http.WHIRLPOOL_87 == "378c84a4126e2dc6e56dcc7458377aac838d00032230f53ce1f5700c0ffb4d3b8421557659ef55c106b4b52ac5a4aaa692ed920052838f3362e86dbd37a8903e" 248 | expect resp.http.WHIRLPOOL_88 == "f1d754662636ffe92c82ebb9212a484a8d38631ead4238f5442ee13b8054e41b08bf2a9251c30b6a0b8aae86177ab4a6f68f673e7207865d5d9819a3dba4eb3b" 249 | expect resp.http.WHIRLPOOL_89 == "dc37e008cf9ee69bf11f00ed9aba26901dd7c28cdec066cc6af42e40f82f3a1e08eba26629129d8fb7cb57211b9281a65517cc879d7b962142c65f5a7af01467" 250 | expect resp.http.WHIRLPOOL_90 == "466ef18babb0154d25b9d38a6414f5c08784372bccb204d6549c4afadb6014294d5bd8df2a6c44e538cd047b2681a51a2c60481e88c5a20b2c2a80cf3a9a083b" 251 | expect resp.http.WHIRLPOOL_91 == "2a987ea40f917061f5d6f0a0e4644f488a7a5a52deee656207c562f988e95c6916bdc8031bc5be1b7b947639fe050b56939baaa0adff9ae6745b7b181c3be3fd" 252 | } 253 | 254 | client c1 -run 255 | -------------------------------------------------------------------------------- /src/tests/test_hex.vtc: -------------------------------------------------------------------------------- 1 | varnishtest "Test base64 hex encoding" 2 | 3 | server s1 { 4 | rxreq 5 | txresp 6 | } -start 7 | 8 | varnish v1 -vcl+backend { 9 | import digest from "${vmod_topbuild}/src/.libs/libvmod_digest.so"; 10 | 11 | sub vcl_deliver { 12 | set resp.http.hmac_sha1 = digest.hmac_sha1("secret", "test string"); 13 | set resp.http.hmac_sha1_b64 = digest.base64(digest.hmac_sha1("secret", "test string")); 14 | set resp.http.hmac_sha1_b64_hex = digest.base64_hex(digest.hmac_sha1("secret", "test string")); 15 | 16 | set resp.http.md5 = digest.hash_md5("test string"); 17 | set resp.http.md5_b64 = digest.base64(digest.hash_md5("test string")); 18 | set resp.http.md5_b64_hex = digest.base64_hex(digest.hash_md5("test string")); 19 | 20 | set resp.http.test1_b64 = digest.base64("TeST"); 21 | set resp.http.test1_b64_hex = digest.base64_hex("0x54655354"); 22 | 23 | set resp.http.test2_b64_url = digest.base64url("Interesting!"); 24 | set resp.http.test2_b64_url_hex = digest.base64url_hex("496E746572657374696E6721"); 25 | 26 | set resp.http.test3_b64_unopad = digest.base64url_nopad("$"); 27 | set resp.http.test3_b64_unopad_hex = digest.base64url_nopad_hex("0x24"); 28 | } 29 | } -start 30 | 31 | client c1 { 32 | txreq -url "/" 33 | rxresp 34 | 35 | expect resp.http.hmac_sha1 == "0xdd26bfddf122c1055d4cd5b054227727e1e3eecf" 36 | expect resp.http.hmac_sha1_b64 == "MHhkZDI2YmZkZGYxMjJjMTA1NWQ0Y2Q1YjA1NDIyNzcyN2UxZTNlZWNm" 37 | expect resp.http.hmac_sha1_b64_hex == "3Sa/3fEiwQVdTNWwVCJ3J+Hj7s8=" 38 | 39 | expect resp.http.md5 == "6f8db599de986fab7a21625b7916589c" 40 | expect resp.http.md5_b64 == "NmY4ZGI1OTlkZTk4NmZhYjdhMjE2MjViNzkxNjU4OWM=" 41 | expect resp.http.md5_b64_hex == "b421md6Yb6t6IWJbeRZYnA==" 42 | 43 | expect resp.http.test1_b64 == resp.http.test1_b64_hex 44 | expect resp.http.test2_b64_url == resp.http.test2_b64_url_hex 45 | expect resp.http.test3_b64_unopad == resp.http.test3_b64_unopad_hex 46 | } 47 | 48 | client c1 -run 49 | -------------------------------------------------------------------------------- /src/tests/test_nullstring.vtc: -------------------------------------------------------------------------------- 1 | varnishtest "Test digest vmod for nullstrings" 2 | 3 | # Blank keys should return NULL/"", while blank data should be treated as 4 | # an empty string (i.e. ""). We treat keys differently because there should 5 | # always be a key, and not having one is almost certainly a bug and should 6 | # be painfully visible. 7 | 8 | server s1 { 9 | rxreq 10 | txresp 11 | } -start 12 | 13 | varnish v1 -vcl+backend { 14 | import digest from "${vmod_topbuild}/src/.libs/libvmod_digest.so"; 15 | 16 | sub vcl_deliver { 17 | set resp.http.sha1 = digest.hash_sha1(resp.http.blank-header); 18 | set resp.http.hmac_sha1 = "BUNNY"; 19 | set resp.http.hmac_sha1 = resp.http.hmac_sha1 + digest.hmac_sha1(resp.http.blank-header, "The quick brown fox jumps over the lazy dog"); 20 | } 21 | } -start 22 | 23 | client c1 { 24 | txreq -url "/" 25 | rxresp 26 | expect resp.http.sha1 == "da39a3ee5e6b4b0d3255bfef95601890afd80709" 27 | expect resp.http.hmac_sha1 == "BUNNY" 28 | } 29 | 30 | client c1 -run 31 | -------------------------------------------------------------------------------- /src/vmod_digest.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2011-2019 Varnish Software AS 3 | * All rights reserved. 4 | * 5 | * Author: Kristian Lyngstøl 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | 29 | /* 30 | * Digest vmod for Varnish, using libmhash. 31 | * See README.rst for usage. 32 | */ 33 | 34 | #include "config.h" 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | /* 42 | * mhash.h has a habit of pulling in assert(). Let's hope it's a define, 43 | * and that we can undef it, since Varnish has a better one. 44 | */ 45 | #include 46 | #ifdef assert 47 | # undef assert 48 | #endif 49 | 50 | #include 51 | #include 52 | 53 | #include "vcc_if.h" 54 | 55 | /* Varnish < 6.2 compat */ 56 | #ifndef VPFX 57 | # define VPFX(a) vmod_ ## a 58 | # define VARGS(a) vmod_ ## a ## _arg 59 | # define VENUM(a) vmod_enum_ ## a 60 | # define VEVENT(a) a 61 | #else 62 | # define VEVENT(a) VPFX(a) 63 | #endif 64 | 65 | #ifndef MIN 66 | # define MIN(a,b) ((a) > (b) ? (b) : (a)) 67 | #endif 68 | 69 | enum alphabets { 70 | BASE64 = 0, 71 | BASE64URL = 1, 72 | BASE64URLNOPAD = 2, 73 | N_ALPHA 74 | }; 75 | 76 | static struct e_alphabet { 77 | char *b64; 78 | int8_t i64[256]; 79 | char padding; 80 | } alphabet[N_ALPHA]; 81 | 82 | /* 83 | * Initializes the reverse lookup-table for the relevant base-N alphabet. 84 | */ 85 | static void 86 | VPFX(digest_alpha_init)(struct e_alphabet *alpha) 87 | { 88 | int i; 89 | const char *p; 90 | 91 | for (i = 0; i < 256; i++) 92 | alpha->i64[i] = -1; 93 | for (p = alpha->b64, i = 0; *p; p++, i++) 94 | alpha->i64[(int)*p] = (char)i; 95 | if (alpha->padding) 96 | alpha->i64[(int)alpha->padding] = 0; 97 | } 98 | 99 | int 100 | VEVENT(event_function)(VRT_CTX, struct VPFX(priv) *priv, enum vcl_event_e e) 101 | { 102 | (void)ctx; 103 | (void)priv; 104 | 105 | if (e != VCL_EVENT_LOAD) 106 | return (0); 107 | 108 | alphabet[BASE64].b64 = 109 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef" 110 | "ghijklmnopqrstuvwxyz0123456789+/"; 111 | alphabet[BASE64].padding = '='; 112 | alphabet[BASE64URL].b64 = 113 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef" 114 | "ghijklmnopqrstuvwxyz0123456789-_"; 115 | alphabet[BASE64URL].padding = '='; 116 | alphabet[BASE64URLNOPAD].b64 = 117 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef" 118 | "ghijklmnopqrstuvwxyz0123456789-_"; 119 | alphabet[BASE64URLNOPAD].padding = 0; 120 | VPFX(digest_alpha_init)(&alphabet[BASE64]); 121 | VPFX(digest_alpha_init)(&alphabet[BASE64URL]); 122 | VPFX(digest_alpha_init)(&alphabet[BASE64URLNOPAD]); 123 | return (0); 124 | } 125 | 126 | /* 127 | * Decodes the string s into the buffer d (size dlen), using the alphabet 128 | * specified. 129 | * 130 | * Modified slightly from varnishncsa's decoder. Mainly because the 131 | * input-length is known, so padding is optional (this is per the RFC and 132 | * allows this code to be used regardless of whether padding is present). 133 | * Also returns the length of data when it succeeds. 134 | */ 135 | static int 136 | base64_decode(struct e_alphabet *alpha, char *d, unsigned dlen, const char *s) 137 | { 138 | unsigned u, v, l; 139 | int8_t i; 140 | 141 | u = 0; 142 | l = 0; 143 | while (*s) { 144 | for (v = 0; v < 4; v++) { 145 | if (*s) 146 | i = alpha->i64[(uint8_t)*s++]; 147 | else 148 | i = 0; 149 | if (i < 0) 150 | return (-1); 151 | u <<= 6; 152 | u |= i; 153 | } 154 | for (v = 0; v < 3; v++) { 155 | if (l >= dlen - 1) 156 | return (0); 157 | *d = (u >> 16) & 0xff; 158 | u <<= 8; 159 | l++; 160 | d++; 161 | } 162 | if (!*s) 163 | break; 164 | } 165 | *d = '\0'; 166 | l++; 167 | return (l); 168 | } 169 | 170 | /* 171 | * Convert a hex character into an int 172 | */ 173 | static unsigned char 174 | char_to_int (char c) 175 | { 176 | if (c >= '0' && c <= '9') 177 | return (c - '0'); 178 | else if (c >= 'a' && c <= 'f') 179 | return (c - 87); 180 | else if (c >= 'A' && c <= 'F') 181 | return (c - 55); 182 | else 183 | return (0); 184 | } 185 | 186 | /* 187 | * Convert a hex value into an 8bit int 188 | */ 189 | static unsigned char 190 | hex_to_int(const char *in, size_t inlen) 191 | { 192 | unsigned char value = 0; 193 | 194 | assert(inlen >= 2); 195 | 196 | value = char_to_int(in[0]) << 4; 197 | value += char_to_int(in[1]); 198 | 199 | return (value); 200 | } 201 | 202 | /* 203 | * Base64-encode *in (size: inlen) into *out, max outlen bytes. If there is 204 | * insufficient space, it will bail out and return -1. Otherwise, it will 205 | * null-terminate and return the used space. 206 | * The alphabet `a` defines... the alphabet. Padding is optional. 207 | * Inspired heavily by gnulib/Simon Josefsson (as referenced in RFC4648) 208 | */ 209 | static size_t 210 | base64_encode(struct e_alphabet *alpha, const char *in, 211 | size_t inlen, int is_hex, char *out, size_t outlen) 212 | { 213 | size_t out_used = 0; 214 | 215 | /* 216 | * If reading a hex string, if "0x" is present, strip. When no further 217 | * characters follow, we return an empty output string. 218 | */ 219 | if (is_hex && inlen > 2 && in[0] == '0' && in[1] == 'x') { 220 | in += 2; 221 | inlen -= 2; 222 | } 223 | 224 | /* 225 | * B64 requires 4*ceil(n/3) bytes of space + 1 nul terminator 226 | * byte to generate output for a given input length n. When is_hex is 227 | * set, each character of inlen represents half a byte, hence the 228 | * division by 6. 229 | */ 230 | if ((!is_hex && outlen < 4 * (inlen + 2 / 3) + 1) || 231 | ( is_hex && outlen < 4 * (inlen + 5 / 6) + 1)) 232 | return (-1); 233 | 234 | while ((!is_hex && inlen) || (is_hex && inlen >= 2)) { 235 | unsigned char tmp[3] = {0, 0, 0}; 236 | unsigned char idx; 237 | int min_avail = is_hex ? MIN(inlen, 6) : MIN(inlen, 3); 238 | int nread = 0; 239 | int off = 0; 240 | 241 | if (is_hex) { 242 | while (min_avail >= 2) { 243 | tmp[off++] = hex_to_int(in, inlen); 244 | in += 2; 245 | inlen -= 2; 246 | nread++; 247 | min_avail -= 2; 248 | } 249 | } else { 250 | memcpy(tmp, in, min_avail); 251 | in += min_avail; 252 | inlen -= min_avail; 253 | nread = min_avail; 254 | } 255 | 256 | *out++ = alpha->b64[(tmp[0] >> 2) & 0x3f]; 257 | 258 | idx = (tmp[0] << 4); 259 | if (nread > 1) 260 | idx += (tmp[1] >> 4); 261 | idx &= 0x3f; 262 | *out++ = alpha->b64[idx]; 263 | 264 | if (nread > 1) { 265 | idx = (tmp[1] << 2); 266 | if (nread > 2) 267 | idx += tmp[2] >> 6; 268 | idx &= 0x3f; 269 | 270 | *out++ = alpha->b64[idx]; 271 | } else if (alpha->padding) 272 | *out++ = alpha->padding; 273 | 274 | if (nread > 2) 275 | *out++ = alpha->b64[tmp[2] & 0x3f]; 276 | else if (alpha->padding) 277 | *out++ = alpha->padding; 278 | 279 | if (alpha->padding) 280 | out_used += 4; 281 | else 282 | out_used += 2 + (nread - 1); 283 | } 284 | 285 | *out = '\0'; 286 | 287 | return (out_used + 1); 288 | } 289 | 290 | VCL_STRING 291 | VPFX(hmac_generic)(VRT_CTX, hashid hash, const char *key, const char *msg) 292 | { 293 | size_t blocksize = mhash_get_block_size(hash); 294 | unsigned char mac[blocksize]; 295 | unsigned char *hexenc; 296 | unsigned char *hexptr; 297 | size_t j; 298 | MHASH td; 299 | 300 | assert(msg); 301 | assert(key); 302 | CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); 303 | CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); 304 | 305 | /* 306 | * XXX: From mhash(3): 307 | * size_t mhash_get_hash_pblock(hashid type); 308 | * It returns the block size that the algorithm operates. This 309 | * is used in mhash_hmac_init. If the return value is 0 you 310 | * shouldn't use that algorithm in HMAC. 311 | */ 312 | assert(mhash_get_hash_pblock(hash) > 0); 313 | 314 | td = mhash_hmac_init(hash, (void *) key, strlen(key), 315 | mhash_get_hash_pblock(hash)); 316 | mhash(td, msg, strlen(msg)); 317 | mhash_hmac_deinit(td,mac); 318 | 319 | /* 320 | * HEX-encode 321 | */ 322 | hexenc = (void *)WS_Alloc(ctx->ws, 2*blocksize+3); // 0x, '\0' + 2 per input 323 | if (hexenc == NULL) { 324 | VRT_fail(ctx, "digest.hmac_generic() Error: Out of Workspace"); 325 | return (NULL); 326 | } 327 | hexptr = hexenc; 328 | sprintf((char*)hexptr,"0x"); 329 | hexptr+=2; 330 | for (j = 0; j < blocksize; j++) { 331 | sprintf((char*)hexptr,"%.2x", mac[j]); 332 | hexptr+=2; 333 | assert((hexptr-hexenc)<(2*(long)blocksize + 3)); 334 | } 335 | *hexptr = '\0'; 336 | return ((const char *)hexenc); 337 | } 338 | 339 | VCL_STRING 340 | VPFX(base64_generic)(VRT_CTX, enum alphabets a, const char *msg, int is_hex) 341 | { 342 | char *p; 343 | int u; 344 | 345 | assert(msg); 346 | assert(aws, WS_MAGIC); 350 | 351 | u = WS_ReserveAll(ctx->ws); 352 | if (u <= 0) { 353 | VRT_fail(ctx, "digest.base64_generic() Error: Out of Workspace"); 354 | WS_Release(ctx->ws,0); 355 | return (NULL); 356 | } 357 | p = ctx->ws->f; 358 | u = base64_encode(&alphabet[a],msg,strlen(msg),is_hex,p,u); 359 | WS_Release(ctx->ws,u); 360 | return (p); 361 | } 362 | 363 | VCL_STRING 364 | VPFX(base64_decode_generic)(VRT_CTX, enum alphabets a, const char *msg) 365 | { 366 | char *p; 367 | int u; 368 | 369 | assert(msg); 370 | assert(aws, WS_MAGIC); 374 | 375 | u = WS_ReserveAll(ctx->ws); 376 | if (u <= 0) { 377 | VRT_fail(ctx, "digest.base64_decode_generic() Error: " 378 | "Out of Workspace"); 379 | WS_Release(ctx->ws,0); 380 | return (NULL); 381 | } 382 | p = ctx->ws->f; 383 | u = base64_decode(&alphabet[a], p, u, msg); 384 | if (u == 0) { 385 | WS_Release(ctx->ws, 0); 386 | VSLb(ctx->vsl, SLT_VCL_Error, "digest: Out of workspace"); 387 | return (""); 388 | } 389 | 390 | if (u < 0) { 391 | WS_Release(ctx->ws, 0); 392 | VSLb(ctx->vsl, SLT_VCL_Error, 393 | "digest: Base64 input contains invalid characters"); 394 | return (""); 395 | } 396 | WS_Release(ctx->ws, u); 397 | return (p); 398 | } 399 | 400 | VCL_STRING 401 | VPFX(hash_generic)(VRT_CTX, hashid hash, const char *msg) 402 | { 403 | MHASH td; 404 | unsigned char h[mhash_get_block_size(hash)]; 405 | unsigned int i; 406 | char *p; 407 | char *ptmp; 408 | 409 | CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); 410 | td = mhash_init(hash); 411 | mhash(td, msg, strlen(msg)); 412 | mhash_deinit(td, h); 413 | p = WS_Alloc(ctx->ws,mhash_get_block_size(hash)*2 + 1); 414 | if (p == NULL) { 415 | VRT_fail(ctx, "digest.hash_generic() Error: Out of Workspace"); 416 | return (NULL); 417 | } 418 | ptmp = p; 419 | for (i = 0; i