]> git.ipfire.org Git - pakfire.git/commitdiff
key: Implement fetching keys from the internet
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 8 Jul 2021 12:57:23 +0000 (12:57 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 8 Jul 2021 12:57:23 +0000 (12:57 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/pakfire.c
src/libpakfire/include/pakfire/key.h
src/libpakfire/key.c
src/libpakfire/libpakfire.sym
src/scripts/pakfire.in

index 56facb85ea601efb2d0da28b296f45e2b8127c2e..4c83e170037d051829c785489f2e5e4c0f41bae0 100644 (file)
@@ -482,6 +482,29 @@ static PyObject* Pakfire_import_key(PakfireObject* self, PyObject* args) {
        return _import_keylist(self, keys);
 }
 
+static PyObject* Pakfire_fetch_key(PakfireObject* self, PyObject* args, PyObject* kwds) {
+       char* kwlist[] = { "userid", "fingerprint", NULL };
+       struct pakfire_key* key = NULL;
+       const char* userid = NULL;
+       const char* fingerprint = NULL;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$zz", kwlist, &userid, &fingerprint))
+               return NULL;
+
+       // Fetch the key
+       int r = pakfire_key_fetch(&key, self->pakfire, userid, fingerprint);
+       if (r) {
+               PyErr_SetFromErrno(PyExc_OSError);
+               return NULL;
+       }
+
+       // Return the result
+       if (key)
+               return new_key(&KeyType, key);
+
+       Py_RETURN_NONE;
+}
+
 static PyObject* Pakfire_whatprovides(PakfireObject* self, PyObject* args) {
        const char* provides = NULL;
        struct pakfire_packagelist* list = NULL;
@@ -1007,6 +1030,12 @@ static struct PyMethodDef Pakfire_methods[] = {
                METH_VARARGS|METH_KEYWORDS,
                NULL
        },
+       {
+               "fetch_key",
+               (PyCFunction)Pakfire_fetch_key,
+               METH_VARARGS|METH_KEYWORDS,
+               NULL
+       },
        {
                "generate_key",
                (PyCFunction)Pakfire_generate_key,
index 49329952163e42879a79b0c8c9654febb606d19f..ccfa151dbe432e640f0faafd5afc7a12917b29ad 100644 (file)
@@ -35,6 +35,9 @@ typedef enum pakfire_key_export_mode {
 struct pakfire_key* pakfire_key_ref(struct pakfire_key* key);
 void pakfire_key_unref(struct pakfire_key* key);
 
+int pakfire_key_fetch(struct pakfire_key** key, Pakfire pakfire,
+       const char* uid, const char* fingerprint);
+
 struct pakfire_key* pakfire_key_get(Pakfire pakfire, const char* fingerprint);
 int pakfire_key_delete(struct pakfire_key* key);
 
index 67683dbc42501034f056ff7925b099d7e3590123..3d4cb639ab400af52d4fd8d06389c7fd724534a8 100644 (file)
@@ -64,6 +64,131 @@ int pakfire_key_create(struct pakfire_key** key, Pakfire pakfire, gpgme_key_t gp
        return 0;
 }
 
+static int pakfire_key_extract_email(const char* uid, char** email) {
+       if (!uid)
+               return 1;
+
+       // Find a start
+       char* start = strrchr(uid, '<');
+       if (!start)
+               return 1;
+
+       // Find the end
+       char* end = strchr(start, '>');
+       if (!end)
+               return 1;
+
+       // Copy email address to new memory
+       int r = asprintf(email, "%.*s", (int)(end - start - 1), start + 1);
+       if (r < 0)
+               return 1;
+
+       return 0;
+}
+
+static int __pakfire_key_fetch(gpgme_key_t* key, Pakfire pakfire,
+               const char* what, gpgme_keylist_mode_t flags) {
+       // Fetch GPGME context
+       gpgme_ctx_t gpgctx = pakfire_get_gpgctx(pakfire);
+       if (!gpgctx)
+               return 1;
+
+       int r = 1;
+
+       // Fetch current keylist mode
+       gpgme_keylist_mode_t mode = gpgme_get_keylist_mode(gpgctx);
+
+       // Set keylist mode
+       gpgme_error_t error = gpgme_set_keylist_mode(gpgctx, (mode|flags) & ~GPGME_KEYLIST_MODE_LOCAL);
+       if (error != GPG_ERR_NO_ERROR) {
+               ERROR(pakfire, "Could not set GPG keylist mode: %s\n",
+                       gpgme_strerror(error));
+               goto ERROR;
+       }
+
+       // Fetch the key
+       error = gpgme_get_key(gpgctx, what, key, 0);
+       switch (gpg_err_code(error)) {
+               case GPG_ERR_NO_ERROR:
+               case GPG_ERR_EOF:
+                       break;
+
+               default:
+                       ERROR(pakfire, "Could not fetch key %s: %s\n", what, gpgme_strerror(error));
+                       r = 1;
+                       goto ERROR;
+       }
+
+       // Success
+       r = 0;
+
+ERROR:
+       if (r && *key)
+               gpgme_key_unref(*key);
+
+       // Reset keylist mode
+       gpgme_set_keylist_mode(gpgctx, mode);
+
+       return r;
+}
+
+static int pakfire_key_fetch_from_wkd(gpgme_key_t* key, Pakfire pakfire, const char* email) {
+       return __pakfire_key_fetch(key, pakfire, email, GPGME_KEYLIST_MODE_LOCATE);
+}
+
+static int pakfire_key_fetch_from_keyserver(gpgme_key_t* key, Pakfire pakfire, const char* fpr) {
+       return __pakfire_key_fetch(key, pakfire, fpr, GPGME_KEYLIST_MODE_EXTERN);
+}
+
+PAKFIRE_EXPORT int pakfire_key_fetch(struct pakfire_key** key, Pakfire pakfire,
+               const char* uid, const char* fingerprint) {
+       // At least one (uid or fingerprint) must be set
+       if (!uid && !fingerprint) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       gpgme_key_t gpgkey = NULL;
+       char* email = NULL;
+       int r;
+
+       // Extract email address from uid
+       if (uid) {
+               r = pakfire_key_extract_email(uid, &email);
+               if (r)
+                       goto ERROR;
+       }
+
+       // Try importing the key using Web Key Directory
+       if (email) {
+               r = pakfire_key_fetch_from_wkd(&gpgkey, pakfire, email);
+               if (r)
+                       goto ERROR;
+       }
+
+       // If nothing was found and we have a fingerprint, let's try a keyserver
+       if (!gpgkey && fingerprint) {
+               r = pakfire_key_fetch_from_keyserver(&gpgkey, pakfire, fingerprint);
+               if (r)
+                       goto ERROR;
+       }
+
+       // Create a pakfire_key out of the gpg key object
+       if (gpgkey) {
+               r = pakfire_key_create(key, pakfire, gpgkey);
+               if (r)
+                       goto ERROR;
+       }
+
+ERROR:
+       if (gpgkey)
+               gpgme_key_unref(gpgkey);
+       if (email)
+               free(email);
+
+       return r;
+}
+
 static void pakfire_key_free(struct pakfire_key* key) {
        gpgme_key_unref(key->gpgkey);
        pakfire_unref(key->pakfire);
index dd8d6aa2ef5f07f8c6de1fb04810084c70e1e8af..8b920918a600cc9f204bea5d8cbe2099526b6b1e 100644 (file)
@@ -107,6 +107,7 @@ global:
        pakfire_key_delete;
        pakfire_key_dump;
        pakfire_key_export;
+       pakfire_key_fetch;
        pakfire_key_generate;
        pakfire_key_get;
        pakfire_key_get_email;
index d6aa8ac8c7186821781f5e4ae82bd9407d0c5bb6..112c2625003173edff3efbcee214e2463aa7ed3c 100644 (file)
@@ -88,6 +88,17 @@ class Cli(object):
                        help=_("Include the secret key"))
                export_key.set_defaults(func=self._export_key)
 
+               # fetch-key
+               fetch_key = subparsers.add_parser("fetch-key",
+                       help=_("Download a key"))
+               fetch_key.add_argument("--userid",
+                       help=_("The name/email address")
+               )
+               fetch_key.add_argument("--fingerprint",
+                       help=_("The fingerprint of the key")
+               )
+               fetch_key.set_defaults(func=self._fetch_key)
+
                # generate-key
                generate_key = subparsers.add_parser("generate-key",
                        help=_("Generate a new key"))
@@ -261,6 +272,13 @@ class Cli(object):
                else:
                        print(data)
 
+       def _fetch_key(self, p, args):
+               key = p.fetch_key(userid=args.userid, fingerprint=args.fingerprint)
+
+               # Print the key
+               if key:
+                       print(key)
+
        def _generate_key(self, p, args):
                # Generate a new key
                key = p.generate_key(