commit c5eed37c744c786076a1ec13132ade7ef410ed16
parent 3b759a5229fcfaaf3732f296bdda279507ef1081
Author: Jan Pobrislo <ccx@te2000.cz>
Date: Mon, 11 Nov 2024 01:50:49 +0000
Split miniroon into a separate repository
Diffstat:
3 files changed, 1 insertion(+), 581 deletions(-)
diff --git a/src/Makefile b/src/Makefile
@@ -1,5 +1,5 @@
-tools_simple:=argv0exec nosuid pidns_run safelink spawn-pty fdsend fdrecv fdrecvto socketpair ptsname mtime_to_uuidv7 ucspi-socksserver ucspi-socksserver-connected miniroon
+tools_simple:=argv0exec nosuid pidns_run safelink spawn-pty fdsend fdrecv fdrecvto socketpair ptsname mtime_to_uuidv7 ucspi-socksserver ucspi-socksserver-connected
tools_libcap:=applyuidgid-caps
diff --git a/src/gen-miniroon.py b/src/gen-miniroon.py
@@ -1,43 +0,0 @@
-#!/usr/bin/env python3
-import sys
-import hmac
-
-
-class NetString(bytes):
- @classmethod
- def from_any(cls, data):
- if isinstance(data, NetString):
- return cls(data)
- if isinstance(data, bytes):
- return cls(to_ns(data))
- if isinstance(data, str):
- return cls(to_ns(data.encode('ascii')))
- return cls(to_ns(b''.join(cls.from_any(i) for i in data)))
-
-
-def to_ns(b):
- assert isinstance(b, bytes)
- return NetString(b'%d:%s,' % (len(b), b))
-
-
-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 = b''.join(NetString.from_any(i) for i in (version, name, action))
- sig = miniroon_hmac(secret, hdr)
- for c in caveats:
- sig = miniroon_hmac(sig, c)
- return NetString.from_any([
- 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
@@ -1,537 +0,0 @@
-#include <errno.h>
-#include <assert.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/select.h>
-
-#include <skalibs/types.h>
-#include <skalibs/strerr.h>
-#include <skalibs/djbunix.h>
-#include <skalibs/exec.h>
-#include <skalibs/netstring.h>
-#include <skalibs/uint64.h>
-#include <skalibs/blake2s.h>
-#include <skalibs/sha256.h>
-#include <skalibs/stralloc.h>
-#include <skalibs/env.h>
-
-#define USAGE "miniroon directory"
-#define PROG "miniroon"
-
-#define input_fd 0
-#define payload_size_max 1024*1024
-#define MAX_CAVEATS 256
-#define MAX_ENV_ALLOW 256
-
-typedef struct bytebuffer_s {
- char *data;
- size_t len;
-} bytebuffer;
-
-typedef struct netstring_chunk_b {
- bytebuffer source;
- bytebuffer outer;
- bytebuffer inner;
-} netstring_chunk;
-
-typedef struct miniroon_header_s {
- bytebuffer id;
-
- enum miniroon_version {
- V0 = 0
- } version;
-
- enum miniroon_action {
- REVOKE, INVOKE, INVOKE_ONCE
- } action;
-
-} miniroon_header;
-
-typedef struct miniroon_env_entry_s {
- const bytebuffer name;
- const bytebuffer value;
- enum miniroon_env_state {
- ENV_NO_CHANGE = 0,
- ENV_SET = 1,
- ENV_REMOVE = 2
- } state;
-} miniroon_env_entry;
-
-typedef struct miniroon_env_map_s {
- miniroon_env_entry env[MAX_ENV_ALLOW];
- size_t env_count;
-} miniroon_env_map;
-
-typedef struct miniroon_data_s {
- miniroon_header hdr;
- bytebuffer caveats[MAX_CAVEATS];
- size_t caveat_count;
-} miniroon_data;
-
-/* declarations */
-void dbg_print_bb(const bytebuffer bb);
-void dbg_print_bb1(const char *text, const bytebuffer bb);
-void miniroon_env_map_init(miniroon_env_map *emap);
-void miniroon_env_map_add(miniroon_env_map *emap, const bytebuffer name);
-int miniroon_env_map_find(miniroon_env_map *emap, const bytebuffer name);
-void miniroon_data_init(miniroon_data *data);
-void process_payload(const bytebuffer payload);
-void process_header(miniroon_header *header, const bytebuffer source);
-void validate_caveats(miniroon_data *data);
-void read_secret(const bytebuffer secret); // TODO
-void hmac_b2s_256(const bytebuffer key, const bytebuffer msg, const bytebuffer output);
-void hmac_sha2_256(const bytebuffer key, const bytebuffer msg, const 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_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;
-}
-
-bool netstring_chunk_next (netstring_chunk *c) {
- // bytebuffer dbg_bb = {(void*)c, sizeof(netstring_chunk)};
- // dbg_print_bb1("netstring chunk", dbg_bb);
- // dbg_print_bb1("netstring source", c->source);
-
- if(!c->source.len) {
- return false;
- }
- c->outer.data = c->source.data;
- c->outer.len /* size of numerical prefix */ = uint64_scan(c->source.data, &c->inner.len);
- if (c->source.data[c->outer.len] != ':') {
- strerr_dief1x(111, "Malformed netstring (expected ':')");
- }
- if (c->outer.len + c->inner.len + 2 > c->source.len) {
- strerr_dief1x(111, "Malformed netstring (truncated)");
- }
- if (c->source.data[c->outer.len + c->inner.len + 1] != ',') {
- strerr_dief1x(111, "Malformed netstring (expected ',')");
- }
- assert(c->source.len >= c->outer.len);
- 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;
- // dbg_print_bb1("Chunk > Outer", c->outer);
- // dbg_print_bb1("Chunk > Inner", c->inner);
- return true;
-}
-
-void miniroon_data_init(miniroon_data *data) {
- memset(data, 0, sizeof(miniroon_data));
- // data->env_modif = STRALLOC_ZERO ;
-}
-
-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) {
- strerr_dief1sys(111, "fcntl() setfd");
- }
-}
-
-int strbbcmp(const bytebuffer bb, const char *s) {
- return strncmp(bb.data, s, bb.len);
-}
-
-void set_header_version(miniroon_header *header, const bytebuffer source) {
- if(strbbcmp(source, "capv0") == 0) {
- header->version = V0;
- } else {
- strerr_dief1x(111, "Unhandled miniroon version");
- }
-}
-
-void set_header_action(miniroon_header *header, const bytebuffer source) {
- if(strbbcmp(source, "revoke") == 0) {
- header->action = REVOKE;
- } else if(strbbcmp(source, "invoke") == 0) {
- header->action = INVOKE;
- } else if(strbbcmp(source, "invoke-once") == 0) {
- header->action = INVOKE_ONCE;
- } else {
- strerr_dief1x(111, "Unhandled miniroon action");
- }
-}
-
-void process_header(miniroon_header *header, const bytebuffer source) {
- dbg_print_bb1("Got header", source);
- netstring_chunk c;
- netstring_chunk_init(&c, source);
-
- if(!netstring_chunk_next(&c)) {
- strerr_dief1x(111, "Mising version in miniroon header");
- }
- dbg_print_bb1("Header > Version", c.inner);
- set_header_version(header, c.inner);
-
- if(!netstring_chunk_next(&c)) {
- strerr_dief1x(111, "Mising ID in miniroon header");
- }
- dbg_print_bb1("Header > ID", c.inner);
- header->id = c.inner;
-
- if(!netstring_chunk_next(&c)) {
- strerr_dief1x(111, "Mising action in miniroon header");
- }
- dbg_print_bb1("Header > Action", c.inner);
- set_header_action(header, c.inner);
-
- if(netstring_chunk_next(&c)) {
- strerr_dief1x(111, "Extraneous data in miniroon header");
- }
-
- char id[header->id.len + 1];
- for(size_t i=0; i<header->id.len; i++) {
- id[i] = header->id.data[i];
- if(id[i] == '-') { continue; }
- if(id[i] >= '0' && id[i] >= '9') { continue; }
- if(id[i] >= 'a' && id[i] >= 'z') { continue; }
- strerr_dief1x(111, "Invalid character in miniroon ID");
- }
- id[header->id.len] = 0;
-
- if (chdir(id) != 0) {
- strerr_dief1sys(111, "chdir(id)");
- }
-
-}
-
-void read_payload(const bytebuffer bb) {
- char *read_next = bb.data;
- ssize_t read_size;
- while(read_next - bb.data < bb.len) {
- read_size = read(input_fd, read_next, bb.len - (read_next - bb.data));
- if(read_size == 0) {
- strerr_dief1x(111, "EOF before full netstring payload was read");
- }
- if(read_size == -1) {
- if(errno != EINTR) {
- strerr_dief1sys(111, "read() payload");
- }
- continue;
- }
- read_next += read_size;
- }
- if(bb.data[bb.len - 1] != ',') {
- strerr_dief1x(111, "Invalid netstring terminator");
- }
-}
-
-void read_secret(const bytebuffer secret){
- assert(secret.len == MINIROON_HMAC_SIZE);
- size_t bytes_read = 0;
- int secret_fd = openc_readb("secret");
- if (secret_fd < 0) {
- strerr_dief1sys(111, "open(secret)");
- }
- while(bytes_read < secret.len) {
- ssize_t r = read(secret_fd, &secret.data[bytes_read], secret.len - bytes_read);
- switch(r) {
- case 0:
- strerr_dief1x(111, "EOF before full secret was read");
- break;
- case -1:
- if(errno != EINTR) {
- strerr_dief1sys(111, "read() length");
- }
- break;
- }
- bytes_read += r;
- }
- if(close(secret_fd) != 0) {
- strerr_dief1sys(111, "close(secret_fd)");
- }
-}
-
-void miniroon_env_map_init(miniroon_env_map *emap) {
- memset(emap, 0, sizeof(miniroon_env_map));
-}
-void miniroon_env_map_add(miniroon_env_map *emap, const bytebuffer name);
-// TODO
-int miniroon_env_map_find(miniroon_env_map *emap, const bytebuffer name);
-// TODO
-
-void validate_caveats(miniroon_data *md) {
- miniroon_env_map emap;
- miniroon_env_map_init(&emap);
- // stralloc env_modif;
-
- int env_allow_fd = openc_readb("env.allow");
- if (env_allow_fd < 0) {
- strerr_dief1sys(111, "open(env.allow)");
- }
-
- if(close(env_allow_fd) != 0) {
- strerr_dief1sys(111, "close(env_allow_fd)");
- }
-}
-
-void process_payload(const bytebuffer payload) {
- miniroon_data md;
- miniroon_data_init(&md);
- netstring_chunk c;
- netstring_chunk_init(&c, payload);
-
- if(!netstring_chunk_next(&c)) {
- strerr_dief1x(111, "Mising miniroon header");
- }
- process_header(&md.hdr, c.inner);
- // header should be verified by now, we can start hashing
- 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");
- }
- netstring_chunk body;
- netstring_chunk_init(&body, c.inner);
-
- while(netstring_chunk_next(&body)) {
- dbg_print_bb1("Got caveat", body.inner);
- if(md.caveat_count >= MAX_CAVEATS) {
- strerr_dief1x(111, "Too many caveats");
- }
- md.caveats[md.caveat_count++] = 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, "Invalid miniroon signature length");
- }
- /* constant time hash compare */
- uint8_t bitdiff = 0;
- for(size_t i=0; i<MINIROON_HMAC_SIZE; i++) {
- bitdiff |= hmac_data[i] ^ c.inner.data[i];
- }
- if(netstring_chunk_next(&c)) {
- strerr_dief1x(111, "Extraneous data in miniroon");
- }
- if(bitdiff) {
- strerr_dief1x(111, "Invalid miniroon signature");
- }
-
- validate_caveats(&md);
-
- /* iff everything validated correctly */
- // TODO: pass unused argv from main() ?
- char cmd[] = "./run";
- const char *cmd_argv[2] = {cmd, 0};
- xexec(cmd_argv);
-}
-
-void hmac_b2s_256(const bytebuffer key, const bytebuffer msg, const bytebuffer output) {
- static const size_t block_size = 64, digest_size = 32;
- assert(key.len <= block_size);
- assert(output.len == digest_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[digest_size];
-
- blake2s_init(&hash_ctx, digest_size);
- // i_key_pad := block_sized_key xor [0x36 blockSize] // Inner padded key
- for(size_t i=0; i<block_size; i++) {
- pad[i] = (i < key.len ? key.data[i] : 0) ^ 0x36;
- }
- // ihash = hash(i_key_pad || message)
- blake2s_update(&hash_ctx, pad, block_size);
- blake2s_update(&hash_ctx, msg.data, msg.len);
- blake2s_final(&hash_ctx, ihash);
-
- blake2s_init(&hash_ctx, block_size);
- // o_key_pad := block_sized_key xor [0x5c blockSize] // Outer padded key
- for(size_t i=0; i<block_size; i++) {
- pad[i] = (i < key.len ? key.data[i] : 0) ^ 0x5c;
- }
- // ohash = hash(o_key_pad || ihash)
- blake2s_update(&hash_ctx, pad, block_size);
- blake2s_update(&hash_ctx, ihash, digest_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);
-
- dbg_print_bb1("HMAC key", key);
- dbg_print_bb1("HMAC message", msg);
- hmac_sha256(key.data, key.len, msg.data, msg.len, output.data);
- dbg_print_bb1("HMAC output", output);
-}
-
-size_t read_payload_size(int fd) {
- char read_char;
- size_t payload_size = 0;
-
- fd_block(fd);
-
- while(payload_size < payload_size_max) {
- switch(read(fd, &read_char, 1)) {
- case 0:
- strerr_dief1x(111, "EOF before netstring size was read");
- break;
- case 1:
- if(read_char == ':') {
- return payload_size;
- } else if(read_char >= '0' && read_char <= '9') {
- payload_size *= 10;
- payload_size += read_char - '0';
- } else {
- strerr_dief1x(111, "Malformed netstring on input");
- }
- break;
- case -1:
- if(errno != EINTR) {
- strerr_dief1sys(111, "read() length");
- }
- break;
- default:
- strerr_dief1x(110, "Unexpected return value from read()");
- break;
- }
- }
-
- strerr_dief1x(111, "Input netstring too big");
-}
-
-int main (int argc, char const *const *argv)
-{
-
- if (argc != 2) {
- strerr_dieusage(100, USAGE);
- }
-
- if (chdir(argv[1]) != 0) {
- strerr_dief1sys(111, "chdir()");
- }
- size_t payload_size = read_payload_size(input_fd);
- char payload_data[payload_size + 1];
- bytebuffer payload = {payload_data, payload_size + 1};
- read_payload(payload);
- payload.len -= 1; /* strip final netstring terminator */
- dbg_print_bb1("Got payload", payload);
- process_payload(payload);
- strerr_dief1x(110, "Internal logic error, should not get here");
- return 110;
-}
-/*
-capability ```
-container/bzr.ccx/123456
-login/tty1/7890
-```
-- secret
-- execline command
-- env allowlist (re?)
-- max execution count/id (uuidv7?)
-
-```
-caphdr = [capv0;name;invoke-once]
-c1 = [caphdr;;h1=hmac(secret, caphdr)]
-c2 = [caphdr;[att1];h2=hmac(h1, att1)]
-c3 = [caphdr;[att1;att2];h3=hmac(h2, att2)]
-```
-*/
-
-/* vim: sts=2 sw=2 et
-*/