Provide an alternative way to validate package and repository signatures
using libasignify. See: https://github.com/vstakhov/asignify

Signed-off-by: Jeremy Huntwork <[email protected]>
---
 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

Reply via email to