commit 8fd4617d0ee6399ca30e97bc1a73244c87137af4
parent 696fba72d238d361b65997b495c9c29af1bdd582
Author: lash <dev@holbrook.no>
Date: Tue, 23 Apr 2024 17:19:04 +0100
Add serialization for ledger and ledgeritem
Diffstat:
6 files changed, 370 insertions(+), 20 deletions(-)
diff --git a/src/gpg.c b/src/gpg.c
@@ -217,34 +217,26 @@ static int key_from_path(gcry_sexp_t *key, const char *p, const char *passphrase
* \todo implement MAC
* \todo test new data length location (part of ciphertext)
*/
-static int key_create(gcry_sexp_t *key, const char *p, const char *passphrase) {
+static int key_create_file(gcry_sexp_t *key, const char *p, const char *passphrase) {
int r;
- FILE *f;
- const char *sexp_quick = "(genkey(ecc(curve Ed25519)))";
- //char *pv;
+ int kl;
+ char v[BUFLEN];
int i;
int l;
- int kl;
size_t c;
- gcry_sexp_t in;
- gcry_error_t e;
- char v[BUFLEN];
+ FILE *f;
char nonce[CHACHA20_NONCE_LENGTH_BYTES];
- e = gcry_sexp_new(&in, (const void*)sexp_quick, strlen(sexp_quick), 0);
- if (e) {
- printf("error sexp: %s\n", gcry_strerror(e));
- return (int)e;
- }
- e = gcry_pk_genkey(key, in);
- if (e) {
- printf("error gen: %s\n", gcry_strerror(e));
- return (int)e;
+ r = gpg_key_create(key);
+ if (r) {
+ return ERR_KEYFAIL;
}
+
kl = gcry_sexp_sprint(*key, GCRYSEXP_FMT_CANON, v+sizeof(int), BUFLEN);
memcpy(v, &kl, sizeof(int));
c = get_padsize(kl, ENCRYPT_BLOCKSIZE);
+ /// \todo malloc
char ciphertext[c];
gcry_create_nonce(nonce, CHACHA20_NONCE_LENGTH_BYTES);
@@ -281,6 +273,26 @@ static int key_create(gcry_sexp_t *key, const char *p, const char *passphrase) {
return ERR_OK;
}
+
+int gpg_key_create(gcry_sexp_t *key) {
+ const char *sexp_quick = "(genkey(ecc(curve Ed25519)))";
+ //char *pv;
+ gcry_sexp_t in;
+ gcry_error_t e;
+
+ e = gcry_sexp_new(&in, (const void*)sexp_quick, strlen(sexp_quick), 0);
+ if (e) {
+ printf("error sexp: %s\n", gcry_strerror(e));
+ return (int)e;
+ }
+ e = gcry_pk_genkey(key, in);
+ if (e) {
+ printf("error gen: %s\n", gcry_strerror(e));
+ return (int)e;
+ }
+ return 0;
+}
+
static int sign(gcry_sexp_t *out, gcry_sexp_t *key, const char *v) {
gcry_error_t e;
gcry_sexp_t data;
@@ -360,7 +372,7 @@ int gpg_store_check(struct gpg_store *gpg, const char *passphrase) {
char pp[2048];
//sprintf(pp, "%s/key.bin", p.c_str());
sprintf(pp, "%s/key.bin", p);
- r = key_create(&k, pp, passphrase_hash);
+ r = key_create_file(&k, pp, passphrase_hash);
if (r != ERR_OK) {
return r;
}
diff --git a/src/gpg.h b/src/gpg.h
@@ -3,6 +3,7 @@
//#include <string>
#include <stddef.h>
+#include <gcrypt.h>
#define GPG_MIN_VERSION "1.10.2"
#define CHACHA20_KEY_LENGTH_BYTES 32
@@ -86,5 +87,6 @@ void gpg_store_init(struct gpg_store *gpg, const char *path);
int gpg_store_check(struct gpg_store *gpg, const char *passphrase);
int gpg_store_digest(struct gpg_store *gpg, char *out, const char *in);
char *gpg_store_get_fingerprint(struct gpg_store *gpg);
+int gpg_key_create(gcry_sexp_t *key);
#endif
diff --git a/src/ledger.c b/src/ledger.c
@@ -10,9 +10,11 @@
#include "digest.h"
#include "strip.h"
#include "content.h"
+#include "endian.h"
extern const asn1_static_node schema_entry_asn1_tab[];
+const char zero_content[64];
static char *get_message(asn1_node item, char *out_digest, char *out_data, size_t *out_len) {
int r;
@@ -340,6 +342,10 @@ void kee_ledger_init(struct kee_ledger_t *ledger) {
memset(ledger, 0, sizeof(struct kee_ledger_t));
}
+void kee_ledger_item_init(struct kee_ledger_item_t *item) {
+ memset(item, 0, sizeof(struct kee_ledger_item_t));
+}
+
int kee_ledger_parse(struct kee_ledger_t *ledger, const char *data, size_t data_len) {
int r;
char err[1024];
@@ -418,3 +424,183 @@ void kee_ledger_resolve(struct kee_ledger_t *ledger, Cadiz *cadiz) {
item = item->prev_item;
}
}
+
+int kee_ledger_serialize(struct kee_ledger_t *ledger, char *out, size_t *out_len) {
+ int r;
+ char err[1024];
+ asn1_node node;
+ int c;
+
+ //memset(&root, 0, sizeof(root));
+ memset(&node, 0, sizeof(node));
+ //r = asn1_array2tree(schema_entry_asn1_tab, &root, err);
+ r = asn1_array2tree(schema_entry_asn1_tab, &node, err);
+ if (r != ASN1_SUCCESS) {
+ return ERR_FAIL;
+ }
+
+ c = strlen(ledger->uoa);
+ r = asn1_write_value(node, "Kee.KeeEntryHead.uoa", ledger->uoa, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ c = 4;
+ r = asn1_write_value(node, "Kee.KeeEntryHead.uoaDecimals", &ledger->uoa_decimals, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ c = 32;
+ r = asn1_write_value(node, "Kee.KeeEntryHead.alicePubKey", ledger->pubkey_alice, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ c = 32;
+ r = asn1_write_value(node, "Kee.KeeEntryHead.bobPubKey", ledger->pubkey_bob, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ c = 64;
+ r = asn1_write_value(node, "Kee.KeeEntryHead.body", ledger->content.key, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ r = asn1_der_coding(node, "Kee.KeeEntryHead", out, (int*)out_len, err);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ return 0;
+}
+
+int kee_ledger_item_serialize(struct kee_ledger_item_t *item, char *out, size_t *out_len, enum kee_item_serialize_mode_e mode) {
+ int r;
+ char err[1024];
+ asn1_node node;
+// char timedata[8];
+ long long nanotime;
+ int c;
+ int credit_delta;
+ int collateral_delta;
+ char *signature_request;
+ char *signature_response;
+ char *response_s;
+
+ //memset(&root, 0, sizeof(root));
+ memset(&node, 0, sizeof(node));
+ //r = asn1_array2tree(schema_entry_asn1_tab, &root, err);
+ r = asn1_array2tree(schema_entry_asn1_tab, &node, err);
+ if (r != ASN1_SUCCESS) {
+ return ERR_FAIL;
+ }
+
+ c = 64;
+ if (item->prev_item == NULL) {
+ r = asn1_write_value(node, "Kee.KeeEntry.parent", zero_content, c);
+ } else {
+ r = asn1_write_value(node, "Kee.KeeEntry.parent", item->prev_item, c);
+ }
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+// memcpy(timedata, item->time, 4);
+// r = to_endian(TO_ENDIAN_BIG, 4, timedata);
+// if (r) {
+// return 1;
+// }
+//
+// memcpy(timedata+4, item->time+4, 4);
+// r = to_endian(TO_ENDIAN_BIG, 4, timedata+4);
+// if (r) {
+// return 1;
+// }
+
+ nanotime = item->time.tv_sec * 1000000000;
+ nanotime += item->time.tv_nsec;
+ r = to_endian(TO_ENDIAN_BIG, 8, &nanotime);
+ if (r) {
+ return 1;
+ }
+
+ c = 8;
+ r = asn1_write_value(node, "Kee.KeeEntry.timestamp", &nanotime, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ if (item->initiator == BOB) {
+ credit_delta = item->bob_credit_delta;
+ collateral_delta = item->bob_collateral_delta;
+ signature_request = item->bob_signature;
+ signature_response = item->alice_signature;
+
+ } else {
+ credit_delta = item->alice_credit_delta;
+ collateral_delta = item->alice_collateral_delta;
+ signature_request = item->alice_signature;
+ signature_response = item->bob_signature;
+ }
+ c = 4;
+ r = asn1_write_value(node, "Kee.KeeEntry.creditDelta", &credit_delta, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ c = 4;
+ r = asn1_write_value(node, "Kee.KeeEntry.collateralDelta", &collateral_delta, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ c = 64;
+ r = asn1_write_value(node, "Kee.KeeEntry.body", item->content.key, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ if (mode == KEE_LEDGER_ITEM_SERIALIZE_REQUEST) {
+ signature_request = zero_content;
+ c = 0;
+ } else {
+ c = 64;
+ }
+ r = asn1_write_value(node, "Kee.KeeEntry.signatureRequest", signature_request, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ c = 5;
+ if (item->response) {
+ response_s = "TRUE";
+ } else {
+ response_s = "FALSE";
+ c++;
+ }
+ r = asn1_write_value(node, "Kee.KeeEntry.response", response_s, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ if (mode < KEE_LEDGER_ITEM_SERIALIZE_FINAL) {
+ signature_response = zero_content;
+ c = 0;
+ } else {
+ c = 64;
+ }
+ r = asn1_write_value(node, "Kee.KeeEntry.signatureResponse", signature_response, c);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ r = asn1_der_coding(node, "Kee.KeeEntry", out, (int*)out_len, err);
+ if (r != ASN1_SUCCESS) {
+ return r;
+ }
+
+ return 0;
+}
diff --git a/src/ledger.h b/src/ledger.h
@@ -11,15 +11,23 @@ enum kee_initiator_e {
BOB,
};
+enum kee_item_serialize_mode_e {
+ KEE_LEDGER_ITEM_SERIALIZE_REQUEST,
+ KEE_LEDGER_ITEM_SERIALIZE_RESPONSE,
+ KEE_LEDGER_ITEM_SERIALIZE_FINAL,
+};
+
struct kee_ledger_item_t {
struct kee_ledger_item_t *prev_item;
int alice_credit_delta;
int bob_credit_delta;
int alice_collateral_delta;
int bob_collateral_delta;
- time_t time;
+ struct timespec time;
enum kee_initiator_e initiator;
char response;
+ char alice_signature[64];
+ char bob_signature[64];
struct kee_content_t content;
};
@@ -32,7 +40,7 @@ struct kee_ledger_cache_t {
};
struct kee_ledger_t {
- const char digest[64];
+ char digest[64];
struct kee_ledger_item_t *last_item;
char pubkey_alice[32];
char pubkey_bob[32];
@@ -44,10 +52,14 @@ struct kee_ledger_t {
struct kee_ledger_item_t *kee_ledger_parse_item(struct kee_ledger_t *ledger, const char *data, size_t data_len);
int kee_ledger_parse(struct kee_ledger_t *ledger, const char *data, size_t data_len);
+int kee_ledger_serialize(struct kee_ledger_t *ledger, char *out, size_t *out_len);
void kee_ledger_init(struct kee_ledger_t *ledger);
void kee_ledger_free(struct kee_ledger_t *ledger);
void kee_ledger_item_free(struct kee_ledger_item_t *item);
void kee_ledger_resolve(struct kee_ledger_t *ledger, Cadiz *cadiz);
void kee_ledger_reset_cache(struct kee_ledger_t *ledger);
+void kee_ledger_item_init(struct kee_ledger_item_t *item);
+int kee_ledger_item_serialize(struct kee_ledger_item_t *item, char *out, size_t *out_len, enum kee_item_serialize_mode_e mode);
+
#endif
diff --git a/src/tests/Makefile b/src/tests/Makefile
@@ -23,6 +23,7 @@ test_run:
./test_content
./test_ledger
./test_dn
+ ./test_sign
test: all test_run
diff --git a/src/tests/sign.c b/src/tests/sign.c
@@ -0,0 +1,137 @@
+#include <gcrypt.h>
+
+#include "ledger.h"
+#include "gpg.h"
+#include "digest.h"
+
+const char *content_test = "Subject: foo\n\nsome content\n";
+const char *content_test_item = "Subject: bar\n\nsome other content\n";
+const char *content_test_item_two = "Subject: baz\n\nmore more more content\n";
+
+int main() {
+ int r;
+ gcry_sexp_t alice;
+ gcry_sexp_t bob;
+ gcry_sexp_t tmp;
+ char *out;
+ size_t out_len;
+ char *out_item;
+ size_t out_item_len;
+ struct kee_ledger_t ledger;
+ struct kee_ledger_item_t item;
+ struct kee_ledger_item_t item_two;
+ struct kee_content_t content;
+ struct kee_content_t content_item;
+ struct kee_content_t content_item_two;
+ char item_sum[64];
+
+ r = gpg_key_create(&alice);
+ if (r) {
+ return 1;
+ }
+ r = gpg_key_create(&bob);
+ if (r) {
+ return 1;
+ }
+
+ kee_ledger_init(&ledger);
+
+ tmp = gcry_sexp_find_token(alice, "public-key", 10);
+ if (tmp == NULL) {
+ return 1;
+ }
+ tmp = gcry_sexp_find_token(tmp, "q", 1);
+ if (tmp == NULL) {
+ return 1;
+ }
+ out_len = 32;
+ out = gcry_sexp_nth_data(tmp, 1, &out_len);
+ if (tmp == NULL) {
+ return 1;
+ }
+ memcpy(ledger.pubkey_alice, out, 32);
+
+ tmp = gcry_sexp_find_token(bob, "public-key", 10);
+ if (tmp == NULL) {
+ return 1;
+ }
+ tmp = gcry_sexp_find_token(tmp, "q", 1);
+ if (tmp == NULL) {
+ return 1;
+ }
+ out_len = 32;
+ out = gcry_sexp_nth_data(tmp, 1, &out_len);
+ if (tmp == NULL) {
+ return 1;
+ }
+ memcpy(ledger.pubkey_bob, out, 32);
+
+ strcpy(ledger.uoa, "USD");
+ ledger.uoa_decimals = 2;
+
+ r = calculate_digest_algo(content_test, strlen(content_test), content.key, GCRY_MD_SHA512);
+ if (r) {
+ return 1;
+ }
+ r = kee_content_init(&content, content.key, 0);
+ if (r) {
+ return 1;
+ }
+
+ r = calculate_digest_algo(content_test, strlen(content_test), content.key, GCRY_MD_SHA512);
+ if (r) {
+ return 1;
+ }
+
+ out_len = 4096;
+ out = malloc(out_len);
+ r = kee_ledger_serialize(&ledger, out, &out_len);
+ if (r) {
+ return 1;
+ }
+
+ r = calculate_digest_algo(out, out_len, ledger.digest, GCRY_MD_SHA512);
+ if (r) {
+ return 1;
+ }
+
+ kee_ledger_item_init(&item);
+ item.alice_credit_delta = 666;
+ item.bob_credit_delta = -42;
+ item.alice_collateral_delta = 1024;
+ item.bob_collateral_delta = 2048;
+ r = clock_gettime(CLOCK_REALTIME, &item.time);
+ if (r) {
+ return 1;
+ }
+ item.initiator = BOB;
+ item.response = 1;
+
+ r = calculate_digest_algo(content_test, strlen(content_test_item), content_item.key, GCRY_MD_SHA512);
+ if (r) {
+ return 1;
+ }
+ r = kee_content_init(&content_item, content_item.key, 0);
+ if (r) {
+ return 1;
+ }
+
+ free(out);
+ kee_content_free(&content_item);
+ kee_content_free(&content);
+ kee_ledger_free(&ledger);
+
+ out_item_len = 4096;
+ out_item = malloc(out_len);
+ r = kee_ledger_item_serialize(&item, out_item, &out_item_len, KEE_LEDGER_ITEM_SERIALIZE_REQUEST);
+ if (r) {
+ return 1;
+ }
+
+ r = calculate_digest_algo(out_item, out_item_len, item_sum, GCRY_MD_SHA512);
+ if (r) {
+ return 1;
+ }
+
+ return 0;
+}