miniroon-verify.c (6030B)
1 #include <errno.h> 2 #include <assert.h> 3 #include <stdbool.h> 4 #include <unistd.h> 5 #include <sys/select.h> 6 7 // for debug prints 8 #include <stdio.h> 9 10 #include <skalibs/types.h> 11 #include <skalibs/strerr.h> 12 #include <skalibs/djbunix.h> 13 #include <skalibs/exec.h> 14 #include <skalibs/netstring.h> 15 #include <skalibs/uint64.h> 16 #include <skalibs/stralloc.h> 17 #include <skalibs/env.h> 18 19 #include "verify_common.h" 20 #include "bytebuffer.h" 21 #include "netstring.h" 22 #include "hmac_sha2_256.h" 23 #include "miniroon-header.h" 24 #include "caveats.h" 25 26 typedef struct miniroon_data_s { 27 miniroon_header hdr; 28 bytebuffer caveats[MAX_CAVEATS]; 29 size_t caveat_count; 30 } miniroon_data; 31 32 /* declarations */ 33 void miniroon_data_init(miniroon_data *data); 34 void process_payload(const bytebuffer payload); 35 void validate_and_exec(miniroon_data *data); 36 void read_secret(const bytebuffer secret); 37 38 #define MINIROON_HMAC_SIZE 32 39 //#define MINIROON_HMAC_FUNC(key, msg, out) hmac_b2s_256(key, msg, out) 40 #define MINIROON_HMAC_FUNC(key, msg, out) hmac_sha2_256(key, msg, out) 41 42 /* definitions */ 43 44 45 void miniroon_data_init(miniroon_data *data) { 46 memset(data, 0, sizeof(miniroon_data)); 47 // data->env_modif = STRALLOC_ZERO ; 48 } 49 50 void read_secret(const bytebuffer secret){ 51 assert(secret.len == MINIROON_HMAC_SIZE); 52 size_t bytes_read = 0; 53 int secret_fd = openc_readb("secret"); 54 if (secret_fd < 0) { 55 strerr_dief1sys(111, "open(secret)"); 56 } 57 while(bytes_read < secret.len) { 58 ssize_t r = read(secret_fd, &secret.data[bytes_read], secret.len - bytes_read); 59 switch(r) { 60 case 0: 61 strerr_dief1x(111, "EOF before full secret was read"); 62 break; 63 case -1: 64 if(errno != EINTR) { 65 strerr_dief1sys(111, "read() length"); 66 } 67 break; 68 } 69 bytes_read += r; 70 } 71 if(close(secret_fd) != 0) { 72 strerr_dief1sys(111, "close(secret_fd)"); 73 } 74 } 75 76 77 void validate_and_exec(miniroon_data *md) { 78 miniroon_caveats_state state; 79 miniroon_caveats_state_init(&state); 80 // stralloc env_modif; 81 82 for(size_t i=0; i < md->caveat_count; i++) { 83 dbg_print_bb1("Validate caveat", md->caveats[i]); 84 miniroon_caveat_prepare(md->caveats[i], &state); 85 } 86 for(size_t i=0; i < md->caveat_count; i++) { 87 dbg_print_bb1("Validate caveat", md->caveats[i]); 88 miniroon_caveat_validate(md->caveats[i], &state); 89 } 90 91 /* iff everything validated correctly */ 92 // TODO: pass unused argv from main() ? 93 char cmd[] = "./run"; 94 const char *cmd_argv[2] = {cmd, 0}; 95 miniroon_caveats_state_exec(&state, cmd_argv); 96 } 97 98 void process_payload(const bytebuffer payload) { 99 miniroon_data md; 100 miniroon_data_init(&md); 101 netstring_chunk c; 102 netstring_chunk_init(&c, payload); 103 104 if(!netstring_chunk_next(&c)) { 105 strerr_dief1x(111, "Mising miniroon header"); 106 } 107 parse_header(&md.hdr, c.inner); 108 // header should be verified by now, we can start hashing 109 uint8_t hmac_data[MINIROON_HMAC_SIZE]; 110 bytebuffer hmac_bb = {hmac_data, MINIROON_HMAC_SIZE}; 111 read_secret(hmac_bb); 112 // dbg_print_bb1("Secret", hmac_bb); 113 MINIROON_HMAC_FUNC(hmac_bb, c.inner, hmac_bb); 114 // dbg_print_bb1("Signature update", hmac_bb); 115 116 if(!netstring_chunk_next(&c)) { 117 strerr_dief1x(111, "Mising miniroon body"); 118 } 119 netstring_chunk body; 120 netstring_chunk_init(&body, c.inner); 121 122 while(netstring_chunk_next(&body)) { 123 dbg_print_bb1("Got caveat", body.inner); 124 if(md.caveat_count >= MAX_CAVEATS) { 125 strerr_dief1x(111, "Too many caveats"); 126 } 127 md.caveats[md.caveat_count++] = body.inner; 128 MINIROON_HMAC_FUNC(hmac_bb, body.inner, hmac_bb); 129 // dbg_print_bb1("Signature update", hmac_bb); 130 } 131 132 if(!netstring_chunk_next(&c)) { 133 strerr_dief1x(111, "Mising miniroon signature"); 134 } 135 dbg_print_bb1("Got signature", c.inner); 136 if(c.inner.len != MINIROON_HMAC_SIZE) { 137 strerr_dief1x(111, "Invalid miniroon signature length"); 138 } 139 /* constant time hash compare */ 140 uint8_t bitdiff = 0; 141 for(size_t i=0; i<MINIROON_HMAC_SIZE; i++) { 142 bitdiff |= hmac_data[i] ^ c.inner.data[i]; 143 } 144 if(netstring_chunk_next(&c)) { 145 strerr_dief1x(111, "Extraneous data in miniroon"); 146 } 147 if(bitdiff) { 148 strerr_dief1x(111, "Invalid miniroon signature"); 149 } 150 151 validate_and_exec(&md); 152 strerr_dief1x(110, "Internal logic error, should not get here"); 153 } 154 155 void read_payload(int payload_fd, const bytebuffer bb) { 156 int flags = fcntl(payload_fd, F_GETFL); 157 if(flags == -1) { 158 strerr_dief1sys(111, "fcntl(payload_fd) getfd"); 159 } 160 if(fcntl(payload_fd, F_SETFL, flags & ~O_NONBLOCK) < 0) { 161 strerr_dief1sys(111, "fcntl(payload_fd) setfd"); 162 } 163 164 ssize_t payload_read = fd_read(payload_fd, bb.data, bb.len); 165 if(payload_read < 0 ) { 166 strerr_dief1sys(111, "read(payload)"); 167 } 168 if(payload_read != bb.len) { 169 strerr_dief1x(111, "could not read whole payload"); 170 } 171 } 172 173 bool parse_fd(char const *arg, int *fd) { 174 size_t arg_size = strlen(arg); 175 return int_scan(arg, fd) == arg_size; 176 } 177 178 bool parse_size(char const *arg, size_t *size) { 179 size_t arg_size = strlen(arg); 180 return size_scan(arg, size) == arg_size; 181 } 182 183 int main (int argc, char const *const *argv) 184 { 185 if (argc != 3) { 186 strerr_dieusage(100, USAGE); 187 } 188 189 int payload_fd; 190 size_t payload_size; 191 192 if(!parse_fd(argv[1], &payload_fd)) { 193 strerr_dief1x(100, "could not parse payload fd"); 194 } 195 196 if(!parse_size(argv[2], &payload_size)) { 197 strerr_dief1x(100, "could not parse payload length"); 198 } 199 200 char payload_data[payload_size]; 201 bytebuffer payload = {payload_data, payload_size}; 202 read_payload(payload_fd, payload); 203 fd_close(payload_fd); 204 205 dbg_print_bb1("Got payload", payload); 206 process_payload(payload); 207 strerr_dief1x(110, "Internal logic error, should not get here"); 208 return 110; 209 } 210 /* 211 capability ``` 212 container/bzr.ccx/123456 213 login/tty1/7890 214 ``` 215 - secret 216 - execline command 217 - env allowlist (re?) 218 - max execution count/id (uuidv7?) 219 220 ``` 221 caphdr = [capv0;name;invoke-once] 222 c1 = [caphdr;;h1=hmac(secret, caphdr)] 223 c2 = [caphdr;[att1];h2=hmac(h1, att1)] 224 c3 = [caphdr;[att1;att2];h3=hmac(h2, att2)] 225 ``` 226 */ 227 228 /* vim: sts=2 sw=2 et 229 */