Start crypto implementation, remove debug printfs, partial application of s/reverse_index/uri_index/, fix memory leak in rie_reader, start writing outbox processing

master
teknomunk 1 year ago
parent ec7147dfff
commit b7bef499e6

@ -1,2 +1,2 @@
FLAGS="-g -MP -MD -Os"
LDFLAGS = "-lcurl"
LDFLAGS = "-lcurl -lssl -lcrypto"

@ -15,9 +15,13 @@ libCURL
# TODO
[ ] Process /inbox
[ ] Autmatic verification of /inbox items
[ ] Fetch signing keys
[ ] Verify HTTP Signature
[ ] Implement follow replies
[X] Fetch remote account data
[ ] Create outbox Accept activity
[ ] Create notification
[ ] Process /outbox
[ ] Implement HTTP Signatures

@ -3,7 +3,7 @@
set -e
rm debug release 2>/dev/null || true
find src | egrep "\.template$" | while read FILE; do
find src | grep -E "\.template$" | while read FILE; do
ruby src/embed.rb "$FILE"
done

@ -0,0 +1,35 @@
#include "outbox.h"
#include "fs_list.h"
#include "model/crypto/keys.h"
#include "sha256/sha256.h"
#include <stdlib.h>
#include <stdio.h>
static void process_one()
{
int tail = fs_list_get("data/outbox/TAIL");
printf( "To handle: %d\n", tail );
}
void process_outbox()
{
struct crypto_keys* keys = crypto_keys_new();
if( !crypto_keys_load_private( keys, "data/owner/private.pem" ) ) {
printf( "Failed to load private key\n" );
}
char hash[32];
sha256_easy_hash( "Hello, World!", 13, hash );
char* signature = crypto_keys_sign( keys, hash, 32 );
printf( "signature = %s\n", signature );
free(signature);
crypto_keys_free(keys);
exit(0);
}

@ -0,0 +1,4 @@
#pragma once
void process_outbox();

@ -1 +1 @@
Subproject commit 0c8f1e1d52b6dd89876c3f3c05a28c468bf68d43
Subproject commit 0f07cd429652690aba5a6dc8908072f75b1df03a

@ -12,6 +12,7 @@
#include "controller/main.h"
#include "controller/inbox.h"
#include "controller/outbox.h"
#include <curl/curl.h>
@ -75,7 +76,9 @@ int main( int argc, char* argv[] )
sscanf(argv[1],"--section=%d",&section);
switch( section ) {
case 1: process_inbox(); return 0;
case 2: develop(); return 0;
case 2: process_outbox(); return 0;
case 100: develop(); return 0;
}
}
@ -87,6 +90,12 @@ int main( int argc, char* argv[] )
process_inbox();
}
// Process outbox
if( !( inbox_handler_pid = fork() ) ) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
process_outbox();
}
// TODO: Process outbox
int code = 0;

