Tokens work now, proper verification. Working on shortening.
This commit is contained in:
parent
f35923ab74
commit
0cabf2536b
6 changed files with 281 additions and 4 deletions
22
base64.c
22
base64.c
|
@ -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
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "base64.h"
|
||||
|
||||
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_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);
|
||||
}
|
2
base64.h
2
base64.h
|
@ -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_decode_oneshot(char* input, int input_len, char* output);
|
||||
int base64_binlength(char* b64);
|
||||
int base64_base64length(int binlength);
|
||||
|
||||
#endif
|
||||
|
|
223
ctm.c
223
ctm.c
|
@ -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 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 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 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);
|
||||
if(*targ_path == NULL) return 1;
|
||||
|
@ -53,7 +57,7 @@ int get_targ_path(char* target, char** targ_path){
|
|||
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;
|
||||
char *targ_path;
|
||||
|
||||
|
@ -81,6 +85,154 @@ int get_fixed_length(char* dest, size_t dest_size){
|
|||
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){
|
||||
fstoken_request req;
|
||||
fstoken_target_descriptor targ;
|
||||
|
@ -105,6 +257,19 @@ int sign_single(char* targ_name, char* req_b64){
|
|||
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){
|
||||
fstoken_request req;
|
||||
fstoken_request_descriptor reqdesc;
|
||||
|
@ -150,6 +315,20 @@ int interactive_request(char* targ_name, byte* token_id, byte* blinding_factor){
|
|||
printf("\nToken: ");
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -500,6 +679,44 @@ int main(int argc, char *argv[]){
|
|||
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]));
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ void print_base64(void *toprint, int input_len){
|
|||
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
|
||||
if(output == NULL) return;
|
||||
|
||||
base64_encode_oneshot(toprint, input_len, output);
|
||||
printf("%s\n", output);
|
||||
|
|
25
fstoken.c
25
fstoken.c
|
@ -117,6 +117,26 @@ int fstoken_gen_token(fstoken_request_descriptor* req, fstoken_signature* sig, f
|
|||
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){
|
||||
uint8_t bitmask;
|
||||
int bytes;
|
||||
|
@ -130,4 +150,9 @@ void bit_truncated_copy(byte* src, byte* dest, size_t destlen, int bits){
|
|||
bitmask = 0xFF >> (bits % 8);
|
||||
//printf("mask: 0x%0x\n", 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;
|
||||
}
|
12
fstoken.h
12
fstoken.h
|
@ -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)
|
||||
// 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
|
||||
// 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];
|
||||
} 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_get_pk_from_sk(byte* sk_byte, byte* pk_byte);
|
||||
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);
|
||||
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_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
|
Loading…
Reference in a new issue