Commit 824323e5 authored by Geoff Simmons's avatar Geoff Simmons

First version with the digest object, passes tests with MD5.

This is still WIP, has a number of todos and needs more tests.
parent 03d6167e
Pipeline #42 skipped
......@@ -66,11 +66,36 @@ values:
CONTENTS
========
* Object digest
* BLOB digest.final()
* BOOL digest.update(BLOB)
* BLOB hash(ENUM, BLOB)
* Object hmac
* BLOB hmac.hmac(BLOB)
* STRING version()
.. _obj_digest:
Object digest
=============
.. _func_digest.update:
BOOL digest.update(BLOB)
------------------------
Prototype
BOOL digest.update(BLOB)
.. _func_digest.final:
BLOB digest.final()
-------------------
Prototype
BLOB digest.final()
.. _func_hash:
BLOB hash(ENUM, BLOB)
......
......@@ -30,6 +30,39 @@ varnish v1 -vcl {
new k6 = blobcode.blob(HEX,
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
new rfc2202t6 = blobdigest.hmac(MD5, k6.get());
new d1 = blobdigest.digest(MD5);
new d2 = blobdigest.digest(MD5);
new a = blobcode.blob(IDENTITY, "a");
new d3 = blobdigest.digest(MD5, a.get());
new msg = blobcode.blob(IDENTITY, "message");
new d4 = blobdigest.digest(MD5, msg.get());
new alphalc = blobcode.blob(IDENTITY,
"abcdefghijklmnopqrstuvwxyz");
new d5 = blobdigest.digest(MD5, alphalc.get());
new empty = blobcode.blob(IDENTITY, "");
new d6 = blobdigest.digest(MD5, empty.get());
new alphauc = blobcode.blob(IDENTITY,
"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
new d7 = blobdigest.digest(MD5, alphauc.get());
new digits = blobcode.blob(IDENTITY, "1234567890");
new d8 = blobdigest.digest(MD5, digits.get());
new pangram =
blobcode.blob(IDENTITY,
"The quick brown fox jumps over the lazy dog");
new d9 = blobdigest.digest(MD5, pangram.get());
new d10 = blobdigest.digest(MD5, pangram.get());
# Byte values 0 to 63, 64 to 127, etc up to 255
new b0to63 = blobcode.blob(BASE64,
"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==");
new b64to127 = blobcode.blob(BASE64,
"QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+fw==");
new b128to191 = blobcode.blob(BASE64,
"gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+vw==");
new b192to255 = blobcode.blob(BASE64,
"wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==");
new d11 = blobdigest.digest(MD5, b0to63.get());
}
sub vcl_recv {
......@@ -37,58 +70,165 @@ varnish v1 -vcl {
}
sub vcl_synth {
set resp.http.empty
= blobcode.encode(HEXUC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY, "")));
set resp.http.a
if (!d1.update(empty.get())) {
set resp.status = 500;
return(deliver);
}
set resp.http.empty = blobcode.encode(HEXUC, d1.final());
if (!d2.update(a.get())) {
set resp.status = 500;
return(deliver);
}
set resp.http.a = blobcode.encode(HEXUC, d2.final());
if (!d3.update(blobcode.decode(IDENTITY, "b"))) {
set resp.status = 500;
return(deliver);
}
if (!d3.update(blobcode.decode(IDENTITY, "c"))) {
set resp.status = 500;
return(deliver);
}
set resp.http.abc = blobcode.encode(HEXUC, d3.final());
if (!d4.update(blobcode.decode(IDENTITY, " "))) {
set resp.status = 500;
return(deliver);
}
if (!d4.update(blobcode.decode(IDENTITY, "digest"))) {
set resp.status = 500;
return(deliver);
}
set resp.http.msgdigest = blobcode.encode(HEXUC, d4.final());
if (!d5.update(blobcode.decode(IDENTITY, ""))) {
set resp.status = 500;
return(deliver);
}
set resp.http.alphalc = blobcode.encode(HEXUC, d5.final());
if (!d6.update(blobcode.decode(IDENTITY,
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))) {
set resp.status = 500;
return(deliver);
}
set resp.http.alphasoup = blobcode.encode(HEXUC, d6.final());
if (!d7.update(alphalc.get())) {
set resp.status = 500;
return(deliver);
}
if (!d7.update(blobcode.decode(IDENTITY, "0123456789"))) {
set resp.status = 500;
return(deliver);
}
set resp.http.alphanum = blobcode.encode(HEXUC, d7.final());
if (!d8.update(digits.get())) {
set resp.status = 500;
return(deliver);
}
if (!d8.update(digits.get())) {
set resp.status = 500;
return(deliver);
}
if (!d8.update(digits.get())) {
set resp.status = 500;
return(deliver);
}
if (!d8.update(digits.get())) {
set resp.status = 500;
return(deliver);
}
if (!d8.update(digits.get())) {
set resp.status = 500;
return(deliver);
}
if (!d8.update(digits.get())) {
set resp.status = 500;
return(deliver);
}
if (!d8.update(digits.get())) {
set resp.status = 500;
return(deliver);
}
set resp.http.digits = blobcode.encode(HEXUC, d8.final());
set resp.http.pangram = blobcode.encode(HEXLC, d9.final());
if (!d10.update(blobcode.decode(IDENTITY, "."))) {
set resp.status = 500;
return(deliver);
}
set resp.http.pangramperiod = blobcode.encode(HEXLC,
d10.final());
if (!d11.update(b64to127.get())) {
set resp.status = 500;
return(deliver);
}
if (!d11.update(b128to191.get())) {
set resp.status = 500;
return(deliver);
}
if (!d11.update(b192to255.get())) {
set resp.status = 500;
return(deliver);
}
set resp.http.allbytes = blobcode.encode(HEXLC, d11.final());
set resp.http.emptyf
= blobcode.encode(HEXUC, blobdigest.hash(MD5, empty.get()));
set resp.http.af
= blobcode.encode(HEXUC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY, "a")));
set resp.http.abc
set resp.http.abcf
= blobcode.encode(HEXUC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY, "abc")));
set resp.http.msgdigest
set resp.http.msgdigestf
= blobcode.encode(HEXUC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY,
"message digest")));
set resp.http.alphalc
set resp.http.alphalcf
= blobcode.encode(HEXUC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY,
"abcdefghijklmnopqrstuvwxyz")));
set resp.http.alphasoup
set resp.http.alphasoupf
= blobcode.encode(HEXUC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY,
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
set resp.http.alphanum
set resp.http.alphanumf
= blobcode.encode(HEXUC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY,
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")));
set resp.http.digits
set resp.http.digitsf
= blobcode.encode(HEXUC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY,
"12345678901234567890123456789012345678901234567890123456789012345678901234567890")));
set resp.http.pangram
set resp.http.pangramf
= blobcode.encode(HEXLC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY,
"The quick brown fox jumps over the lazy dog")));
set resp.http.pangramperiod
set resp.http.pangramperiodf
= blobcode.encode(HEXLC, blobdigest.hash(MD5,
blobcode.decode(IDENTITY,
"The quick brown fox jumps over the lazy dog.")));
# all 256 byte values in ascending, big-endian order
set resp.http.allbytes
# all 256 byte values in ascending order
set resp.http.allbytesf
= blobcode.encode(HEXLC, blobdigest.hash(MD5,
blobcode.decode(BASE64,
"AQACAQMCBAMFBAYFBwYIBwkICgkLCgwLDQwODQ8OEA8REBIRExIUExUUFhUXFhgXGRgaGRsaHBsdHB4dHx4gHyEgIiEjIiQjJSQmJScmKCcpKCopKyosKy0sLi0vLjAvMTAyMTMyNDM1NDY1NzY4Nzk4Ojk7Ojw7PTw+PT8+QD9BQEJBQ0JEQ0VERkVHRkhHSUhKSUtKTEtNTE5NT05QT1FQUlFTUlRTVVRWVVdWWFdZWFpZW1pcW11cXl1fXmBfYWBiYWNiZGNlZGZlZ2ZoZ2loamlramxrbWxubW9ucG9xcHJxc3J0c3V0dnV3dnh3eXh6eXt6fHt9fH59f36Afw==")));
"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==")));
set resp.http.rfc2202t1 = blobcode.encode(HEXLC,
rfc2202t1.hmac(blobcode.decode(IDENTITY, "Hi There")));
......@@ -142,15 +282,27 @@ client c1 {
expect resp.http.abc == "900150983CD24FB0D6963F7D28E17F72"
expect resp.http.msgdigest == "F96B697D7CB7938D525A2F31AAF161D0"
expect resp.http.alphalc == "C3FCD3D76192E4007DFB496CCA67E13B"
expect resp.http.alphasoup == "8215EF0796A20BCAAAE116D3876C664A"
expect resp.http.alphanum == "D174AB98D277D9F5A5611C2C9F419D9F"
expect resp.http.digits == "57EDF4A22BE3C955AC49DA2E2107B67A"
expect resp.http.emptyf == "D41D8CD98F00B204E9800998ECF8427E"
expect resp.http.af == "0CC175B9C0F1B6A831C399E269772661"
expect resp.http.abcf == "900150983CD24FB0D6963F7D28E17F72"
expect resp.http.msgdigestf == "F96B697D7CB7938D525A2F31AAF161D0"
expect resp.http.alphalcf == "C3FCD3D76192E4007DFB496CCA67E13B"
expect resp.http.alphasoupf == "8215EF0796A20BCAAAE116D3876C664A"
expect resp.http.alphanumf == "D174AB98D277D9F5A5611C2C9F419D9F"
expect resp.http.digitsf == "57EDF4A22BE3C955AC49DA2E2107B67A"
# from Wikipedia
expect resp.http.pangram == "9e107d9d372bb6826bd81d3542a419d6"
expect resp.http.pangramperiod == "e4d909c290d0fb1ca068ffaddf22cbd0"
expect resp.http.pangramf == "9e107d9d372bb6826bd81d3542a419d6"
expect resp.http.pangramperiodf == "e4d909c290d0fb1ca068ffaddf22cbd0"
# verified with: base64 -d | md5sum
expect resp.http.allbytes == "2553b585b093fa52dd2526595bb2fb0d"
expect resp.http.allbytes == "e2c865db4162bed963bfaa9ef6ac18f0"
expect resp.http.allbytesf == "e2c865db4162bed963bfaa9ef6ac18f0"
# RFC2202 test cases
expect resp.http.rfc2202t1 == "9294727a3638bb1c13f48ef8158bfc9d"
......
......@@ -25,7 +25,11 @@
*
*/
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "config.h"
......@@ -50,6 +54,23 @@
#define ILLEGAL(ctx, m) \
ERR((ctx), m " is illegal in vcl_init() and vcl_fini().")
struct digest_task {
unsigned magic;
#define VMOD_BLOBDIGEST_DIGEST_TASK_MAGIC 0x646937a8
hash_ctx ctx;
unsigned xid;
int finalized;
};
struct vmod_blobdigest_digest {
unsigned magic;
#define VMOD_BLOBDIGEST_DIGEST_MAGIC 0xaccb2e25
hash_ctx ctx;
char *vcl_name;
pthread_key_t task;
enum algorithm hash;
};
struct vmod_blobdigest_hmac {
unsigned magic;
#define VMOD_BLOBDIGEST_HMAC_MAGIC 0x85678153
......@@ -191,6 +212,156 @@ digest(const enum algorithm hash, hash_ctx *restrict const hctx,
/* Objects */
static inline int
WS_Contains(struct ws * const restrict ws, const void * const restrict ptr,
const size_t len)
{
return ((char *)ptr >= ws->s && (char *)(ptr + len) <= ws->e);
}
static struct digest_task *
get_task(const struct vrt_ctx * const restrict ctx,
const struct vmod_blobdigest_digest * const restrict h)
{
unsigned xid;
struct digest_task *task = NULL;
void *p;
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
AN(ctx->vsl);
xid = VXID(ctx->vsl->wid);
if ((p = pthread_getspecific(h->task)) != NULL)
CAST_OBJ(task, p, VMOD_BLOBDIGEST_DIGEST_TASK_MAGIC);
if (p == NULL ||
! WS_Contains(ctx->ws, task, sizeof(struct digest_task))) {
if ((task = WS_Alloc(ctx->ws, sizeof(struct digest_task)))
== NULL)
return NULL;
task->magic = VMOD_BLOBDIGEST_DIGEST_TASK_MAGIC;
task->xid = ~xid;
AZ(pthread_setspecific(h->task, task));
}
assert(WS_Contains(ctx->ws, task, sizeof(struct digest_task)));
if (p == NULL || task->xid != xid) {
memcpy(&task->ctx, &h->ctx, sizeof(hash_ctx));
task->xid = xid;
task->finalized = 0;
}
return task;
}
VCL_VOID
vmod_digest__init(VRT_CTX, struct vmod_blobdigest_digest **digestp,
const char *vcl_name, VCL_ENUM hashs, VCL_BLOB initb)
{
struct vmod_blobdigest_digest *digest;
enum algorithm hash = parse_algorithm(hashs);
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(digestp);
AZ(*digestp);
AN(vcl_name);
ALLOC_OBJ(digest, VMOD_BLOBDIGEST_DIGEST_MAGIC);
AN(digest);
*digestp = digest;
digest->hash = hash;
AZ(pthread_key_create(&digest->task, NULL));
digest->vcl_name = strdup(vcl_name);
AN(digest->vcl_name);
init(hash, &digest->ctx);
if (initb != NULL)
update(hash, &digest->ctx, initb->priv, initb->len);
}
VCL_VOID
vmod_digest__fini(struct vmod_blobdigest_digest **digestp)
{
struct vmod_blobdigest_digest *digest;
digest = *digestp;
*digestp = NULL;
CHECK_OBJ_NOTNULL(digest, VMOD_BLOBDIGEST_DIGEST_MAGIC);
AZ(pthread_key_delete(digest->task));
if (digest->vcl_name != NULL)
free(digest->vcl_name);
FREE_OBJ(digest);
}
VCL_BOOL
vmod_digest_update(VRT_CTX, struct vmod_blobdigest_digest *h, VCL_BLOB b)
{
struct digest_task *task;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(h, VMOD_BLOBDIGEST_DIGEST_MAGIC);
/* XXX: is b == NULL an error? */
if (b == NULL || b->len == 0 || b->priv == NULL)
return 1;
/* XXX: if in init or fini, just update the object context */
task = get_task(ctx, h);
if (task == NULL) {
ERRNOMEM(ctx, "digest.update()"); // XXX: use vcl_name
return 0;
}
if (task->finalized) {
ERR(ctx, "already finalized in digest.update()");
return 0;
}
update(h->hash, &task->ctx, b->priv, b->len);
return 1;
}
VCL_BLOB
vmod_digest_final(VRT_CTX, struct vmod_blobdigest_digest *h)
{
struct vmod_priv *b;
struct digest_task *task;
char *snap;
enum algorithm hash;
size_t digestsz;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(h, VMOD_BLOBDIGEST_DIGEST_MAGIC);
/* XXX: if in init or fini, just finalize the object context */
task = get_task(ctx, h);
if (task == NULL) {
ERRNOMEM(ctx, "digest.final()"); // XXX: use vcl_name
return NULL;
}
if (task->finalized) {
ERR(ctx, "already finalized in digest.final()");
return NULL;
}
hash = h->hash;
digestsz = hashspec[hash].digestsz;
CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
snap = WS_Snapshot(ctx->ws);
/* XXX: use vcl_name in err messages */
if ((b = WS_Alloc(ctx->ws, sizeof(struct vmod_priv))) == NULL) {
ERRNOMEM(ctx, "allocating blob in digest.final()");
return NULL;
}
if ((b->priv = WS_Alloc(ctx->ws, digestsz)) == NULL) {
WS_Reset(ctx->ws, snap);
ERRNOMEM(ctx, "allocating hash result in digest.final()");
return NULL;
}
b->len = digestsz;
b->free = NULL;
final(hash, &task->ctx, b->priv);
task->finalized = 1;
return b;
}
VCL_VOID
vmod_hmac__init(VRT_CTX, struct vmod_blobdigest_hmac **hmacp,
const char *vcl_name, VCL_ENUM hashs, VCL_BLOB key)
......
......@@ -48,6 +48,13 @@ values:
* ``SHA3_384``
* ``SHA3_512``
$Object digest(ENUM {MD5, SHA1, SHA224, SHA256, SHA384, SHA512, SHA3_224,
SHA3_256, SHA3_384, SHA3_512} hash, BLOB init=0)
$Method BOOL .update(BLOB)
$Method BLOB .final()
$Function BLOB hash(ENUM {MD5, SHA1, SHA224, SHA256, SHA384, SHA512, SHA3_224,
SHA3_256, SHA3_384, SHA3_512} hash, BLOB msg)
......
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