@ -83,8 +83,11 @@ struct reverse_index_entry
bool rie_reader( struct json_pull_parser* jpp, void* field_data, struct json_object_field* layout_field_data )
{
*(void**)field_data = malloc(sizeof(struct reverse_index_entry));
bool res = json_read_object_layout( jpp, reverse_index_entry_layout, *(void**)field_data );
void* data = *(void**)field_data = malloc(sizeof(struct reverse_index_entry));
bool res = json_read_object_layout( jpp, reverse_index_entry_layout, data );
if( !res ) {
free( data );
}
return res;
}
void rie_writer( struct json_writer* jpp, void* field_data, struct json_object_field* layout_field_data )
@ -114,6 +117,7 @@ struct account_reverse_index
{ NULL },
};
// TODO: move this and the lookup to new model
static int index_uri_to_account_id( const char* uri, int account_id )
{
char hash[65] = "";
@ -121,7 +125,7 @@ static int index_uri_to_account_id( const char* uri, int account_id )
hash[5] = '\0';
char filename[512];
snprintf( filename, 512, "data/accounts/reverse_index/%s.json", hash );
snprintf( filename, 512, "data/accounts/uri_index/%s.json", hash );
struct account_reverse_index ari;
memset( &ari, 0, sizeof(ari) );
@ -138,7 +142,7 @@ static int index_uri_to_account_id( const char* uri, int account_id )
struct reverse_index_entry* entry = ari.entries.items[i];
printf( "\tentry[%d] = { .uri = %s, .account_id = %d }\n", i, entry->uri, entry->account_id );
}
*/
//*/
array_append( &ari.entries, sizeof(struct reverse_index_entry), &ptr );
@ -157,7 +161,7 @@ static int lookup_account_id_from_uri( const char* uri )
hash[5] = '\0';
char filename[512];
snprintf( filename, 512, "data/accounts/reverse_index/%s.json", hash );
snprintf( filename, 512, "data/accounts/uri_index/%s.json", hash );
struct account_reverse_index ari;
memset( &ari, 0, sizeof(ari) );
@ -165,6 +169,13 @@ static int lookup_account_id_from_uri( const char* uri )
return -1;
}
/*
for( int i = 0; i < ari.entries.count; ++i ) {
struct reverse_index_entry* entry = ari.entries.items[i];
printf( "\tentry[%d] = %p{ .uri = %s, .account_id = %d }\n", i, entry, entry->uri, entry->account_id );
}
//*/
int result = -1;
for( int i = 0; i < ari.entries.count; ++i ) {
struct reverse_index_entry* entry = ari.entries.items[i];
@ -287,6 +298,20 @@ void account_sync_from_acitvity_pub( unsigned int account_id )
account_free(a);
}
static void create_account_skeleton( int account_id )
{
// Make sure the account directory exists
char dirname[512];
snprintf( dirname, 512, "data/accounts/%d", account_id );
mkdir( dirname, 0755 );
snprintf( dirname, 512, "data/accounts/%d/timeline", account_id );
mkdir( dirname, 0755 );
char filename[512];
snprintf( filename, 512, "data/accounts/%d/timeline/HEAD", account_id );
fs_list_set( filename, 0 );
}
struct account* account_fetch_from_uri( const char* uri )
{
int account_id = lookup_account_id_from_uri( uri );
@ -300,10 +325,7 @@ struct account* account_fetch_from_uri( const char* uri )
printf( "account_id = %d\n", account_id );
// Make sure the account directory exists
char dirname[512];
snprintf( dirname, 512, "data/accounts/%d", account_id );
mkdir( dirname, 0755 );
create_account_skeleton(account_id);
// Fetch the ActivityPub actor data if we don't already have it
char filename[512];

@ -71,7 +71,6 @@ struct ap_activity* ap_activity_dup( struct ap_activity* act )
new_act->object.ptr = ap_activity_dup(act->object.ptr);
break;
}
printf( "duplicated tag = %d\n", act->object.tag );
new_act->object.tag = act->object.tag;
new_act->signature.type = act->signature.type;
@ -94,7 +93,6 @@ static void* ap_activity_alloc()
void ap_activity_free( struct ap_activity* act )
{
if( !act ) { return; }
printf( "ap_activity_free( %p )\n", act );
ap_activity_free_composite(act);
free(act);
}
@ -195,8 +193,6 @@ struct ap_activity* ap_activity_create_accept( struct ap_activity* act )
accept->actor = actor;
char* new_act_actor = strdup(act->actor);
array_append( &accept->to, sizeof(char*), &new_act_actor );
printf( "accept->to = { .count = %d, .items = %p }\n", accept->to.count, accept->to.items );
printf( "...->to.items[0] = %s\n", accept->to.items[0] );
accept->object.tag = apaot_activity;
accept->object.ptr = ap_activity_dup(act);
accept->signature.type = apst_rsa_signature_2017;

