From e0d2bd3e4ca5de486fc14ed64b843a4dcdebf12f Mon Sep 17 00:00:00 2001 From: John Doe Date: Fri, 9 Sep 2022 04:48:16 -0400 Subject: [PATCH] Switch to single-file targets, target_descriptor struct for target data, rework target handling to accomodate --- ctm.c | 234 ++++++++++++++++----------------------------------- debugprint.c | 6 +- debugprint.h | 4 +- fstoken.h | 14 ++- 4 files changed, 90 insertions(+), 168 deletions(-) diff --git a/ctm.c b/ctm.c index 7e13f45..c1d574d 100644 --- a/ctm.c +++ b/ctm.c @@ -27,126 +27,71 @@ void print_help(char* name){ printf("%s keygen [targ] [tfs] - create a new target keypair [targ] using token format [tfs] and the system true randomness source\n", name); printf("%s keygen [targ] [tfs] [ikm] - create a new target keypair [targ] using token format specifier [tfs] and 32-byte hexadecimal seed [ikm]\n", name); printf("%s keydump [targ] - dump Public and, if available, Secret Keys for target [targ]\n", name); - printf("%s keyrepair [targ] - regenerate a missing Public Key for a target [targ] for which a Secret Key is available\n", name); + //printf("%s keyrepair [targ] - regenerate a missing Public Key for a target [targ] for which a Secret Key is available\n", name); printf("%s req [targ] - generate a token request for target [targ]\n", name); } -int get_key_paths(char* target, char** sk_path, char** pk_path, char** tfs_path){ - int key_path_len; +int get_targ_path(char* target, char** targ_path){ + int path_len; - key_path_len = strlen(token_path) + strlen(target) + 13; + path_len = strlen(token_path) + strlen(target) + 17; - *sk_path = malloc(key_path_len); - if(*sk_path == NULL) return 1; + *targ_path = malloc(path_len); + if(*targ_path == NULL) return 1; - *pk_path = malloc(key_path_len); - if(*pk_path == NULL) return 1; + strcpy(*targ_path, token_path); + strcat(*targ_path, "/targets/"); + strcat(*targ_path, target); + strcat(*targ_path, ".target"); - *tfs_path = malloc(key_path_len + 1); - if(*tfs_path == NULL) return 1; - - strcpy(*sk_path, token_path); - strcat(*sk_path, "/targets/"); - strcat(*sk_path, target); - strcpy(*pk_path, *sk_path); - strcpy(*tfs_path, *sk_path); - strcat(*sk_path, ".sk"); - strcat(*pk_path, ".pk"); - strcat(*tfs_path, ".tfs"); return 0; } -int get_keys(char* target, byte* sk, byte* pk, int* idbits, int* hashbits){ // pk/sk/idbits/hasbits pointers can be NULL if you don't want to read those +int get_target(char* targ_name, target_descriptor* target){ // pk/sk/idbits/hasbits pointers can be NULL if you don't want to read those FILE *targ_file; - char *sk_path; - char *pk_path; - char *tfs_path; - bool sk_available, pk_available, tfs_available; - int idbits_buf, hashbits_buf; + char *targ_path; - get_key_paths(target, &sk_path, &pk_path, &tfs_path); + get_targ_path(targ_name, &targ_path); - sk_available = (access(sk_path, R_OK) == 0); - pk_available = (access(pk_path, R_OK) == 0); - tfs_available = (access(tfs_path, R_OK) == 0); - - if(sk_available && sk != NULL){ - targ_file = fopen(sk_path, "r"); - if(!targ_file){ - printf("Could not open Secret Key file. Exiting.\n"); - return 1; - } - fread(sk, 32, 1, targ_file); - fclose(targ_file); + targ_file = fopen(targ_path, "r"); + if(!targ_file){ + return 0; } + fread(target, sizeof(target_descriptor), 1, targ_file); + fclose(targ_file); - if(pk_available && pk != NULL){ - targ_file = fopen(pk_path, "r"); - if(!targ_file){ - printf("Could not open Public Key file. Exiting.\n"); - return 1; - } - fread(pk, 96, 1, targ_file); - fclose(targ_file); - } - - if(idbits != NULL || hashbits != NULL){ - if(tfs_available){ - targ_file = fopen(tfs_path, "r"); - if(!targ_file){ - printf("Could not open Token Format Specifier file. Exiting.\n"); - return 1; - } - fscanf(targ_file, "%i/%i", &idbits_buf, &hashbits_buf); - fclose(targ_file); - - if(idbits != NULL) *idbits = idbits_buf; - if(hashbits != NULL) *hashbits = hashbits_buf; - }else{ - printf("WARNING: Token Format Specifier not set, this is a broken state. Using default (128/256) - please add a .tfs file for the target\n"); - if(idbits != NULL) *idbits = IDBITS_DEFAULT; - if(hashbits != NULL) *hashbits = HASHBITS_DEFAULT; - } - } - - // 0 = no keys (bad target), 1 = PK only, 2 = SK only (broken state), 3 = PK+SK (can sign) - return (2 * sk_available) + pk_available; + // 0 = no keys (bad target), 1 = PK only, 2 = PK+SK + return target->sk_available + 1; } -int keydump(char* target){ - byte sk[32]; - byte pk[96]; - int key_status; - int idbits, hashbits; +int keydump(char* targ_name){ + int targ_status; + target_descriptor target; - key_status = get_keys(target, sk, pk, &idbits, &hashbits); + targ_status = get_target(targ_name, &target); - switch(key_status){ + switch(targ_status){ case 0: - printf("No keys found - target unknown.\n"); - break; + printf("No target file found - target unknown.\n"); + return 1; case 1: printf("Public Key available - can verify and request for this target\n"); - print_bytes("Public Key: ", pk, 96); + print_bytes("Public Key: ", target.pk, 96); break; case 2: - printf("Secret Key ONLY available - this is a broken state, please keyrepair this keypair (see help)\n"); - print_bytes("Secret Key: ", sk, 32); - break; - case 3: printf("Secret Key and Public Key available - can verify, request, and sign for this target.\n"); - print_bytes("Secret Key: ", sk, 32); - print_bytes("Public Key: ", pk, 96); + print_bytes("Secret Key: ", target.sk, 32); + print_bytes("Public Key: ", target.pk, 96); break; } - printf("Token Format Specifier: %i/%i (%i ID bits, %i hash bits)\n", idbits, hashbits, idbits, hashbits); + printf("Token Format Specifier: %i/%i (%i ID bits, %i hash bits)\n", target.idbits, target.hashbits, target.idbits, target.hashbits); return 0; } -int keyrepair(char* target){ +/*int keyrepair(char* target){ FILE *key_file; byte sk[32]; byte pk[96]; @@ -180,53 +125,35 @@ int keyrepair(char* target){ printf("Saved to %s\n", pk_path); return 0; -} +}*/ int keygen(char* target, byte* ikm, int idbits, int hashbits){ - char *sk_path; - char *pk_path; - char* tfs_path; + char *targ_path; FILE *targ_file; - byte sk_byte[32]; - byte pk_byte[96]; + target_descriptor targ; debug_print_bytes("IKM: ", ikm, 32); - fstoken_keygen(ikm, sk_byte, pk_byte); + fstoken_keygen(ikm, targ.sk, targ.pk); - debug_print_bytes("Secret Key: ", sk_byte, 32); - debug_print_bytes("Public Key: ", pk_byte, 96); + debug_print_bytes("Secret Key: ", targ.sk, 32); + debug_print_bytes("Public Key: ", targ.pk, 96); - if(get_key_paths(target, &sk_path, &pk_path, &tfs_path)) return 1; + targ.idbits = idbits; + targ.hashbits = hashbits; + targ.target_descriptor_version = 0x00; + targ.sk_available = true; - printf("Writing Secret Key to %s\n", sk_path); + debug_print_bytes("Target Struct: ", &targ, sizeof(targ)); - targ_file = fopen(sk_path, "w"); + if(get_targ_path(target, &targ_path)) return 1; + + targ_file = fopen(targ_path, "w"); if(!targ_file){ - printf("Could not open Secret Key file. Exiting.\n"); + printf("Could not open target file. Exiting.\n"); return 1; } - fwrite(sk_byte, 32, 1, targ_file); - fclose(targ_file); - - printf("Writing Public Key to %s\n", pk_path); - - targ_file = fopen(pk_path, "w"); - if(!targ_file){ - printf("Could not open Public Key file. Exiting.\n"); - return 1; - } - fwrite(pk_byte, 96, 1, targ_file); - fclose(targ_file); - - printf("Writing Token Format Specifier to %s\n", tfs_path); - - targ_file = fopen(tfs_path, "w"); - if(!targ_file){ - printf("Could not open Token Format Specifier file. Exiting.\n"); - return 1; - } - fprintf(targ_file, "%i/%i", idbits, hashbits); + fwrite(&targ, sizeof(targ), 1, targ_file); fclose(targ_file); return 0; @@ -246,22 +173,22 @@ bool string_endswith(const char *str, const char *suffix){ return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; } -// This function is awful because strings in C. It should probably be improved. +// Believe it or not, this function used to be WORSE, and substantially so. It could still do to be cleaned up. int list_targets(bool verbose){ printf("Listing all targets - you have secret keys for, and can issue tokens for, targets marked with (*)\n\n"); - int n, keyname_len; + int n, targname_len; struct dirent **files; - char *keydir_path, *key_path, *key_name; - bool sk_available; + char *targdir_path, *targ_path, *targ_name; + target_descriptor targ; - keydir_path = malloc(strlen(token_path) + 9); - if(keydir_path == NULL) return 1; + targdir_path = malloc(strlen(token_path) + 9); + if(targdir_path == NULL) return 1; - strcpy(keydir_path, token_path); - strcat(keydir_path, "/targets"); + strcpy(targdir_path, token_path); + strcat(targdir_path, "/targets"); #ifndef __INTELLISENSE__ // VSCodium doesn't know where alphasort is and highlights an error - n = scandir(keydir_path, &files, NULL, alphasort); + n = scandir(targdir_path, &files, NULL, alphasort); #endif if(n == -1){ @@ -270,45 +197,30 @@ int list_targets(bool verbose){ } for(int i=0;id_name, ".pk")){ - keyname_len = strlen(files[i]->d_name); + if(string_endswith(files[i]->d_name, ".target")){ + targname_len = strlen(files[i]->d_name); - key_name = malloc(keyname_len + 1); - if(key_name == NULL) return 1; + targ_name = malloc(targname_len + 1); + if(targ_name == NULL) return 1; - strcpy(key_name, files[i]->d_name); - key_name[keyname_len - 3] = '\0'; + strcpy(targ_name, files[i]->d_name); + targ_name[targname_len - 7] = '\0'; - printf("%s", key_name); - - key_path = malloc(strlen(token_path) + 9 + strlen(files[i]->d_name)); - if(key_path == NULL) return 1; + printf("%s", targ_name); - strcpy(key_path, token_path); - strcat(key_path, "/targets/"); - strcat(key_path, files[i]->d_name); + get_target(targ_name, &targ); + if(targ.sk_available) printf(" (*)"); - if(verbose) printf(" (PK: %s", key_path); - - key_path[strlen(key_path) - 2] = 's'; - - if(access(key_path, R_OK) == 0){ - sk_available = true; - - if(verbose) printf(", SK: %s", key_path); - }else{ - sk_available = false; + if(verbose){ + get_targ_path(targ_name, &targ_path); + printf(" (Path: %s, Token Format Specifier: %i/%i)", targ_path, targ.idbits, targ.hashbits); } - if(verbose) printf(")"); - if(sk_available) printf(" (*)"); - printf("\n"); - free(key_path); - free(key_name); + free(targ_name); } } - free(keydir_path); + free(targdir_path); return 0; } @@ -392,7 +304,7 @@ int main(int argc, char *argv[]){ } return keydump(argv[2]); - }else if(strcmp(argv[1], "keyrepair") == 0){ + }/*else if(strcmp(argv[1], "keyrepair") == 0){ // Make sure there's a target name if(argc < 3){ fprintf(stderr, "A target name must be provided, e.g. %s keyrepair [targ]\n", argv[0]); @@ -400,5 +312,5 @@ int main(int argc, char *argv[]){ } return keyrepair(argv[2]); - } + }*/ } \ No newline at end of file diff --git a/debugprint.c b/debugprint.c index 4a72ca0..fb885c2 100644 --- a/debugprint.c +++ b/debugprint.c @@ -2,15 +2,15 @@ #include "debugprint.h" #include "blst/blst.h" -void print_bytes(const char* label, byte *toprint, int length){ +void print_bytes(const char* label, void *toprint, int length){ printf("%s", label); for(int i=0;i +#include #define IDBITS_DEFAULT 128 #define IDBITS_MAX 256 #define HASHBITS_DEFAULT 256 #define HASHBITS_MAX 256 +// For efficiency's sake, structs intended for use with the FemtoStar Protocol must be strictly-aligned without padding, with little-endian byte ordering. +// This avoids wasting network capacity on padding, and avoids the performance impact of reordering on most modern platforms (most importantly x86 and RISC-V) +// while ensuring compatibility with strict-alignment architectures. Take note: This is NOT typical network-order! + typedef struct{ + #pragma scalar_storage_order little-endian + + uint8_t target_descriptor_version; + bool sk_available; + uint16_t idbits; + uint16_t hashbits; byte sk[32]; byte pk[96]; - uint8_t idbits; - uint8_t hashbits; } target_descriptor; void fstoken_keygen(byte* ikm, byte* sk_byte, byte* pk_byte);