[PATCH 1/4] libalpm: Add support for asignify signatures
Jeremy Huntwork
jeremy at merelinux.org
Sat Jan 1 19:49:31 UTC 2022
Provide an alternative way to validate package and repository signatures
using libasignify. See: https://github.com/vstakhov/asignify
Signed-off-by: Jeremy Huntwork <jeremy at merelinux.org>
---
lib/libalpm/alpm.c | 2 +-
lib/libalpm/alpm.h | 19 ++++++++++++
lib/libalpm/be_package.c | 22 +++++++++++---
lib/libalpm/be_sync.c | 2 +-
lib/libalpm/error.c | 8 ++---
lib/libalpm/handle.c | 23 ++++++++++++--
lib/libalpm/handle.h | 1 +
lib/libalpm/signing.c | 65 ++++++++++++++++++++++++++++++++++++++++
lib/libalpm/signing.h | 1 +
9 files changed, 130 insertions(+), 13 deletions(-)
diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c
index 5b326ab0..d1261660 100644
--- a/lib/libalpm/alpm.c
+++ b/lib/libalpm/alpm.c
@@ -137,7 +137,7 @@ int SYMEXPORT alpm_capabilities(void)
#ifdef HAVE_LIBCURL
| ALPM_CAPABILITY_DOWNLOADER
#endif
-#ifdef HAVE_LIBGPGME
+#if defined(HAVE_LIBGPGME) || defined(HAVE_LIBASIGNIFY)
| ALPM_CAPABILITY_SIGNATURES
#endif
| 0;
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 7f3fc8d5..aaa0acb9 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -1833,6 +1833,25 @@ int alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir);
/* End of gpdir accessors */
/** @} */
+/** @name Accessors to asignify's trusted public keys directory
+ *
+ * This controls where libalpm will store asignify's public keys.
+ * @{
+ */
+
+/** Returns the path to libalpm's asignify trusted public keys directory.
+ * @param handle the context handle
+ * @return the path to libalpms's trusted public keys directory
+ */
+const char *alpm_option_get_asignifydir(alpm_handle_t *handle);
+
+/** Sets the path to libalpm's asignify trusted public keys directory.
+ * @param handle the context handle
+ * @param asignifydir the asignifydir to set
+ */
+int alpm_option_set_asignifydir(alpm_handle_t *handle, const char *asignifydir);
+/* End of asignifydir accessors */
+/** @} */
/** @name Accessors for use syslog
*
diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c
index 5ca2865c..db6341d6 100644
--- a/lib/libalpm/be_package.c
+++ b/lib/libalpm/be_package.c
@@ -342,12 +342,23 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle,
handle->pm_errno = ALPM_ERR_PKG_MISSING_SIG;
return -1;
}
+#ifdef HAVE_LIBGPGME
if(_alpm_check_pgp_helper(handle, pkgfile, sig,
level & ALPM_SIG_PACKAGE_OPTIONAL, level & ALPM_SIG_PACKAGE_MARGINAL_OK,
level & ALPM_SIG_PACKAGE_UNKNOWN_OK, sigdata)) {
handle->pm_errno = ALPM_ERR_PKG_INVALID_SIG;
return -1;
}
+#endif
+#ifdef HAVE_LIBASIGNIFY
+ if (sigdata) {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "sigdata is unused with libasignify\n");
+ }
+ if(_alpm_check_asignify_helper(handle, pkgfile)) {
+ handle->pm_errno = ALPM_ERR_PKG_INVALID_SIG;
+ return -1;
+ }
+#endif
if(validation && has_sig) {
*validation |= ALPM_PKG_VALIDATION_SIGNATURE;
}
@@ -722,8 +733,6 @@ int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int ful
{
int validation = 0;
char *sigpath;
- alpm_pkg_t *pkg_temp;
- char *packager;
CHECK_HANDLE(handle, return -1);
ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
@@ -731,8 +740,6 @@ int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int ful
sigpath = _alpm_sigpath(handle, filename);
if(sigpath && !_alpm_access(handle, NULL, sigpath, R_OK)) {
if(level & ALPM_SIG_PACKAGE) {
- alpm_list_t *keys = NULL;
- int fail = 0;
unsigned char *sig = NULL;
int len = read_sigfile(sigpath, &sig);
@@ -743,6 +750,12 @@ int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int ful
return -1;
}
+#ifdef HAVE_LIBGPGME
+ alpm_list_t *keys = NULL;
+ int fail = 0;
+ alpm_pkg_t *pkg_temp;
+ char *packager;
+
if(alpm_extract_keyid(handle, filename, sig, len, &keys) == 0) {
alpm_list_t *k;
for(k = keys; k; k = k->next) {
@@ -771,6 +784,7 @@ int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int ful
free(sigpath);
return -1;
}
+#endif
}
}
free(sigpath);
diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c
index ede25985..81654902 100644
--- a/lib/libalpm/be_sync.c
+++ b/lib/libalpm/be_sync.c
@@ -697,7 +697,7 @@ alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename,
_alpm_log(handle, ALPM_LOG_DEBUG, "registering sync database '%s'\n", treename);
-#ifndef HAVE_LIBGPGME
+#if !defined(HAVE_LIBGPGME) || !defined(HAVE_LIBASIGNIFY)
if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
RET_ERR(handle, ALPM_ERR_MISSING_CAPABILITY_SIGNATURES, NULL);
}
diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c
index 644a6577..78b44418 100644
--- a/lib/libalpm/error.c
+++ b/lib/libalpm/error.c
@@ -71,7 +71,7 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
case ALPM_ERR_DB_INVALID:
return _("invalid or corrupted database");
case ALPM_ERR_DB_INVALID_SIG:
- return _("invalid or corrupted database (PGP signature)");
+ return _("invalid or corrupted database (signature)");
case ALPM_ERR_DB_VERSION:
return _("database is incorrect version");
case ALPM_ERR_DB_WRITE:
@@ -114,7 +114,7 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
case ALPM_ERR_PKG_INVALID_CHECKSUM:
return _("invalid or corrupted package (checksum)");
case ALPM_ERR_PKG_INVALID_SIG:
- return _("invalid or corrupted package (PGP signature)");
+ return _("invalid or corrupted package (signature)");
case ALPM_ERR_PKG_MISSING_SIG:
return _("package missing required signature");
case ALPM_ERR_PKG_OPEN:
@@ -127,9 +127,9 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
return _("package architecture is not valid");
/* Signatures */
case ALPM_ERR_SIG_MISSING:
- return _("missing PGP signature");
+ return _("missing signature");
case ALPM_ERR_SIG_INVALID:
- return _("invalid PGP signature");
+ return _("invalid signature");
/* Dependencies */
case ALPM_ERR_UNSATISFIED_DEPS:
return _("could not satisfy dependencies");
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 101d4a78..4b588e58 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -270,6 +270,12 @@ const char SYMEXPORT *alpm_option_get_gpgdir(alpm_handle_t *handle)
return handle->gpgdir;
}
+const char SYMEXPORT *alpm_option_get_asignifydir(alpm_handle_t *handle)
+{
+ CHECK_HANDLE(handle, return NULL);
+ return handle->asignifydir;
+}
+
int SYMEXPORT alpm_option_get_usesyslog(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
@@ -573,6 +579,17 @@ int SYMEXPORT alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir)
return 0;
}
+int SYMEXPORT alpm_option_set_asignifydir(alpm_handle_t *handle, const char *asignifydir)
+{
+ int err;
+ CHECK_HANDLE(handle, return -1);
+ if((err = _alpm_set_directory_option(asignifydir, &(handle->asignifydir), 0))) {
+ RET_ERR(handle, err, -1);
+ }
+ _alpm_log(handle, ALPM_LOG_DEBUG, "option 'asignifydir' = %s\n", handle->asignifydir);
+ return 0;
+}
+
int SYMEXPORT alpm_option_set_usesyslog(alpm_handle_t *handle, int usesyslog)
{
CHECK_HANDLE(handle, return -1);
@@ -829,7 +846,7 @@ int SYMEXPORT alpm_option_set_default_siglevel(alpm_handle_t *handle,
if(level == ALPM_SIG_USE_DEFAULT) {
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
}
-#ifdef HAVE_LIBGPGME
+#if defined(HAVE_LIBGPGME) || defined(HAVE_LIBASIGNIFY)
handle->siglevel = level;
#else
if(level != 0) {
@@ -849,7 +866,7 @@ int SYMEXPORT alpm_option_set_local_file_siglevel(alpm_handle_t *handle,
int level)
{
CHECK_HANDLE(handle, return -1);
-#ifdef HAVE_LIBGPGME
+#if defined(HAVE_LIBGPGME) || defined(HAVE_LIBASIGNIFY)
handle->localfilesiglevel = level;
#else
if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
@@ -873,7 +890,7 @@ int SYMEXPORT alpm_option_set_remote_file_siglevel(alpm_handle_t *handle,
int level)
{
CHECK_HANDLE(handle, return -1);
-#ifdef HAVE_LIBGPGME
+#if defined(HAVE_LIBGPGME) || defined(HAVE_LIBASIGNIFY)
handle->remotefilesiglevel = level;
#else
if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index e1af117d..22b0689d 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -91,6 +91,7 @@ struct _alpm_handle_t {
char *logfile; /* Name of the log file */
char *lockfile; /* Name of the lock file */
char *gpgdir; /* Directory where GnuPG files are stored */
+ char *asignifydir; /* Directory where asignify trusted public keys are stored */
alpm_list_t *cachedirs; /* Paths to pacman cache directories */
alpm_list_t *hookdirs; /* Paths to hook directories */
alpm_list_t *overwrite_files; /* Paths that may be overwritten */
diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c
index 66cc3923..aa4ba19f 100644
--- a/lib/libalpm/signing.c
+++ b/lib/libalpm/signing.c
@@ -26,6 +26,11 @@
#include <gpgme.h>
#endif
+#ifdef HAVE_LIBASIGNIFY
+#include <asignify.h>
+#include <dirent.h>
+#endif
+
/* libalpm */
#include "signing.h"
#include "package.h"
@@ -810,6 +815,66 @@ char *_alpm_sigpath(alpm_handle_t *handle, const char *path)
return sigpath;
}
+#ifdef HAVE_LIBASIGNIFY
+/**
+ * Helper for checking the asignify signature for the given file path.
+ * @param handle the context handle
+ * @param path the full path to a file
+ * @return 0 on success, -1 on error (consult pm_errno or sigdata)
+ */
+int _alpm_check_asignify_helper(alpm_handle_t *handle, const char *path)
+{
+ int ret = 0;
+ struct dirent *entry;
+ struct stat statbuf;
+
+ char *sigpath = _alpm_sigpath(handle, path);
+ asignify_verify_t *vrf = asignify_verify_init();
+
+ DIR *ad = opendir(handle->asignifydir);
+ if(ad == NULL) {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "cannot open directory: %s\n", handle->asignifydir);
+ return -1;
+ }
+
+ while((entry = readdir(ad)) != NULL) {
+ char *fullpath = malloc(strlen(handle->asignifydir) + strlen(entry->d_name) + 2);
+ if (fullpath == NULL) {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "malloc error\n");
+ return -1;
+ }
+ sprintf(fullpath, "%s/%s", handle->asignifydir, entry->d_name);
+ stat(fullpath, &statbuf);
+ if (S_ISREG(statbuf.st_mode)) {
+ if (!asignify_verify_load_pubkey(vrf, fullpath)) {
+ /* Don't return here because there may be multiple public keys to load. */
+ _alpm_log(handle, ALPM_LOG_DEBUG, "cannot load public key file: %s\n", fullpath);
+ }
+ }
+ free(fullpath);
+ }
+
+ if (!asignify_verify_load_signature(vrf, sigpath)) {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "cannot load signature\n");
+ ret = -1;
+ goto asignify_cleanup;
+ }
+
+ if (!asignify_verify_file(vrf, path)) {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "signature is not valid\n");
+ ret = -1;
+ goto asignify_cleanup;
+ }
+
+ _alpm_log(handle, ALPM_LOG_DEBUG, "signature is valid\n");
+
+asignify_cleanup:
+ free(sigpath);
+ asignify_verify_free(vrf);
+ return ret;
+}
+#endif
+
/**
* Helper for checking the PGP signature for the given file path.
* This wraps #_alpm_gpgme_checksig in a slightly friendlier manner to simplify
diff --git a/lib/libalpm/signing.h b/lib/libalpm/signing.h
index 112b2a1f..a7f75ad7 100644
--- a/lib/libalpm/signing.h
+++ b/lib/libalpm/signing.h
@@ -25,6 +25,7 @@ char *_alpm_sigpath(alpm_handle_t *handle, const char *path);
int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path,
const char *base64_sig, alpm_siglist_t *result);
+int _alpm_check_asignify_helper(alpm_handle_t *handle, const char *path);
int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path,
const char *base64_sig, int optional, int marginal, int unknown,
alpm_siglist_t **sigdata);
--
2.34.1
More information about the pacman-dev
mailing list