Tokens work now, proper verification. Working on shortening.

This commit is contained in:
John Doe 2023-03-21 16:46:42 -04:00
parent f35923ab74
commit 0cabf2536b
6 changed files with 281 additions and 4 deletions

View file

@ -3,6 +3,7 @@ This is derived from the libb64 project, which has been placed in the public dom
For details, see http://sourceforge.net/projects/libb64 For details, see http://sourceforge.net/projects/libb64
*/ */
#include <string.h>
#include "base64.h" #include "base64.h"
int base64_decode_value(char value_in) int base64_decode_value(char value_in)
@ -211,4 +212,25 @@ void base64_decode_oneshot(char* input, int input_len, char* output){
base64_init_decodestate(&s); base64_init_decodestate(&s);
base64_decode_block(input, input_len, output, &s); base64_decode_block(input, input_len, output, &s);
}
// Provides the length of the binary you would get if you decoded base64 string b64, accounting for padding
int base64_binlength(char* b64){
int length, padding;
length = strlen(b64);
if(length % 4 != 0) return -1; // return -1 if length is not divisible by four (i.e. if invalid base64)
// somewhat messy way to determine how many bytes of padding are at the end of a base64 string
if(b64[length - 1] == '=' && b64[length - 2] == '=' && b64[length - 3] == '='){padding = 3;}
else if(b64[length - 1] == '=' && b64[length - 2] == '='){padding = 2;}
else if(b64[length - 1] == '='){padding = 1;}
else{padding = 0;}
return(((length / 4) * 3) - padding);
}
// Provides the base64 length of a binary of length binlength bytes
int base64_base64length(int binlength){
return(((binlength + 2) / 3) * 4);
} }

View file

@ -48,5 +48,7 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
void base64_encode_oneshot(char* input, int input_len, char* output); void base64_encode_oneshot(char* input, int input_len, char* output);
void base64_decode_oneshot(char* input, int input_len, char* output); void base64_decode_oneshot(char* input, int input_len, char* output);
int base64_binlength(char* b64);
int base64_base64length(int binlength);
#endif #endif

223
ctm.c
View file

