Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libjcat for openSUSE:Factory checked in at 2024-10-22 14:51:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libjcat (Old) and /work/SRC/openSUSE:Factory/.libjcat.new.26871 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libjcat" Tue Oct 22 14:51:05 2024 rev:15 rq:1216604 version:0.2.2 Changes: -------- --- /work/SRC/openSUSE:Factory/libjcat/libjcat.changes 2024-01-30 18:23:54.918695703 +0100 +++ /work/SRC/openSUSE:Factory/.libjcat.new.26871/libjcat.changes 2024-10-22 14:51:14.643700490 +0200 @@ -1,0 +2,12 @@ +Mon Oct 14 13:09:54 UTC 2024 - Dominique Leuenberger <dims...@opensuse.org> + +- Update to version 0.2.2: + + New Features: + - Add bt-logindex blob kind. + + Bugfixes: + - Increase test coverage for ED25519 support. + - Save the auto-generated private key with 0600 file + permissions. + - Switch ED25519 support to not directly using Nettle. + +------------------------------------------------------------------- Old: ---- libjcat-0.2.1.tar.gz New: ---- libjcat-0.2.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libjcat.spec ++++++ --- /var/tmp/diff_new_pack.lA9uAz/_old 2024-10-22 14:51:16.003757387 +0200 +++ /var/tmp/diff_new_pack.lA9uAz/_new 2024-10-22 14:51:16.007757554 +0200 @@ -19,7 +19,7 @@ %define sover 1 Name: libjcat -Version: 0.2.1 +Version: 0.2.2 Release: 0 Summary: Library for reading and writing gzip-compressed JSON catalog files License: LGPL-2.1-or-later ++++++ libjcat-0.2.1.tar.gz -> libjcat-0.2.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/.github/dependabot.yml new/libjcat-0.2.2/.github/dependabot.yml --- old/libjcat-0.2.1/.github/dependabot.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/libjcat-0.2.2/.github/dependabot.yml 2024-10-14 14:40:12.000000000 +0200 @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/.github/workflows/ccpp.yml new/libjcat-0.2.2/.github/workflows/ccpp.yml --- old/libjcat-0.2.1/.github/workflows/ccpp.yml 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/.github/workflows/ccpp.yml 2024-10-14 14:40:12.000000000 +0200 @@ -10,8 +10,8 @@ gcc: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v4.2.1 + - uses: actions/setup-python@v5 - name: deps run: | sudo apt-get update @@ -36,20 +36,3 @@ setup-options: -Db_coverage=false options: --verbose meson-version: 0.56.0 - - build-freebsd: - runs-on: macos-12 - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Build - id: test - uses: vmactions/freebsd-vm@v0.3.1 - with: - usesh: true - mem: 8192 - prepare: | - pkg install -y git python3 glib meson pkgconf gobject-introspection \ - json-glib gnutls gtk-doc vala - sync: rsync - run: ./contrib/ci/build-debian.sh -Dgpg=false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/.github/workflows/scorecard.yml new/libjcat-0.2.2/.github/workflows/scorecard.yml --- old/libjcat-0.2.1/.github/workflows/scorecard.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/libjcat-0.2.2/.github/workflows/scorecard.yml 2024-10-14 14:40:12.000000000 +0200 @@ -0,0 +1,73 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '43 15 * * 5' + push: + branches: [ "main" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + # Uncomment the permissions below if installing in a private repository. + # contents: read + # actions: read + + steps: + - name: "Checkout code" + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecard on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard (optional). + # Commenting out will disable upload of results to your repo's Code Scanning dashboard + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 + with: + sarif_file: results.sarif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/NEWS new/libjcat-0.2.2/NEWS --- old/libjcat-0.2.1/NEWS 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/NEWS 2024-10-14 14:40:12.000000000 +0200 @@ -1,3 +1,15 @@ +Version 0.2.2 +~~~~~~~~~~~~~ +Released: 2024-10-14 + +New Features: + - Add bt-logindex blob kind (Richard Hughes) + +Bugfixes: + - Increase test coverage for ED25519 support (Daiki Ueno) + - Save the auto-generated private key with 0600 file permissions (Richard Hughes) + - Switch ED25519 support to not directly using Nettle (Daiki Ueno) + Version 0.2.1 ~~~~~~~~~~~~~ Released: 2024-01-20 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/RELEASE new/libjcat-0.2.2/RELEASE --- old/libjcat-0.2.1/RELEASE 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/RELEASE 2024-10-14 14:40:12.000000000 +0200 @@ -2,9 +2,9 @@ 1. Write NEWS entries for libjcat in the same format as usual. -git shortlog 0.2.0.. | grep -i -v trivial | grep -v Merge > NEWS.new +git shortlog 0.2.1.. | grep -i -v trivial | grep -v Merge > NEWS.new -Version 0.2.1 +Version 0.2.2 ~~~~~~~~~~~~~ Released: 2024-xx-xx @@ -15,7 +15,7 @@ Commit changes to git: # MAKE SURE THESE ARE CORRECT -export release_ver="0.2.1" +export release_ver="0.2.2" git commit -a -m "Release libjcat ${release_ver}" git tag -s -f -m "Release libjcat ${release_ver}" "${release_ver}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/SECURITY.md new/libjcat-0.2.2/SECURITY.md --- old/libjcat-0.2.1/SECURITY.md 1970-01-01 01:00:00.000000000 +0100 +++ new/libjcat-0.2.2/SECURITY.md 2024-10-14 14:40:12.000000000 +0200 @@ -0,0 +1,12 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 0.2.x | :white_check_mark: | +| 0.1.x | :x: | + +## Reporting a Vulnerability + +We have enabled private reporting in GitHub, so please [follow these steps](https://github.com/hughsie/libjcat/security) to report vulnerabilities. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/libjcat/jcat-blob.c new/libjcat-0.2.2/libjcat/jcat-blob.c --- old/libjcat-0.2.1/libjcat/jcat-blob.c 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/libjcat/jcat-blob.c 2024-10-14 14:40:12.000000000 +0200 @@ -80,6 +80,8 @@ return JCAT_BLOB_KIND_ED25519; if (g_strcmp0(kind, "sha512") == 0) return JCAT_BLOB_KIND_SHA512; + if (g_strcmp0(kind, "bt-logindex") == 0) + return JCAT_BLOB_KIND_BT_LOGINDEX; return JCAT_BLOB_KIND_UNKNOWN; } @@ -116,6 +118,8 @@ return "ed25519"; if (kind == JCAT_BLOB_KIND_SHA512) return "sha512"; + if (kind == JCAT_BLOB_KIND_BT_LOGINDEX) + return "bt-logindex"; return NULL; } @@ -152,6 +156,8 @@ return "ed25519"; if (kind == JCAT_BLOB_KIND_SHA512) return "sha512"; + if (kind == JCAT_BLOB_KIND_BT_LOGINDEX) + return "btlogindex"; return NULL; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/libjcat/jcat-blob.h new/libjcat-0.2.2/libjcat/jcat-blob.h --- old/libjcat-0.2.1/libjcat/jcat-blob.h 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/libjcat/jcat-blob.h 2024-10-14 14:40:12.000000000 +0200 @@ -25,6 +25,7 @@ * @JCAT_BLOB_KIND_BT_VERIFIER: Binary transparency verifier * @JCAT_BLOB_KIND_ED25519: ED25519 signature * @JCAT_BLOB_KIND_SHA512: SHA-512 checksum + * @JCAT_BLOB_KIND_BT_LOGINDEX: Binary transparency log index * * The kind of blob stored as a signature on the item. **/ @@ -40,6 +41,7 @@ JCAT_BLOB_KIND_BT_VERIFIER, /* Since: 0.1.9 */ JCAT_BLOB_KIND_ED25519, /* Since: 0.1.9 */ JCAT_BLOB_KIND_SHA512, /* Since: 0.1.13 */ + JCAT_BLOB_KIND_BT_LOGINDEX, /* Since: 0.2.2 */ /*< private >*/ JCAT_BLOB_KIND_LAST } JcatBlobKind; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/libjcat/jcat-common-private.h new/libjcat-0.2.2/libjcat/jcat-common-private.h --- old/libjcat-0.2.1/libjcat/jcat-common-private.h 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/libjcat/jcat-common-private.h 2024-10-14 14:40:12.000000000 +0200 @@ -15,7 +15,7 @@ gboolean jcat_mkdir_parent(const gchar *filename, GError **error) G_GNUC_NON_NULL(1); gboolean -jcat_set_contents_bytes(const gchar *filename, GBytes *bytes, GError **error) G_GNUC_NON_NULL(1, 2); +jcat_set_contents_bytes(const gchar *filename, GBytes *bytes, gint mode, GError **error) G_GNUC_NON_NULL(1, 2); GBytes * jcat_get_contents_bytes(const gchar *filename, GError **error) G_GNUC_NON_NULL(1); void diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/libjcat/jcat-common.c new/libjcat-0.2.2/libjcat/jcat-common.c --- old/libjcat-0.2.1/libjcat/jcat-common.c 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/libjcat/jcat-common.c 2024-10-14 14:40:12.000000000 +0200 @@ -25,7 +25,7 @@ /* private */ gboolean -jcat_set_contents_bytes(const gchar *filename, GBytes *bytes, GError **error) +jcat_set_contents_bytes(const gchar *filename, GBytes *bytes, gint mode, GError **error) { const gchar *data; gsize size; @@ -40,7 +40,16 @@ } data = g_bytes_get_data(bytes, &size); g_debug("writing %s with %" G_GSIZE_FORMAT " bytes", filename, size); +#if GLIB_CHECK_VERSION(2,66,0) + return g_file_set_contents_full(filename, + data, + size, + G_FILE_SET_CONTENTS_CONSISTENT, + mode, + error); +#else return g_file_set_contents(filename, data, size, error); +#endif } /* private */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/libjcat/jcat-ed25519-engine.c new/libjcat-0.2.2/libjcat/jcat-ed25519-engine.c --- old/libjcat-0.2.1/libjcat/jcat-ed25519-engine.c 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/libjcat/jcat-ed25519-engine.c 2024-10-14 14:40:12.000000000 +0200 @@ -6,8 +6,9 @@ #include "config.h" +#include <gnutls/abstract.h> #include <gnutls/crypto.h> -#include <nettle/eddsa.h> +#include <gnutls/gnutls.h> #include <string.h> #include "jcat-common-private.h" @@ -16,51 +17,105 @@ struct _JcatEd25519Engine { JcatEngine parent_instance; - GPtrArray *pubkeys; /* of Ed25519Key */ + GPtrArray *pubkeys; /* of gnutls_pubkey_t */ }; -typedef unsigned char Ed25519Key[ED25519_KEY_SIZE]; -typedef unsigned char Ed25519Sig[ED25519_SIGNATURE_SIZE]; - G_DEFINE_TYPE(JcatEd25519Engine, jcat_ed25519_engine, JCAT_TYPE_ENGINE) +static void +jcat_ed25519_datum_clear(gnutls_datum_t *data) +{ + gnutls_free(data->data); +} + +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pubkey_t, gnutls_pubkey_deinit, NULL) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_privkey_t, gnutls_privkey_deinit, NULL) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(gnutls_datum_t, jcat_ed25519_datum_clear) + static GBytes * -jcat_ed25519_sig_to_bytes(const Ed25519Sig privkey) +jcat_ed25519_pubkey_to_bytes(const gnutls_pubkey_t pubkey, GError **error) { - return g_bytes_new(privkey, sizeof(Ed25519Sig)); + gint rc; + g_auto(gnutls_datum_t) x = {NULL, 0}; + + rc = gnutls_pubkey_export_ecc_raw(pubkey, NULL, &x, NULL); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to export pubkey: %s", + gnutls_strerror(rc)); + return NULL; + } + return g_bytes_new(x.data, x.size); } static gboolean -jcat_ed25519_sig_from_bytes(GBytes *blob, Ed25519Sig privkey, GError **error) +jcat_ed25519_pubkey_from_bytes(GBytes *blob, gnutls_pubkey_t pubkey, GError **error) { - if (g_bytes_get_size(blob) != sizeof(Ed25519Sig)) { - g_set_error_literal(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid privkey size"); + gint rc; + gnutls_datum_t x = {NULL, 0}; + + x.data = g_bytes_get_data(blob, NULL); + x.size = g_bytes_get_size(blob); + + rc = gnutls_pubkey_import_ecc_raw(pubkey, GNUTLS_ECC_CURVE_ED25519, &x, NULL); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to import pubkey: %s", + gnutls_strerror(rc)); return FALSE; } - memcpy(privkey, g_bytes_get_data(blob, NULL), sizeof(Ed25519Sig)); + return TRUE; } static GBytes * -jcat_ed25519_key_to_bytes(const Ed25519Key pubkey) +jcat_ed25519_privkey_to_bytes(const gnutls_privkey_t privkey, GError **error) { - return g_bytes_new(pubkey, sizeof(Ed25519Key)); + gint rc; + g_auto(gnutls_datum_t) k = {NULL, 0}; + + rc = gnutls_privkey_export_ecc_raw2(privkey, NULL, NULL, NULL, &k, 0); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to export pubkey: %s", + gnutls_strerror(rc)); + return NULL; + } + return g_bytes_new(k.data, k.size); } static gboolean -jcat_ed25519_key_from_bytes(GBytes *blob, Ed25519Key pubkey, GError **error) +jcat_ed25519_privkey_from_bytes(GBytes *blob_public, + GBytes *blob_privkey, + gnutls_privkey_t privkey, + GError **error) { - if (g_bytes_get_size(blob) != sizeof(Ed25519Key)) { - g_set_error_literal(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid pubkey size"); + gint rc; + gnutls_datum_t x = {NULL, 0}; + gnutls_datum_t k = {NULL, 0}; + + x.data = g_bytes_get_data(blob_public, NULL); + x.size = g_bytes_get_size(blob_public); + + k.data = g_bytes_get_data(blob_privkey, NULL); + k.size = g_bytes_get_size(blob_privkey); + + rc = gnutls_privkey_import_ecc_raw(privkey, GNUTLS_ECC_CURVE_ED25519, &x, NULL, &k); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to import privkey: %s", + gnutls_strerror(rc)); return FALSE; } - memcpy(pubkey, g_bytes_get_data(blob, NULL), sizeof(Ed25519Key)); + return TRUE; } @@ -68,9 +123,22 @@ jcat_ed25519_engine_add_public_key_raw(JcatEngine *engine, GBytes *blob, GError **error) { JcatEd25519Engine *self = JCAT_ED25519_ENGINE(engine); - g_autofree Ed25519Key *pubkey = g_new0(Ed25519Key, 1); - if (!jcat_ed25519_key_from_bytes(blob, *pubkey, error)) + gint rc; + g_auto(gnutls_pubkey_t) pubkey = NULL; + + rc = gnutls_pubkey_init(&pubkey); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to allocate pubkey: %s", + gnutls_strerror(rc)); return FALSE; + } + + if (!jcat_ed25519_pubkey_from_bytes(blob, pubkey, error)) + return FALSE; + g_ptr_array_add(self->pubkeys, g_steal_pointer(&pubkey)); return TRUE; } @@ -98,25 +166,27 @@ GError **error) { JcatEd25519Engine *self = JCAT_ED25519_ENGINE(engine); - Ed25519Sig sig = {0}; /* sanity check */ if (self->pubkeys->len == 0) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "no keys in keyring"); return NULL; } - if (!jcat_ed25519_sig_from_bytes(blob_signature, sig, error)) - return NULL; /* verifies against any of the public keys */ for (guint i = 0; i < self->pubkeys->len; i++) { - Ed25519Key *pubkey = g_ptr_array_index(self->pubkeys, i); - if (ed25519_sha512_verify(*pubkey, - g_bytes_get_size(blob), - g_bytes_get_data(blob, NULL), - sig) != 0) { + gint rc; + gnutls_pubkey_t pubkey = g_ptr_array_index(self->pubkeys, i); + gnutls_datum_t data = {NULL, 0}; + gnutls_datum_t sig = {NULL, 0}; + + data.data = g_bytes_get_data(blob, NULL); + data.size = g_bytes_get_size(blob); + sig.data = g_bytes_get_data(blob_signature, NULL); + sig.size = g_bytes_get_size(blob_signature); + rc = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_EDDSA_ED25519, 0, &data, &sig); + if (rc == GNUTLS_E_SUCCESS) return JCAT_RESULT(g_object_new(JCAT_TYPE_RESULT, "engine", engine, NULL)); - } } /* nothing found */ @@ -132,10 +202,12 @@ JcatSignFlags flags, GError **error) { - Ed25519Key pubkey = {0}; - Ed25519Sig privkey = {0}; - Ed25519Sig sig = {0}; + gint rc; + gnutls_datum_t data = {NULL, 0}; g_autoptr(GBytes) blob_sig = NULL; + g_auto(gnutls_pubkey_t) pubkey = NULL; + g_auto(gnutls_privkey_t) privkey = NULL; + g_auto(gnutls_datum_t) sig = {NULL, 0}; /* nothing to do */ if (g_bytes_get_size(blob) == 0) { @@ -144,18 +216,31 @@ } /* load */ - if (!jcat_ed25519_sig_from_bytes(blob_privkey, privkey, error)) + rc = gnutls_privkey_init(&privkey); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to allocate privkey: %s", + gnutls_strerror(rc)); return NULL; - if (!jcat_ed25519_key_from_bytes(blob_cert, pubkey, error)) + } + if (!jcat_ed25519_privkey_from_bytes(blob_cert, blob_privkey, privkey, error)) return NULL; - /* simple */ - ed25519_sha512_sign(pubkey, - privkey, - g_bytes_get_size(blob), - g_bytes_get_data(blob, NULL), - sig); - blob_sig = jcat_ed25519_sig_to_bytes(sig); + /* sign */ + data.data = g_bytes_get_data(blob, NULL); + data.size = g_bytes_get_size(blob); + rc = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_EDDSA_ED25519, 0, &data, &sig); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to sign data: %s", + gnutls_strerror(rc)); + return NULL; + } + blob_sig = g_bytes_new(sig.data, sig.size); return jcat_blob_new(JCAT_BLOB_KIND_ED25519, blob_sig); } @@ -166,28 +251,41 @@ JcatVerifyFlags flags, GError **error) { - Ed25519Key pubkey = {0}; - Ed25519Sig sig = {0}; + gint rc; + gnutls_datum_t data = {NULL, 0}; + gnutls_datum_t sig = {NULL, 0}; const gchar *keyring_path = jcat_engine_get_keyring_path(engine); g_autofree gchar *fn_pubkey = NULL; g_autoptr(GBytes) blob_pubkey = NULL; + g_auto(gnutls_pubkey_t) pubkey = NULL; fn_pubkey = g_build_filename(keyring_path, "pki", "public.ed25519", NULL); blob_pubkey = jcat_get_contents_bytes(fn_pubkey, error); if (blob_pubkey == NULL) return NULL; - if (!jcat_ed25519_key_from_bytes(blob_pubkey, pubkey, error)) + rc = gnutls_pubkey_init(&pubkey); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to allocate pubkey: %s", + gnutls_strerror(rc)); return NULL; - if (!jcat_ed25519_sig_from_bytes(blob_signature, sig, error)) + } + if (!jcat_ed25519_pubkey_from_bytes(blob_pubkey, pubkey, error)) return NULL; - if (ed25519_sha512_verify(pubkey, - g_bytes_get_size(blob), - g_bytes_get_data(blob, NULL), - sig) == 0) { - g_set_error_literal(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "failed to verify data"); + + data.data = g_bytes_get_data(blob, NULL); + data.size = g_bytes_get_size(blob); + sig.data = g_bytes_get_data(blob_signature, NULL); + sig.size = g_bytes_get_size(blob_signature); + rc = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_EDDSA_ED25519, 0, &data, &sig); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "failed to verify data: %s", + gnutls_strerror(rc)); return NULL; } @@ -198,24 +296,43 @@ static JcatBlob * jcat_ed25519_engine_self_sign(JcatEngine *engine, GBytes *blob, JcatSignFlags flags, GError **error) { - Ed25519Key pubkey = {0}; - Ed25519Sig privkey = {0}; - Ed25519Sig sig = {0}; + gint rc; + gnutls_datum_t data = {NULL, 0}; const gchar *keyring_path = jcat_engine_get_keyring_path(engine); g_autofree gchar *fn_privkey = NULL; g_autofree gchar *fn_pubkey = NULL; g_autoptr(GBytes) blob_privkey = NULL; g_autoptr(GBytes) blob_pubkey = NULL; + g_auto(gnutls_pubkey_t) pubkey = NULL; + g_auto(gnutls_privkey_t) privkey = NULL; g_autoptr(GBytes) blob_sig = NULL; + g_auto(gnutls_datum_t) sig = {NULL, 0}; + + rc = gnutls_privkey_init(&privkey); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to allocate privkey: %s", + gnutls_strerror(rc)); + return NULL; + } + + rc = gnutls_pubkey_init(&pubkey); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to allocate pubkey: %s", + gnutls_strerror(rc)); + return NULL; + } /* check keypair exists, otherwise generate and save */ fn_privkey = g_build_filename(keyring_path, "pki", "secret.ed25519", NULL); fn_pubkey = g_build_filename(keyring_path, "pki", "public.ed25519", NULL); if (!g_file_test(fn_privkey, G_FILE_TEST_EXISTS)) { - gint rc; - - /* randomize contents */ - rc = gnutls_rnd(GNUTLS_RND_KEY, privkey, sizeof(Ed25519Sig)); + rc = gnutls_privkey_generate2(privkey, GNUTLS_PK_EDDSA_ED25519, 0, 0, NULL, 0); if (rc < 0) { g_set_error(error, G_IO_ERROR, @@ -225,35 +342,52 @@ rc); return NULL; } - ed25519_sha512_public_key(pubkey, privkey); + rc = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to import pubkey from privkey: %s", + gnutls_strerror(rc)); + return NULL; + } if (!jcat_mkdir_parent(fn_privkey, error)) return NULL; - blob_privkey = jcat_ed25519_sig_to_bytes(privkey); - if (!jcat_set_contents_bytes(fn_privkey, blob_privkey, error)) + blob_pubkey = jcat_ed25519_pubkey_to_bytes(pubkey, error); + if (!blob_pubkey) return NULL; - blob_pubkey = jcat_ed25519_key_to_bytes(pubkey); - if (!jcat_set_contents_bytes(fn_pubkey, blob_pubkey, error)) + if (!jcat_set_contents_bytes(fn_pubkey, blob_pubkey, 0666, error)) return NULL; - } else { - blob_privkey = jcat_get_contents_bytes(fn_privkey, error); - if (blob_privkey == NULL) + blob_privkey = jcat_ed25519_privkey_to_bytes(privkey, error); + if (!blob_privkey) return NULL; - if (!jcat_ed25519_sig_from_bytes(blob_privkey, privkey, error)) + if (!jcat_set_contents_bytes(fn_privkey, blob_privkey, 0600, error)) return NULL; + } else { blob_pubkey = jcat_get_contents_bytes(fn_pubkey, error); if (blob_pubkey == NULL) return NULL; - if (!jcat_ed25519_key_from_bytes(blob_pubkey, pubkey, error)) + if (!jcat_ed25519_pubkey_from_bytes(blob_pubkey, pubkey, error)) + return NULL; + blob_privkey = jcat_get_contents_bytes(fn_privkey, error); + if (blob_privkey == NULL) + return NULL; + if (!jcat_ed25519_privkey_from_bytes(blob_pubkey, blob_privkey, privkey, error)) return NULL; } - /* simple */ - ed25519_sha512_sign(pubkey, - privkey, - g_bytes_get_size(blob), - g_bytes_get_data(blob, NULL), - sig); - blob_sig = jcat_ed25519_sig_to_bytes(sig); + data.data = g_bytes_get_data(blob, NULL); + data.size = g_bytes_get_size(blob); + rc = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_EDDSA_ED25519, 0, &data, &sig); + if (rc < 0) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unable to sign data: %s", + gnutls_strerror(rc)); + return NULL; + } + blob_sig = g_bytes_new(sig.data, sig.size); return jcat_blob_new(JCAT_BLOB_KIND_ED25519, blob_sig); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/libjcat/jcat-pkcs7-engine.c new/libjcat-0.2.2/libjcat/jcat-pkcs7-engine.c --- old/libjcat-0.2.1/libjcat/jcat-pkcs7-engine.c 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/libjcat/jcat-pkcs7-engine.c 2024-10-14 14:40:12.000000000 +0200 @@ -418,7 +418,7 @@ return NULL; if (!jcat_mkdir_parent(fn_privkey, error)) return NULL; - if (!jcat_set_contents_bytes(fn_privkey, privkey, error)) + if (!jcat_set_contents_bytes(fn_privkey, privkey, 0600, error)) return NULL; } @@ -438,7 +438,7 @@ return NULL; if (!jcat_mkdir_parent(fn_cert, error)) return NULL; - if (!jcat_set_contents_bytes(fn_cert, cert, error)) + if (!jcat_set_contents_bytes(fn_cert, cert, 0666, error)) return NULL; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/libjcat/jcat-self-test.c new/libjcat-0.2.2/libjcat/jcat-self-test.c --- old/libjcat-0.2.1/libjcat/jcat-self-test.c 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/libjcat/jcat-self-test.c 2024-10-14 14:40:12.000000000 +0200 @@ -644,12 +644,9 @@ { #ifdef ENABLE_ED25519 static const char payload_str[] = "Hello, world!"; - g_autofree gchar *str = NULL; - g_autoptr(JcatBlob) signature = NULL; + g_autofree gchar *tmp_dir = NULL; g_autoptr(JcatContext) context = jcat_context_new(); g_autoptr(JcatEngine) engine = NULL; - g_autoptr(JcatEngine) engine2 = NULL; - g_autoptr(JcatResult) result = NULL; g_autoptr(GBytes) payload = NULL; g_autoptr(GError) error = NULL; const gchar *str_perfect = "JcatResult:\n" @@ -659,7 +656,9 @@ " VerifyKind: signature\n"; /* set up context */ - jcat_context_set_keyring_path(context, "/tmp"); + tmp_dir = g_dir_make_tmp(NULL, &error); + g_assert_no_error(error); + jcat_context_set_keyring_path(context, tmp_dir); /* get engine */ engine = jcat_context_get_engine(context, JCAT_BLOB_KIND_ED25519, &error); @@ -668,26 +667,39 @@ payload = g_bytes_new_static(payload_str, sizeof(payload_str)); g_assert_nonnull(payload); - signature = jcat_engine_self_sign(engine, payload, JCAT_SIGN_FLAG_ADD_TIMESTAMP, &error); - g_assert_no_error(error); - g_assert_nonnull(signature); - result = jcat_engine_self_verify(engine, - payload, - jcat_blob_get_data(signature), - JCAT_VERIFY_FLAG_NONE, - &error); - g_assert_no_error(error); - g_assert_nonnull(result); - /* verify engine set */ - engine2 = jcat_result_get_engine(result); - g_assert(engine == engine2); - - /* to string */ - g_object_set(result, "timestamp", (gint64)12345, NULL); - str = jcat_result_to_string(result); - g_print("%s", str); - g_assert_cmpstr(str, ==, str_perfect); + /* do signing and verification twice: first with no keys exist + * (thus new keys are generated), secondly with keys already + * exist. */ + for (gsize i = 0; i < 2; i++) { + g_autofree gchar *str = NULL; + g_autoptr(JcatBlob) signature = NULL; + g_autoptr(JcatEngine) engine2 = NULL; + g_autoptr(JcatResult) result = NULL; + g_autoptr(JcatResult) result2 = NULL; + + signature = + jcat_engine_self_sign(engine, payload, JCAT_SIGN_FLAG_ADD_TIMESTAMP, &error); + g_assert_no_error(error); + g_assert_nonnull(signature); + result = jcat_engine_self_verify(engine, + payload, + jcat_blob_get_data(signature), + JCAT_VERIFY_FLAG_NONE, + &error); + g_assert_no_error(error); + g_assert_nonnull(result); + + /* verify engine set */ + engine2 = jcat_result_get_engine(result); + g_assert(engine == engine2); + + /* to string */ + g_object_set(result, "timestamp", (gint64)12345, NULL); + str = jcat_result_to_string(result); + g_print("%s", str); + g_assert_cmpstr(str, ==, str_perfect); + } #else g_test_skip("no GnuTLS support enabled"); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/libjcat/jcat-tool.c new/libjcat-0.2.2/libjcat/jcat-tool.c --- old/libjcat-0.2.1/libjcat/jcat-tool.c 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/libjcat/jcat-tool.c 2024-10-14 14:40:12.000000000 +0200 @@ -319,6 +319,10 @@ blob = jcat_blob_new_full(JCAT_BLOB_KIND_BT_VERIFIER, data_sig, JCAT_BLOB_FLAG_IS_UTF8); + } else if (g_str_has_suffix(values[2], ".btlogindex")) { + blob = jcat_blob_new_full(JCAT_BLOB_KIND_BT_LOGINDEX, + data_sig, + JCAT_BLOB_FLAG_IS_UTF8); } else if (g_str_has_suffix(values[2], ".p7b") || g_str_has_suffix(values[2], ".p7c") || g_str_has_suffix(values[2], ".pem")) { blob = jcat_blob_new_full(JCAT_BLOB_KIND_PKCS7, data_sig, JCAT_BLOB_FLAG_IS_UTF8); @@ -672,7 +676,7 @@ ".%s", jcat_blob_kind_to_filename_ext(jcat_blob_get_kind(blob))); fn = g_build_filename(priv->prefix, str->str, NULL); - if (!jcat_set_contents_bytes(fn, jcat_blob_get_data(blob), error)) + if (!jcat_set_contents_bytes(fn, jcat_blob_get_data(blob), 0666, error)) return FALSE; g_print("Wrote %s\n", fn); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libjcat-0.2.1/meson.build new/libjcat-0.2.2/meson.build --- old/libjcat-0.2.1/meson.build 2024-01-20 16:28:52.000000000 +0100 +++ new/libjcat-0.2.2/meson.build 2024-10-14 14:40:12.000000000 +0200 @@ -1,5 +1,5 @@ project('libjcat', 'c', - version : '0.2.1', + version : '0.2.2', license : 'LGPL-2.1+', meson_version : '>=0.56.0', default_options : ['warning_level=2', 'c_std=c99'], @@ -144,7 +144,6 @@ if get_option('ed25519') conf.set('ENABLE_ED25519', '1') - libjcat_deps += dependency('hogweed') libjcat_deps += dependency('gnutls') endif