commit 0b0759e1f402682a269c94c928237ee5984206ca
parent 645f54a19044620cd75a93cd454cd62ec24ae49e
Author: lash <dev@holbrook.no>
Date: Tue, 25 Mar 2025 02:11:13 +0000
Add signature verify, but cert sig verify now fails in tests
Diffstat:
3 files changed, 107 insertions(+), 14 deletions(-)
diff --git a/src/crypto/gcrypt.c b/src/crypto/gcrypt.c
@@ -42,9 +42,7 @@ int lq_crypto_init() {
#ifdef RERR
rerr_register(RERR_PFX_GPG, "crypto", _rerr);
#endif
- //char *p;
- //size_t c;
- char *v;
+ const char *v;
if (gpg_version == NULL) {
v = gcry_check_version(GPG_MIN_VERSION);
@@ -271,7 +269,7 @@ int lq_privatekey_unlock(LQPrivKey *pk, const char *passphrase, size_t passphras
// }
//}
-static int sign(struct gpg_store *gpg, char *data, size_t data_len, const char *salt) {
+static int sign(struct gpg_store *gpg, const char *data, size_t data_len, const char *salt) {
int r;
size_t c;
char *p;
@@ -327,21 +325,20 @@ static int sign(struct gpg_store *gpg, char *data, size_t data_len, const char *
return 0;
}
-LQSig* lq_privatekey_sign(LQPrivKey *pk, const char *msg, size_t msg_len, const char *salt) {
+LQSig* lq_privatekey_sign(LQPrivKey *pk, const char *data, size_t data_len, const char *salt) {
int r;
struct gpg_store *gpg;
LQSig *sig;
+ char digest[LQ_DIGEST_LEN];
if ((pk->key_state & LQ_KEY_LOCK) > 0) {
return NULL;
}
- if (msg_len != LQ_DIGEST_LEN) {
- return NULL;
- }
+ lq_digest(data, strlen(data), (char*)digest);
gpg = (struct gpg_store*)pk->impl;
- r = sign(gpg, msg, msg_len, salt);
+ r = sign(gpg, digest, LQ_DIGEST_LEN, salt);
if (r != ERR_OK) {
return NULL;
}
@@ -365,6 +362,72 @@ size_t lq_signature_bytes(LQSig *sig, char **out) {
return LQ_SIGN_LEN;
}
+int lq_signature_verify(LQSig *sig, const char *data, size_t data_len) {
+ int r;
+ size_t c;
+ gcry_mpi_t sig_r;
+ gcry_mpi_t sig_s;
+ gcry_error_t err;
+ gcry_sexp_t sigx;
+ gcry_sexp_t msgx;
+ gcry_sexp_t pubkey;
+ struct gpg_store *gpg;
+ char digest[LQ_DIGEST_LEN];
+
+ if (sig->pubkey == NULL) {
+ return ERR_NOENT;
+ }
+
+ gpg = (struct gpg_store*)sig->pubkey->impl;
+ c = 0;
+ err = gcry_sexp_build(&pubkey, &c, "(key-data(public-key(ecc(curve Ed25519)(q %b))))", LQ_PUBKEY_LEN, gpg->public_key);
+ if (err != GPG_ERR_NO_ERROR) {
+ return ERR_CRYPTO;
+ }
+
+ c = 0;
+ err = gcry_mpi_scan(&sig_r, GCRYMPI_FMT_STD, sig->impl, LQ_POINT_LEN, &c);
+ if (err != GPG_ERR_NO_ERROR) {
+ return ERR_CRYPTO;
+ }
+ if (c != 32) {
+ return ERR_CRYPTO;
+ }
+
+ c = 0;
+ err = gcry_mpi_scan(&sig_s, GCRYMPI_FMT_STD, sig->impl + LQ_POINT_LEN, LQ_POINT_LEN, &c);
+ if (err != GPG_ERR_NO_ERROR) {
+ return ERR_CRYPTO;
+ }
+ if (c != 32) {
+ return ERR_CRYPTO;
+ }
+
+ c = 0;
+ err = gcry_sexp_build(&sigx, &c, "(sig-val(eddsa(r %m)(s %m)))", sig_r, sig_s);
+ if (err != GPG_ERR_NO_ERROR) {
+ return ERR_CRYPTO;
+ }
+
+ r = calculate_digest_algo(data, data_len, digest, GCRY_MD_SHA512);
+ if (r) {
+ return ERR_CRYPTO;
+ }
+
+ c = 0;
+ err = gcry_sexp_build(&msgx, &c, "(data(flags eddsa)(hash-algo sha512)(value %b))", LQ_DIGEST_LEN, digest);
+ if (err != GPG_ERR_NO_ERROR) {
+ return ERR_CRYPTO;
+ }
+
+ err = gcry_pk_verify(sigx, msgx, pubkey);
+ if (err != GPG_ERR_NO_ERROR) {
+ return ERR_ENCODING;
+ }
+
+ return ERR_OK;
+}
+
void lq_privatekey_free(LQPrivKey *pk) {
lq_free(pk->impl);
lq_free(pk);
@@ -413,6 +476,7 @@ LQPubKey* lq_publickey_new(const char *full) {
if (e != GPG_ERR_NO_ERROR) {
return NULL;
}
+ lq_cpy(gpg->public_key, full, LQ_PUBKEY_LEN);
r = (char*)gcry_pk_get_keygrip(gpg->k, (unsigned char*)gpg->fingerprint);
if (r == NULL) {
diff --git a/src/lq/crypto.h b/src/lq/crypto.h
@@ -4,7 +4,7 @@
#include <stddef.h>
#ifndef LQ_DIGEST_LEN
-#define LQ_DIGEST_LEN 32
+#define LQ_DIGEST_LEN 64
#endif
#ifndef LQ_PUBKEY_LEN
@@ -209,6 +209,12 @@ LQSig* lq_signature_from_bytes(const char *sig_data, size_t sig_len, LQPubKey *p
size_t lq_signature_bytes(LQSig *sig, char **out);
/**
+ * @brief Verify a signature against a private key and message.
+ *
+ */
+int lq_signature_verify(LQSig *sig, const char *msg, size_t msg_len);
+
+/**
* @brief Free an allocated public key.
* @param[in] Public key to free.
*/
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
@@ -49,7 +49,7 @@ START_TEST(check_privatekey) {
r = lq_crypto_init();
ck_assert_int_eq(r, 0);
- pk = lq_privatekey_new(privkeydata, 32, NULL, 0);
+ pk = lq_privatekey_new(privkeydata, LQ_PRIVKEY_LEN, NULL, 0);
ck_assert_ptr_nonnull(pk);
lq_privatekey_free(pk);
}
@@ -62,7 +62,7 @@ START_TEST(check_publickey) {
char *keydata;
char *keydata_manual;
- pk = lq_privatekey_new(privkeydata, 32, passphrase, 32);
+ pk = lq_privatekey_new(privkeydata, LQ_PRIVKEY_LEN, passphrase, 32);
pubk = lq_publickey_from_privatekey(pk);
lq_publickey_bytes(pubk, &keydata);
pubk_manual = lq_publickey_new(keydata);
@@ -82,8 +82,7 @@ START_TEST(check_signature) {
char *sigdata;
pk = lq_privatekey_new(privkeydata, 32, passphrase, 32);
- lq_digest(data, strlen(data), (char*)digest);
- sig = lq_privatekey_sign(pk, digest, 32, salt);
+ sig = lq_privatekey_sign(pk, data, strlen(data), salt);
ck_assert_ptr_null(sig);
r = lq_privatekey_unlock(pk, passphrase, 32);
@@ -100,6 +99,29 @@ START_TEST(check_signature) {
}
END_TEST
+START_TEST(check_verify) {
+ char r;
+ LQPrivKey *pk;
+ LQSig *sig;
+ char *sigdata;
+
+ pk = lq_privatekey_new(privkeydata, LQ_PRIVKEY_LEN, passphrase, 32);
+ sig = lq_privatekey_sign(pk, data, strlen(data), salt);
+ ck_assert_ptr_null(sig);
+
+ r = lq_privatekey_unlock(pk, passphrase, 32);
+ ck_assert_int_eq(r, 0);
+
+ sig = lq_privatekey_sign(pk, data, strlen(data), salt);
+ ck_assert_ptr_nonnull(sig);
+
+ r = lq_signature_verify(sig, data, strlen(data));
+
+ lq_signature_free(sig);
+ lq_privatekey_free(pk);
+}
+END_TEST
+
Suite * common_suite(void) {
Suite *s;
TCase *tc;
@@ -110,6 +132,7 @@ Suite * common_suite(void) {
tcase_add_test(tc, check_privatekey);
tcase_add_test(tc, check_publickey);
tcase_add_test(tc, check_signature);
+ tcase_add_test(tc, check_verify);
suite_add_tcase(s, tc);
return s;