@ -0,0 +1,131 @@
#include "keys.h"
#include <openssl/pem.h>
#include <openssl/evp.h>
struct crypto_keys
{
EVP_PKEY* pubkey;
EVP_PKEY* privkey;
};
struct crypto_keys* crypto_keys_new()
{
struct crypto_keys* k;
k = malloc(sizeof(*k));
memset(k,0,sizeof(*k));
return k;
}
void crypto_keys_free( struct crypto_keys* keys )
{
if( !keys ) { return; }
if( keys->pubkey ) {
EVP_PKEY_free(keys->pubkey);
}
if( keys->privkey ) {
EVP_PKEY_free(keys->privkey);
}
free(keys);
}
bool crypto_keys_load_private( struct crypto_keys* keys, const char* filename )
{
if( keys->privkey ) {
EVP_PKEY_free( keys->privkey );
keys->privkey = NULL;
}
FILE* f = fopen(filename,"r");
keys->privkey = PEM_read_PrivateKey( f, NULL, NULL, NULL );
fclose(f);
return !!keys->privkey;
}
char* base64_strict_encode( void* v_binary, size_t len )
{
// RFC 4648 - https://www.rfc-editor.org/rfc/rfc4648.html
static const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
enum { pad = '=' };
uint8_t* binary = v_binary;
const int groups = ( len + 2 ) / 3;
const int padding = len % 3;
char* result = malloc( groups * 4 + 1 );
result[groups*4] = '\0';
uint32_t word;
char* out = result;
for( int remain = len; remain > 0; remain -= 3, binary += 3, out += 4 ) {
word = 0;
switch( remain ) {
default:
word |= binary[2] << (8*0);
case 2:
word |= binary[1] << (8*1);
case 1:
word |= binary[0] << (8*2);
}
switch( remain ) {
default:
out[3] = alphabet[ ( word >> (6*0) ) % 64 ];
case 2:
out[2] = alphabet[ ( word >> (6*1) ) % 64 ];
case 1:
out[1] = alphabet[ ( word >> (6*2) ) % 64 ];
out[0] = alphabet[ ( word >> (6*3) ) % 64 ];
}
switch( remain ) {
case 1:
out[3] = '=';
out[2] = '=';
break;
case 2:
out[3] = '=';
break;
}
}
return result;
}
char* crypto_keys_sign( struct crypto_keys* keys, void* data, unsigned int size )
{
char* result = NULL;
char* sign_binary = NULL;
EVP_PKEY_CTX* ctx = NULL;
if( !keys->privkey ) { return NULL; }
// Setup for signature
// Code based on https://www.openssl.org/docs/man3.1/man3/EVP_PKEY_sign.html
ctx = EVP_PKEY_CTX_new(keys->privkey, NULL /* no engine */);
if( !ctx ) { goto failed; }
if( EVP_PKEY_sign_init(ctx) <= 0 ) { goto failed; }
if( EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ) { goto failed; }
if( EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0 ) { goto failed; }
size_t siglen;
if( EVP_PKEY_sign(ctx, NULL, &siglen, data, size ) <= 0 ) { goto failed; }
sign_binary = malloc(siglen);
if( EVP_PKEY_sign(ctx, sign_binary, &siglen, data, size) <= 0 ) { goto failed; }
result = base64_strict_encode( sign_binary, siglen );
cleanup:
free(sign_binary);
EVP_PKEY_CTX_free(ctx);
return result;
failed:
free(result); result = NULL;
goto cleanup;
}

@ -0,0 +1,18 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
struct crypto_keys;
struct crypto_keys* crypto_keys_new();
void crypto_keys_free( struct crypto_keys* keys );
bool crypto_keys_load_public ( struct crypto_keys* keys, const char* filename );
bool crypto_keys_load_private( struct crypto_keys* keys, const char* filename );
char* crypto_keys_sign( struct crypto_keys* keys, void* data, unsigned int size );
bool crypto_keys_verify( struct crypto_keys* keys, void* data, unsigned int size );
char* base64_strict_encode( void* v_binary, size_t len );
Loading…
Cancel
Save