@ -35,12 +35,16 @@ void print_help(char* name){
printf("%s ireq [targ] [id] [factor] - interactively generate a Token Request Code for target [targ] using a set Token ID [id] and Blinding Factor [factor]\n", name); printf("%s ireq [targ] [id] [factor] - interactively generate a Token Request Code for target [targ] using a set Token ID [id] and Blinding Factor [factor]\n", name);
printf("%s sign [targ] [req] - generate a signature for Token Request Code [req], on target [targ]\n", name); printf("%s sign [targ] [req] - generate a signature for Token Request Code [req], on target [targ]\n", name);
printf("%s bsign [targ] - bulk-sign token requests, accepting Token Request Codes on stdin and outputting signatures to stdout\n", name); printf("%s bsign [targ] - bulk-sign token requests, accepting Token Request Codes on stdin and outputting signatures to stdout\n", name);
printf("%s verify [targ] [token] - verify token [token] against target [targ], as base64 - returns 0 on verified\n", name);
printf("%s bverify [targ] - bulk-verify tokens against target [targ], accepting base64 tokens on stdin and outputting 0 (verified) or 1 to stdout\n", name);
printf("%s inspect [targ] [token] - inpect a token [token] for target [targ], to see its token ID and signature\n", name);
printf("%s shorten [targ] [token] - shorten a token [token] for target [targ], generating a symmetrically-verifiable short token\n", name);
} }
int get_targ_path(char* target, char** targ_path){ int get_targ_path(char* target, char** targ_path){
int path_len; int path_len;
path_len = strlen(token_path) + strlen(target) + 17; path_len = strlen(token_path) + strlen(target) + 17; //string length of "/targets/", ".target", and null terminator
*targ_path = malloc(path_len); *targ_path = malloc(path_len);
if(*targ_path == NULL) return 1; if(*targ_path == NULL) return 1;
@ -53,7 +57,7 @@ int get_targ_path(char* target, char** targ_path){
return 0; return 0;
} }
int get_target(char* targ_name, fstoken_target_descriptor* target){ // pk/sk/idbits/hasbits pointers can be NULL if you don't want to read those int get_target(char* targ_name, fstoken_target_descriptor* target){
FILE *targ_file; FILE *targ_file;
char *targ_path; char *targ_path;
@ -81,6 +85,154 @@ int get_fixed_length(char* dest, size_t dest_size){
return 0; return 0;
} }
int decode_base64_token(fstoken_target_descriptor* target, fstoken_token* token, char* token_b64){
int token_length, target_token_length;
target_token_length = fstoken_target_token_length(target);
token_length = base64_binlength(token_b64);
if(token_length == -1){
fprintf(stderr, "Invalid base64 provided\n");
return 3; // should be an enum
}
if(token_length != target_token_length){
fprintf(stderr, "Provided token (%i bytes) of incorrect length for specified target (%i bytes).\n", token_length, target_token_length);
return 4;
}
base64_decode_oneshot(token_b64, strlen(token_b64), (char*) token);
return 0;
}
int inspect_token(char* targ_name, char* token_b64){
fstoken_target_descriptor target;
fstoken_token token;
int targ_idbytes;
if(!get_target(targ_name, &target)){
printf("Invalid target %s\n", targ_name);
return -1;
}
if(decode_base64_token(&target, &token, token_b64)){
return 2;
}
if(fstoken_verify_token(&token, &target) == 0){
printf("Token is valid for target %s.\n", targ_name);
}else{
printf("Token is not valid for target!\n");
return 1;
}
targ_idbytes = (target.idbits + 7) / 8;
printf("\n");
print_bytes("Signature (hex): ", token.signature, 48, ' ');
printf("Signature (base64): ");
print_base64(token.signature, 48);
printf("\n");
print_bytes("Token ID (hex): ", token.token_id, targ_idbytes, ' ');
printf("Token ID (base64): ");
print_base64(token.token_id, targ_idbytes);
return 0;
}
// Receives tokens on stdin and provides 0 (valid), 1 (invalid), or 2/3/4 (various bad input) to stdout, with additional messages on stderr in case of error
int verify_bulk(char* targ_name){
char token_b64[((((HASHBYTES_MAX + IDBYTES_MAX) + 2) / 3) * 4) + 2]; // maximum possible base64 length + 2 characters for get_fixed_length
fstoken_target_descriptor target;
fstoken_token token;
int target_token_b64_length, result;
if(!get_target(targ_name, &target)){
fprintf(stderr, "Invalid target %s\n", targ_name);
return -1;
}
target_token_b64_length = base64_base64length(fstoken_target_token_length(&target));
printf("Target token length %i\n", target_token_b64_length);
while(1){
if(get_fixed_length(token_b64, target_token_b64_length + 2)){ // +2 because of get_fixed_length, I should probably change that to be not stupid
printf("2");
fprintf(stderr, "Provided token base64 incorrect length for target (should be %i characters).\n", target_token_b64_length);
continue;
}
result = decode_base64_token(&target, &token, token_b64);
if(result){
printf("%i", result);
continue;
}
if(fstoken_verify_token(&token, &target) == 0){
printf("0");
}else{
printf("1");
}
}
}
int verify_single(char* targ_name, char* token_b64){
fstoken_target_descriptor target;
fstoken_token token;
if(!get_target(targ_name, &target)){
printf("Invalid target %s\n", targ_name);
return -1;
}
decode_base64_token(&target, &token, token_b64);
if(fstoken_verify_token(&token, &target) == 0){
printf("Verified!\n");
return 0;
}else{
printf("Not verified!\n");
return 1;
}
}
int sign_bulk(char* targ_name){
char req_b64[66];
fstoken_request req;
fstoken_target_descriptor targ;
fstoken_signature sig;
if(get_target(targ_name, &targ) != 2){
printf("Target or private key unavailable. Are you sure you have a private key for this target?\n");
return 1;
}
fprintf(stderr, "Bulk signing started. Enter token requests\n");
while(1){
if(get_fixed_length(req_b64, sizeof(req_b64))){
fprintf(stderr, "Invalid request length\n");
continue;
};
base64_decode_oneshot((char*) req_b64, 64, (char*) req.id_blind);
//debug_print_bytes("Signature hex: ", req.id_blind, 48);
if(fstoken_sign_request(&req, &sig, &targ)){
fprintf(stderr, "Signing failed. Is the token request valid?\n");
continue;
};
print_base64(sig.signature, 48);
}
return 0;
}
int sign_single(char* targ_name, char* req_b64){ int sign_single(char* targ_name, char* req_b64){
fstoken_request req; fstoken_request req;
fstoken_target_descriptor targ; fstoken_target_descriptor targ;
@ -105,6 +257,19 @@ int sign_single(char* targ_name, char* req_b64){
return 0; return 0;
} }
/*int verify_token(char* targ_name, byte* token_bytes){
fstoken_target_descriptor target;
fstoken_token token;
int token_length;
if(!get_target(targ_name, &target)){
printf("Invalid target %s\n", targ_name);
return 1;
}
//base64_decode_oneshot(token_bytes, )
}*/
int interactive_request(char* targ_name, byte* token_id, byte* blinding_factor){ int interactive_request(char* targ_name, byte* token_id, byte* blinding_factor){
fstoken_request req; fstoken_request req;
fstoken_request_descriptor reqdesc; fstoken_request_descriptor reqdesc;
@ -150,6 +315,20 @@ int interactive_request(char* targ_name, byte* token_id, byte* blinding_factor){
printf("\nToken: "); printf("\nToken: ");
print_base64(&token, token_length); print_base64(&token, token_length);
//token.token_id[3] = '\0';
switch(fstoken_verify_token(&token, &target)){
case 0:
printf("Verified!\n");
break;
case 1:
printf("Signature does not match Token ID for target. Did the signer sign for the wrong target or sign the wrong request?\n");
return 1;
case 2:
printf("Invalid signature (not in G1 group - either something has gone very wrong or the signer is attempting to do something malicious)\n");
return 1;
}
return 0; return 0;
} }
@ -500,6 +679,44 @@ int main(int argc, char *argv[]){
return 1; return 1;
} }
sign_single(argv[2], argv[3]); return sign_single(argv[2], argv[3]);
}else if(strcmp(argv[1], "bsign") == 0){
if(argc != 3){
fprintf(stderr, "Please provide a target [targ]. See help.\n");
return 1;
}
return sign_bulk(argv[2]);
}else if(strcmp(argv[1], "verify") == 0){
if(argc != 4){
fprintf(stderr, "Please provide a target [targ] and a token [token]. See help.\n");
return 1;
}
if(strlen(argv[3]) < 68){
fprintf(stderr, "Token must be at least 49 bytes (68 base64 characters).\n");
return 1;
}
return(verify_single(argv[2], argv[3]));
}else if(strcmp(argv[1], "bverify") == 0){
if(argc != 3){
fprintf(stderr, "Please provide a target [targ]. See help.\n");
return 1;
}
verify_bulk(argv[2]);
}else if(strcmp(argv[1], "inspect") == 0){
if(argc != 4){
fprintf(stderr, "Please provide a target [targ] and a token [token]. See help.\n");
return 1;
}
if(strlen(argv[3]) < 68){
fprintf(stderr, "Token must be at least 49 bytes (68 base64 characters).\n");
return 1;
}
return(inspect_token(argv[2], argv[3]));
} }
} }

