ccx-utils

Miscellaneous utilities written in C
git clone https://ccx.te2000.cz/git/ccx-utils
Log | Files | Refs

commit 65157e646a6fd2a156aa09eee7d008686a6ea4b7
parent 526fce1ea18343535048def444d86cc2cf22da98
Author: Jan Pobrislo <ccx@te2000.cz>
Date:   Mon,  7 Oct 2024 13:06:52 +0000

Rudimentary miniroon parsing and signature check

Diffstat:
Asrc/gen-miniroon.py | 38++++++++++++++++++++++++++++++++++++++
Msrc/miniroon.c | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
2 files changed, 181 insertions(+), 49 deletions(-)

diff --git a/src/gen-miniroon.py b/src/gen-miniroon.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +import sys +import hmac + +def to_ns(b): + assert isinstance(b, bytes) + return b'%d:%s,' % (len(b), b) + + +def rec_ns(data): + if isinstance(data, bytes): + return to_ns(data) + if isinstance(data, str): + return to_ns(data.encode('ascii')) + return to_ns(b''.join(rec_ns(i) for i in data)) + + +def miniroon_hmac(key, msg): + print('miniroon_hmac%r' % ((key, msg),), file=sys.stderr) + #return hmac.digest(key, msg, 'blake2s') + return hmac.digest(key, msg, 'sha256') + + +def make_miniroon(name, action='invoke-once', secret=b'\0'*32, caveats=(), version='capv0'): + hdr = rec_ns((version, name, action)) + sig = miniroon_hmac(secret, hdr) + for c in caveats: + sig = miniroon_hmac(sig, c) + return rec_ns([ + hdr, + caveats, + sig, + ]) + + +if __name__ == '__main__': + import os + os.write(1, make_miniroon(name='ccx')) diff --git a/src/miniroon.c b/src/miniroon.c @@ -11,9 +11,10 @@ #include <skalibs/netstring.h> #include <skalibs/uint64.h> #include <skalibs/blake2s.h> +#include <skalibs/sha256.h> -#define USAGE "macrun directory" -#define PROG "macrun" +#define USAGE "miniroon directory" +#define PROG "miniroon" #define input_fd 0 #define payload_size_max 1024*1024 @@ -43,16 +44,59 @@ typedef struct miniroon_header_s { } miniroon_header; /* declarations */ +void dbg_print_bb(const bytebuffer *bb); +void dbg_print_bb1(const char *text, const bytebuffer *bb); void parse_payload(bytebuffer *payload); void parse_header(miniroon_header *header, bytebuffer *source); void parse_caveat(bytebuffer *source); // TODO void read_secret(bytebuffer *secret); // TODO void hmac_b2s_256(const bytebuffer *key, const bytebuffer *msg, bytebuffer *output); +void hmac_sha2_256(const bytebuffer *key, const bytebuffer *msg, bytebuffer *output); #define MINIROON_HMAC_SIZE 32 -#define MINIROON_HMAC_FUNC(key, msg, out) hmac_b2s_256(key, msg, out) +//#define MINIROON_HMAC_FUNC(key, msg, out) hmac_b2s_256(key, msg, out) +#define MINIROON_HMAC_FUNC(key, msg, out) hmac_sha2_256(key, msg, out) /* definitions */ +void dbg_print_bb(const bytebuffer *bb) { + static const char digit[] = "0123456789abcdef"; + char ascii[16]; + char hex[32]; + size_t i, j, a_off=0, h_off=0; + for (i = 0; i < bb->len; ++i) { + if (i % 16 == 0) { + if(i) { + write(2, "|", 1); + write(2, hex, h_off); + write(2, "| [", 3); + write(2, ascii, a_off); + write(2, "]\n", 2); + } + a_off=0; + h_off=0; + } + unsigned char c = bb->data[i]; + ascii[a_off++] = (c >= ' ' && c <= '~') ? c : '.'; + hex[h_off++] = digit[0xf & (c >> 4)]; + hex[h_off++] = digit[0xf & c]; + } + while(h_off < 32) { + hex[h_off++] = ' '; + } + write(2, "|", 1); + write(2, hex, h_off); + write(2, "| [", 3); + write(2, ascii, a_off); + write(2, "]\n", 2); +} + +void dbg_print_bb1(const char *text, const bytebuffer *bb) { + write(2, "\n", 1); + write(2, text, strlen(text)); + write(2, ":\n", 2); + dbg_print_bb(bb); +} + void netstring_chunk_init (netstring_chunk *chunk, const bytebuffer source) { memset(chunk, 0, sizeof(netstring_chunk)); chunk->source = source; @@ -70,66 +114,30 @@ bool netstring_chunk_next (netstring_chunk *c) { if (c->outer.len + c->inner.len >= c->source.len) { strerr_dief1x(111, "Malformed netstring (truncated)"); } - if (c->source.data[c->outer.len + c->inner.len] != ',') { + if (c->source.data[c->outer.len + c->inner.len + 1] != ',') { strerr_dief1x(111, "Malformed netstring (expected ',')"); } c->inner.data = &c->source.data[c->outer.len + 1]; c->outer.len += c->inner.len + 2; c->source.data += c->outer.len; c->source.len -= c->outer.len; + return true; } -int netstring_get_chunk (const bytebuffer *input, bytebuffer *chunk, bytebuffer *rest) -{ - uint64_t nlen; /* size of payload */ - size_t pos; /* size of numerical prefix */ - if (!input->len) { - return 0; - } - pos = uint64_scan(input->data, &nlen) ; - if (pos >= input->len) { - return 0; - } - if (input->data[pos] != ':') { - return 0; - } - char *s = input->data + pos + 1; /* start of payload */ - if (input->len <= nlen + pos + 1) { - return 0; - } - if (s[nlen] != ',') { - return 0; - } - if (chunk != NULL) { - chunk->data = s; - chunk->len = nlen; - } - if (rest != NULL) { - chunk->data = s + 1; - chunk->len = input->len - nlen - pos - 2; - } - return 1; -} void fd_block(int fd) { int flags = fcntl(fd, F_GETFL); if(flags == -1) { strerr_dief1sys(111, "fcntl() getfd"); } - if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + if(fcntl(fd, F_SETFL, flags | ~O_NONBLOCK) < 0) { strerr_dief1sys(111, "fcntl() setfd"); } } -void parse_header(miniroon_header *header, bytebuffer *outer) { - bytebuffer input=*outer, chunk, next; - if(!input.len) { - strerr_dief1x(111, "Empty header"); - } - if(!netstring_get_chunk(&input, &chunk, &next)) { - strerr_dief1x(111, "Malformed netstring"); - } - +void parse_header(miniroon_header *header, bytebuffer *source) { + // TODO + dbg_print_bb1("Got header", source); } void handle_payload(size_t payload_size) { @@ -143,7 +151,7 @@ void handle_payload(size_t payload_size) { } if(read_size == -1) { if(errno != EINTR) { - strerr_dief1sys(111, "read()"); + strerr_dief1sys(111, "read() payload"); } continue; } @@ -154,6 +162,7 @@ void handle_payload(size_t payload_size) { } bytebuffer payload_bb = {payload, payload_size}; + dbg_print_bb1("Got payload", &payload_bb); parse_payload(&payload_bb); } @@ -180,7 +189,9 @@ void parse_payload(bytebuffer *payload) { uint8_t hmac_data[MINIROON_HMAC_SIZE]; bytebuffer hmac_bb = {hmac_data, MINIROON_HMAC_SIZE}; read_secret(&hmac_bb); + // dbg_print_bb1("Secret", &hmac_bb); MINIROON_HMAC_FUNC(&hmac_bb, &c.inner, &hmac_bb); + // dbg_print_bb1("Signature update", &hmac_bb); if(!netstring_chunk_next(&c)) { strerr_dief1x(111, "Mising miniroon body"); @@ -189,19 +200,22 @@ void parse_payload(bytebuffer *payload) { netstring_chunk_init(&body, c.inner); while(netstring_chunk_next(&body)) { + dbg_print_bb1("Got caveat", &body.inner); parse_caveat(&body.inner); MINIROON_HMAC_FUNC(&hmac_bb, &body.inner, &hmac_bb); + // dbg_print_bb1("Signature update", &hmac_bb); } if(!netstring_chunk_next(&c)) { strerr_dief1x(111, "Mising miniroon signature"); } + dbg_print_bb1("Got signature", &c.inner); if(c.inner.len != MINIROON_HMAC_SIZE) { - strerr_dief1x(111, "Mising miniroon signature length"); + strerr_dief1x(111, "Invalid miniroon signature length"); } /* constant time hash compare */ uint8_t bitdiff = 0; - for(size_t i=0; i<=MINIROON_HMAC_SIZE; i++) { + for(size_t i=0; i<MINIROON_HMAC_SIZE; i++) { bitdiff |= hmac_data[i] ^ c.inner.data[i]; } if(netstring_chunk_next(&c)) { @@ -218,6 +232,8 @@ void hmac_b2s_256(const bytebuffer *key, const bytebuffer *msg, bytebuffer *outp assert(output->len == block_size); assert(msg); + dbg_print_bb1("HMAC key", key); + dbg_print_bb1("HMAC message", msg); blake2s_ctx hash_ctx; uint8_t pad[block_size], ihash[block_size]; @@ -240,6 +256,84 @@ void hmac_b2s_256(const bytebuffer *key, const bytebuffer *msg, bytebuffer *outp blake2s_update(&hash_ctx, pad, block_size); blake2s_update(&hash_ctx, ihash, block_size); blake2s_final(&hash_ctx, output->data); + dbg_print_bb1("HMAC output", output); +} + +/* function doing the HMAC-SHA-256 calculation */ +void hmac_sha256(const uint8_t* key, const uint32_t keysize, const uint8_t* msg, const uint32_t msgsize, uint8_t* output) +{ + static const size_t block_size = 64, digest_size = 32; + SHA256Schedule outer, inner; + uint8_t tmp; + + if (keysize > block_size) // if len(key) > blocksize(sha256) => key = sha256(key) + { + uint8_t new_key[digest_size]; + sha256_init(&outer); + sha256_update(&outer, key, keysize); + sha256_final(&outer, new_key); + return hmac_sha256(new_key, digest_size, msg, msgsize, output); + } + sha256_init(&outer); + sha256_init(&inner); + + uint32_t i; + for (i = 0; i < keysize; ++i) + { + tmp = key[i] ^ 0x5C; + sha256_update(&outer, &tmp, 1); + tmp = key[i] ^ 0x36; + sha256_update(&inner, &tmp, 1); + } + for (; i < block_size; ++i) + { + tmp = 0x5C; + sha256_update(&outer, &tmp, 1); + tmp = 0x36; + sha256_update(&inner, &tmp, 1); + } + + sha256_update(&inner, msg, msgsize); + sha256_final(&inner, output); + + sha256_update(&outer, output, digest_size); + sha256_final(&outer, output); +} + +void hmac_sha2_256(const bytebuffer *key, const bytebuffer *msg, bytebuffer *output) { + static const size_t block_size = 32; + assert(key->len == block_size); + assert(output->len == block_size); + assert(msg); + + dbg_print_bb1("HMAC key", key); + dbg_print_bb1("HMAC message", msg); + hmac_sha256(key->data, key->len, msg->data, msg->len, output->data); + /* + SHA256Schedule hash_ctx; + uint8_t pad[block_size], ihash[block_size]; + + sha256_init(&hash_ctx); + // i_key_pad := block_sized_key xor [0x36 blockSize] // Inner padded key + for(size_t i=0; i<block_size; i++) { + pad[i] = key->data[i] ^ 0x36; + } + // ihash = hash(i_key_pad || message) + sha256_update(&hash_ctx, pad, block_size); + sha256_update(&hash_ctx, msg->data, msg->len); + sha256_final(&hash_ctx, ihash); + + sha256_init(&hash_ctx); + // o_key_pad := block_sized_key xor [0x5c blockSize] // Outer padded key + for(size_t i=0; i<block_size; i++) { + pad[i] = key->data[i] ^ 0x5c; + } + // ohash = hash(o_key_pad || ihash) + sha256_update(&hash_ctx, pad, block_size); + sha256_update(&hash_ctx, ihash, block_size); + sha256_final(&hash_ctx, output->data); + */ + dbg_print_bb1("HMAC output", output); } /* @@ -294,7 +388,7 @@ int main (int argc, char const *const *argv) break; case -1: if(errno != EINTR) { - strerr_dief1sys(111, "read()"); + strerr_dief1sys(111, "read() length"); } break; default: