2022-09-09 06:47:49 +00:00
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <dirent.h>
# include <unistd.h>
# include <sys/random.h>
# include <stdbool.h>
# include <assert.h>
# include "blst/blst.h"
# include "debugprint.h"
# include "fstoken.h"
char * token_path ;
void print_help ( char * name ) {
printf ( " FemtoStar Credit Token Manager (ctm) \n " ) ;
printf ( " This tool can be used to generate and process Credit Tokens for use with the FemtoStar Protocol. \n \n " ) ;
printf ( " Warning: This tool lets you do insecure or broken things! Be careful with it. \n " ) ;
printf ( " ctm is still under development! Do not assume it is secure or complete yet. \n " ) ;
printf ( " In particular, note that keys and tokens are currently stored unencrypted on-disk. \n \n " ) ;
printf ( " %s help - display this help \n " , name ) ;
printf ( " %s path - display your token path \n " , name ) ;
printf ( " %s list - list targets you have keys for - use \" %s list verbose \" to also display paths to the keys \n " , name , name ) ;
printf ( " %s keygen [targ] - create a new target keypair [targ] using the default token format (128/256) and the system true randomness source \n " , 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 ) ;
2022-09-09 08:48:16 +00:00
//printf("%s keyrepair [targ] - regenerate a missing Public Key for a target [targ] for which a Secret Key is available\n", name);
2022-09-09 06:47:49 +00:00
printf ( " %s req [targ] - generate a token request for target [targ] \n " , name ) ;
}
2022-09-09 08:48:16 +00:00
int get_targ_path ( char * target , char * * targ_path ) {
int path_len ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
path_len = strlen ( token_path ) + strlen ( target ) + 17 ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
* targ_path = malloc ( path_len ) ;
if ( * targ_path = = NULL ) return 1 ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
strcpy ( * targ_path , token_path ) ;
strcat ( * targ_path , " /targets/ " ) ;
strcat ( * targ_path , target ) ;
strcat ( * targ_path , " .target " ) ;
2022-09-09 06:47:49 +00:00
return 0 ;
}
2022-09-09 08:48:16 +00:00
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
2022-09-09 06:47:49 +00:00
FILE * targ_file ;
2022-09-09 08:48:16 +00:00
char * targ_path ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
get_targ_path ( targ_name , & targ_path ) ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
targ_file = fopen ( targ_path , " r " ) ;
if ( ! targ_file ) {
return 0 ;
2022-09-09 06:47:49 +00:00
}
2022-09-09 08:48:16 +00:00
fread ( target , sizeof ( target_descriptor ) , 1 , targ_file ) ;
fclose ( targ_file ) ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
// 0 = no keys (bad target), 1 = PK only, 2 = PK+SK
return target - > sk_available + 1 ;
2022-09-09 06:47:49 +00:00
}
2022-09-09 08:48:16 +00:00
int keydump ( char * targ_name ) {
int targ_status ;
target_descriptor target ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
targ_status = get_target ( targ_name , & target ) ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
switch ( targ_status ) {
2022-09-09 06:47:49 +00:00
case 0 :
2022-09-09 08:48:16 +00:00
printf ( " No target file found - target unknown. \n " ) ;
return 1 ;
2022-09-09 06:47:49 +00:00
case 1 :
printf ( " Public Key available - can verify and request for this target \n " ) ;
2022-09-09 08:48:16 +00:00
print_bytes ( " Public Key: " , target . pk , 96 ) ;
2022-09-09 06:47:49 +00:00
break ;
case 2 :
printf ( " Secret Key and Public Key available - can verify, request, and sign for this target. \n " ) ;
2022-09-09 08:48:16 +00:00
print_bytes ( " Secret Key: " , target . sk , 32 ) ;
print_bytes ( " Public Key: " , target . pk , 96 ) ;
2022-09-09 06:47:49 +00:00
break ;
}
2022-09-09 08:48:16 +00:00
printf ( " Token Format Specifier: %i/%i (%i ID bits, %i hash bits) \n " , target . idbits , target . hashbits , target . idbits , target . hashbits ) ;
2022-09-09 06:47:49 +00:00
return 0 ;
}
2022-09-09 08:48:16 +00:00
/*int keyrepair(char* target){
2022-09-09 06:47:49 +00:00
FILE * key_file ;
byte sk [ 32 ] ;
byte pk [ 96 ] ;
char * sk_path ;
char * pk_path ;
char * tfs_path ;
int key_status ;
key_status = get_keys ( target , sk , NULL , NULL , NULL ) ;
if ( key_status ! = 2 ) {
printf ( " This target does not refer to a keypair with only a Secret Key available. Exiting. \n " ) ;
return 1 ;
}
printf ( " Regenerating Public Key from Private Key for broken keypair %s \n " , target ) ;
fstoken_get_pk_from_sk ( sk , pk ) ;
debug_print_bytes ( " Regenerated Public Key: " , pk , 96 ) ;
get_key_paths ( target , & sk_path , & pk_path , & tfs_path ) ;
key_file = fopen ( pk_path , " w " ) ;
if ( ! key_file ) {
printf ( " Could not open Public Key file. Exiting. \n " ) ;
return 1 ;
}
fwrite ( pk , 96 , 1 , key_file ) ;
fclose ( key_file ) ;
printf ( " Saved to %s \n " , pk_path ) ;
return 0 ;
2022-09-09 08:48:16 +00:00
} */
2022-09-09 06:47:49 +00:00
int keygen ( char * target , byte * ikm , int idbits , int hashbits ) {
2022-09-09 08:48:16 +00:00
char * targ_path ;
2022-09-09 06:47:49 +00:00
FILE * targ_file ;
2022-09-09 08:48:16 +00:00
target_descriptor targ ;
2022-09-09 06:47:49 +00:00
debug_print_bytes ( " IKM: " , ikm , 32 ) ;
2022-09-09 08:48:16 +00:00
fstoken_keygen ( ikm , targ . sk , targ . pk ) ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
debug_print_bytes ( " Secret Key: " , targ . sk , 32 ) ;
debug_print_bytes ( " Public Key: " , targ . pk , 96 ) ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
targ . idbits = idbits ;
targ . hashbits = hashbits ;
targ . target_descriptor_version = 0x00 ;
targ . sk_available = true ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
debug_print_bytes ( " Target Struct: " , & targ , sizeof ( targ ) ) ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
if ( get_targ_path ( target , & targ_path ) ) return 1 ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
targ_file = fopen ( targ_path , " w " ) ;
2022-09-09 06:47:49 +00:00
if ( ! targ_file ) {
2022-09-09 08:48:16 +00:00
printf ( " Could not open target file. Exiting. \n " ) ;
2022-09-09 06:47:49 +00:00
return 1 ;
}
2022-09-09 08:48:16 +00:00
fwrite ( & targ , sizeof ( targ ) , 1 , targ_file ) ;
2022-09-09 06:47:49 +00:00
fclose ( targ_file ) ;
return 0 ;
}
void print_path ( ) {
printf ( " Token Path (from FEMTOSTAR_TOKEN_PATH environment variable): %s \n " , token_path ) ;
}
bool string_endswith ( const char * str , const char * suffix ) {
if ( ! str | | ! suffix )
return 0 ;
size_t lenstr = strlen ( str ) ;
size_t lensuffix = strlen ( suffix ) ;
if ( lensuffix > lenstr )
return 0 ;
return strncmp ( str + lenstr - lensuffix , suffix , lensuffix ) = = 0 ;
}
2022-09-09 08:48:16 +00:00
// Believe it or not, this function used to be WORSE, and substantially so. It could still do to be cleaned up.
2022-09-09 06:47:49 +00:00
int list_targets ( bool verbose ) {
printf ( " Listing all targets - you have secret keys for, and can issue tokens for, targets marked with (*) \n \n " ) ;
2022-09-09 08:48:16 +00:00
int n , targname_len ;
2022-09-09 06:47:49 +00:00
struct dirent * * files ;
2022-09-09 08:48:16 +00:00
char * targdir_path , * targ_path , * targ_name ;
target_descriptor targ ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
targdir_path = malloc ( strlen ( token_path ) + 9 ) ;
if ( targdir_path = = NULL ) return 1 ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
strcpy ( targdir_path , token_path ) ;
strcat ( targdir_path , " /targets " ) ;
2022-09-09 06:47:49 +00:00
# ifndef __INTELLISENSE__ // VSCodium doesn't know where alphasort is and highlights an error
2022-09-09 08:48:16 +00:00
n = scandir ( targdir_path , & files , NULL , alphasort ) ;
2022-09-09 06:47:49 +00:00
# endif
if ( n = = - 1 ) {
fprintf ( stderr , " Could not list directory at token path. \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < n ; i + + ) {
2022-09-09 08:48:16 +00:00
if ( string_endswith ( files [ i ] - > d_name , " .target " ) ) {
targname_len = strlen ( files [ i ] - > d_name ) ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
targ_name = malloc ( targname_len + 1 ) ;
if ( targ_name = = NULL ) return 1 ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
strcpy ( targ_name , files [ i ] - > d_name ) ;
targ_name [ targname_len - 7 ] = ' \0 ' ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
printf ( " %s " , targ_name ) ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
get_target ( targ_name , & targ ) ;
if ( targ . sk_available ) printf ( " (*) " ) ;
2022-09-09 06:47:49 +00:00
2022-09-09 08:48:16 +00:00
if ( verbose ) {
get_targ_path ( targ_name , & targ_path ) ;
printf ( " (Path: %s, Token Format Specifier: %i/%i) " , targ_path , targ . idbits , targ . hashbits ) ;
2022-09-09 06:47:49 +00:00
}
printf ( " \n " ) ;
2022-09-09 08:48:16 +00:00
free ( targ_name ) ;
2022-09-09 06:47:49 +00:00
}
}
2022-09-09 08:48:16 +00:00
free ( targdir_path ) ;
2022-09-09 06:47:49 +00:00
return 0 ;
}
void bendian_from_hex_string ( byte * bendian , char * string , int length ) {
char byte [ 2 ] ;
for ( int i = 0 ; i < length ; i + + ) {
memcpy ( byte , & string [ i * 2 ] , 2 ) ;
bendian [ i ] = strtol ( byte , 0 , 16 ) ;
}
}
// mostly boring command line parsing
int main ( int argc , char * argv [ ] ) {
token_path = getenv ( " FEMTOSTAR_TOKEN_PATH " ) ;
if ( ! token_path ) {
fprintf ( stderr , " The environment variable FEMTOSTAR_TOKEN_PATH does not exist! Please set it before using ctm. \n " ) ;
exit ( 1 ) ;
}
if ( argc < 2 ) {
fprintf ( stderr , " Provide at least one argument. Try \" %s help \" for more information. \n " , argv [ 0 ] ) ;
return 1 ;
} else if ( strcmp ( argv [ 1 ] , " help " ) = = 0 ) {
print_help ( argv [ 0 ] ) ;
return 0 ;
} else if ( strcmp ( argv [ 1 ] , " path " ) = = 0 ) {
print_path ( ) ;
return 0 ;
} else if ( strcmp ( argv [ 1 ] , " list " ) = = 0 ) {
return list_targets ( argc > 2 & & strcmp ( argv [ 2 ] , " verbose " ) = = 0 ) ; // i don't know if this is cursed or genius
} else if ( strcmp ( argv [ 1 ] , " keygen " ) = = 0 ) {
byte ikm [ 32 ] ;
int idbits , hashbits ;
if ( argc > 5 ) {
printf ( " Too many arguments. Exiting. \n " ) ;
}
// Make sure there's a target name
if ( argc < 3 ) {
fprintf ( stderr , " A target name must be provided, e.g. %s keygen [targ] \n " , argv [ 0 ] ) ;
return ( 1 ) ;
}
// Default behaviour for if only target name is provided: default TFS, random IKM. Otherwise, validate and use provided.
if ( argc < 4 ) {
idbits = IDBITS_DEFAULT ;
hashbits = HASHBITS_DEFAULT ;
} else {
sscanf ( argv [ 3 ] , " %i/%i " , & idbits , & hashbits ) ;
if ( idbits < 1 | | idbits > IDBITS_MAX ) {
printf ( " Invalid Token Format Specifier: number of ID bits must be between 1 and 256 inclusive \n " ) ;
return 1 ;
}
if ( hashbits < 1 | | hashbits > HASHBITS_MAX ) {
printf ( " Invalid Token Format Specifier: number of hash bits must be between 1 and 256 inclusive \n " ) ;
return 1 ;
}
}
// If no IKM is provided, use the system true randomness source
if ( argc < 5 ) {
getrandom ( ikm , 32 , GRND_RANDOM ) ;
} else {
if ( strlen ( argv [ 4 ] ) ! = 64 ) {
fprintf ( stderr , " If providing IKM, it must be 32 bytes (64 hexadecimal digits) \n " ) ;
return 1 ;
}
bendian_from_hex_string ( ikm , argv [ 4 ] , 64 ) ;
}
return keygen ( argv [ 2 ] , ikm , idbits , hashbits ) ;
} else if ( strcmp ( argv [ 1 ] , " keydump " ) = = 0 ) {
// Make sure there's a target name
if ( argc < 3 ) {
fprintf ( stderr , " A target name must be provided, e.g. %s keydump [targ] \n " , argv [ 0 ] ) ;
return ( 1 ) ;
}
return keydump ( argv [ 2 ] ) ;
2022-09-09 08:48:16 +00:00
} /*else if(strcmp(argv[1], "keyrepair") == 0){
2022-09-09 06:47:49 +00:00
// 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 ] ) ;
return ( 1 ) ;
}
return keyrepair ( argv [ 2 ] ) ;
2022-09-09 08:48:16 +00:00
} */
2022-09-09 06:47:49 +00:00
}