Skip to content

Commit

Permalink
Merge branch 'latchset:master' into cirrus
Browse files Browse the repository at this point in the history
  • Loading branch information
hdholm authored May 28, 2024
2 parents 5b34d2c + 339ad6c commit 67757f3
Show file tree
Hide file tree
Showing 18 changed files with 290 additions and 32 deletions.
2 changes: 2 additions & 0 deletions lib/hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include <jose/jws.h>
#include <jose/jwe.h>

#define MAX_COMPRESSED_SIZE (256*1024)

typedef enum {
JOSE_HOOK_JWK_KIND_NONE = 0,
JOSE_HOOK_JWK_KIND_TYPE,
Expand Down
26 changes: 7 additions & 19 deletions lib/jwe.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,14 +275,8 @@ jose_jwe_enc_cek_io(jose_cfg_t *cfg, json_t *jwe, const json_t *cek,
jose_io_t *next)
{
const jose_hook_alg_t *alg = NULL;
jose_io_auto_t *zip = NULL;
json_auto_t *prt = NULL;
const char *h = NULL;
const char *k = NULL;
const char *z = NULL;

prt = jose_b64_dec_load(json_object_get(jwe, "protected"));
(void) json_unpack(prt, "{s:s}", "zip", &z);

if (json_unpack(jwe, "{s?{s?s}}", "unprotected", "enc", &h) < 0)
return NULL;
Expand Down Expand Up @@ -336,19 +330,7 @@ jose_jwe_enc_cek_io(jose_cfg_t *cfg, json_t *jwe, const json_t *cek,
if (!encode_protected(jwe))
return NULL;

if (z) {
const jose_hook_alg_t *a = NULL;

a = jose_hook_alg_find(JOSE_HOOK_ALG_KIND_COMP, z);
if (!a)
return NULL;

zip = a->comp.def(a, cfg, next);
if (!zip)
return NULL;
}

return alg->encr.enc(alg, cfg, jwe, cek, zip ? zip : next);
return alg->encr.enc(alg, cfg, jwe, cek, next);
}

void *
Expand Down Expand Up @@ -463,6 +445,12 @@ jose_jwe_dec_cek(jose_cfg_t *cfg, const json_t *jwe, const json_t *cek,
o = jose_io_malloc(cfg, &pt, ptl);
d = jose_jwe_dec_cek_io(cfg, jwe, cek, o);
i = jose_b64_dec_io(d);

/* Here we make sure the ciphertext is not larger than our
* compression limit. */
if (zip_in_protected_header((json_t*)jwe) && ctl > MAX_COMPRESSED_SIZE)
return false;

if (!o || !d || !i || !i->feed(i, ct, ctl) || !i->done(i))
return NULL;

Expand Down
10 changes: 8 additions & 2 deletions lib/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ flags = '-Wl,--version-script=' + meson.current_source_dir() + '/libjose.map'
code = 'int main() { return 0; }'
cc = meson.get_compiler('c')

if not cc.links(code, args: flags, name: '-Wl,--version-script=...')
flags = [ '-export-symbols-regex=^jose_.*' ]
if host_machine.system() == 'freebsd'
if not cc.links(code, args: flags + ',--undefined-version' , name: '-Wl,--version-script=...')
flags = [ '-export-symbols-regex=^jose_.*' ]
endif
else
if not cc.links(code, args: flags, name: '-Wl,--version-script=...')
flags = [ '-export-symbols-regex=^jose_.*' ]
endif
endif

libjose_lib = shared_library('jose',
Expand Down
58 changes: 58 additions & 0 deletions lib/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "misc.h"
#include <jose/b64.h>
#include <string.h>
#include "hooks.h"

bool
encode_protected(json_t *obj)
Expand All @@ -42,6 +43,63 @@ zero(void *mem, size_t len)
memset(mem, 0, len);
}


bool
handle_zip_enc(json_t *json, const void *in, size_t len, void **data, size_t *datalen)
{
json_t *prt = NULL;
char *z = NULL;
const jose_hook_alg_t *a = NULL;
jose_io_auto_t *zip = NULL;
jose_io_auto_t *zipdata = NULL;

prt = json_object_get(json, "protected");
if (prt && json_is_string(prt))
prt = jose_b64_dec_load(prt);

/* Check if we have "zip" in the protected header. */
if (json_unpack(prt, "{s:s}", "zip", &z) == -1) {
/* No zip. */
*data = (void*)in;
*datalen = len;
return true;
}

/* OK, we have "zip", so we should compress the payload before
* the encryption takes place. */
a = jose_hook_alg_find(JOSE_HOOK_ALG_KIND_COMP, z);
if (!a)
return false;

zipdata = jose_io_malloc(NULL, data, datalen);
if (!zipdata)
return false;

zip = a->comp.def(a, NULL, zipdata);
if (!zip || !zip->feed(zip, in, len) || !zip->done(zip))
return false;

return true;
}

bool
zip_in_protected_header(json_t *json)
{
json_t *prt = NULL;
char *z = NULL;

prt = json_object_get(json, "protected");
if (prt && json_is_string(prt))
prt = jose_b64_dec_load(prt);

/* Check if we have "zip" in the protected header. */
if (json_unpack(prt, "{s:s}", "zip", &z) == -1)
return false;

/* We have "zip", but let's validate the alg also. */
return jose_hook_alg_find(JOSE_HOOK_ALG_KIND_COMP, z) != NULL;
}

static void __attribute__((constructor))
constructor(void)
{
Expand Down
6 changes: 6 additions & 0 deletions lib/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ encode_protected(json_t *obj);

void
zero(void *mem, size_t len);

bool
handle_zip_enc(json_t *jwe, const void *in, size_t len, void **data, size_t *data_len);

bool
zip_in_protected_header(json_t *jwe);
9 changes: 7 additions & 2 deletions lib/openssl/aescbch.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "misc.h"
#include <jose/b64.h>
#include "../hooks.h"
#include "../misc.h"

#include <openssl/rand.h>
#include <openssl/sha.h>
Expand Down Expand Up @@ -155,9 +156,13 @@ enc_feed(jose_io_t *io, const void *in, size_t len)
io_t *i = containerof(io, io_t, io);

uint8_t ct[EVP_CIPHER_CTX_block_size(i->cctx) + 1];
const uint8_t *pt = in;
uint8_t *pt = NULL;
size_t ptlen = 0;

for (size_t j = 0; j < len; j++) {
if (!handle_zip_enc(i->json, in, len, (void**)&pt, &ptlen))
return false;

for (size_t j = 0; j < ptlen; j++) {
int l = 0;

if (EVP_EncryptUpdate(i->cctx, ct, &l, &pt[j], 1) <= 0)
Expand Down
10 changes: 8 additions & 2 deletions lib/openssl/aesgcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "misc.h"
#include <jose/b64.h>
#include "../hooks.h"
#include "../misc.h"

#include <openssl/rand.h>

Expand Down Expand Up @@ -103,10 +104,15 @@ static bool
enc_feed(jose_io_t *io, const void *in, size_t len)
{
io_t *i = containerof(io, io_t, io);
const uint8_t *pt = in;
int l = 0;

for (size_t j = 0; j < len; j++) {
uint8_t *pt = NULL;
size_t ptlen = 0;

if (!handle_zip_enc(i->json, in, len, (void**)&pt, &ptlen))
return false;

for (size_t j = 0; j < ptlen; j++) {
uint8_t ct[EVP_CIPHER_CTX_block_size(i->cctx) + 1];

if (EVP_EncryptUpdate(i->cctx, ct, &l, &pt[j], 1) <= 0)
Expand Down
2 changes: 1 addition & 1 deletion lib/openssl/oct.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jwk_make_execute(jose_cfg_t *cfg, json_t *jwk)
if (json_unpack(jwk, "{s:I}", "bytes", &len) < 0)
return false;

if (len > KEYMAX)
if (len <= 0 || len > KEYMAX)
return false;

if (RAND_bytes(key, len) <= 0)
Expand Down
9 changes: 7 additions & 2 deletions lib/openssl/pbes2.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <string.h>

#define NAMES "PBES2-HS256+A128KW", "PBES2-HS384+A192KW", "PBES2-HS512+A256KW"
#define P2C_MIN_ITERATIONS 1000
#define P2C_MAX_ITERATIONS 32768

static json_t *
pbkdf2(const char *alg, jose_cfg_t *cfg, const json_t *jwk, int iter,
Expand Down Expand Up @@ -193,7 +195,7 @@ alg_wrap_wrp(const jose_hook_alg_t *alg, jose_cfg_t *cfg, json_t *jwe,
json_auto_t *hdr = NULL;
const char *aes = NULL;
json_t *h = NULL;
int p2c = 10000;
int p2c = P2C_MAX_ITERATIONS;
size_t stl = 0;

if (!json_object_get(cek, "k") && !jose_jwk_gen(cfg, cek))
Expand Down Expand Up @@ -226,7 +228,7 @@ alg_wrap_wrp(const jose_hook_alg_t *alg, jose_cfg_t *cfg, json_t *jwe,
json_object_set_new(h, "p2c", json_integer(p2c)) < 0)
return false;

if (p2c < 1000)
if (p2c < P2C_MIN_ITERATIONS || p2c > P2C_MAX_ITERATIONS)
return false;

if (json_object_set_new(h, "p2s", jose_b64_enc(st, stl)) == -1)
Expand Down Expand Up @@ -268,6 +270,9 @@ alg_wrap_unw(const jose_hook_alg_t *alg, jose_cfg_t *cfg, const json_t *jwe,
if (json_unpack(hdr, "{s:I}", "p2c", &p2c) == -1)
return false;

if (p2c > P2C_MAX_ITERATIONS)
return false;

stl = jose_b64_dec(json_object_get(hdr, "p2s"), NULL, 0);
if (stl < 8 || stl > sizeof(st))
return false;
Expand Down
3 changes: 3 additions & 0 deletions lib/zlib/deflate.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ def_free(jose_io_t *io)
static bool
inf_feed(jose_io_t *io, const void *in, size_t len)
{
if (len > MAX_COMPRESSED_SIZE) {
return false;
}
return feed(io, in, len, inflate);
}

Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
project('jose', 'c', license: 'APL2',
version: '12',
version: '14',
default_options: [
'c_std=gnu99',
'prefix=/usr',
Expand Down
68 changes: 68 additions & 0 deletions tests/alg_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include <jose/jose.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>

static int g_high_compression_tested = 0;
static int g_low_compression_tested = 0;

const struct {
const char *alg;
Expand All @@ -41,6 +45,63 @@ const struct {
{}
};

const uint32_t long_string_tests[] = {
2000, 200000, 10000000, 0
};

static uint8_t* get_random_string(uint32_t length)
{
assert(length);
uint8_t* c = (uint8_t*)malloc(length*sizeof(uint8_t));
assert(c);
for (uint32_t i=0; i<length; i++) {
c[i] = 'A' + (random() % 26);
}
return c;
}

static void
test_long_string(size_t inputlen) {
jose_io_auto_t *b = NULL;
jose_io_auto_t *c = NULL;
jose_io_auto_t *z = NULL;
void *buf1 = NULL;
void *buf2 = NULL;
size_t blen = 0;
size_t clen = 0;
const jose_hook_alg_t *a = jose_hook_alg_find(JOSE_HOOK_ALG_KIND_COMP, "DEF");
uint8_t* str = get_random_string(inputlen);

/* Test compression first. */
b = jose_io_malloc(NULL, &buf1, &blen);
assert(b);
z = a->comp.def(a, NULL, b);
assert(z);

assert(z->feed(z, str, inputlen));
assert(z->done(z));

/* Test decompression now */
c = jose_io_malloc(NULL, &buf2, &clen);
assert(b);
z = a->comp.inf(a, NULL, c);
assert(z);

/* If length>MAX_COMPRESSED_SIZE, it must fail due to high decompression size */
if(blen > MAX_COMPRESSED_SIZE) {
assert(!z->feed(z, buf1, blen));
g_high_compression_tested = 1;
} else {
assert(z->feed(z, buf1, blen));
g_low_compression_tested = 1;
/* Compare the final output with the original input. */
assert(clen == inputlen);
assert(memcmp(buf2, str, inputlen) == 0);
}
assert(z->done(z));
free(str);
}

static void
test(const jose_hook_alg_t *a, bool iter,
const uint8_t *i, size_t il)
Expand Down Expand Up @@ -119,5 +180,12 @@ main(int argc, char *argv[])
tst_inf, sizeof(tst_inf));
}

for (size_t i = 0; long_string_tests[i]; i++) {
test_long_string(long_string_tests[i]);
}

assert(1 == g_high_compression_tested);
assert(1 == g_low_compression_tested);

return EXIT_SUCCESS;
}
Loading

0 comments on commit 67757f3

Please sign in to comment.