|
|
|
@ -17,7 +17,7 @@ bool http_signature_make( const char* inbox, struct crypto_keys* keys, struct ht
|
|
|
|
|
memset(sign,0,sizeof(*sign));
|
|
|
|
|
|
|
|
|
|
if( 0 != strncmp( "https://", inbox, 8 ) ) {
|
|
|
|
|
printf( "Invalid inbox: %s\n", inbox );
|
|
|
|
|
printf( "! Invalid inbox: %s\n", inbox );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -85,8 +85,6 @@ void print_header_line( FILE* hl, struct ap_envelope* env, const char* header_na
|
|
|
|
|
first = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf( hl, "\n" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool validate_body_digest( struct ap_envelope* env )
|
|
|
|
@ -137,20 +135,18 @@ static bool validate_body_digest( struct ap_envelope* env )
|
|
|
|
|
cleanup:
|
|
|
|
|
free(hash);
|
|
|
|
|
free(digest_header);
|
|
|
|
|
free(content_length_header);
|
|
|
|
|
return result;
|
|
|
|
|
failed:
|
|
|
|
|
result = false;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool http_signature_validate( struct ap_envelope* env )
|
|
|
|
|
bool http_signature_validate( struct ap_envelope* env, const char* request_target )
|
|
|
|
|
{
|
|
|
|
|
char* signature_header = NULL;
|
|
|
|
|
char* date_header = NULL;
|
|
|
|
|
char* algorithm = NULL;
|
|
|
|
|
char* key_id = NULL;
|
|
|
|
|
char* headers = NULL;
|
|
|
|
|
char* signature = NULL;
|
|
|
|
|
struct crypto_keys* keys = NULL;
|
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
|
|
// Get the Signature header
|
|
|
|
@ -166,7 +162,7 @@ bool http_signature_validate( struct ap_envelope* env )
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( !signature_header ) { return false; }
|
|
|
|
|
printf( "Found Signature: %s\n", signature_header );
|
|
|
|
|
//printf( "Found Signature: %s\n", signature_header );
|
|
|
|
|
|
|
|
|
|
// Validate time
|
|
|
|
|
if( date_header ) {
|
|
|
|
@ -175,6 +171,10 @@ bool http_signature_validate( struct ap_envelope* env )
|
|
|
|
|
|
|
|
|
|
// Break apart the header
|
|
|
|
|
char* rem = NULL;
|
|
|
|
|
char* algorithm = NULL;
|
|
|
|
|
char* key_id = NULL;
|
|
|
|
|
char* headers = NULL;
|
|
|
|
|
char* signature = NULL;
|
|
|
|
|
for( char* part = strtok_r(signature_header,",",&rem); part; part = strtok_r(NULL,",",&rem) ) {
|
|
|
|
|
// Split apart the key="value" pair
|
|
|
|
|
char* key;
|
|
|
|
@ -199,65 +199,84 @@ bool http_signature_validate( struct ap_envelope* env )
|
|
|
|
|
signature = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf( "\t%s = %s\n", key, value );
|
|
|
|
|
//printf( "\t%s = %s\n", key, value );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure we got all the required information
|
|
|
|
|
if( !signature ) { goto failed; }
|
|
|
|
|
if( !headers ) { goto failed; }
|
|
|
|
|
if( !key_id ) { goto failed; }
|
|
|
|
|
if( !signature ) { printf( "! No signature\n" ); goto failed; }
|
|
|
|
|
if( !headers ) { printf( "! No headers\n" ); goto failed; }
|
|
|
|
|
if( !key_id ) { printf( "! no key_id\n" ); goto failed; }
|
|
|
|
|
|
|
|
|
|
// Get actor URI
|
|
|
|
|
if( 0 == strcmp(key_id,"Test") ) {
|
|
|
|
|
keys = crypto_keys_new();
|
|
|
|
|
if( !crypto_keys_load_public( keys, "assets/test.public.pem" ) ) {
|
|
|
|
|
printf( "! Failed to load public key\n" );
|
|
|
|
|
goto failed;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
char* key_name = NULL;
|
|
|
|
|
char* actor_uri = strtok_r( key_id, "#", &key_name );
|
|
|
|
|
if( !actor_uri ) { goto failed; }
|
|
|
|
|
if( !actor_uri ) {
|
|
|
|
|
printf( "! Failed to get actor\n" );
|
|
|
|
|
goto failed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the account
|
|
|
|
|
struct account* actor = account_fetch_from_uri(actor_uri);
|
|
|
|
|
if( !actor ) { printf( "failed to load account for %s\n", actor_uri ); goto failed; }
|
|
|
|
|
if( !actor ) { printf( "! failed to load account for %s\n", actor_uri ); goto failed; }
|
|
|
|
|
|
|
|
|
|
// Get the public key
|
|
|
|
|
struct crypto_keys* keys = account_get_public_key( actor, key_name );
|
|
|
|
|
keys = account_get_public_key( actor, key_name );
|
|
|
|
|
if( !keys ) { goto failed; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the hash line
|
|
|
|
|
char* hash_line = NULL;
|
|
|
|
|
size_t hash_line_size = 0;
|
|
|
|
|
FILE* hl = open_memstream( &hash_line, &hash_line_size );
|
|
|
|
|
|
|
|
|
|
bool is_first = true;
|
|
|
|
|
for( char* part = strtok_r( headers, " ", &rem ); part; part = strtok_r(NULL," ",&rem) ) {
|
|
|
|
|
printf( "header: %s\n", part );
|
|
|
|
|
//printf( "header: %s\n", part );
|
|
|
|
|
if( !is_first ) {
|
|
|
|
|
fprintf( hl, "\n" );
|
|
|
|
|
}
|
|
|
|
|
if( 0 == strcmp(part,"(request-target)") ) {
|
|
|
|
|
fprintf( hl, "(request-target): post /inbox\n" );
|
|
|
|
|
fprintf( hl, "(request-target): %s", request_target );
|
|
|
|
|
} else if( 0 == strcmp(part,"digest") ) {
|
|
|
|
|
if( !validate_body_digest( env ) ) {
|
|
|
|
|
printf( "Digest validation failed\n" );
|
|
|
|
|
printf( "! Digest validation failed" );
|
|
|
|
|
goto failed;
|
|
|
|
|
}
|
|
|
|
|
print_header_line( hl, env, part );
|
|
|
|
|
} else {
|
|
|
|
|
print_header_line( hl, env, part );
|
|
|
|
|
}
|
|
|
|
|
is_first = false;
|
|
|
|
|
}
|
|
|
|
|
fclose(hl);
|
|
|
|
|
|
|
|
|
|
hash_line = realloc(hash_line, hash_line_size+1 );
|
|
|
|
|
hash_line[hash_line_size] = '\0';
|
|
|
|
|
printf( "\nhash_line:\n%s\n", hash_line );
|
|
|
|
|
//printf( "\nhash_line:\n%s|\n\n", hash_line );
|
|
|
|
|
|
|
|
|
|
char raw_hash[32];
|
|
|
|
|
sha256_easy_hash( hash_line, hash_line_size, raw_hash );
|
|
|
|
|
|
|
|
|
|
char* signature_bin = NULL;
|
|
|
|
|
size_t signature_len = 0;
|
|
|
|
|
if( !base64_decode( signature, (void**)&signature_bin, &signature_len ) ) {
|
|
|
|
|
printf( "Failed to decode base64 signature\n" );
|
|
|
|
|
//result = crypto_keys_verify( keys, raw_hash, 32, signature );
|
|
|
|
|
result = crypto_keys_verify( keys, hash_line, hash_line_size, signature );
|
|
|
|
|
if( !result ) {
|
|
|
|
|
printf( "! Signature is not valid\n" );
|
|
|
|
|
goto failed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf( "TODO: validate HTTP signature - so far, so good\n" );
|
|
|
|
|
result = true;
|
|
|
|
|
cleanup:
|
|
|
|
|
crypto_keys_free(keys);
|
|
|
|
|
free(signature_header);
|
|
|
|
|
free(date_header);
|
|
|
|
|
free(hash_line);
|
|
|
|
|
return result;
|
|
|
|
|
failed:
|
|
|
|
|
result = false;
|
|
|
|
|