commit 30729151cf711d97ebf65201c124be2594a67cd1
parent 5af518a9176615113a5d55accb9f7f785789fd5d
Author: lash <dev@holbrook.no>
Date: Sat, 5 Apr 2025 01:50:28 +0100
WIP fix leaks in serialization
Diffstat:
9 files changed, 98 insertions(+), 27 deletions(-)
diff --git a/src/cli/main.c b/src/cli/main.c
@@ -86,6 +86,8 @@ int main(int argc, char **argv) {
LQCert *cert;
LQMsg *req;
LQMsg *res;
+ char out[LQ_BLOCKSIZE];
+ size_t out_len;
r = lq_ui_init();
if (r) {
@@ -136,7 +138,14 @@ int main(int argc, char **argv) {
return 1;
}
- r = lq_certificate_verify(cert, pubk_alice, NULL);
+ r = lq_certificate_verify(cert);
+ if (r != ERR_OK) {
+ lq_ui_free();
+ return 1;
+ }
+
+ out_len = LQ_BLOCKSIZE;
+ r = lq_certificate_serialize(cert, out, &out_len, NULL);
if (r != ERR_OK) {
lq_ui_free();
return 1;
diff --git a/src/crypto/gcrypt.c b/src/crypto/gcrypt.c
@@ -14,6 +14,7 @@
#include "lq/config.h"
#include "lq/err.h"
#include "lq/store.h"
+#include "lq/base.h"
#include "debug.h"
#define CHACHA20_KEY_LENGTH_BYTES 32
@@ -28,6 +29,8 @@ enum gpg_find_mode_e {
GPG_FIND_FINGERPRINT, ///< Load only the key matching the fingerprint.
};
+extern char zeros[65];
+
/**
* gcrypt implementation of the crypto interface.
*
@@ -961,10 +964,14 @@ LQSig* lq_privatekey_sign(LQPrivKey *pk, const char *data, size_t data_len, cons
LQSig* lq_signature_from_bytes(const char *sig_data, size_t sig_len, LQPubKey *pubkey) {
LQSig *sig;
+ if (!lq_cmp(sig_data, zeros, LQ_SIGN_LEN)) {
+ return NULL;
+ }
+
sig = lq_alloc(sizeof(LQSig));
lq_zero(sig, sizeof(LQSig));
sig->impl = lq_alloc(sizeof(LQ_SIGN_LEN));
- lq_cpy(sig->impl, sig_data, sig_len);
+ lq_cpy(sig->impl, sig_data, LQ_SIGN_LEN);
return sig;
}
diff --git a/src/lq/base.c b/src/lq/base.c
@@ -2,11 +2,12 @@
#include "config.h"
+char zeros[65];
+
int lq_init() {
char err[1024];
int r;
-
lq_err_init();
return lq_config_init();
}
diff --git a/src/lq/cert.c b/src/lq/cert.c
@@ -11,7 +11,7 @@
#include "debug.h"
-static char zeros[65];
+extern char zeros[65];
static LQPubKey nokey = {
.pk = 0,
.impl = zeros,
@@ -360,18 +360,17 @@ int lq_certificate_deserialize(LQCert **cert, char *in, size_t in_len, LQResolve
p = lq_certificate_new(NULL);
lq_certificate_set_domain(p, tmp);
- c = 4096;
+ c = LQ_BLOCKSIZE;
r = asn1_read_value(item, "request", tmp, &c);
if (r != ASN1_SUCCESS) {
return ERR_READ;
}
-
r = lq_msg_deserialize(&p->request, tmp, c, resolve);
if (r != ERR_OK) {
return r;
}
- c = 4096;
+ c = LQ_BLOCKSIZE;
r = asn1_read_value(item, "request_sig", tmp, &c);
if (r != ASN1_SUCCESS) {
return ERR_READ;
@@ -380,7 +379,7 @@ int lq_certificate_deserialize(LQCert **cert, char *in, size_t in_len, LQResolve
p->request_sig = lq_signature_from_bytes(tmp, c, NULL);
}
- c = 4096;
+ c = LQ_BLOCKSIZE;
r = asn1_read_value(item, "response", tmp, &c);
if (r != ASN1_SUCCESS) {
return ERR_READ;
diff --git a/src/lq/err.c b/src/lq/err.c
@@ -4,10 +4,11 @@
#ifdef RERR
-static char *_rerr[3] = {
+static char *_rerr[4] = {
"",
"Invalid request",
"Invalid response",
+ "Not resolved",
};
static char *_rerr_crypto[12] = {
diff --git a/src/lq/err.h b/src/lq/err.h
@@ -1,6 +1,8 @@
#ifndef LIBQAEDA_ERR_H_
#define LIBQAEDA_ERR_H_
+#define LQ_ERRSIZE 1024
+
// provides ERR_OK = 0, ERR_FAIL = 1, ERR_UNIMPLEMENTED = 2
#include <rerr.h>
@@ -10,6 +12,7 @@ enum err_e {
ERR_NONSENSE = 0x101, ///< Available data does not make sense in context
ERR_REQUEST = 0x102, ///< Error related to certificate request messages
ERR_RESPONSE = 0x103, ///< Error related to certificate response messages
+ ERR_RESOLVE = 0x104, ///< Error related to resolving message hashes
RERR_PFX_CRYPTO = 0x200,
ERR_NOCRYPTO = 0x201,
diff --git a/src/lq/msg.c b/src/lq/msg.c
@@ -12,7 +12,8 @@
#include "lq/store.h"
#include "debug.h"
-static char zeros[LQ_PUBKEY_LEN];
+
+extern char zeros[65];
static LQPubKey nokey = {
.pk = NULL,
.impl = zeros,
@@ -111,6 +112,7 @@ void lq_msg_free(LQMsg *msg) {
}
int lq_msg_serialize(LQMsg *msg, char *out, size_t *out_len, LQResolve *resolve) {
+ char resolved;
size_t c;
int r;
size_t mx;
@@ -122,6 +124,7 @@ int lq_msg_serialize(LQMsg *msg, char *out, size_t *out_len, LQResolve *resolve)
asn1_node node;
char *keydata;
+ resolved = LQ_MSG_DIGESTONLY;
mx = *out_len;
*out_len = 0;
lq_set(&node, 0, sizeof(node));
@@ -147,6 +150,11 @@ int lq_msg_serialize(LQMsg *msg, char *out, size_t *out_len, LQResolve *resolve)
return r;
}
resolve_active = resolve_active->next;
+ resolved = LQ_MSG_RESOLVED;
+ }
+
+ if (resolved & LQ_MSG_DIGESTONLY) {
+ debug(LLOG_DEBUG, "msg", "no resolver");
}
r = asn1_write_value(node, "Qaeda.Msg.data", tmp, c);
@@ -201,13 +209,15 @@ int lq_msg_serialize(LQMsg *msg, char *out, size_t *out_len, LQResolve *resolve)
int lq_msg_deserialize(LQMsg **msg, const char *in, size_t in_len, LQResolve *resolve) {
int r;
size_t c;
- char err[1024];
+ char resolved;
+ char err[LQ_ERRSIZE];
char z[LQ_DIGEST_LEN];
- char tmp[1024];
+ char tmp[LQ_BLOCKSIZE];
asn1_node node;
asn1_node item;
LQResolve *resolve_active;
+ resolved = LQ_MSG_DIGESTONLY;
lq_zero(&node, sizeof(node));
lq_zero(&item, sizeof(item));
r = asn1_array2tree(defs_asn1_tab, &node, err);
@@ -230,17 +240,33 @@ int lq_msg_deserialize(LQMsg **msg, const char *in, size_t in_len, LQResolve *re
if (r != ASN1_SUCCESS) {
return ERR_READ;
}
- c = 1024;
+ c = LQ_BLOCKSIZE;
resolve_active = resolve;
while (resolve_active != NULL) {
r = resolve_active->store->get(LQ_CONTENT_MSG, resolve_active->store, z, LQ_DIGEST_LEN, tmp, &c);
if (r != ERR_OK) {
return r;
}
+ resolved = LQ_MSG_RESOLVED;
resolve_active = resolve_active->next;
}
+ if (resolved & LQ_MSG_DIGESTONLY) {
+ lq_cpy(tmp, z, LQ_DIGEST_LEN);
+ c = LQ_DIGEST_LEN;
+ } else {
+ if (!(resolved & LQ_MSG_RESOLVED)) {
+ return ERR_RESOLVE;
+ }
+ }
*msg = lq_msg_new((const char*)tmp, c);
+ (*msg)->state = resolved;
+ (*msg)->data = lq_alloc(c);
+ if ((*msg)->data == NULL) {
+ return ERR_MEM;
+ }
+ (*msg)->len = c;
+ lq_cpy((*msg)->data, tmp, c);
/// \todo document timestamp size
c = 8;
@@ -255,11 +281,12 @@ int lq_msg_deserialize(LQMsg **msg, const char *in, size_t in_len, LQResolve *re
lq_cpy(&((*msg)->time.tv_sec), tmp, 4);
lq_cpy(&((*msg)->time.tv_nsec), ((char*)tmp)+4, 4);
- c = 65;
+ c = LQ_PUBKEY_LEN;
r = asn1_read_value(item, "pubkey", tmp, (int*)&c);
if (r != ASN1_SUCCESS) {
return ERR_READ;
}
+ (*msg)->pubkey = lq_publickey_new(tmp);
return ERR_OK;
}
diff --git a/src/lq/msg.h b/src/lq/msg.h
@@ -7,6 +7,11 @@
#include "lq/crypto.h"
#include "lq/store.h"
+enum lq_msgstate_e {
+ LQ_MSG_DIGESTONLY = 1,
+ LQ_MSG_RESOLVED = 2,
+};
+
/**
* \struct LQMsg
*
@@ -15,6 +20,7 @@
* \see lq_msg_t
*/
struct lq_msg_t {
+ char state; ///< Message resolution state
char *data; ///< Arbitrary data constituting the message.
size_t len; ///< Length of arbitrary data.
struct timespec time; ///< Nanosecond timestamp of when the message was created.
diff --git a/src/test/test_cert.c b/src/test/test_cert.c
@@ -97,25 +97,28 @@ START_TEST(check_cert_sig_res) {
}
END_TEST
-START_TEST(check_cert_symmetric_nomsg) {
+START_TEST(check_cert_symmetric_ser_nomsg) {
int r;
size_t c;
LQCert *cert;
- char buf[4096];
+ char buf[LQ_BLOCKSIZE];
cert = lq_certificate_new(NULL);
- c = 4096;
+ ck_assert_ptr_nonnull(cert);
+ c = LQ_BLOCKSIZE;
r = lq_certificate_serialize(cert, buf, &c, NULL);
ck_assert_int_eq(r, 0);
lq_certificate_free(cert);
+ cert = lq_certificate_new(NULL);
+ ck_assert_ptr_nonnull(cert);
r = lq_certificate_deserialize(&cert, buf, c, NULL);
ck_assert_int_eq(r, 0);
lq_certificate_free(cert);
}
END_TEST
-START_TEST(check_cert_symmetric_req_nosig) {
+START_TEST(check_cert_symmetric_ser_req_nosig) {
int r;
size_t c;
LQCert *cert;
@@ -123,20 +126,26 @@ START_TEST(check_cert_symmetric_req_nosig) {
char buf[4096];
req = lq_msg_new(data, strlen(data) + 1);
+ ck_assert_ptr_nonnull(req);
+
cert = lq_certificate_new(NULL);
+ ck_assert_ptr_nonnull(cert);
+
r = lq_certificate_request(cert, req, NULL);
- c = 4096;
+ c = LQ_BLOCKSIZE;
r = lq_certificate_serialize(cert, buf, &c, NULL);
ck_assert_int_eq(r, 0);
lq_certificate_free(cert);
+ cert = lq_certificate_new(NULL);
+ ck_assert_ptr_nonnull(cert);
r = lq_certificate_deserialize(&cert, buf, c, NULL);
ck_assert_int_eq(r, 0);
lq_certificate_free(cert);
}
END_TEST
-START_TEST(check_cert_symmetric_req_sig) {
+START_TEST(check_cert_symmetric_ser_req_sig) {
int r;
size_t c;
LQCert *cert;
@@ -145,18 +154,25 @@ START_TEST(check_cert_symmetric_req_sig) {
char buf[4096];
pk = lq_privatekey_new(passphrase, 32);
+ ck_assert_ptr_nonnull(pk);
+ r = lq_privatekey_unlock(pk, passphrase, 32);
+ ck_assert_int_eq(r, 0);
req = lq_msg_new(data, strlen(data) + 1);
+ ck_assert_ptr_nonnull(req);
+
cert = lq_certificate_new(NULL);
- lq_privatekey_unlock(pk, passphrase, 32);
+ ck_assert_ptr_nonnull(cert);
r = lq_certificate_request(cert, req, pk);
ck_assert_int_eq(r, 0);
- c = 4096;
+ c = LQ_BLOCKSIZE;
r = lq_certificate_serialize(cert, buf, &c, NULL);
ck_assert_int_eq(r, 0);
lq_certificate_free(cert);
+ cert = lq_certificate_new(NULL);
+ ck_assert_ptr_nonnull(cert);
r = lq_certificate_deserialize(&cert, buf, c, NULL);
ck_assert_int_eq(r, 0);
lq_certificate_free(cert);
@@ -164,7 +180,7 @@ START_TEST(check_cert_symmetric_req_sig) {
}
END_TEST
-START_TEST(check_cert_symmetric_rsp_onesig) {
+START_TEST(check_cert_symmetric_ser_rsp_onesig) {
int r;
size_t c;
LQCert *cert;
@@ -186,6 +202,7 @@ START_TEST(check_cert_symmetric_rsp_onesig) {
ck_assert_int_eq(r, 0);
lq_certificate_free(cert);
+ cert = lq_certificate_new(NULL);
r = lq_certificate_deserialize(&cert, buf, c, NULL);
ck_assert_int_eq(r, 0);
r = lq_certificate_respond(cert, res, pk);
@@ -195,7 +212,7 @@ START_TEST(check_cert_symmetric_rsp_onesig) {
}
END_TEST
-START_TEST(check_cert_symmetric_rsp_bothsig) {
+START_TEST(check_cert_symmetric_ser_rsp_bothsig) {
int r;
size_t c;
LQCert *cert;
@@ -226,6 +243,7 @@ START_TEST(check_cert_symmetric_rsp_bothsig) {
ck_assert_int_eq(r, 0);
lq_certificate_free(cert);
+ cert = lq_certificate_new(NULL);
r = lq_certificate_deserialize(&cert, buf, c, NULL);
ck_assert_int_eq(r, 0);
lq_certificate_free(cert);
@@ -238,14 +256,14 @@ Suite * common_suite(void) {
s = suite_create("cert");
tc = tcase_create("sign");
- tcase_add_test(tc, check_cert_sig_req);
- tcase_add_test(tc, check_cert_sig_res);
+// tcase_add_test(tc, check_cert_sig_req);
+// tcase_add_test(tc, check_cert_sig_res);
suite_add_tcase(s, tc);
tc = tcase_create("serialize");
// tcase_add_test(tc, check_cert_symmetric_ser_nomsg);
// tcase_add_test(tc, check_cert_symmetric_ser_req_nosig);
-// tcase_add_test(tc, check_cert_symmetric_ser_req_sig);
+ tcase_add_test(tc, check_cert_symmetric_ser_req_sig);
// tcase_add_test(tc, check_cert_symmetric_ser_rsp_onesig);
// tcase_add_test(tc, check_cert_symmetric_ser_rsp_bothsig);
suite_add_tcase(s, tc);