Script 'mail_helper' called by obssrc Hello community,
here is the log from the commit of package otpclient for openSUSE:Factory checked in at 2022-12-30 11:08:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/otpclient (Old) and /work/SRC/openSUSE:Factory/.otpclient.new.1563 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "otpclient"
Fri Dec 30 11:08:53 2022 rev:21 rq:1045797 version:3.1.1
Changes: -------- --- /work/SRC/openSUSE:Factory/otpclient/otpclient.changes 2022-12-20 20:21:03.782067662 +0100 +++ /work/SRC/openSUSE:Factory/.otpclient.new.1563/otpclient.changes 2022-12-30 11:09:08.201318769 +0100 @@ -1,0 +2,8 @@ +Fri Dec 30 07:06:40 UTC 2022 - Paolo Stivanin info@paolostivanin.com + +- Update to 3.1.1: + * Fixed some memory leaks. + * Improved error handling. + * Use secure functions instead of standard ones . + +-------------------------------------------------------------------
Old: ---- v3.1.0.tar.gz v3.1.0.tar.gz.asc
New: ---- v3.1.1.tar.gz v3.1.1.tar.gz.asc
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences: ------------------ ++++++ otpclient.spec ++++++ --- /var/tmp/diff_new_pack.huiRqu/_old 2022-12-30 11:09:08.609321208 +0100 +++ /var/tmp/diff_new_pack.huiRqu/_new 2022-12-30 11:09:08.613321232 +0100 @@ -18,7 +18,7 @@
%define uclname OTPClient Name: otpclient -Version: 3.1.0 +Version: 3.1.1 Release: 0 Summary: Simple GTK+ client for managing TOTP and HOTP License: GPL-3.0-or-later
++++++ v3.1.0.tar.gz -> v3.1.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/.github/workflows/codeql-analysis.yml new/OTPClient-3.1.1/.github/workflows/codeql-analysis.yml --- old/OTPClient-3.1.0/.github/workflows/codeql-analysis.yml 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/.github/workflows/codeql-analysis.yml 2022-12-28 17:02:45.000000000 +0100 @@ -24,7 +24,7 @@ uses: actions/checkout@v2
- name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }}
@@ -41,4 +41,4 @@ make
- name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/CMakeLists.txt new/OTPClient-3.1.1/CMakeLists.txt --- old/OTPClient-3.1.0/CMakeLists.txt 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/CMakeLists.txt 2022-12-28 17:02:45.000000000 +0100 @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(OTPClient VERSION "3.1.0" LANGUAGES "C") +project(OTPClient VERSION "3.1.1" LANGUAGES "C") include(GNUInstallDirs)
configure_file("src/common/version.h.in" "version.h") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/README.md new/OTPClient-3.1.1/README.md --- old/OTPClient-3.1.0/README.md 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/README.md 2022-12-28 17:02:45.000000000 +0100 @@ -2,6 +2,10 @@ <a href="https://circleci.com/gh/paolostivanin/OTPClient"> <img alt="CircleCI" src="https://circleci.com/gh/paolostivanin/OTPClient.svg?style=svg"/> </a> +<a href="https://scan.coverity.com/projects/paolostivanin-otpclient"> + <img alt="Coverity Scan Build Status" + src="https://scan.coverity.com/projects/12749/badge.svg"/> +</a>
Highly secure and easy to use GTK+ software for two-factor authentication that supports both Time-based One-time Passwords (TOTP) and HMAC-Based One-Time Passwords (HOTP).
@@ -42,7 +46,7 @@ - decrypted file is never saved (and hopefully never swapped) to disk. While the app is running, the decrypted content resides in a "secure memory" buffer allocated by Gcrypt
## Testing -* Before each release, I run PVS Studio in order to catch even more errors and/or corner cases +* Before each release, I run PVS Studio and Coverity in order to catch even more bugs. * With every commit to master, OTPClient is compiled in CircleCI against different distros
## Protobuf diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/data/com.github.paolostivanin.OTPClient.appdata.xml new/OTPClient-3.1.1/data/com.github.paolostivanin.OTPClient.appdata.xml --- old/OTPClient-3.1.0/data/com.github.paolostivanin.OTPClient.appdata.xml 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/data/com.github.paolostivanin.OTPClient.appdata.xml 2022-12-28 17:02:45.000000000 +0100 @@ -83,6 +83,16 @@ </content_rating>
<releases> + <release version="3.1.1" date="2022-12-29"> + <description> + <p>OTPClient 3.1.1 brings lots of small under-the-hood changes:</p> + <ul> + <li>Fixed some memory leaks</li> + <li>Improved error handling</li> + <li>Use secure functions instead of standard ones</li> + </ul> + </description> + </release> <release version="3.1.0" date="2022-12-19"> <description> <p>OTPClient 3.1.0 the following feature and fixes:</p> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/add-common.c new/OTPClient-3.1.1/src/add-common.c --- old/OTPClient-3.1.0/src/add-common.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/add-common.c 2022-12-28 17:02:45.000000000 +0100 @@ -47,6 +47,7 @@ if (otp->period < 10 || otp->period > 120) { gchar *msg = g_strconcat("[INFO]: invalid period for '", otp->account_name, "'. Defaulting back to 30 seconds.", NULL); g_printerr ("%s\n", msg); + g_free (msg); otp->period = 30; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/add-from-qr.c new/OTPClient-3.1.1/src/add-from-qr.c --- old/OTPClient-3.1.0/src/add-from-qr.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/add-from-qr.c 2022-12-28 17:02:45.000000000 +0100 @@ -1,6 +1,7 @@ #include <gtk/gtk.h> #include <gcrypt.h> #include <glib/gstdio.h> +#include <glib/gi18n.h> #include "imports.h" #include "qrcode-parser.h" #include "message-dialogs.h" @@ -169,7 +170,9 @@ gchar *filename = g_build_filename (g_get_tmp_dir (), "qrcode_from_cb_uri.png", NULL); gdk_pixbuf_save (pbuf, filename, "png", &err, NULL); parse_file_and_update_db (filename, app_data, FALSE); - g_unlink (filename); + if (g_unlink (filename) == -1) { + g_printerr ("%s\n", _("Couldn't unlink the temp pixbuf.")); + } g_free (filename); g_object_unref (pbuf); } @@ -196,7 +199,9 @@ } else { parse_file_and_update_db (filename, app_data, FALSE); } - g_unlink (filename); + if (g_unlink (filename) == -1) { + g_printerr ("%s\n", _("Error while unlinking the temp png.")); + } g_free (filename); } else { show_message_dialog (app_data->main_window, "Couldn't get QR code image from clipboard", GTK_MESSAGE_ERROR); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/app.c new/OTPClient-3.1.1/src/app.c --- old/OTPClient-3.1.0/src/app.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/app.c 2022-12-28 17:02:45.000000000 +0100 @@ -356,6 +356,7 @@ return kf; } g_printerr ("%s\n", err->message); + g_clear_error (&err); } g_free (cfg_file_path); g_key_file_free (kf); @@ -419,6 +420,7 @@ #endif if (!g_key_file_save_to_file (kf, cfg_file_path, &err)) { g_printerr ("%s\n", err->message); + g_clear_error (&err); } g_free (cfg_file_path); g_key_file_free (kf); @@ -492,9 +494,9 @@ #else cfg_file_path = g_build_filename (g_get_user_data_dir (), "otpclient.cfg", NULL); #endif - g_key_file_save_to_file (kf, cfg_file_path, &err); - if (err != NULL) { + if (!g_key_file_save_to_file (kf, cfg_file_path, &err)) { g_printerr ("%s\n", err->message); + g_clear_error (&err); } g_free (cfg_file_path); } @@ -568,9 +570,10 @@ if (!g_key_file_load_from_file (kf, cfg_file_path, G_KEY_FILE_NONE, &err)) { show_message_dialog (app_data->main_window, err->message, GTK_MESSAGE_ERROR); g_key_file_free (kf); + g_clear_error (&err); return NULL; } - db_path = g_key_file_get_string (kf, "config", "db_path", &err); + db_path = g_key_file_get_string (kf, "config", "db_path", NULL); if (db_path == NULL) { goto new_db; } @@ -601,9 +604,9 @@ if (res == GTK_RESPONSE_ACCEPT) { db_path = gtk_file_chooser_get_filename (chooser); g_key_file_set_string (kf, "config", "db_path", db_path); - g_key_file_save_to_file (kf, cfg_file_path, &err); - if (err != NULL) { + if (!g_key_file_save_to_file (kf, cfg_file_path, &err)) { g_printerr ("%s\n", err->message); + g_clear_error (&err); } }
@@ -764,11 +767,13 @@ if (g_file_test (cfg_file_path, G_FILE_TEST_EXISTS)) { if (!g_key_file_load_from_file (kf, cfg_file_path, G_KEY_FILE_NONE, &err)) { g_printerr ("%s\n", err->message); + g_clear_error (&err); } else { g_key_file_set_integer (kf, "config", param1_name, param1_value); g_key_file_set_integer (kf, "config", param2_name, param2_value); if (!g_key_file_save_to_file (kf, cfg_file_path, &err)) { g_printerr ("%s\n", err->message); + g_clear_error (&err); } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/change-file-cb.c new/OTPClient-3.1.1/src/change-file-cb.c --- old/OTPClient-3.1.0/src/change-file-cb.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/change-file-cb.c 2022-12-28 17:02:45.000000000 +0100 @@ -1,5 +1,7 @@ #include <gtk/gtk.h> +#include <glib/gi18n.h> #include "db-misc.h" +#include "message-dialogs.h"
gboolean change_file (AppData *app_data) @@ -40,7 +42,13 @@ cfg_file_path = g_build_filename (g_get_user_data_dir (), "otpclient.cfg", NULL); #endif g_key_file_set_string (kf, "config", "db_path", db_path); - g_key_file_save_to_file (kf, cfg_file_path, NULL); + GError *err = NULL; + if (!g_key_file_save_to_file (kf, cfg_file_path, &err)) { + gchar *err_msg = g_strconcat (_("Couldn't save the config file: "), err->message, NULL); + show_message_dialog (app_data->main_window, err_msg, GTK_MESSAGE_ERROR); + g_free (err_msg); + g_clear_error (&err); + } g_free (app_data->db_data->db_path); app_data->db_data->db_path = g_strdup (db_path); g_free (db_path); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/change-pwd-cb.c new/OTPClient-3.1.1/src/change-pwd-cb.c --- old/OTPClient-3.1.0/src/change-pwd-cb.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/change-pwd-cb.c 2022-12-28 17:02:45.000000000 +0100 @@ -27,6 +27,7 @@ GtkApplication *app = gtk_window_get_application (GTK_WINDOW(app_data->main_window)); destroy_cb (app_data->main_window, app_data); g_application_quit (G_APPLICATION(app)); + return; } show_message_dialog (app_data->main_window, "Password successfully changed", GTK_MESSAGE_INFO); secret_password_store (OTPCLIENT_SCHEMA, SECRET_COLLECTION_DEFAULT, "main_pwd", app_data->db_data->key, NULL, on_password_stored, NULL, "string", "main_pwd", NULL); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/cli/main.c new/OTPClient-3.1.1/src/cli/main.c --- old/OTPClient-3.1.0/src/cli/main.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/cli/main.c 2022-12-28 17:02:45.000000000 +0100 @@ -206,9 +206,10 @@ if (!g_key_file_load_from_file (kf, cfg_file_path, G_KEY_FILE_NONE, &err)) { g_printerr ("%s\n", err->message); g_key_file_free (kf); + g_clear_error (&err); return NULL; } - db_path = g_key_file_get_string (kf, "config", "db_path", &err); + db_path = g_key_file_get_string (kf, "config", "db_path", NULL); if (db_path == NULL) { goto type_db_path; } @@ -226,6 +227,7 @@ if (fgets (db_path, MAX_ABS_PATH_LEN, stdin) == NULL) { g_printerr ("%s\n", _("Couldn't get db path from stdin")); g_free (cfg_file_path); + g_free (db_path); return NULL; } else { // remove the newline char @@ -233,6 +235,7 @@ if (!g_file_test (db_path, G_FILE_TEST_EXISTS)) { g_printerr (_("File '%s' does not exist\n"), db_path); g_free (cfg_file_path); + g_free (db_path); return NULL; } } @@ -291,6 +294,7 @@ if (!g_key_file_load_from_file (kf, cfg_file_path, G_KEY_FILE_NONE, &err)) { g_printerr ("%s\n", err->message); g_key_file_free (kf); + g_clear_error (&err); return FALSE; } disable_secret_service = g_key_file_get_boolean (kf, "config", "disable_secret_service", NULL); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/common/aegis.c new/OTPClient-3.1.1/src/common/aegis.c --- old/OTPClient-3.1.0/src/common/aegis.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/common/aegis.c 2022-12-28 17:02:45.000000000 +0100 @@ -90,12 +90,25 @@ guchar *key_tag = hexstr_to_bytes (json_string_value (json_object_get (kp, "tag"))); json_t *dbp = json_object_get(json_object_get(json, "header"), "params"); guchar *keybuf = gcry_malloc (KEY_SIZE); - gcry_kdf_derive (password, strlen (password) + 1, GCRY_KDF_SCRYPT, n, salt, SALT_SIZE, p, KEY_SIZE, keybuf); + if (gcry_kdf_derive (password, strlen (password) + 1, GCRY_KDF_SCRYPT, n, salt, SALT_SIZE, p, KEY_SIZE, keybuf) != 0) { + g_printerr ("Error while deriving the key.\n"); + g_free (salt); + g_free (enc_key); + g_free (key_nonce); + g_free (key_tag); + gcry_free (keybuf); + return NULL; + }
- gcry_cipher_hd_t hd; - gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 0); - gcry_cipher_setkey (hd, keybuf, gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES256)); - gcry_cipher_setiv (hd, key_nonce, NONCE_SIZE); + gcry_cipher_hd_t hd = open_cipher_and_set_data (keybuf, key_nonce, NONCE_SIZE); + if (hd == NULL) { + g_free (salt); + g_free (enc_key); + g_free (key_nonce); + g_free (key_tag); + gcry_free (keybuf); + return NULL; + }
guchar *master_key = gcry_calloc_secure (KEY_SIZE, 1); if (gcry_cipher_decrypt (hd, master_key, KEY_SIZE, enc_key, KEY_SIZE) != 0) { @@ -104,8 +117,9 @@ g_free (enc_key); g_free (key_nonce); g_free (key_tag); - gcry_cipher_close (hd); gcry_free (master_key); + gcry_free (keybuf); + gcry_cipher_close (hd); return NULL; } gpg_error_t gpg_err = gcry_cipher_checktag(hd, key_tag, TAG_SIZE); @@ -115,8 +129,9 @@ g_free (enc_key); g_free (key_nonce); g_free (key_tag); - gcry_cipher_close (hd); gcry_free (master_key); + gcry_free (keybuf); + gcry_cipher_close (hd); return NULL; }
@@ -124,37 +139,55 @@ g_free (enc_key); g_free (key_nonce); g_free (key_tag); + gcry_free (keybuf); gcry_cipher_close (hd);
guchar *nonce = hexstr_to_bytes (json_string_value (json_object_get (dbp, "nonce"))); guchar *tag = hexstr_to_bytes (json_string_value (json_object_get (dbp, "tag"))); - gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 0); - gcry_cipher_setkey (hd, master_key, gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES256)); - gcry_cipher_setiv (hd, nonce, 12); + + hd = open_cipher_and_set_data (master_key, nonce, 12); + if (hd == NULL) { + g_free (tag); + g_free (nonce); + gcry_free (master_key); + return NULL; + } + gsize out_len; - guchar *b64decoded_db = g_base64_decode (json_string_value (json_object_get(json, "db")), &out_len); + guchar *b64decoded_db = g_base64_decode_secure (json_string_value (json_object_get(json, "db")), &out_len); if (out_len > max_file_size) { g_set_error (err, file_too_big_gquark (), FILE_TOO_BIG, "File is too big"); - gcry_cipher_close (hd); + g_free (tag); + g_free (nonce); gcry_free (master_key); + gcry_free (b64decoded_db); + gcry_cipher_close (hd); return NULL; } + gchar *decrypted_db = gcry_calloc_secure (out_len, 1); - gcry_cipher_decrypt (hd, decrypted_db, out_len, b64decoded_db, out_len); - gpg_err = gcry_cipher_checktag(hd, tag, TAG_SIZE); + gpg_err = gcry_cipher_decrypt (hd, decrypted_db, out_len, b64decoded_db, out_len); + if (gpg_err) { + goto clean_and_exit; + } + gpg_err = gcry_cipher_checktag (hd, tag, TAG_SIZE); if (gpg_err != 0) { g_set_error (err, bad_tag_gquark (), BAD_TAG_ERRCODE, "Invalid TAG (database). Either the password is wrong or the file is corrupted."); - gcry_cipher_close (hd); + clean_and_exit: + g_free (nonce); + g_free (tag); gcry_free (master_key); - g_free (decrypted_db); + gcry_free (decrypted_db); + gcry_free (b64decoded_db); + gcry_cipher_close (hd); return NULL; }
- g_free (b64decoded_db); g_free (nonce); g_free (tag); gcry_cipher_close (hd); gcry_free (master_key); + gcry_free (b64decoded_db);
GSList *otps = parse_json_data (decrypted_db, err); gcry_free (decrypted_db); @@ -173,7 +206,7 @@ json_object_set (root, "version", json_integer(1));
gcry_cipher_hd_t hd; - guchar *derived_master_key, *enc_master_key, *key_nonce, *key_tag, *db_nonce, *db_tag, *salt; + guchar *derived_master_key = NULL, *enc_master_key = NULL, *key_nonce = NULL, *key_tag = NULL, *db_nonce = NULL, *db_tag = NULL, *salt = NULL; json_t *aegis_header_obj = json_object (); if (password == NULL) { json_object_set (aegis_header_obj, "slots", json_null ()); @@ -198,18 +231,32 @@ gcry_create_nonce (key_nonce, NONCE_SIZE);
derived_master_key = gcry_calloc_secure(KEY_SIZE, 1); - gcry_kdf_derive (password, strlen (password) + 1, GCRY_KDF_SCRYPT, 32768, salt, SALT_SIZE, 1, KEY_SIZE, derived_master_key); - gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 0); - gcry_cipher_setkey (hd, derived_master_key, gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES256)); - gcry_cipher_setiv (hd, key_nonce, NONCE_SIZE); + gpg_error_t gpg_err = gcry_kdf_derive (password, strlen (password) + 1, GCRY_KDF_SCRYPT, 32768, salt, SALT_SIZE, 1, KEY_SIZE, derived_master_key); + if (gpg_err) { + g_printerr ("Error while deriving the key\n"); + gcry_free (derived_master_key); + return NULL; + } + + hd = open_cipher_and_set_data (derived_master_key, key_nonce, NONCE_SIZE); + if (hd == NULL) { + gcry_free (derived_master_key); + g_free (key_nonce); + g_free (salt); + return NULL; + } + enc_master_key = gcry_malloc (KEY_SIZE); if (gcry_cipher_encrypt (hd, enc_master_key, KEY_SIZE, derived_master_key, KEY_SIZE)) { g_printerr ("Error while encrypting the master key.\n"); gcry_free (derived_master_key); gcry_free (enc_master_key); + g_free (key_nonce); + g_free (salt); gcry_cipher_close (hd); return NULL; } + key_tag = g_malloc0 (TAG_SIZE); gcry_cipher_gettag (hd, key_tag, TAG_SIZE); json_object_set (slot_1, "key", json_string (bytes_to_hexstr (enc_master_key, KEY_SIZE))); @@ -282,9 +329,10 @@ }
if (password != NULL) { - gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 0); - gcry_cipher_setkey (hd, derived_master_key, gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES256)); - gcry_cipher_setiv (hd, db_nonce, NONCE_SIZE); + hd = open_cipher_and_set_data (derived_master_key, db_nonce, NONCE_SIZE); + if (hd == NULL) { + goto clean_and_return; + } size_t db_size = json_dumpb (aegis_db_obj, NULL, 0, 0); guchar *enc_db = g_malloc0 (db_size); gchar *dumped_db = g_malloc0 (db_size); @@ -292,7 +340,9 @@ if (gcry_cipher_encrypt (hd, enc_db, db_size, dumped_db, db_size)) { g_printerr ("Error while encrypting the db.\n"); g_free (enc_db); - gcry_free (dumped_db); + g_free (dumped_db); + gcry_cipher_close (hd); + clean_and_return: g_free (key_nonce); g_free (key_tag); g_free (db_nonce); @@ -305,7 +355,7 @@ gcry_cipher_gettag (hd, db_tag, TAG_SIZE); json_t *db_params = json_object_get (aegis_header_obj, "params"); json_object_set (db_params, "tag", json_string (bytes_to_hexstr (db_tag, TAG_SIZE))); - gcry_free (dumped_db); + g_free (dumped_db); gchar *b64enc_db = g_base64_encode (enc_db, db_size); json_object_set (root, "db", json_string (b64enc_db));
@@ -318,6 +368,7 @@ g_free (salt); gcry_free (derived_master_key); gcry_free (enc_master_key); + gcry_cipher_close (hd); }
FILE *fp = fopen (export_path, "w"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/common/andotp.c new/OTPClient-3.1.1/src/common/andotp.c --- old/OTPClient-3.1.0/src/common/andotp.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/common/andotp.c 2022-12-28 17:02:45.000000000 +0100 @@ -3,6 +3,7 @@ #include <gcrypt.h> #include <jansson.h> #include <time.h> +#include <glib/gi18n.h> #include "../file-size.h" #include "../imports.h" #include "../gquarks.h" @@ -114,8 +115,8 @@ g_set_error (err, file_too_big_gquark (), FILE_TOO_BIG, "File is too big"); return NULL; } - guchar *enc_buf = g_malloc0 (enc_buf_size);
+ guchar *enc_buf = g_malloc0 (enc_buf_size); if (!g_seekable_seek (G_SEEKABLE (in_stream), 4 + ANDOTP_SALT_SIZE + ANDOTP_IV_SIZE, G_SEEK_SET, NULL, err)) { g_object_unref (in_stream); g_object_unref (in_file); @@ -133,18 +134,28 @@
guchar *derived_key = get_derived_key (password, salt, be_iterations);
- gcry_cipher_hd_t hd; - gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, GCRY_CIPHER_SECURE); - gcry_cipher_setkey (hd, derived_key, gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES256)); - gcry_cipher_setiv (hd, iv, ANDOTP_IV_SIZE); + gcry_cipher_hd_t hd = open_cipher_and_set_data (derived_key, iv, ANDOTP_IV_SIZE); + if (hd == NULL) { + gcry_free (derived_key); + g_free (enc_buf); + return NULL; + }
gchar *decrypted_json = gcry_calloc_secure (enc_buf_size, 1); - gcry_cipher_decrypt (hd, decrypted_json, enc_buf_size, enc_buf, enc_buf_size); + gpg_error_t gpg_err = gcry_cipher_decrypt (hd, decrypted_json, enc_buf_size, enc_buf, enc_buf_size); + if (gpg_err) { + g_free (enc_buf); + gcry_free (derived_key); + gcry_free (decrypted_json); + gcry_cipher_close (hd); + return NULL; + } if (gcry_err_code (gcry_cipher_checktag (hd, tag, ANDOTP_TAG_SIZE)) == GPG_ERR_CHECKSUM) { g_set_error (err, bad_tag_gquark (), BAD_TAG_ERRCODE, "Either the file is corrupted or the password is wrong"); gcry_cipher_close (hd); - gcry_free (derived_key); g_free (enc_buf); + gcry_free (derived_key); + gcry_free (decrypted_json); return NULL; }
@@ -240,14 +251,26 @@ guchar *salt = g_malloc0 (ANDOTP_SALT_SIZE); gcry_create_nonce (salt, ANDOTP_SALT_SIZE);
- gcry_cipher_hd_t hd; - gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, GCRY_CIPHER_SECURE); guchar *derived_key = get_derived_key (password, salt, le_iterations); - gcry_cipher_setkey (hd, derived_key, gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES256)); - gcry_cipher_setiv (hd, iv, ANDOTP_IV_SIZE); + gcry_cipher_hd_t hd = open_cipher_and_set_data (derived_key, iv, ANDOTP_IV_SIZE); + if (hd == NULL) { + gcry_free (derived_key); + g_free (iv); + g_free (salt); + return NULL; + }
gchar *enc_buf = gcry_calloc_secure (json_data_size, 1); - gcry_cipher_encrypt (hd, enc_buf, json_data_size, json_data, json_data_size); + gpg_error_t gpg_err = gcry_cipher_encrypt (hd, enc_buf, json_data_size, json_data, json_data_size); + if (gpg_err) { + g_printerr ("%s\n", _("Error while encrypting the data.")); + gcry_free (derived_key); + gcry_free (enc_buf); + g_free (iv); + g_free (salt); + gcry_cipher_close (hd); + return NULL; + } guchar tag[ANDOTP_TAG_SIZE]; gcry_cipher_gettag (hd, tag, ANDOTP_TAG_SIZE); gcry_cipher_close (hd); @@ -257,30 +280,27 @@ if (err != NULL) { goto cleanup_before_exiting; } - g_output_stream_write (G_OUTPUT_STREAM (out_stream), &be_iterations, 4, NULL, &err); - if (err != NULL) { + if (g_output_stream_write (G_OUTPUT_STREAM (out_stream), &be_iterations, 4, NULL, &err) == -1) { goto cleanup_before_exiting; } - g_output_stream_write (G_OUTPUT_STREAM (out_stream), salt, ANDOTP_SALT_SIZE, NULL, &err); - if (err != NULL) { + if (g_output_stream_write (G_OUTPUT_STREAM (out_stream), salt, ANDOTP_SALT_SIZE, NULL, &err) == -1) { goto cleanup_before_exiting; } - g_output_stream_write (G_OUTPUT_STREAM (out_stream), iv, ANDOTP_IV_SIZE, NULL, &err); - if (err != NULL) { + if (g_output_stream_write (G_OUTPUT_STREAM (out_stream), iv, ANDOTP_IV_SIZE, NULL, &err) == -1) { goto cleanup_before_exiting; } - g_output_stream_write (G_OUTPUT_STREAM (out_stream), enc_buf, json_data_size, NULL, &err); - if (err != NULL) { + if (g_output_stream_write (G_OUTPUT_STREAM (out_stream), enc_buf, json_data_size, NULL, &err) == -1) { goto cleanup_before_exiting; } - g_output_stream_write (G_OUTPUT_STREAM (out_stream), tag, ANDOTP_TAG_SIZE, NULL, &err); - if (err != NULL) { + if (g_output_stream_write (G_OUTPUT_STREAM (out_stream), tag, ANDOTP_TAG_SIZE, NULL, &err) == -1) { goto cleanup_before_exiting; }
cleanup_before_exiting: g_free (iv); + g_free (salt); gcry_free (json_data); + gcry_free (derived_key); gcry_free (enc_buf); json_array_clear (array); g_object_unref (out_stream); @@ -299,6 +319,7 @@ guchar *derived_key = gcry_malloc_secure (32); if (gcry_kdf_derive (password, (gsize) g_utf8_strlen (password, -1), GCRY_KDF_PBKDF2, GCRY_MD_SHA1, salt, ANDOTP_SALT_SIZE, iterations, 32, derived_key) != 0) { + gcry_free (derived_key); return NULL; }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/common/common.c new/OTPClient-3.1.1/src/common/common.c --- old/OTPClient-3.1.0/src/common/common.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/common/common.c 2022-12-28 17:02:45.000000000 +0100 @@ -2,6 +2,7 @@ #include <sys/resource.h> #include <cotp.h> #include <baseencode.h> +#include <glib/gi18n.h> #include "gcrypt.h" #include "jansson.h" #include "../google-migration.pb-c.h" @@ -92,7 +93,9 @@ json_int_t v = json_integer_value (value); g_snprintf (tmp_string + strlen (tmp_string), 256, "%ld", (gint64) v); } else { - g_strlcat (tmp_string, json_string_value (value), 256); + if (g_strlcat (tmp_string, json_string_value (value), 256) > 256) { + g_printerr ("%s\n", _("Truncation occurred.")); + } } }
@@ -127,9 +130,9 @@ } } sec_buf[pos] = '\0'; - gcry_realloc (sec_buf, g_utf8_strlen(sec_buf, -1) + 1); + gchar *secubf_newpos = (gchar *)gcry_realloc (sec_buf, g_utf8_strlen(sec_buf, -1) + 1);
- return sec_buf; + return secubf_newpos; }
@@ -169,6 +172,139 @@ }
+// Backported from Glib 2.68 in order to support Debian "bullseye" and Ubuntu 20.04 +guint +g_string_replace_backported (GString *string, + const gchar *find, + const gchar *replace, + guint limit) +{ + gsize f_len, r_len, pos; + gchar *cur, *next; + guint n = 0; + + g_return_val_if_fail (string != NULL, 0); + g_return_val_if_fail (find != NULL, 0); + g_return_val_if_fail (replace != NULL, 0); + + f_len = strlen (find); + r_len = strlen (replace); + cur = string->str; + + while ((next = strstr (cur, find)) != NULL) + { + pos = next - string->str; + g_string_erase (string, (gssize)pos, (gssize)f_len); + g_string_insert (string, (gssize)pos, replace); + cur = string->str + pos + r_len; + n++; + /* Only match the empty string once at any given position, to + * avoid infinite loops */ + if (f_len == 0) + { + if (cur[0] == '\0') + break; + else + cur++; + } + if (n == limit) + break; + } + + return n; +} + + +// Backported from Glib. The only difference is that it's using gcrypt to allocate a secure buffer. +static int +unescape_character (const char *scanner) +{ + int first_digit; + int second_digit; + + first_digit = g_ascii_xdigit_value (*scanner++); + if (first_digit < 0) + return -1; + + second_digit = g_ascii_xdigit_value (*scanner++); + if (second_digit < 0) + return -1; + + return (first_digit << 4) | second_digit; +} + + +// Backported from Glib. The only difference is that it's using gcrypt to allocate a secure buffer. +gchar * +g_uri_unescape_string_secure (const gchar *escaped_string, + const gchar *illegal_characters) +{ + if (escaped_string == NULL) + return NULL; + + const gchar *escaped_string_end = escaped_string + strlen (escaped_string); + + gchar *result = gcry_calloc_secure (escaped_string_end - escaped_string + 1, 1); + gchar *out = result; + + const gchar *in; + gint character; + for (in = escaped_string; in < escaped_string_end; in++) { + character = *in; + + if (*in == '%') { + in++; + if (escaped_string_end - in < 2) { + // Invalid escaped char (to short) + gcry_free (result); + return NULL; + } + + character = unescape_character (in); + + // Check for an illegal character. We consider '\0' illegal here. + if (character <= 0 || + (illegal_characters != NULL && + strchr (illegal_characters, (char)character) != NULL)) { + gcry_free (result); + return NULL; + } + + in++; // The other char will be eaten in the loop header + } + *out++ = (char)character; + } + + *out = '\0'; + + return result; +} + + +guchar * +g_base64_decode_secure (const gchar *text, + gsize *out_len) +{ + guchar *ret; + gsize input_length; + gint state = 0; + guint save = 0; + + g_return_val_if_fail (text != NULL, NULL); + g_return_val_if_fail (out_len != NULL, NULL); + + input_length = strlen (text); + + /* We can use a smaller limit here, since we know the saved state is 0, + +1 used to avoid calling g_malloc0(0), and hence returning NULL */ + ret = gcry_calloc_secure ((input_length / 4) * 3 + 1, 1); + + *out_len = g_base64_decode_step (text, input_length, ret, &state, &save); + + return ret; +} + + GSList * decode_migration_data (const gchar *encoded_uri) { @@ -178,50 +314,58 @@ } encoded_uri_copy += 33; gsize out_len; - guchar *data = g_base64_decode (g_uri_unescape_string ((encoded_uri_copy), NULL), &out_len); + gchar *unesc_str = g_uri_unescape_string_secure (encoded_uri_copy, NULL); + guchar *data = g_base64_decode_secure (unesc_str, &out_len); + gcry_free (unesc_str);
GSList *uris = NULL; - gchar *uri = NULL; + GString *uri = NULL; MigrationPayload *msg = migration_payload__unpack (NULL, out_len, data); + gcry_free (data); for (gint i = 0; i < msg->n_otp_parameters; i++) { - uri = g_strconcat ("otpauth://", NULL); + uri = g_string_new ("otpauth://"); if (msg->otp_parameters[i]->type == 1) { - uri = g_strconcat (uri, "hotp/", NULL); + g_string_append (uri, "hotp/"); } else if (msg->otp_parameters[i]->type == 2) { - uri = g_strconcat (uri, "totp/", NULL); + g_string_append (uri, "totp/"); } else { g_printerr ("OTP type not recognized, skipping %s\n", msg->otp_parameters[i]->name); goto end; }
- uri = g_strconcat (uri, msg->otp_parameters[i]->name, "?", NULL); + g_string_append (uri, msg->otp_parameters[i]->name); + g_string_append (uri, "?");
if (msg->otp_parameters[i]->algorithm == 1) { - uri = g_strconcat (uri, "algorithm=SHA1&", NULL); + g_string_append (uri, "algorithm=SHA1&"); } else if (msg->otp_parameters[i]->algorithm == 2) { - uri = g_strconcat (uri, "algorithm=SHA256&", NULL); + g_string_append (uri, "algorithm=SHA256&"); } else if (msg->otp_parameters[i]->algorithm == 3) { - uri = g_strconcat (uri, "algorithm=SHA512&", NULL); + g_string_append (uri, "algorithm=SHA512&"); } else { g_printerr ("Algorithm type not supported, skipping %s\n", msg->otp_parameters[i]->name); goto end; }
if (msg->otp_parameters[i]->digits == 1) { - uri = g_strconcat (uri, "digits=6&", NULL); + g_string_append (uri, "digits=6&"); } else if (msg->otp_parameters[i]->digits == 2) { - uri = g_strconcat (uri, "digits=8&", NULL); + g_string_append (uri, "digits=8&"); } else { g_printerr ("Algorithm type not supported, skipping %s\n", msg->otp_parameters[i]->name); goto end; }
if (msg->otp_parameters[i]->issuer != NULL) { - uri = g_strconcat (uri, "issuer=", msg->otp_parameters[i]->issuer, "&", NULL); + g_string_append (uri, "issuer="); + g_string_append (uri, msg->otp_parameters[i]->issuer); + g_string_append (uri, "&"); }
if (msg->otp_parameters[i]->type == 1) { - uri = g_strconcat (uri, "counter=", msg->otp_parameters[i]->counter, "&", NULL); + g_string_append (uri, "counter="); + g_string_append_printf(uri, "%ld", msg->otp_parameters[i]->counter); + g_string_append (uri, "&"); }
baseencode_error_t b_err; @@ -231,56 +375,46 @@ goto end; }
- uri = g_strconcat (uri, "secret=", b32_encoded_secret, NULL); + g_string_append (uri, "secret="); + g_string_append (uri, b32_encoded_secret);
- uris = g_slist_append (uris, g_strdup (uri)); + uris = g_slist_append (uris, g_strdup (uri->str));
end: - g_free (uri); + g_string_free (uri, TRUE); }
+ migration_payload__free_unpacked (msg, NULL); + return uris; }
-// Backported from Glib 2.68 in order to support Debian "bullseye" and Ubuntu 20.04 -guint -g_string_replace_backported (GString *string, - const gchar *find, - const gchar *replace, - guint limit) -{ - gsize f_len, r_len, pos; - gchar *cur, *next; - guint n = 0; - - g_return_val_if_fail (string != NULL, 0); - g_return_val_if_fail (find != NULL, 0); - g_return_val_if_fail (replace != NULL, 0); +gcry_cipher_hd_t +open_cipher_and_set_data (guchar *derived_key, + guchar *iv, + gsize iv_len) +{ + gcry_cipher_hd_t hd; + gpg_error_t gpg_err = gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, GCRY_CIPHER_SECURE); + if (gpg_err) { + g_printerr ("%s\n", _("Error while opening the cipher handle.")); + return NULL; + }
- f_len = strlen (find); - r_len = strlen (replace); - cur = string->str; + gpg_err = gcry_cipher_setkey (hd, derived_key, gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES256)); + if (gpg_err) { + g_printerr ("%s\n", _("Error while setting the cipher key.")); + gcry_cipher_close (hd); + return NULL; + }
- while ((next = strstr (cur, find)) != NULL) - { - pos = next - string->str; - g_string_erase (string, pos, f_len); - g_string_insert (string, pos, replace); - cur = string->str + pos + r_len; - n++; - /* Only match the empty string once at any given position, to - * avoid infinite loops */ - if (f_len == 0) - { - if (cur[0] == '\0') - break; - else - cur++; - } - if (n == limit) - break; + gpg_err = gcry_cipher_setiv (hd, iv, iv_len); + if (gpg_err) { + g_printerr ("%s\n", _("Error while setting the cipher iv.")); + gcry_cipher_close (hd); + return NULL; }
- return n; -} + return hd; +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/common/common.h new/OTPClient-3.1.1/src/common/common.h --- old/OTPClient-3.1.0/src/common/common.h 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/common/common.h 2022-12-28 17:02:45.000000000 +0100 @@ -2,6 +2,7 @@
#include <glib.h> #include <jansson.h> +#include <gcrypt.h>
G_BEGIN_DECLS
@@ -38,4 +39,14 @@ const gchar *replace, guint limit);
+gchar *g_uri_unescape_string_secure (const gchar *escaped_string, + const gchar *illegal_characters); + +guchar *g_base64_decode_secure (const gchar *text, + gsize *out_len); + +gcry_cipher_hd_t open_cipher_and_set_data (guchar *derived_key, + guchar *iv, + gsize iv_len); + G_END_DECLS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/common/freeotp.c new/OTPClient-3.1.1/src/common/freeotp.c --- old/OTPClient-3.1.0/src/common/freeotp.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/common/freeotp.c 2022-12-28 17:02:45.000000000 +0100 @@ -11,9 +11,15 @@ GError **err) { GSList *otps = NULL; - gchar *sec_buf = gcry_calloc_secure (get_file_size (path), 1); + goffset fs = get_file_size (path); + if (fs < 10) { + g_printerr ("Couldn't get the file size (file doesn't exit or wrong file selected\n"); + return NULL; + } + gchar *sec_buf = gcry_calloc_secure (fs, 1); if (!g_file_get_contents (path, &sec_buf, NULL, err)) { g_printerr("Couldn't read into memory the freeotp txt file\n"); + gcry_free (sec_buf); return NULL; }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/db-actions.c new/OTPClient-3.1.1/src/db-actions.c --- old/OTPClient-3.1.0/src/db-actions.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/db-actions.c 2022-12-28 17:02:45.000000000 +0100 @@ -1,4 +1,5 @@ #include <gtk/gtk.h> +#include <glib/gi18n.h> #include "data.h" #include "message-dialogs.h" #include "db-actions.h" @@ -36,8 +37,6 @@ void update_cfg_file (AppData *app_data) { - GError *cfg_err = NULL; - gchar *msg = NULL; GKeyFile *kf = g_key_file_new (); gchar *cfg_file_path; #ifndef USE_FLATPAK_APP_FOLDER @@ -45,15 +44,20 @@ #else cfg_file_path = g_build_filename (g_get_user_data_dir (), "otpclient.cfg", NULL); #endif - g_key_file_load_from_file (kf, cfg_file_path, G_KEY_FILE_NONE, NULL); + if (!g_key_file_load_from_file (kf, cfg_file_path, G_KEY_FILE_NONE, NULL)) { + g_printerr ("%s\n", _("Error while loading the config file.")); + } g_key_file_set_string (kf, "config", "db_path", app_data->db_data->db_path); - g_key_file_save_to_file (kf, cfg_file_path, &cfg_err); - if (cfg_err != NULL) { - msg = g_strconcat ("Couldn't save the change to the config file: ", &cfg_err->message, NULL); - show_message_dialog (app_data->main_window, msg, GTK_MESSAGE_ERROR); - g_free (msg); - g_clear_error (&cfg_err); + GError *cfg_err = NULL; + if (!g_key_file_save_to_file (kf, cfg_file_path, &cfg_err)) { + if (cfg_err != NULL) { + gchar *msg = g_strconcat ("Couldn't save the change to the config file: ", &cfg_err->message, NULL); + show_message_dialog (app_data->main_window, msg, GTK_MESSAGE_ERROR); + g_free (msg); + g_clear_error (&cfg_err); + } } + g_free (cfg_file_path); g_key_file_free (kf); } \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/db-misc.c new/OTPClient-3.1.1/src/db-misc.c --- old/OTPClient-3.1.0/src/db-misc.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/db-misc.c 2022-12-28 17:02:45.000000000 +0100 @@ -2,6 +2,7 @@ #include <gcrypt.h> #include <jansson.h> #include <glib/gstdio.h> +#include <glib/gi18n.h> #include "db-misc.h" #include "otpclient.h" #include "file-size.h" @@ -166,7 +167,9 @@ } else { g_printerr ("Couldn't update the database (encrypt_db failed)\n"); if (g_file_test (db_data->db_path, G_FILE_TEST_EXISTS)) { - g_unlink (db_data->db_path); + if (g_unlink (db_data->db_path) == -1) { + g_printerr ("%s\n", _("Error while unlinking the file.")); + } } } } else { @@ -193,7 +196,6 @@ GError **err) { GError *local_err = NULL; - gcry_cipher_hd_t hd; HeaderData *header_data = g_new0 (HeaderData, 1);
gcry_create_nonce (header_data->iv, IV_SIZE); @@ -224,35 +226,64 @@ gsize input_data_len = strlen (in_memory_json) + 1; guchar *enc_buffer = g_malloc0 (input_data_len);
- gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 0); - gcry_cipher_setkey (hd, derived_key, gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES256)); - gcry_cipher_setiv (hd, header_data->iv, IV_SIZE); - gcry_cipher_authenticate (hd, header_data, sizeof (HeaderData)); - gcry_cipher_encrypt (hd, enc_buffer, input_data_len, in_memory_json, input_data_len); + gcry_cipher_hd_t hd = open_cipher_and_set_data (derived_key, header_data->iv, IV_SIZE); + if (hd == NULL) { + gcry_free (derived_key); + g_free (header_data); + g_free (enc_buffer); + return NULL; + } + + gpg_error_t gpg_err = gcry_cipher_authenticate (hd, header_data, sizeof (HeaderData)); + if (gpg_err) { + g_printerr ("%s\n", _("Error while processing the authenticated data.")); + gcry_free (derived_key); + g_free (header_data); + g_free (enc_buffer); + gcry_cipher_close (hd); + return GENERIC_ERROR; + } + gpg_err = gcry_cipher_encrypt (hd, enc_buffer, input_data_len, in_memory_json, input_data_len); + if (gpg_err) { + g_printerr ("%s\n", _("Error while encrypting the data.")); + gcry_free (derived_key); + g_free (enc_buffer); + g_free (header_data); + gcry_cipher_close (hd); + return GENERIC_ERROR; + }
guchar tag[TAG_SIZE]; - gcry_cipher_gettag (hd, tag, TAG_SIZE); //append tag to outfile + gpg_err = gcry_cipher_gettag (hd, tag, TAG_SIZE); //append tag to outfile + if (gpg_err) { + g_printerr ("%s\n", _("Error while getting the tag.")); + gcry_free (derived_key); + g_free (enc_buffer); + g_free (header_data); + gcry_cipher_close (hd); + return GENERIC_ERROR; + }
if (g_output_stream_write (G_OUTPUT_STREAM(out_stream), enc_buffer, input_data_len, NULL, &local_err) == -1) { g_set_error (err, generic_error_gquark (), GENERIC_ERRCODE, "Failed while writing encrypted buffer to file"); cleanup (out_file, out_stream, header_data, local_err); - gcry_cipher_close (hd); g_free (enc_buffer); gcry_free (derived_key); + gcry_cipher_close (hd); return GENERIC_ERROR; } if (g_output_stream_write (G_OUTPUT_STREAM(out_stream), tag, TAG_SIZE, NULL, &local_err) == -1) { g_set_error (err, generic_error_gquark (), GENERIC_ERRCODE, "Failed while writing tag data to file"); cleanup (out_file, out_stream, header_data, local_err); - gcry_cipher_close (hd); g_free (enc_buffer); gcry_free (derived_key); + gcry_cipher_close (hd); return GENERIC_ERROR; }
- gcry_cipher_close (hd); - gcry_free (derived_key); g_free (enc_buffer); + gcry_free (derived_key); + gcry_cipher_close (hd); cleanup (out_file, out_stream, header_data, NULL);
return NULL; @@ -264,7 +295,6 @@ const gchar *password) { GError *err = NULL; - gcry_cipher_hd_t hd; HeaderData *header_data = g_new0 (HeaderData, 1);
goffset input_file_size = get_file_size (db_path); @@ -319,19 +349,49 @@ return (gpointer)derived_key; }
- gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 0); - gcry_cipher_setkey (hd, derived_key, gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES256)); - gcry_cipher_setiv (hd, header_data->iv, IV_SIZE); - gcry_cipher_authenticate (hd, header_data, sizeof (HeaderData)); + gcry_cipher_hd_t hd = open_cipher_and_set_data (derived_key, header_data->iv, IV_SIZE); + if (hd == NULL) { + gcry_free (derived_key); + g_free (enc_buf); + g_free (header_data); + return GENERIC_ERROR; + } + + gpg_error_t gpg_err = gcry_cipher_authenticate (hd, header_data, sizeof (HeaderData)); + if (gpg_err) { + g_printerr ("%s\n", _("Error while processing the authenticated data.")); + gcry_free (derived_key); + g_free (header_data); + g_free (enc_buf); + gcry_cipher_close (hd); + return GENERIC_ERROR; + }
gchar *dec_buf = gcry_calloc_secure (enc_buf_size, 1); - gcry_cipher_decrypt (hd, dec_buf, enc_buf_size, enc_buf, enc_buf_size); - if (gcry_err_code (gcry_cipher_checktag (hd, tag, TAG_SIZE)) == GPG_ERR_CHECKSUM) { + if (dec_buf == NULL) { + g_printerr ("%s\n", _("Error while allocating secure memory.")); + gcry_free (derived_key); + g_free (header_data); + g_free (enc_buf); gcry_cipher_close (hd); + return GENERIC_ERROR; + } + gpg_err = gcry_cipher_decrypt (hd, dec_buf, enc_buf_size, enc_buf, enc_buf_size); + if (gpg_err) { + g_printerr ("%s\n", _("Error while decrypting the data.")); gcry_free (derived_key); + gcry_free (dec_buf); g_free (header_data); g_free (enc_buf); + gcry_cipher_close (hd); + return GENERIC_ERROR; + } + if (gcry_err_code (gcry_cipher_checktag (hd, tag, TAG_SIZE)) == GPG_ERR_CHECKSUM) { + gcry_cipher_close (hd); + gcry_free (derived_key); gcry_free (dec_buf); + g_free (header_data); + g_free (enc_buf); return TAG_MISMATCH; }
@@ -353,14 +413,14 @@
guchar *derived_key = gcry_malloc_secure (key_len); if (derived_key == NULL) { - g_printerr ("Couldn't allocate secure memory\n"); + g_printerr ("%s\n", _("Couldn't allocate the needed secure memory.")); return SECURE_MEMORY_ALLOC_ERR; }
gpg_error_t ret = gcry_kdf_derive (pwd, pwd_len, GCRY_KDF_PBKDF2, GCRY_MD_SHA512, header_data->salt, KDF_SALT_SIZE, KDF_ITERATIONS, key_len, derived_key); if (ret != 0) { gcry_free (derived_key); - g_printerr ("Error during key derivation\n"); + g_printerr ("%s\n", _("Error during key derivation.")); return KEY_DERIV_ERR; } return derived_key; @@ -396,7 +456,7 @@ g_printerr ("Couldn't restore the backup file: %s\n", err->message); g_clear_error (&err); } else { - g_print ("Backup copy successfully restored.\n"); + g_print ("%s\n", _("Backup copy successfully restored.")); } g_object_unref (src); g_object_unref (dst); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/exports.c new/OTPClient-3.1.1/src/exports.c --- old/OTPClient-3.1.0/src/exports.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/exports.c 2022-12-28 17:02:45.000000000 +0100 @@ -1,5 +1,6 @@ #include <gtk/gtk.h> #include <jansson.h> +#include <gcrypt.h> #include "password-cb.h" #include "message-dialogs.h" #include "common/exports.h" @@ -54,6 +55,9 @@ } g_free (ret_msg); g_free (exported_file_path); + if (encrypted == TRUE) { + gcry_free (password); + } }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/imports.c new/OTPClient-3.1.1/src/imports.c --- old/OTPClient-3.1.0/src/imports.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/imports.c 2022-12-28 17:02:45.000000000 +0100 @@ -120,6 +120,12 @@ } show_message_dialog (app_data->main_window, msg, GTK_MESSAGE_ERROR); g_free (msg_with_err); + if (err != NULL){ + g_clear_error (&err); + } + if (pwd != NULL) { + gcry_free (pwd); + } return FALSE; }
@@ -127,6 +133,9 @@ if (err_msg != NULL) { show_message_dialog (app_data->main_window, err_msg, GTK_MESSAGE_ERROR); g_free (err_msg); + if (pwd != NULL) { + gcry_free (pwd); + } return FALSE; }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/parse-uri.c new/OTPClient-3.1.1/src/parse-uri.c --- old/OTPClient-3.1.0/src/parse-uri.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/parse-uri.c 2022-12-28 17:02:45.000000000 +0100 @@ -74,7 +74,7 @@ gchar *escaped_label = g_uri_escape_string (constructed_label, NULL, FALSE); g_string_append (uri, escaped_label); g_string_append (uri, "?secret="); - g_string_append (uri,json_string_value (json_object_get (db_obj, "secret"))); + g_string_append (uri, json_string_value (json_object_get (db_obj, "secret"))); if (issuer != NULL && g_ascii_strcasecmp (issuer, "steam") == 0) { g_string_append (uri, "&issuer=Steam"); } @@ -83,27 +83,32 @@ g_string_append (uri, json_string_value (json_object_get (db_obj, "issuer"))); }
+ gchar *str_to_append = NULL; g_string_append (uri, "&digits="); - g_string_append (uri,g_strdup_printf ("%lld", json_integer_value ( json_object_get (db_obj, "digits")))); + str_to_append = g_strdup_printf ("%lld", json_integer_value ( json_object_get (db_obj, "digits"))); + g_string_append (uri,str_to_append); + g_free (str_to_append); g_string_append (uri, "&algorithm="); g_string_append (uri, json_string_value ( json_object_get (db_obj, "algo")));
if (g_ascii_strcasecmp (json_string_value (json_object_get (db_obj, "type")), "TOTP") == 0) { g_string_append (uri, "&period="); - g_string_append (uri, g_strdup_printf ("%lld",json_integer_value ( json_object_get (db_obj, "period")))); + str_to_append = g_strdup_printf ("%lld", json_integer_value ( json_object_get (db_obj, "period"))); + g_string_append (uri, str_to_append); + g_free (str_to_append); } else { g_string_append (uri, "&counter="); - g_string_append (uri, g_strdup_printf ("%lld",json_integer_value ( json_object_get (db_obj, "counter")))); + str_to_append = g_strdup_printf ("%lld", json_integer_value ( json_object_get (db_obj, "counter"))); + g_string_append (uri, str_to_append); + g_free (str_to_append); }
g_string_append (uri, "\n"); - gchar *ret_uri = g_strdup (uri->str);
g_free (constructed_label); g_free (escaped_label); - g_string_free (uri, TRUE);
- return ret_uri; + return g_string_free (uri, FALSE); }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/qrcode-parser.c new/OTPClient-3.1.1/src/qrcode-parser.c --- old/OTPClient-3.1.0/src/qrcode-parser.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/qrcode-parser.c 2022-12-28 17:02:45.000000000 +0100 @@ -2,6 +2,7 @@ #include <zbar.h> #include <png.h> #include <glib/gstdio.h> +#include <gcrypt.h> #include "common/common.h"
typedef struct image_data_t { @@ -46,7 +47,9 @@
const zbar_symbol_t *symbol = zbar_image_first_symbol (image); for (; symbol; symbol = zbar_symbol_next (symbol)) { - *otpauth_uri = secure_strdup (g_uri_unescape_string (zbar_symbol_get_data (symbol), NULL)); + gchar *unesc_str = g_uri_unescape_string_secure (zbar_symbol_get_data (symbol), NULL); + *otpauth_uri = secure_strdup (unesc_str); + gcry_free (unesc_str); }
zbar_image_destroy (image); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/settings-cb.c new/OTPClient-3.1.1/src/settings-cb.c --- old/OTPClient-3.1.0/src/settings-cb.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/settings-cb.c 2022-12-28 17:02:45.000000000 +0100 @@ -1,4 +1,5 @@ #include <gtk/gtk.h> +#include <glib/gi18n.h> #include "otpclient.h" #include "message-dialogs.h" #include "get-builder.h" @@ -24,6 +25,7 @@ g_free (msg); g_free (cfg_file_path); g_key_file_free (kf); + g_clear_error (&err); return; }
@@ -79,7 +81,9 @@ g_key_file_set_integer (kf, "config", "inactivity_timeout", app_data->inactivity_timeout); g_key_file_set_boolean (kf, "config", "dark_theme", app_data->use_dark_theme); g_key_file_set_boolean (kf, "config", "disable_secret_service", app_data->disable_secret_service); - g_key_file_save_to_file (kf, cfg_file_path, NULL); + if (!g_key_file_save_to_file (kf, cfg_file_path, NULL)) { + g_printerr ("%s\n", _("Error while saving the config file.")); + } gtk_tree_view_set_search_column (GTK_TREE_VIEW(app_data->tree_view), app_data->search_column + 1); break; case GTK_RESPONSE_CANCEL: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/show-qr-cb.c new/OTPClient-3.1.1/src/show-qr-cb.c --- old/OTPClient-3.1.0/src/show-qr-cb.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/show-qr-cb.c 2022-12-28 17:02:45.000000000 +0100 @@ -2,6 +2,7 @@ #include <png.h> #include <qrencode.h> #include <glib/gstdio.h> +#include <glib/gi18n.h> #include "data.h" #include "parse-uri.h" #include "get-builder.h" @@ -45,7 +46,9 @@ gtk_widget_destroy (diag); g_object_unref (pbuf); g_object_unref (builder); - g_unlink (PNG_OUT); + if (g_unlink (PNG_OUT) == -1) { + g_printerr ("%s\n", _("Couldn't unlink the PNG file.")); + } } }
@@ -62,40 +65,37 @@ write_png (const QRcode *qrcode) { guint realwidth = (qrcode->width + MARGIN * 2) * SIZE; - guchar *row = (guchar *)malloc ((size_t)((realwidth + 7) / 8)); + guchar *row = (guchar *)g_malloc0 ((size_t)((realwidth + 7) / 8)); if (row == NULL) { g_printerr ("Failed to allocate memory.\n"); return -1; }
- FILE *fp = fopen (PNG_OUT, "wb"); - if (fp == NULL) { - g_printerr ("Failed to create file: %s\n", PNG_OUT); - perror(NULL); - return -1; - } - png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { g_printerr ("Failed to initialize PNG writer.\n"); + g_free (row); return -1; }
png_infop info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { g_printerr ("Failed to initialize PNG write.\n"); + g_free (row); return -1; }
if (setjmp (png_jmpbuf(png_ptr))) { png_destroy_write_struct (&png_ptr, &info_ptr); g_printerr ("Failed to write PNG image.\n"); + g_free (row); return -1; }
- png_colorp palette = (png_colorp)malloc(sizeof (png_color) * 2); + png_colorp palette = (png_colorp)g_malloc0 (sizeof (png_color) * 2); if (palette == NULL) { g_printerr ("Failed to allocate memory.\n"); + g_free (row); return -1; }
@@ -114,6 +114,12 @@ png_set_PLTE(png_ptr, info_ptr, palette, 2); png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL);
+ FILE *fp = fopen (PNG_OUT, "wb"); + if (fp == NULL) { + g_printerr ("Failed to create file: %s\n", PNG_OUT); + g_free (row); + return -1; + } png_init_io (png_ptr, fp); png_set_IHDR (png_ptr, info_ptr, (guint)realwidth, (guint)realwidth, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/OTPClient-3.1.0/src/webcam-add-cb.c new/OTPClient-3.1.1/src/webcam-add-cb.c --- old/OTPClient-3.1.0/src/webcam-add-cb.c 2022-12-19 14:16:00.000000000 +0100 +++ new/OTPClient-3.1.1/src/webcam-add-cb.c 2022-12-28 17:02:45.000000000 +0100 @@ -111,7 +111,9 @@ ConfigData *cfg_data = (ConfigData *)user_data; const zbar_symbol_t *symbol = zbar_image_first_symbol (image); for (; symbol; symbol = zbar_symbol_next (symbol)) { - cfg_data->otp_uri = secure_strdup (g_uri_unescape_string (zbar_symbol_get_data (symbol), NULL)); + gchar *unesc_str = g_uri_unescape_string_secure (zbar_symbol_get_data (symbol), NULL); + cfg_data->otp_uri = secure_strdup (unesc_str); cfg_data->qrcode_found = TRUE; + gcry_free (unesc_str); } }