View file

@ -20,6 +20,7 @@ void print_base64(void *toprint, int input_len){
buffer_size = (((input_len + 2) / 3) * 4) + 1; buffer_size = (((input_len + 2) / 3) * 4) + 1;
output = malloc(buffer_size); //create a buffer large enough for the base64'd input, including with padding if need be output = malloc(buffer_size); //create a buffer large enough for the base64'd input, including with padding if need be
if(output == NULL) return;
base64_encode_oneshot(toprint, input_len, output); base64_encode_oneshot(toprint, input_len, output);
printf("%s\n", output); printf("%s\n", output);

View file

@ -117,6 +117,26 @@ int fstoken_gen_token(fstoken_request_descriptor* req, fstoken_signature* sig, f
return 0; return 0;
} }
// 0 = valid token, 1 = signature check failed, 2 = signature point invalid
int fstoken_verify_token(fstoken_token* token, fstoken_target_descriptor* targ){
int targ_idbytes;
blst_p1_affine sig;
blst_p2_affine pk;
blst_p1_uncompress(&sig, token->signature);
blst_p2_uncompress(&pk, targ->pk);
BLST_ERROR returned;
if(!blst_p1_affine_in_g1(&sig)) return 2;
targ_idbytes = (targ->idbits + 7) / 8;
returned = blst_core_verify_pk_in_g2(&pk, &sig, 1, token->token_id, targ_idbytes, FSTOKEN_DST, strlen((char *) FSTOKEN_DST), targ->pk, 96);
return (returned != BLST_SUCCESS);
}
void bit_truncated_copy(byte* src, byte* dest, size_t destlen, int bits){ void bit_truncated_copy(byte* src, byte* dest, size_t destlen, int bits){
uint8_t bitmask; uint8_t bitmask;
int bytes; int bytes;
@ -130,4 +150,9 @@ void bit_truncated_copy(byte* src, byte* dest, size_t destlen, int bits){
bitmask = 0xFF >> (bits % 8); bitmask = 0xFF >> (bits % 8);
//printf("mask: 0x%0x\n", bitmask); //printf("mask: 0x%0x\n", bitmask);
dest[bytes - 1] = dest[bytes - 1] & bitmask; dest[bytes - 1] = dest[bytes - 1] & bitmask;
}
// Helper function to get the length (in bytes) of an (unshortened) token for the target
int fstoken_target_token_length(fstoken_target_descriptor* target){
return 48 + (target->idbits + 7) / 8;
} }

View file

@ -25,7 +25,7 @@
// This avoids wasting network capacity on padding, and avoids the performance impact of reordering on most modern platforms (most importantly x86 and RISC-V) // 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! // while ensuring compatibility with strict-alignment architectures. Take note: This is NOT typical network-order!
// Additionally, note that most structs do not explicitly include what target they are for (even the target descriptor!). Keeping what is for what target is // Additionally, note that most structs do not explicitly include what target they are for (even the target descriptor!). Tracking what is for what target is
// not a core part of fstoken, and is the responsibility of the software using fstoken (e.g. ctm or an implementation of fsp). This keeps tokens light in // not a core part of fstoken, and is the responsibility of the software using fstoken (e.g. ctm or an implementation of fsp). This keeps tokens light in
// situations where which target is relevant is unambiguous (e.g. in the session setup with a satellite, where the satellite is always the same target). // situations where which target is relevant is unambiguous (e.g. in the session setup with a satellite, where the satellite is always the same target).
@ -70,11 +70,21 @@ typedef struct{
byte token_id[IDBYTES_MAX]; byte token_id[IDBYTES_MAX];
} fstoken_token; } fstoken_token;
typedef struct{
#pragma scalar_storage_order little-endian
byte hash[HASHBYTES_MAX];
byte token_id[IDBYTES_MAX];
} fstoken_short_token;
void fstoken_keygen(byte* ikm, byte* sk_byte, byte* pk_byte); void fstoken_keygen(byte* ikm, byte* sk_byte, byte* pk_byte);
void fstoken_get_pk_from_sk(byte* sk_byte, byte* pk_byte); void fstoken_get_pk_from_sk(byte* sk_byte, byte* pk_byte);
void bit_truncated_copy(byte* src, byte* dest, size_t destlen, int bits); void bit_truncated_copy(byte* src, byte* dest, size_t destlen, int bits);
void fstoken_gen_request(fstoken_request* req, fstoken_request_descriptor* reqdesc, fstoken_target_descriptor* target, byte* token_id, byte* blinding_factor); void fstoken_gen_request(fstoken_request* req, fstoken_request_descriptor* reqdesc, fstoken_target_descriptor* target, byte* token_id, byte* blinding_factor);
int fstoken_sign_request(fstoken_request* req, fstoken_signature* sig, fstoken_target_descriptor* targ); int fstoken_sign_request(fstoken_request* req, fstoken_signature* sig, fstoken_target_descriptor* targ);
int fstoken_gen_token(fstoken_request_descriptor* req, fstoken_signature* sig, fstoken_token* token); int fstoken_gen_token(fstoken_request_descriptor* req, fstoken_signature* sig, fstoken_token* token);
int fstoken_verify_token(fstoken_token* token, fstoken_target_descriptor* targ);
int fstoken_shorten_token(fstoken_token* token, fstoken_short_token short_token);
int fstoken_target_token_length(fstoken_target_descriptor* target);
#endif #endif