kee

Offline IOU signer with QR as transport
git clone https://holbrook.no/src/kee
Info | Log | Files | Refs | README | LICENSE

commit 6db4d1cecaadc5336d78381b528d6d40147667ae
parent d10488b4fc62f6e6454edfe884df53035b45d9fa
Author: lash <dev@holbrook.no>
Date:   Fri,  3 May 2024 16:57:49 +0100

Rehabilitate key load

Diffstat:
Mrequirements.txt | 1+
Msrc/gpg.c | 70++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/gpg.h | 2+-
Msrc/gtk/kee-entry.c | 13+++++++++++--
Msrc/gtk/kee-key.c | 11++++++++---
Msrc/ledger.c | 20++++++++++++--------
Msrc/ledger.h | 3++-
Msrc/settings.c | 2+-
Msrc/tests/testutil.c | 6++++--
Mtestdata_asn1.py | 22+++++++++++++++++-----
10 files changed, 93 insertions(+), 57 deletions(-)

diff --git a/requirements.txt b/requirements.txt @@ -4,3 +4,4 @@ faker~=24.0.0 pycryptodome==3.20.0 asn1ate~=0.6 pyasn1~=0.5.0 +pygcrypt~=1.0.1 diff --git a/src/gpg.c b/src/gpg.c @@ -200,8 +200,10 @@ static char *key_filename(struct gpg_store *gpg, char *path) { static int key_from_data(gcry_sexp_t *key, const char *indata, size_t indata_len) { gcry_error_t e; + size_t c; - e = gcry_sexp_new(key, indata, indata_len, 1); + c = 0; + e = gcry_sexp_sscan(key, &c, indata, indata_len); if (e != GPG_ERR_NO_ERROR) { //debug_log(DEBUG_DEBUG, indata); return ERR_KEYFAIL; @@ -309,15 +311,15 @@ static int key_create_file(struct gpg_store *gpg, gcry_sexp_t *key, const char * } kl = gcry_sexp_sprint(*key, GCRYSEXP_FMT_CANON, NULL, 0); - m = (size_t)kl; + m = (size_t)kl + 1; p = (char*)v + sizeof(int); c = 0; - while (m > 0) { - kl = gcry_sexp_sprint(*key, GCRYSEXP_FMT_CANON, p, BUFLEN-m); - m -= (size_t)(kl + 1); - p += kl; - c += kl; - } +// while (m > 0) { +// kl = gcry_sexp_sprint(*key, GCRYSEXP_FMT_CANON, p, BUFLEN-m); +// m -= (size_t)(kl + 1); +// p += kl; +// c += kl; +// } memcpy(v, &c, sizeof(int)); m = c; @@ -400,6 +402,7 @@ int gpg_key_create(struct gpg_store *gpg, const char *passphrase) { return ERR_OK; } +/// \todo add key unload to destroy memory int gpg_key_load(struct gpg_store *gpg, const char *passphrase, enum gpg_find_mode_e mode, const void *criteria) { int r; size_t c; @@ -411,7 +414,7 @@ int gpg_key_load(struct gpg_store *gpg, const char *passphrase, enum gpg_find_mo strcpy(path, gpg->path); p = path + strlen(path); strcpy(p, "kee.key"); - r = key_from_file(gpg->k, path, passphrase); + r = key_from_file(&gpg->k, path, passphrase); if (r) { return ERR_FAIL; } @@ -424,7 +427,7 @@ int gpg_key_load(struct gpg_store *gpg, const char *passphrase, enum gpg_find_mo if (r) { return ERR_FAIL; } - r = key_from_file(gpg->k, path, passphrase); + r = key_from_file(&gpg->k, path, passphrase); if (r) { return ERR_FAIL; } @@ -433,12 +436,12 @@ int gpg_key_load(struct gpg_store *gpg, const char *passphrase, enum gpg_find_mo return ERR_FAIL; } - p = (char*)gcry_pk_get_keygrip(*gpg->k, (unsigned char*)gpg->fingerprint); + p = (char*)gcry_pk_get_keygrip(gpg->k, (unsigned char*)gpg->fingerprint); if (p == NULL) { return ERR_KEYFAIL; } - r = key_apply_public(gpg, *gpg->k); + r = key_apply_public(gpg, gpg->k); if (r) { return ERR_FAIL; } @@ -505,7 +508,9 @@ int gpg_store_check(struct gpg_store *gpg, const char *passphrase) { char d[1024]; gcry_sexp_t k; char *p; - unsigned char fingerprint[20] = { 0x00 }; + //unsigned char fingerprint[20] = { 0x00 }; + unsigned char fingerprint[41] = { 0x00 }; + //size_t fingerprint_len = 41; size_t fingerprint_len = 41; //char passphrase_hash[m_passphrase_digest_len]; char passphrase_hash[gpg->passphrase_digest_len]; @@ -525,39 +530,39 @@ int gpg_store_check(struct gpg_store *gpg, const char *passphrase) { gpgVersion = v; sprintf(d, "Using gpg version: %s", gpgVersion); debug_log(DEBUG_INFO, d); - //r = key_from_file(&k, p.c_str(), passphrase_hash); - //r = key_from_file(&k, p, passphrase_hash); - r = key_from_file(&k, gpg->path, passphrase_hash); +// r = key_from_file(&k, gpg->path, passphrase_hash); + //r = gpg_key_load(gpg, passphrase_hash, KEE_GPG_FIND_MAIN, NULL); + r = gpg_key_load(gpg, passphrase_hash, KEE_GPG_FIND_MAIN, NULL); if (r == ERR_KEYFAIL) { char pp[2048]; - //sprintf(pp, "could not decrypt key in %s/key.bin", p.c_str()); - sprintf(pp, "could not decrypt key in %s/key.bin", p); + sprintf(pp, "could not decrypt key in %s/kee.key", p); debug_log(DEBUG_INFO, pp); return 1; } if (r != ERR_OK) { char pp[2048]; - //sprintf(pp, "%s/key.bin", p.c_str()); - sprintf(pp, "%s/key.bin", p); + sprintf(pp, "%s/kee.key", p); r = key_create_file(gpg, &k, passphrase_hash); if (r != ERR_OK) { return r; } - gcry_pk_get_keygrip(k, fingerprint); - //bin_to_hex(fingerprint, 20, (unsigned char*)m_fingerprint, &fingerprint_len); - bin_to_hex(fingerprint, 20, (unsigned char*)gpg->fingerprint, &fingerprint_len); + //gcry_pk_get_keygrip(k, fingerprint); + gcry_pk_get_keygrip(k, (unsigned char*)gpg->fingerprint); + //bin_to_hex(fingerprint, 20, (unsigned char*)gpg->fingerprint, &fingerprint_len); + bin_to_hex((unsigned char*)gpg->fingerprint, 20, (unsigned char*)fingerprint, &fingerprint_len); char ppp[4096]; //sprintf(ppp, "created key %s from %s", m_fingerprint, pp); - sprintf(ppp, "created key %s from %s", gpg->fingerprint, pp); + sprintf(ppp, "created key %s from %s", fingerprint, pp); debug_log(DEBUG_INFO, ppp); } else { - gcry_pk_get_keygrip(k, fingerprint); - //bin_to_hex(fingerprint, 20, (unsigned char*)m_fingerprint, &fingerprint_len); - bin_to_hex(fingerprint, 20, (unsigned char*)gpg->fingerprint, &fingerprint_len); + //gcry_pk_get_keygrip(k, fingerprint); + gcry_pk_get_keygrip(k, (unsigned char*)gpg->fingerprint); + //bin_to_hex(fingerprint, 20, (unsigned char*)gpg->fingerprint, &fingerprint_len); + bin_to_hex((unsigned char*)gpg->fingerprint, 20, (unsigned char*)fingerprint, &fingerprint_len); char pp[4096]; //sprintf(pp, "found key %s in %s", (unsigned char*)m_fingerprint, p.c_str()); - sprintf(pp, "found key %s in %s", (unsigned char*)gpg->fingerprint, p); - debug_log(DEBUG_INFO, pp); + sprintf(pp, "found key %s in path: %s", fingerprint, p); + //debug_log(DEBUG_INFO, pp); } //r = gpg_sign(&o, &k, sign_test); //return r; @@ -571,7 +576,6 @@ int gpg_store_sign(struct gpg_store *gpg, char *data, size_t data_len, const cha int gpg_store_sign_with(struct gpg_store *gpg, char *data, size_t data_len, const char *passphrase, const char *fingerprint) { int r; size_t c; - gcry_sexp_t key; gcry_sexp_t pnt; gcry_sexp_t msg; gcry_sexp_t sig; @@ -583,7 +587,6 @@ int gpg_store_sign_with(struct gpg_store *gpg, char *data, size_t data_len, cons return 1; } - gpg->k = &key; if (fingerprint == NULL) { r = gpg_key_load(gpg, passphrase, KEE_GPG_FIND_MAIN, NULL); } else { @@ -599,7 +602,7 @@ int gpg_store_sign_with(struct gpg_store *gpg, char *data, size_t data_len, cons return 1; } - e = gcry_pk_sign(&sig, msg, *gpg->k); + e = gcry_pk_sign(&sig, msg, gpg->k); if (e != GPG_ERR_NO_ERROR) { return 1; } @@ -630,8 +633,7 @@ int gpg_store_sign_with(struct gpg_store *gpg, char *data, size_t data_len, cons } memcpy(gpg->last_signature + POINT_LENGTH, p, c); - gcry_sexp_release(*gpg->k); - gpg->k = NULL; + gcry_sexp_release(gpg->k); return 0; } diff --git a/src/gpg.h b/src/gpg.h @@ -24,7 +24,7 @@ enum gpg_find_mode_e { }; struct gpg_store { - gcry_sexp_t *k; + gcry_sexp_t k; size_t passphrase_digest_len; char fingerprint[FINGERPRINT_LENGTH]; char public_key[PUBKEY_LENGTH]; diff --git a/src/gtk/kee-entry.c b/src/gtk/kee-entry.c @@ -110,13 +110,13 @@ static void kee_entry_handle_add(GtkButton *butt, KeeEntry *o) { buf = gtk_entry_get_buffer(o->form->bob_pubkey); b = (char*)gtk_entry_buffer_get_text(buf); c = hex2bin(b, (unsigned char*)o->ledger.pubkey_bob); -// if (c == 0) { + if (c == 0) { // g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "invalid counterparty public key data"); // return; // } else if (c != PUBKEY_LENGTH) { // g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "wrong size for counterparty public key"); // return; -// } + } o->state |= ENTRYSTATE_LOAD; g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "adding ledger entry"); @@ -128,6 +128,14 @@ static void kee_entry_handle_add(GtkButton *butt, KeeEntry *o) { return; } + buf = gtk_entry_get_buffer(o->form->passphrase); + b = (char*)gtk_entry_buffer_get_text(buf); + r = kee_ledger_sign(&o->ledger, o->ledger.last_item, o->gpg, b); + if (r) { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "fail entry sign"); + return; + } + r = kee_ledger_serialize_open(&o->ledger, out, &out_len); if (r) { g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "qr transport renderer failed"); @@ -151,6 +159,7 @@ static void kee_entry_handle_add(GtkButton *butt, KeeEntry *o) { g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "read from qr transport renderer failed"); return; } + /// \todo verify that this frees the buffer transport_data = g_variant_new_take_string(out); widget = gtk_widget_get_ancestor(GTK_WIDGET(o), GTK_TYPE_WINDOW); diff --git a/src/gtk/kee-key.c b/src/gtk/kee-key.c @@ -4,6 +4,7 @@ #include "kee-key.h" #include "gpg.h" #include "err.h" +#include "hex.h" typedef struct { } KeeKeyPrivate; @@ -39,8 +40,8 @@ static void kee_key_class_init(KeeKeyClass *kls) { static void kee_key_init(KeeKey *o) { } -static void kee_key_finalize(KeeKey *o) { -} +//static void kee_key_finalize(KeeKey *o) { +//} static void kee_key_handle_unlock_click(GtkWidget *button, KeeKey *o) { int r; @@ -87,6 +88,10 @@ KeeKey* kee_key_new(struct gpg_store *gpg) { } const char *kee_key_get_fingerprint(KeeKey *o, char *fingerprint) { - strcpy(fingerprint, o->gpg->fingerprint); + size_t fingerprint_len; + + fingerprint_len = 41; + bin_to_hex((unsigned char*)o->gpg->fingerprint, 20, (unsigned char*)fingerprint, &fingerprint_len); + //strcpy(fingerprint, o->gpg->fingerprint); return fingerprint; } diff --git a/src/ledger.c b/src/ledger.c @@ -725,17 +725,21 @@ int kee_ledger_item_serialize(struct kee_ledger_item_t *item, char *out, size_t /// \todo remove external buffer -int kee_ledger_sign(struct kee_ledger_t *ledger, struct kee_ledger_item_t *item, struct gpg_store *gpg, char *out, size_t *out_len, const char *passphrase) { +//int kee_ledger_sign(struct kee_ledger_t *ledger, struct kee_ledger_item_t *item, struct gpg_store *gpg, char *out, size_t *out_len, const char *passphrase) { +int kee_ledger_sign(struct kee_ledger_t *ledger, struct kee_ledger_item_t *item, struct gpg_store *gpg, const char *passphrase) { int r; char *p; size_t c; size_t l; + char out[1024]; + size_t out_len; enum kee_ledger_state_e mode; - p = out; - c = *out_len; - l = *out_len; - *out_len = 0; + out_len = 1024; + p = (char*)out; + c = out_len; + l = out_len; + out_len = 0; mode = KEE_LEDGER_STATE_REQUEST; if (item->initiator == BOB) { @@ -753,16 +757,16 @@ int kee_ledger_sign(struct kee_ledger_t *ledger, struct kee_ledger_item_t *item, c = DIGEST_LENGTH; p = out + c; l -= c; - *out_len += c; + out_len += c; c = l; r = kee_ledger_item_serialize(item, p, &c, mode); if (r) { return ERR_FAIL; } - *out_len += c; + out_len += c; - r = gpg_store_sign_with(gpg, out, *out_len, passphrase, gpg->fingerprint); + r = gpg_store_sign_with(gpg, (char*)out, out_len, passphrase, gpg->fingerprint); if (r) { return ERR_FAIL; } diff --git a/src/ledger.h b/src/ledger.h @@ -61,7 +61,8 @@ 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); -int kee_ledger_sign(struct kee_ledger_t *ledger, struct kee_ledger_item_t *item, struct gpg_store *gpg, char *out, size_t *out_len, const char *passphrase); +//int kee_ledger_sign(struct kee_ledger_t *ledger, struct kee_ledger_item_t *item, struct gpg_store *gpg, char *out, size_t *out_len, const char *passphrase); +int kee_ledger_sign(struct kee_ledger_t *ledger, struct kee_ledger_item_t *item, struct gpg_store *gpg, const char *passphrase); enum kee_ledger_state_e kee_ledger_item_state(struct kee_ledger_item_t *item); void kee_ledger_item_init(struct kee_ledger_item_t *item); diff --git a/src/settings.c b/src/settings.c @@ -25,7 +25,7 @@ int settings_new_from_xdg(struct kee_settings *z) { memset(z, 0, sizeof(struct kee_settings)); - z->key = (unsigned char*)"."; + z->key = (unsigned char*)"./testdata_crypt"; z->data = malloc(KEE_SETTINGS_CAP); p = z->data; diff --git a/src/tests/testutil.c b/src/tests/testutil.c @@ -35,7 +35,8 @@ int kee_test_sign_request(struct kee_test_t *t) { size_t c; c = 1024; - r = kee_ledger_sign(&t->ledger, t->ledger.last_item, &t->gpg, b, &c, "1234"); + //r = kee_ledger_sign(&t->ledger, t->ledger.last_item, &t->gpg, b, &c, "1234"); + r = kee_ledger_sign(&t->ledger, t->ledger.last_item, &t->gpg, "1234"); if (r) { return 1; } @@ -64,7 +65,8 @@ int kee_test_sign_response(struct kee_test_t *t) { memcpy(t->ledger.last_item->bob_signature, t->ledger.last_item->alice_signature, SIGNATURE_LENGTH); memset(t->ledger.last_item->alice_signature, 0, SIGNATURE_LENGTH); - r = kee_ledger_sign(&t->ledger, t->ledger.last_item, &t->gpg, b, &c, "1234"); + //r = kee_ledger_sign(&t->ledger, t->ledger.last_item, &t->gpg, b, &c, "1234"); + r = kee_ledger_sign(&t->ledger, t->ledger.last_item, &t->gpg, "1234"); if (r) { return 1; } diff --git a/testdata_asn1.py b/testdata_asn1.py @@ -19,6 +19,8 @@ from faker.providers import lorem import varint from pyasn1.codec.der.encoder import encode as der_encode from pyasn1.codec.der.decoder import decode as der_decode +from pygcrypt.gctypes.sexpression import SExpression +from pygcrypt.gctypes.key import Key as GKey from testdata_asn1schema import KeeEntryHead from testdata_asn1schema import KeeEntry @@ -84,6 +86,7 @@ class LedgerEntryContent(LedgerContent): pass +# TODO: do everything with pygcrypt, or calc keygrip with pycryptodome 8| class LedgerSigner: def __init__(self, crypto_dir): @@ -105,9 +108,9 @@ class LedgerSigner: def __write_key(self, keyname, outdir, pin): (pk, pubk) = self.keypair[keyname] wt = io.BytesIO() - wt.write(b"(8:key-data(10:public-key(3:ecc(5:curve7:Ed25519)(1:q32:") + wt.write(b"(8:key-data(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:") wt.write(pubk) - wt.write(b")))(11:private-key(3:ecc(5:curve7:Ed25519)(1:q32:") + wt.write(b")))(11:private-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:") wt.write(pubk) wt.write(b")(1:d32:") wt.write(pk) @@ -118,6 +121,9 @@ class LedgerSigner: w.write(b) w.close() + sexp = SExpression(b) + gk = GKey(sexp) + l = len(b) bl = l.to_bytes(4, byteorder='little') h = hashlib.new('sha256') @@ -133,8 +139,12 @@ class LedgerSigner: w.write(nonce + r) w.close() + # symlink key to keygrip + lp = os.path.join(self.crypto_dir, gk.keygrip) + os.symlink(fp, lp) + wt = io.BytesIO() - wt.write(b"(8:key-data(10:public-key(3:ecc(5:curve7:Ed25519)(1:q32:") + wt.write(b"(8:key-data(10:public-key(3:ecc(5:curve7:Ed25519)(5:flags5:eddsa)(1:q32:") wt.write(pubk) wt.write(b"))))") b = wt.getvalue() @@ -151,7 +161,6 @@ class LedgerSigner: pk = Crypto.Util.asn1.DerOctetString().decode(pk_der[1], strict=True).payload pubk = k.public_key().export_key(format='raw') - self.signer[keyname] = eddsa.new(k, 'rfc8032') self.keypair[keyname] = (pk, pubk) self.pubkey_rindex[pubk] = keyname @@ -461,7 +470,10 @@ if __name__ == '__main__': os.unlink('kee.key') except FileNotFoundError: pass - os.symlink(alice_key, 'kee.key') + alice_key_sym = 'kee.key' + os.symlink(alice_key, alice_key_sym) + alice_key_sym = os.path.join(crypto_dir, alice_key_sym) + os.symlink(alice_key, alice_key_sym) count_ledgers = os.environ.get('COUNT', '1')