From: Michael Tremer Date: Thu, 1 Jun 2023 12:40:55 +0000 (+0000) Subject: keys: Replace usage of PGP by signify X-Git-Tag: 0.9.29~146 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b8effd38e41656371b5a87a7167c90871f62a5aa;p=pakfire.git keys: Replace usage of PGP by signify Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 5e6dd36fa..03cc312ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -337,7 +337,6 @@ libpakfire_la_LIBADD = \ $(CAP_LIBS) \ $(CURL_LIBS) \ $(ELF_LIBS) \ - $(GPGME_LIBS) \ $(JSON_C_LIBS) \ $(LZMA_LIBS) \ $(MAGIC_LIBS) \ @@ -565,8 +564,7 @@ tests_libpakfire_jail_LDADD = \ $(TESTSUITE_LDADD) tests_libpakfire_key_SOURCES = \ - tests/libpakfire/key.c \ - tests/libpakfire/key.h + tests/libpakfire/key.c tests_libpakfire_key_CPPFLAGS = \ $(TESTSUITE_CPPFLAGS) @@ -883,6 +881,7 @@ TESTSUITE_CPPFLAGS = \ $(AM_CPPFLAGS) \ $(PAKFIRE_CPPFLAGS) \ -DABS_TOP_SRCDIR=\"$(abs_top_srcdir)\" \ + -DTEST_DATA_DIR=\"$(abs_top_srcdir)/tests/data\" \ -DTEST_ROOTFS=\"$(TEST_ROOTFS)\" \ -DTEST_STUB_COMMAND=\"$(abs_top_builddir)/tests/stub/root/command\" \ -DTEST_STUB_ROOT=\"$(TEST_STUB_ROOT)\" \ @@ -926,6 +925,9 @@ EXTRA_DIST += \ \ tests/data/digest/random \ \ + tests/data/keys/key1.pub \ + tests/data/keys/key1.sec \ + \ tests/data/packages/dummy/dummy.nm \ \ tests/data/parser/test-comments.txt \ diff --git a/configure.ac b/configure.ac index 467fbad56..414b2885b 100644 --- a/configure.ac +++ b/configure.ac @@ -256,7 +256,6 @@ PKG_CHECK_MODULES([ARCHIVE], [libarchive >= 3.4.0]) PKG_CHECK_MODULES([CAP], [libcap]) PKG_CHECK_MODULES([CURL], [libcurl]) PKG_CHECK_MODULES([ELF], [libelf]) -PKG_CHECK_MODULES([GPGME], [gpgme >= 1.6.0]) PKG_CHECK_MODULES([PYTHON_DEVEL], [python-${PYTHON_VERSION}-embed], [], [PKG_CHECK_MODULES([PYTHON_DEVEL], [python-${PYTHON_VERSION}])]) PKG_CHECK_MODULES([JSON_C], [json-c >= 0.15]) diff --git a/src/_pakfire/key.c b/src/_pakfire/key.c index e7c6f52b3..73083171a 100644 --- a/src/_pakfire/key.c +++ b/src/_pakfire/key.c @@ -52,24 +52,10 @@ static void Key_dealloc(KeyObject* self) { Py_TYPE(self)->tp_free((PyObject *)self); } -static int Key_init(KeyObject* self, PyObject* args, PyObject* kwds) { - PakfireObject* pakfire; - const char* fingerprint = NULL; - - if (!PyArg_ParseTuple(args, "O!s", &PakfireType, &pakfire, &fingerprint)) - return -1; - - self->key = pakfire_key_get(pakfire->pakfire, fingerprint); - if (!self->key) - return -1; - - return 0; -} - static PyObject* Key_repr(KeyObject* self) { - const char* fingerprint = pakfire_key_get_fingerprint(self->key); + const char* id = pakfire_key_get_id(self->key); - return PyUnicode_FromFormat("<_pakfire.Key (%s)>", fingerprint); + return PyUnicode_FromFormat("<_pakfire.Key (%s)>", id); } static PyObject* Key_str(KeyObject* self) { @@ -81,80 +67,28 @@ static PyObject* Key_str(KeyObject* self) { return object; } -static PyObject* Key_get_created_at(KeyObject* self) { - const time_t t = pakfire_key_get_created(self->key); - - return PyDateTime_FromTime_t(&t); -} - -static PyObject* Key_get_expires_at(KeyObject* self) { - const time_t t = pakfire_key_get_expires(self->key); - - // Return None if the key does not expire - if (!t) - Py_RETURN_NONE; - - return PyDateTime_FromTime_t(&t); -} - -static PyObject* Key_get_fingerprint(KeyObject* self) { - const char* fingerprint = pakfire_key_get_fingerprint(self->key); - - return PyUnicode_FromString(fingerprint); -} - -static PyObject* Key_get_uid(KeyObject* self) { - const char* uid = pakfire_key_get_uid(self->key); - - // Raise an error on no input - if (!uid) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - return PyUnicode_FromString(uid); -} - -static PyObject* Key_get_name(KeyObject* self) { - const char* name = pakfire_key_get_name(self->key); - - // Raise an error on no input - if (!name) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - return PyUnicode_FromString(name); -} - -static PyObject* Key_get_email(KeyObject* self) { - const char* email = pakfire_key_get_email(self->key); +static PyObject* Key_get_id(KeyObject* self) { + const char* id = pakfire_key_get_id(self->key); // Raise an error on no input - if (!email) { + if (!id) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } - return PyUnicode_FromString(email); + return PyUnicode_FromString(id); } -static PyObject* Key_get_algo(KeyObject* self) { - const char* algo = pakfire_key_get_pubkey_algo(self->key); +static PyObject* Key_get_algorithm(KeyObject* self) { + const char* algorithm = pakfire_key_get_algo(self->key); // Raise an error on no input - if (!algo) { + if (algorithm) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } - return PyUnicode_FromString(algo); -} - -static PyObject* Key_get_length(KeyObject* self) { - const size_t length = pakfire_key_get_pubkey_length(self->key); - - return PyLong_FromLong(length); + return PyUnicode_FromString(algorithm); } static PyObject* Key_export(KeyObject* self, PyObject* args) { @@ -178,7 +112,7 @@ static PyObject* Key_export(KeyObject* self, PyObject* args) { pakfire_key_export_mode_t mode; if (secret) - mode = PAKFIRE_KEY_EXPORT_MODE_SECRET; + mode = PAKFIRE_KEY_EXPORT_MODE_PRIVATE; else mode = PAKFIRE_KEY_EXPORT_MODE_PUBLIC; @@ -200,54 +134,6 @@ static PyObject* Key_delete(KeyObject* self) { return NULL; } -static PyObject* Key_get_public_key(KeyObject* self) { - char* buffer = NULL; - size_t length = 0; - int r; - - PyObject* object = NULL; - - // Fetch the public key - r = pakfire_key_get_public_key(self->key, &buffer, &length); - if (r) { - PyErr_SetFromErrno(PyExc_OSError); - goto ERROR; - } - - // Create a unicode object - object = PyUnicode_FromStringAndSize(buffer, length); - -ERROR: - if (buffer) - free(buffer); - - return object; -} - -static PyObject* Key_get_secret_key(KeyObject* self) { - char* buffer = NULL; - size_t length = 0; - int r; - - PyObject* object = NULL; - - // Fetch the secret key - r = pakfire_key_get_secret_key(self->key, &buffer, &length); - if (r) { - PyErr_SetFromErrno(PyExc_OSError); - goto ERROR; - } - - // Create a unicode object - object = PyUnicode_FromStringAndSize(buffer, length); - -ERROR: - if (buffer) - free(buffer); - - return object; -} - static struct PyMethodDef Key_methods[] = { { "delete", @@ -266,71 +152,15 @@ static struct PyMethodDef Key_methods[] = { static struct PyGetSetDef Key_getsetters[] = { { - "algo", - (getter)Key_get_algo, - NULL, - NULL, - NULL, - }, - { - "created_at", - (getter)Key_get_created_at, - NULL, - NULL, - NULL, - }, - { - "email", - (getter)Key_get_email, - NULL, - NULL, - NULL, - }, - { - "expires_at", - (getter)Key_get_expires_at, - NULL, - NULL, - NULL, - }, - { - "fingerprint", - (getter)Key_get_fingerprint, - NULL, - NULL, - NULL, - }, - { - "length", - (getter)Key_get_length, - NULL, - NULL, - NULL, - }, - { - "name", - (getter)Key_get_name, - NULL, - NULL, - NULL, - }, - { - "public_key", - (getter)Key_get_public_key, - NULL, - NULL, - NULL, - }, - { - "secret_key", - (getter)Key_get_secret_key, + "algorithm", + (getter)Key_get_algorithm, NULL, NULL, NULL, }, { - "uid", - (getter)Key_get_uid, + "id", + (getter)Key_get_id, NULL, NULL, NULL, @@ -345,7 +175,6 @@ PyTypeObject KeyType = { tp_flags: Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, tp_new: Key_new, tp_dealloc: (destructor)Key_dealloc, - tp_init: (initproc)Key_init, tp_doc: "Key object", tp_methods: Key_methods, tp_getset: Key_getsetters, diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 811206cd3..764e3eb1f 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -641,34 +641,16 @@ static PyObject* Pakfire_get_keys(PakfireObject* self) { return list; } -static PyObject* Pakfire_get_key(PakfireObject* self, PyObject* args) { - const char* pattern = NULL; - - if (!PyArg_ParseTuple(args, "s", &pattern)) - return NULL; - - // Try finding the key - struct pakfire_key* key = pakfire_key_get(self->pakfire, pattern); - if (!key) - Py_RETURN_NONE; - - PyObject* object = new_key(&KeyType, key); - pakfire_key_unref(key); - - return object; -} - static PyObject* Pakfire_generate_key(PakfireObject* self, PyObject* args, PyObject* kwds) { - char* kwlist[] = { "userid", "algorithm", NULL }; + char* kwlist[] = { "algorithm", NULL }; struct pakfire_key* key = NULL; - const char* userid = NULL; - const char* algo = NULL; + pakfire_key_algo_t algo = PAKFIRE_KEY_ALGO_NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|$z", kwlist, &userid, &algo)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &algo)) return NULL; // Generate a new key - int r = pakfire_key_generate(&key, self->pakfire, algo, userid); + int r = pakfire_key_generate(&key, self->pakfire, algo); if (r) { PyErr_SetFromErrno(PyExc_OSError); return NULL; @@ -680,44 +662,6 @@ static PyObject* Pakfire_generate_key(PakfireObject* self, PyObject* args, PyObj return object; } -static PyObject* Pakfire_import_key(PakfireObject* self, PyObject* args) { - PyObject* object = NULL; - - if (!PyArg_ParseTuple(args, "O", &object)) - return NULL; - - // Get a file descriptor from object - int fd = PyObject_AsFileDescriptor(object); - if (fd < 0) - return NULL; - - // Convert to FILE* - FILE* f = fdopen(fd, "r"); - if (!f) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - struct pakfire_key** keys = NULL; - - // Import keys from f - int r = pakfire_key_import(self->pakfire, f, &keys); - if (r) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - // Convert keys to list - PyObject* list = Pakfire_keys_to_list(keys); - - // Free keys - for (struct pakfire_key** key = keys; *key; key++) - pakfire_key_unref(*key); - free(keys); - - return list; -} - static PyObject* Pakfire_whatprovides(PakfireObject* self, PyObject* args) { const char* provides = NULL; struct pakfire_packagelist* list = NULL; @@ -1584,24 +1528,12 @@ static struct PyMethodDef Pakfire_methods[] = { METH_VARARGS|METH_KEYWORDS, NULL }, - { - "get_key", - (PyCFunction)Pakfire_get_key, - METH_VARARGS, - NULL - }, { "get_repo", (PyCFunction)Pakfire_get_repo, METH_VARARGS, NULL }, - { - "import_key", - (PyCFunction)Pakfire_import_key, - METH_VARARGS, - NULL - }, { "install", (PyCFunction)Pakfire_install, diff --git a/src/libpakfire/include/pakfire/key.h b/src/libpakfire/include/pakfire/key.h index 139bc63ca..a083335cf 100644 --- a/src/libpakfire/include/pakfire/key.h +++ b/src/libpakfire/include/pakfire/key.h @@ -27,52 +27,39 @@ struct pakfire_key; #include +typedef enum pakfire_key_algos { + PAKFIRE_KEY_ALGO_NULL = 0, + PAKFIRE_KEY_ALGO_ED25519, +} pakfire_key_algo_t; + typedef enum pakfire_key_export_mode { PAKFIRE_KEY_EXPORT_MODE_PUBLIC = 0, - PAKFIRE_KEY_EXPORT_MODE_SECRET, + PAKFIRE_KEY_EXPORT_MODE_PRIVATE, } pakfire_key_export_mode_t; 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, struct pakfire* pakfire, - const char* uid, const char* fingerprint); - -struct pakfire_key* pakfire_key_get(struct pakfire* pakfire, const char* fingerprint); int pakfire_key_delete(struct pakfire_key* key); // Access key properties -const char* pakfire_key_get_fingerprint(struct pakfire_key* key); -const char* pakfire_key_get_uid(struct pakfire_key* key); -const char* pakfire_key_get_name(struct pakfire_key* key); -const char* pakfire_key_get_email(struct pakfire_key* key); -const char* pakfire_key_get_pubkey_algo(struct pakfire_key* key); -size_t pakfire_key_get_pubkey_length(struct pakfire_key* key); -int pakfire_key_has_secret(struct pakfire_key* key); -time_t pakfire_key_get_created(struct pakfire_key* key); -time_t pakfire_key_get_expires(struct pakfire_key* key); -int pakfire_key_is_revoked(struct pakfire_key* key); +const char* pakfire_key_get_id(struct pakfire_key* key); +const char* pakfire_key_get_algo(struct pakfire_key* key); int pakfire_key_generate(struct pakfire_key** key, struct pakfire* pakfire, - const char* algo, const char* userid); -int pakfire_key_export(struct pakfire_key* key, FILE* f, pakfire_key_export_mode_t mode); -int pakfire_key_import(struct pakfire* pakfire, FILE* f, struct pakfire_key*** keys); - -int pakfire_key_get_public_key(struct pakfire_key* key, char** buffer, size_t* length); -int pakfire_key_get_secret_key(struct pakfire_key* key, char** buffer, size_t* length); + const pakfire_key_algo_t algo); +int pakfire_key_export(struct pakfire_key* key, FILE* f, const pakfire_key_export_mode_t mode); +int pakfire_key_import(struct pakfire_key** key, struct pakfire* pakfire, FILE* f); char* pakfire_key_dump(struct pakfire_key* key); #ifdef PAKFIRE_PRIVATE -#include - -#define PAKFIRE_KEY_FPR_MAXLEN 41 - -int pakfire_key_create(struct pakfire_key** key, struct pakfire* pakfire, gpgme_key_t gpgkey); +int pakfire_key_import_from_string(struct pakfire_key** key, + struct pakfire* pakfire, const char* data, const size_t length); -int pakfire_key_sign(struct pakfire_key* key, const char* buffer, const size_t buffer_length, - char** signature, size_t* signature_length, time_t* timestamp); +int pakfire_key_sign(struct pakfire_key* key, + FILE* f, const char* data, const size_t length, const char* comment); #endif diff --git a/src/libpakfire/include/pakfire/pakfire.h b/src/libpakfire/include/pakfire/pakfire.h index c58b16ba5..9950161ef 100644 --- a/src/libpakfire/include/pakfire/pakfire.h +++ b/src/libpakfire/include/pakfire/pakfire.h @@ -120,7 +120,6 @@ int pakfire_sync(struct pakfire* pakfire, int solver_flags, int flags, int* chan #include -#include #include #include @@ -151,7 +150,6 @@ int pakfire_is_mountpoint(struct pakfire* pakfire, const char* path); int pakfire_confirm(struct pakfire* pakfire, const char* message, const char* question); magic_t pakfire_get_magic(struct pakfire* pakfire); -gpgme_ctx_t pakfire_get_gpgctx(struct pakfire* pakfire); const char* pakfire_get_distro_name(struct pakfire* pakfire); const char* pakfire_get_distro_id(struct pakfire* pakfire); @@ -160,8 +158,6 @@ const char* pakfire_get_distro_version(struct pakfire* pakfire); const char* pakfire_get_distro_version_id(struct pakfire* pakfire); const char* pakfire_get_distro_tag(struct pakfire* pakfire); -const char* pakfire_get_keystore_path(struct pakfire* pakfire); - #define pakfire_path(pakfire, path, format, ...) \ __pakfire_path(pakfire, path, sizeof(path), format, __VA_ARGS__) int __pakfire_path(struct pakfire* pakfire, char* path, const size_t length, diff --git a/src/libpakfire/include/pakfire/util.h b/src/libpakfire/include/pakfire/util.h index d9a1505d5..fee3ab311 100644 --- a/src/libpakfire/include/pakfire/util.h +++ b/src/libpakfire/include/pakfire/util.h @@ -121,6 +121,11 @@ int pakfire_rlimit_reset_nofile(struct pakfire* pakfire); int pakfire_compile_regex(struct pakfire* pakfire, pcre2_code** regex, const char* pattern); +// Base64 + +int pakfire_b64encode(struct pakfire* pakfire, char** output, + const void* buffer, const size_t length); + #endif #endif /* PAKFIRE_UTIL_H */ diff --git a/src/libpakfire/key.c b/src/libpakfire/key.c index f10527d34..d7a07c95e 100644 --- a/src/libpakfire/key.c +++ b/src/libpakfire/key.c @@ -19,13 +19,19 @@ #############################################################################*/ #include -#include #include #include #include +#include #include #include +// OpenSSL +#include +#include +#include +#include + #include #include #include @@ -35,15 +41,53 @@ #include #include +// Size of the buffer to allocate for error messages +#define ERROR_MAX 1024 + +typedef unsigned char pakfire_key_id[8]; + struct pakfire_key { struct pakfire* pakfire; int nrefs; - gpgme_key_t gpgkey; + // Algorithm + pakfire_key_algo_t algo; + + // Key ID + pakfire_key_id id; + + // The public (or private) key + EVP_PKEY* pkey; +}; + +struct pakfire_key_public_key { + unsigned char sig_algo[2]; + pakfire_key_id id; + unsigned char pubkey[32]; +}; + +struct pakfire_key_private_key { + unsigned char sig_algo[2]; + unsigned char kdf_algo[2]; + uint32_t kdf_rounds; + unsigned char kdf_salt[16]; + unsigned char checksum[8]; + pakfire_key_id id; + struct { + unsigned char secret[32]; + unsigned char public[32]; + } keys; +}; + +struct pakfire_key_signature { + unsigned char sig_algo[2]; + pakfire_key_id key_id; + unsigned char signature[64]; }; -int pakfire_key_create(struct pakfire_key** key, struct pakfire* pakfire, gpgme_key_t gpgkey) { - if (!gpgkey) { +static int pakfire_key_create(struct pakfire_key** key, struct pakfire* pakfire, + const pakfire_key_algo_t algo, const pakfire_key_id id, EVP_PKEY* pkey) { + if (!pkey) { errno = EINVAL; return 1; } @@ -57,16 +101,39 @@ int pakfire_key_create(struct pakfire_key** key, struct pakfire* pakfire, gpgme_ k->pakfire = pakfire_ref(pakfire); k->nrefs = 1; + // Store the algorithm + switch (algo) { + case PAKFIRE_KEY_ALGO_ED25519: + k->algo = algo; + break; + + default: + ERROR(pakfire, "Unsupported key algorithm %d\n", algo); + errno = ENOTSUP; + goto ERROR; + } + + // Store the key ID + memcpy(k->id, id, sizeof(k->id)); + // Keep a reference to this key - gpgme_key_ref(gpgkey); - k->gpgkey = gpgkey; + EVP_PKEY_up_ref(pkey); + k->pkey = pkey; *key = k; return 0; + +ERROR: + pakfire_key_unref(k); + + return 1; } static void pakfire_key_free(struct pakfire_key* key) { - gpgme_key_unref(key->gpgkey); + // Free the key + if (key->pkey) + EVP_PKEY_free(key->pkey); + pakfire_unref(key->pakfire); free(key); } @@ -84,631 +151,709 @@ PAKFIRE_EXPORT void pakfire_key_unref(struct pakfire_key* key) { pakfire_key_free(key); } -static int pakfire_find_key(struct pakfire_key** key, struct pakfire* pakfire, const char* fingerprint) { - if (!fingerprint) { - errno = EINVAL; - return 1; - } - - // Reset key - *key = NULL; +PAKFIRE_EXPORT const char* pakfire_key_get_algo(struct pakfire_key* key) { + switch (key->algo) { + case PAKFIRE_KEY_ALGO_ED25519: + return "Ed255919"; - // Fetch GPGME context - gpgme_ctx_t gpgctx = pakfire_get_gpgctx(pakfire); - if (!gpgctx) - return 1; + case PAKFIRE_KEY_ALGO_NULL: + break; + } - DEBUG(pakfire, "Seaching for key with fingerprint %s\n", fingerprint); + return NULL; +} - gpgme_key_t gpgkey = NULL; +PAKFIRE_EXPORT int pakfire_key_generate(struct pakfire_key** key, struct pakfire* pakfire, + const pakfire_key_algo_t algo) { + EVP_PKEY* pkey = NULL; + EVP_PKEY_CTX* pctx = NULL; + pakfire_key_id key_id; + char error[ERROR_MAX]; + int id; int r; - gpgme_error_t error = gpgme_get_key(gpgctx, fingerprint, &gpgkey, 0); - switch (gpg_error(error)) { - // Create a key object if we found something - case GPG_ERR_NO_ERROR: - r = pakfire_key_create(key, pakfire, gpgkey); - gpgme_key_unref(gpgkey); - if (r) - return r; + switch (algo) { + case PAKFIRE_KEY_ALGO_ED25519: + id = EVP_PKEY_ED25519; break; - // Nothing found - case GPG_ERR_EOF: - break; + default: + ERROR(pakfire, "Invalid key algorithm %d\n", algo); + errno = EINVAL; + return 1; } - return 0; -} + // Generate a random key ID + r = RAND_bytes(key_id, sizeof(key_id)); + if (r < 0) { + ERROR(pakfire, "Could not generate the key ID\n"); + r = 1; + goto ERROR; + } -PAKFIRE_EXPORT struct pakfire_key* pakfire_key_get(struct pakfire* pakfire, const char* fingerprint) { - struct pakfire_key* key = NULL; + // Setup the context + pctx = EVP_PKEY_CTX_new_id(id, NULL); + if (!pctx) { + ERROR(pakfire, "Could not allocate the OpenSSL context: %m\n"); + r = 1; + goto ERROR; + } - int r = pakfire_find_key(&key, pakfire, fingerprint); - if (r) - return NULL; + // Prepare the context for key generation + r = EVP_PKEY_keygen_init(pctx); + if (r < 1) { + ERR_error_string_n(r, error, sizeof(error)); - return key; -} + ERROR(pakfire, "Could not prepare the context: %s\n", error); + r = 1; + goto ERROR; + } -PAKFIRE_EXPORT int pakfire_key_delete(struct pakfire_key* key) { - gpgme_ctx_t gpgctx = pakfire_get_gpgctx(key->pakfire); + // Generate the key + r = EVP_PKEY_keygen(pctx, &pkey); + if (r < 1) { + ERR_error_string_n(r, error, sizeof(error)); - int r = 0; - gpgme_error_t error = gpgme_op_delete(gpgctx, key->gpgkey, 1); - if (error != GPG_ERR_NO_ERROR) + ERROR(pakfire, "Could not generate the key: %s\n", error); r = 1; + goto ERROR; + } - return r; -} + // Create a key object + r = pakfire_key_create(key, pakfire, algo, key_id, pkey); + if (r) + goto ERROR; -PAKFIRE_EXPORT const char* pakfire_key_get_fingerprint(struct pakfire_key* key) { - return key->gpgkey->fpr; -} + // Success + r = 0; -PAKFIRE_EXPORT const char* pakfire_key_get_uid(struct pakfire_key* key) { - if (key->gpgkey->uids) - return key->gpgkey->uids->uid; +ERROR: + if (pctx) + EVP_PKEY_CTX_free(pctx); + if (pkey) + EVP_PKEY_free(pkey); - return NULL; + return r; } -PAKFIRE_EXPORT const char* pakfire_key_get_name(struct pakfire_key* key) { - if (key->gpgkey->uids) - return key->gpgkey->uids->name; +/* + Import +*/ - return NULL; -} - -PAKFIRE_EXPORT const char* pakfire_key_get_email(struct pakfire_key* key) { - if (key->gpgkey->uids) - return key->gpgkey->uids->email; +static int pakfire_key_import_secret_key(struct pakfire_key** key, + struct pakfire* pakfire, const struct pakfire_key_private_key* buffer) { + const pakfire_key_algo_t algo = PAKFIRE_KEY_ALGO_ED25519; + EVP_PKEY* pkey = NULL; + char error[ERROR_MAX]; + int r; - return NULL; -} + unsigned char checksum[64]; + unsigned int length = sizeof(checksum); -PAKFIRE_EXPORT const char* pakfire_key_get_pubkey_algo(struct pakfire_key* key) { - if (!key->gpgkey->subkeys) - return NULL; + // Check for input + if (!buffer) { + errno = EINVAL; + return 1; + } - switch (key->gpgkey->subkeys->pubkey_algo) { - case GPGME_PK_RSA: - case GPGME_PK_RSA_E: - case GPGME_PK_RSA_S: - return "RSA"; + // Check the signature algorithm + if (buffer->sig_algo[0] != 'E' || buffer->sig_algo[1] != 'd') { + ERROR(pakfire, "Unsupported signature algorithm\n"); + errno = ENOTSUP; + r = 1; + goto ERROR; + } - case GPGME_PK_DSA: - return "DSA"; + // Check the KDF algorithm + if (buffer->kdf_algo[0] != 'B' || buffer->kdf_algo[1] != 'K') { + ERROR(pakfire, "Unsupported KDF algorithm\n"); + errno = ENOTSUP; + r = 1; + goto ERROR; + } - case GPGME_PK_ECDSA: - return "ECDSA"; + // We don't support encrypted keys here + if (buffer->kdf_rounds) { + ERROR(pakfire, "Encrypted keys are not supported\n"); + errno = ENOTSUP; + r = 1; + goto ERROR; + } - case GPGME_PK_ECDH: - return "ECDH"; + // Compute a SHA512 checksum over the key material + r = EVP_Digest(&buffer->keys, sizeof(buffer->keys), checksum, &length, EVP_sha512(), NULL); + if (r < 0) { + ERROR(pakfire, "Could not compute the checksum: %m\n"); + r = 1; + goto ERROR; + } - case GPGME_PK_ECC: - return "ECC"; + // Compare the checksum + if (memcmp(buffer->checksum, checksum, sizeof(buffer->checksum)) != 0) { + ERROR(pakfire, "Checksum mismatch\n"); + r = 1; + goto ERROR; + } - case GPGME_PK_EDDSA: - return "EDDSA"; + // Load the private key + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, + buffer->keys.secret, sizeof(buffer->keys.secret)); + if (!pkey) { + ERR_error_string_n(ERR_get_error(), error, sizeof(error)); - case GPGME_PK_ELG: - case GPGME_PK_ELG_E: - return "ELG"; + ERROR(pakfire, "Could not load secret key: %s\n", error); + r = 1; + goto ERROR; } - return NULL; -} + // Create a new key object + r = pakfire_key_create(key, pakfire, algo, buffer->id, pkey); + if (r) + goto ERROR; -PAKFIRE_EXPORT size_t pakfire_key_get_pubkey_length(struct pakfire_key* key) { - if (key->gpgkey->subkeys) - return key->gpgkey->subkeys->length; +ERROR: + if (pkey) + EVP_PKEY_free(pkey); return 0; } -PAKFIRE_EXPORT int pakfire_key_has_secret(struct pakfire_key* key) { - if (key->gpgkey) - return key->gpgkey->secret; +static int pakfire_key_import_public_key(struct pakfire_key** key, + struct pakfire* pakfire, const struct pakfire_key_public_key* buffer) { + const pakfire_key_algo_t algo = PAKFIRE_KEY_ALGO_ED25519; + EVP_PKEY* pkey = NULL; + char error[ERROR_MAX]; + int r; - return 0; -} + // Check for input + if (!buffer) { + errno = EINVAL; + return 1; + } -PAKFIRE_EXPORT time_t pakfire_key_get_created(struct pakfire_key* key) { - if (key->gpgkey->subkeys) - return key->gpgkey->subkeys->timestamp; + // Check the signature algorithm + if (buffer->sig_algo[0] != 'E' || buffer->sig_algo[1] != 'd') { + ERROR(pakfire, "Unsupported signature algorithm\n"); + errno = ENOTSUP; + r = 1; + goto ERROR; + } - return 0; -} + // Load the public key + pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, + buffer->pubkey, sizeof(buffer->pubkey)); + if (!pkey) { + ERR_error_string_n(ERR_get_error(), error, sizeof(error)); -PAKFIRE_EXPORT time_t pakfire_key_get_expires(struct pakfire_key* key) { - if (key->gpgkey->subkeys) - return key->gpgkey->subkeys->expires; + ERROR(pakfire, "Could not load public key: %s\n", error); + r = 1; + goto ERROR; + } - return 0; -} + // Create a new key object + r = pakfire_key_create(key, pakfire, algo, buffer->id, pkey); + if (r) + goto ERROR; -PAKFIRE_EXPORT int pakfire_key_is_revoked(struct pakfire_key* key) { - if (key->gpgkey->subkeys) - return key->gpgkey->subkeys->revoked; +ERROR: + if (pkey) + EVP_PKEY_free(pkey); - return 0; + return r; } -static int pakfire_key_write_to_keystore(struct pakfire_key* key) { - // Fetch keystore path - const char* keystore_path = pakfire_get_keystore_path(key->pakfire); - if (!keystore_path) - return 1; - - // Fetch fingerprint - const char* fpr = pakfire_key_get_fingerprint(key); - if (!fpr) - return 1; +PAKFIRE_EXPORT int pakfire_key_import(struct pakfire_key** key, + struct pakfire* pakfire, FILE* f) { + BIO* bio = NULL; + BIO* b64 = NULL; + char buffer[4096]; + size_t bytes_read = 0; + int r; - char path[PATH_MAX]; + // Setup the base64 decoder + b64 = BIO_new(BIO_f_base64()); + if (!b64) { + ERROR(pakfire, "Could not setup the base64 decoder\n"); + r = 1; + goto ERROR; + } - // Make path - int r = pakfire_string_format(path, "%s/%s.key", keystore_path, fpr); - if (r) - return r; + bio = BIO_new_fp(f, BIO_NOCLOSE); + if (!bio) { + ERROR(pakfire, "Could not open BIO\n"); + r = 1; + goto ERROR; + } - // Create parent directory - r = pakfire_mkparentdir(path, 0700); - if (r) - return r; + BIO_push(b64, bio); - // Create file - FILE* f = fopen(path, "w"); - if (!f) { - ERROR(key->pakfire, "Could not open %s for writing: %m\n", path); - return 1; + // Try to read everything into the buffer + r = BIO_read_ex(b64, buffer, sizeof(buffer), &bytes_read); + if (r < 0) { + ERROR(pakfire, "Could not read data\n"); + r = 1; + goto ERROR; } - // Make files with secret keys non-world-readable - if (pakfire_key_has_secret(key)) { - r = chmod(path, 0600); - if (r) { - ERROR(key->pakfire, "Could not chmod %s: %m\n", path); - fclose(f); - return r; - } - } + const struct pakfire_key_private_key* private_key = + (const struct pakfire_key_private_key*)buffer; + const struct pakfire_key_public_key* public_key = + (const struct pakfire_key_public_key*)buffer; - // Write key to file - r = pakfire_key_export(key, f, 0); - if (r) { - ERROR(key->pakfire, "Could not export key %s: %m\n", fpr); - unlink(path); + // Try to find what we have read + switch (bytes_read) { + + // Import a private key + case sizeof(*private_key): + r = pakfire_key_import_secret_key(key, pakfire, private_key); + break; + + // Import a public key + case sizeof(*public_key): + r = pakfire_key_import_public_key(key, pakfire, public_key); + break; + + default: + ERROR(pakfire, "Unsupported key type\n"); + r = 1; + goto ERROR; } - // Close file - fclose(f); +ERROR: + if (b64) + BIO_free(b64); + if (bio) + BIO_free(bio); return r; } -PAKFIRE_EXPORT int pakfire_key_generate(struct pakfire_key** key, struct pakfire* pakfire, - const char* algo, const char* userid) { +int pakfire_key_import_from_string(struct pakfire_key** key, + struct pakfire* pakfire, const char* data, const size_t length) { + FILE* f = NULL; int r; - // Check input - if (!algo || !userid) { - errno = EINVAL; - return 1; + // Map the data to a file + f = fmemopen((char*)data, length, "r"); + if (!f) { + ERROR(pakfire, "Could not map the key to file: %m\n"); + r = 1; + goto ERROR; } - // Fetch GPGME context - gpgme_ctx_t gpgctx = pakfire_get_gpgctx(pakfire); - if (!gpgctx) - return 1; + // Import the key + r = pakfire_key_import(key, pakfire, f); - const unsigned int flags = - // Key should be able to be used to sign - GPGME_CREATE_SIGN | - // Don't set a password - GPGME_CREATE_NOPASSWD | - // The key should never expire - GPGME_CREATE_NOEXPIRE; +ERROR: + if (f) + fclose(f); - // Generate the key - gpgme_error_t error = gpgme_op_createkey(gpgctx, userid, - algo, 0, 0, NULL, flags); - - if (error != GPG_ERR_NO_ERROR) { - switch (gpg_err_code(error)) { - case GPG_ERR_USER_ID_EXISTS: - case GPG_ERR_NAME_EXISTS: - errno = EINVAL; - break; - - default: - break; - } + return r; +} + +static int pakfire_key_get_public_key(struct pakfire_key* key, + unsigned char* buffer, const size_t length) { + char error[ERROR_MAX]; + int r; - ERROR(pakfire, "%s\n", gpgme_strerror(error)); + size_t l = length; + + // Extract the raw public key + r = EVP_PKEY_get_raw_public_key(key->pkey, buffer, &l); + if (r < 0) { + ERR_error_string_n(ERR_get_error(), error, sizeof(error)); + + ERROR(key->pakfire, "Could not extract the public key: %s\n", error); return 1; } - // Retrieve the result - gpgme_genkey_result_t result = gpgme_op_genkey_result(gpgctx); - - // Retrieve the key by its fingerprint - r = pakfire_find_key(key, pakfire, result->fpr); - if (r) - return r; + if (l > length) { + ERROR(key->pakfire, "The buffer was too small to write the public key\n"); + errno = ENOBUFS; + return 1; + } - // Store the key in the keystore - return pakfire_key_write_to_keystore(*key); + return 0; } -static int pakfire_key_data(struct pakfire_key* key, char** buffer, size_t* length, - const pakfire_key_export_mode_t mode) { - char* output = NULL; +static int pakfire_key_get_secret_key(struct pakfire_key* key, + unsigned char* buffer, const size_t length) { + char error[ERROR_MAX]; + int r; - gpgme_ctx_t gpgctx = pakfire_get_gpgctx(key->pakfire); - if (!gpgctx) - return 1; + size_t l = length; - gpgme_export_mode_t gpgmode = 0; - switch (mode) { - case PAKFIRE_KEY_EXPORT_MODE_SECRET: - gpgmode |= GPGME_EXPORT_MODE_SECRET; - break; + // Extract the raw secret key + r = EVP_PKEY_get_raw_private_key(key->pkey, buffer, &l); + if (r < 0) { + ERR_error_string_n(ERR_get_error(), error, sizeof(error)); - default: - break; + ERROR(key->pakfire, "Could not extract the secret key: %s\n", error); + return 1; } - const char* fingerprint = pakfire_key_get_fingerprint(key); - - DEBUG(key->pakfire, "Exporting key %s\n", fingerprint); + if (l > length) { + ERROR(key->pakfire, "The buffer was too small to write the secret key\n"); + errno = ENOBUFS; + return 1; + } - gpgme_data_t data = NULL; - int r = 1; + return 0; +} - // Initialize the buffer - gpgme_error_t e = gpgme_data_new(&data); - if (gpg_err_code(e) != GPG_ERR_NO_ERROR) - goto ERROR; +/* + Export +*/ - // Encode output as ASCII - e = gpgme_data_set_encoding(data, GPGME_DATA_ENCODING_ARMOR); - if (gpg_err_code(e) != GPG_ERR_NO_ERROR) - goto ERROR; +static int pakfire_key_export_private_key(struct pakfire_key* key, + struct pakfire_key_private_key* buffer) { + unsigned char checksum[64]; + unsigned int length = sizeof(checksum); + int r; - // Copy the key to the buffer - e = gpgme_op_export(gpgctx, fingerprint, gpgmode, data); - if (gpg_err_code(e) != GPG_ERR_NO_ERROR) - goto ERROR; + // Write the algorithm + switch (key->algo) { + case PAKFIRE_KEY_ALGO_ED25519: + // Signature Algortihm + buffer->sig_algo[0] = 'E'; + buffer->sig_algo[1] = 'd'; - // Fetch data from buffer - output = gpgme_data_release_and_get_mem(data, length); + // KDF Algorithm + buffer->kdf_algo[0] = 'B'; + buffer->kdf_algo[1] = 'K'; + break; - // Reset data so it won't be freed again - data = NULL; + default: + ERROR(key->pakfire, "Unknown algorithm\n"); + return 1; + } - // Allocate buffer - *buffer = malloc(*length); - if (!*buffer) { - r = 1; - goto ERROR; + // Generate a salt + r = RAND_bytes(buffer->kdf_salt, sizeof(buffer->kdf_salt)); + if (r < 1) { + ERROR(key->pakfire, "Could not generate salt\n"); + return 1; } - // Copy the output buffer - memcpy(*buffer, output, *length); + // Copy the key ID + memcpy(buffer->id, key->id, sizeof(buffer->id)); - // Success - r = 0; + // Write the public key + r = pakfire_key_get_public_key(key, buffer->keys.public, sizeof(buffer->keys.public)); + if (r) { + ERROR(key->pakfire, "Could not export the public key: %m\n"); + return r; + } -ERROR: - if (output) - gpgme_free(output); - if (data) - gpgme_data_release(data); + // Write the secret key + r = pakfire_key_get_secret_key(key, buffer->keys.secret, sizeof(buffer->keys.secret)); + if (r) { + ERROR(key->pakfire, "Could not export the secret key: %m\n"); + return r; + } - return r; -} + // Compute a SHA512 checksum over the key material + r = EVP_Digest(&buffer->keys, sizeof(buffer->keys), checksum, &length, EVP_sha512(), NULL); + if (r < 0) { + ERROR(key->pakfire, "Could not compute the checksum: %m\n"); + return 1; + } -PAKFIRE_EXPORT int pakfire_key_get_public_key(struct pakfire_key* key, - char** buffer, size_t* length) { - // Fetch the public key - return pakfire_key_data(key, buffer, length, PAKFIRE_KEY_EXPORT_MODE_PUBLIC); -} + // Copy the first couple of bytes of the checksum + memcpy(buffer->checksum, checksum, sizeof(buffer->checksum)); -PAKFIRE_EXPORT int pakfire_key_get_secret_key(struct pakfire_key* key, - char** buffer, size_t* length) { - // Fetch the secret key - return pakfire_key_data(key, buffer, length, PAKFIRE_KEY_EXPORT_MODE_SECRET); + // Success! + return 0; } -PAKFIRE_EXPORT int pakfire_key_export(struct pakfire_key* key, FILE* f, - pakfire_key_export_mode_t mode) { - char* buffer = NULL; - size_t length = 0; +static int pakfire_key_export_public_key(struct pakfire_key* key, + struct pakfire_key_public_key* buffer) { int r; - // Check input - if (!f) { - errno = EINVAL; - return 1; - } - - r = pakfire_key_data(key, &buffer, &length, mode); - if (r) - return r; + // Write the algorithm + switch (key->algo) { + case PAKFIRE_KEY_ALGO_ED25519: + buffer->sig_algo[0] = 'E'; + buffer->sig_algo[1] = 'd'; + break; - // Write key to file - size_t bytes_written = fwrite(buffer, 1, length, f); - if (bytes_written < length) { - r = 1; - goto ERROR; + default: + ERROR(key->pakfire, "Unknown algorithm\n"); + return 1; } - // Flush f - r = fflush(f); - if (r) - goto ERROR; - - // Success - r = 0; + // Copy the key ID + memcpy(buffer->id, key->id, sizeof(buffer->id)); -ERROR: - if (buffer) - gpgme_free(buffer); + // Write the public key + r = pakfire_key_get_public_key(key, buffer->pubkey, sizeof(buffer->pubkey)); + if (r) { + ERROR(key->pakfire, "Could not export the public key: %m\n"); + return r; + } - return r; + // Success! + return 0; } -PAKFIRE_EXPORT int pakfire_key_import(struct pakfire* pakfire, FILE* f, - struct pakfire_key*** keys) { - gpgme_data_t data; - int r = 1; - - if (!f) { - errno = EINVAL; - return 1; - } +PAKFIRE_EXPORT int pakfire_key_export(struct pakfire_key* key, FILE* f, + const pakfire_key_export_mode_t mode) { + struct pakfire_key_public_key public_key = { 0 }; + struct pakfire_key_private_key private_key = { 0 }; + int r; - // Reset keys - if (keys) - *keys = NULL; + BIO* bio = NULL; + BIO* b64 = NULL; - // Fetch GPGME context - gpgme_ctx_t gpgctx = pakfire_get_gpgctx(pakfire); - if (!gpgctx) - return 1; + // Setup the base64 encoder + b64 = BIO_new(BIO_f_base64()); + if (!b64) { + ERROR(key->pakfire, "Could not setup the base64 encoder\n"); + r = 1; + goto ERROR; + } - gpgme_import_result_t result = NULL; + // Disable line breaks and a trailing newline + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - // Import key data - gpgme_error_t e = gpgme_data_new_from_stream(&data, f); - if (gpg_error(e) != GPG_ERR_NO_ERROR) + bio = BIO_new_fp(f, BIO_NOCLOSE); + if (!bio) { + ERROR(key->pakfire, "Could not open BIO\n"); + r = 1; goto ERROR; + } - // Try importing the key(s) - e = gpgme_op_import(gpgctx, data); - - switch (gpg_error(e)) { - // Everything went fine - case GPG_ERR_NO_ERROR: - result = gpgme_op_import_result(gpgctx); + BIO_push(b64, bio); - // Keep the result - gpgme_result_ref(result); + switch (mode) { + case PAKFIRE_KEY_EXPORT_MODE_PUBLIC: + r = pakfire_key_export_public_key(key, &public_key); + if (r) + goto ERROR; - // Did we import any keys? - gpgme_import_status_t status = result->imports; - if (!status) { - errno = ENOENT; + // Write the output + r = BIO_write(b64, &public_key, sizeof(public_key)); + if (r < 0) { + ERROR(key->pakfire, "Could not write the public key\n"); + r = 1; goto ERROR; } + break; - DEBUG(pakfire, "Keys considered = %d\n", result->considered); - DEBUG(pakfire, "Keys imported = %d\n", result->imported); - DEBUG(pakfire, "Keys not imported = %d\n", result->not_imported); - - if (keys) { - // Allocate array - *keys = calloc(result->imported + 1, sizeof(**keys)); - if (!*keys) - goto ERROR; - - struct pakfire_key* key = NULL; - - // Retrieve all imported keys - for (int i = 0; i < result->imported && status; i++, status = status->next) { - DEBUG(pakfire, "Imported key %s - %s\n", - status->fpr, gpgme_strerror(status->result)); - - // Fetch the key by its fingerprint - r = pakfire_find_key(&key, pakfire, status->fpr); - if (r) - goto ERROR; - - // Append to array - (*keys)[i] = key; + case PAKFIRE_KEY_EXPORT_MODE_PRIVATE: + r = pakfire_key_export_private_key(key, &private_key); + if (r) + goto ERROR; - // Write key to keystore - r = pakfire_key_write_to_keystore(key); - if (r) - goto ERROR; - } + // Write the output + r = BIO_write(b64, &private_key, sizeof(private_key)); + if (r < 0) { + ERROR(key->pakfire, "Could not write the private key\n"); + r = 1; + goto ERROR; } break; - // Input was invalid - case GPG_ERR_INV_VALUE: - errno = EINVAL; - break; - - // Fall through for any other errors default: - ERROR(pakfire, "Failed with gpgme error: %s\n", gpgme_strerror(e)); - break; + errno = EINVAL; + r = 1; + goto ERROR; } - // Success - r = 0; + // Flush all buffers + BIO_flush(b64); -ERROR: - if (result) - gpgme_result_unref(result); - gpgme_data_release(data); + // Append a trailing newline + fprintf(f, "\n"); - // Free keys on error - if (r && keys && *keys) { - for (struct pakfire_key** key = *keys; *key; key++) - pakfire_key_unref(*key); - free(*keys); + // Success! + r = 0; - *keys = NULL; - } +ERROR: + if (b64) + BIO_free(b64); + if (bio) + BIO_free(bio); return r; } PAKFIRE_EXPORT char* pakfire_key_dump(struct pakfire_key* key) { - char date[1024]; - char* s = NULL; + char* buffer = NULL; + FILE* f = NULL; + int fd = -1; int r; - time_t created = pakfire_key_get_created(key); - - // Format creation time - r = pakfire_strftime(date, "%Y-%m-%d", created); - if (r) + // Allocate a buffer in memory + fd = memfd_create("pakfire-key-dump", MFD_CLOEXEC); + if (fd < 0) { + ERROR(key->pakfire, "Could not allocate a temporary file: %m\n"); + r = 1; goto ERROR; + } - asprintf(&s, "pub %s%zu/%s %s", - pakfire_key_get_pubkey_algo(key), - pakfire_key_get_pubkey_length(key), - pakfire_key_get_fingerprint(key), - date - ); + // Re-open as FILE handle + f = fdopen(fd, "r+"); + if (!f) { + ERROR(key->pakfire, "Could not open file handle for temporary file: %m\n"); + r = 1; + goto ERROR; + } - const char* uid = pakfire_key_get_uid(key); - if (uid) { - asprintf(&s, "%s\n %s", s, uid); + // Export the public part of the key + r = pakfire_key_export(key, f, PAKFIRE_KEY_EXPORT_MODE_PUBLIC); + if (r) { + ERROR(key->pakfire, "Could not export key: %m\n"); + goto ERROR; } - time_t expires = pakfire_key_get_expires(key); - if (expires) { - r = pakfire_strftime(date, "%Y-%m-%d", expires); - if (r) - goto ERROR; + // Determine the length of the buffer + size_t length = ftell(f); + + // Go back to the beginning of the file + rewind(f); - asprintf(&s, "%s\n %s: %s", s, _("Expires"), date); + // Allocate a buffer + buffer = calloc(1, length + 1); + if (!buffer) { + ERROR(key->pakfire, "Could not allocate buffer of %zu byte(s)\n", length + 1); + r = 1; + goto ERROR; } - return s; + // Read everything into the buffer + size_t bytes_read = fread(buffer, 1, length, f); + if (bytes_read < length) { + ERROR(key->pakfire, "Could not read back the buffer: %m\n"); + r = 1; + goto ERROR; + } + + // Success! + r = 0; ERROR: - if (s) - free(s); + if (f) + fclose(f); + if (fd >= 0) + close(fd); + + // Free the buffer on error + if (r && buffer) { + free(buffer); + buffer = NULL; + } - return NULL; + return buffer; } -int pakfire_key_sign(struct pakfire_key* key, const char* buffer, const size_t buffer_length, - char** signature, size_t* signature_length, time_t* timestamp) { - // Fetch GPGME context - gpgme_ctx_t gpgctx = pakfire_get_gpgctx(key->pakfire); - if (!gpgctx) +/* + Sign +*/ + +static int __pakfire_key_sign(struct pakfire_key* key, + struct pakfire_key_signature* signature, const void* data, const size_t length) { + EVP_PKEY_CTX* pctx = NULL; + EVP_MD_CTX* mdctx = NULL; + char error[ERROR_MAX]; + int r; + + // Check inputs + if (!signature || !data || !length) { + errno = EINVAL; return 1; + } - // Remove any previous signers - gpgme_signers_clear(gpgctx); + // Set algorithm + signature->sig_algo[0] = 'E'; + signature->sig_algo[1] = 'd'; - gpgme_data_t data = NULL; - gpgme_data_t sign = NULL; - gpgme_error_t e; - char* __signature = NULL; - int r = 1; + // Set the key ID + memcpy(signature->key_id, key->id, sizeof(signature->key_id)); - // Enable the key - e = gpgme_signers_add(gpgctx, key->gpgkey); - if (gpgme_err_code(e)) { - ERROR(key->pakfire, "Could not select key for signing: %s\n", - gpgme_strerror(e)); + // Create a signing context + pctx = EVP_PKEY_CTX_new(key->pkey, NULL); + if (!pctx) { + ERROR(key->pakfire, "Could not initialize the signing context: %m\n"); + r = 1; goto ERROR; } - // Initialize data buffer - e = gpgme_data_new_from_mem(&data, buffer, buffer_length, 0); - if (gpgme_err_code(e)) { - ERROR(key->pakfire, "Could not initialize data buffer: %s\n", - gpgme_strerror(e)); + // Create a message digest context + mdctx = EVP_MD_CTX_new(); + if (!mdctx) { + ERROR(key->pakfire, "Could not initialize the message digest context: %m\n"); + r = 1; goto ERROR; } - // Initialize signature buffer - e = gpgme_data_new(&sign); - if (gpgme_err_code(e)) { - ERROR(key->pakfire, "Could not initialize signature buffer: %s\n", - gpgme_strerror(e)); + // Connect the two contexts + EVP_MD_CTX_set_pkey_ctx(mdctx, pctx); + + size_t signature_length = sizeof(signature->signature); + + // Create a signature over the digest + r = EVP_DigestSign(mdctx, signature->signature, &signature_length, data, length); + if (r < 1) { + ERR_error_string_n(ERR_get_error(), error, sizeof(error)); + + ERROR(key->pakfire, "Could not sign content: %s\n", error); + r = 1; goto ERROR; } - // Create the signature - e = gpgme_op_sign(gpgctx, data, sign, GPGME_SIG_MODE_DETACH); - switch (gpgme_err_code(e)) { - // Everything went OK - case GPG_ERR_NO_ERROR: - break; + // Success! + r = 0; - default: - ERROR(key->pakfire, "Could not sign: %s\n", gpgme_strerror(e)); +ERROR: + if (pctx) + EVP_PKEY_CTX_free(pctx); + if (mdctx) + EVP_MD_CTX_free(mdctx); - // Set errno to something useful - errno = gpgme_err_code_to_errno(e); - goto ERROR; - } + return r; +} - // Print some status details - gpgme_sign_result_t result = gpgme_op_sign_result(gpgctx); - if (result) { - for (gpgme_new_signature_t s = result->signatures; s; s = s->next) { - DEBUG(key->pakfire, "Signature created\n"); - DEBUG(key->pakfire, " Key : %s\n", s->fpr); - DEBUG(key->pakfire, " Algorithm : %s\n", gpgme_pubkey_algo_name(s->pubkey_algo)); - DEBUG(key->pakfire, " Hash : %s\n", gpgme_hash_algo_name(s->hash_algo)); - DEBUG(key->pakfire, " Timestamp : %ld\n", s->timestamp); +int pakfire_key_sign(struct pakfire_key* key, + FILE* f, const char* data, const size_t length, const char* comment) { + struct pakfire_key_signature signature = { 0 }; + char* s = NULL; + int r; + + // Create a signature + r = __pakfire_key_sign(key, &signature, data, length); + if (r) + return r; - // Store timestamp - if (timestamp) - *timestamp = s->timestamp; + // Write the comment + if (comment) { + r = fprintf(f, "untrusted comment: %s\n", comment); + if (r < 0) { + ERROR(key->pakfire, "Could not write comment: %m\n"); + r = 1; + goto ERROR; } } - // Extract the signature - __signature = gpgme_data_release_and_get_mem(sign, signature_length); - if (!__signature) { - ERROR(key->pakfire, "The signature was unexpectedly empty: %m\n"); + // Encode the signature to base64 + r = pakfire_b64encode(key->pakfire, &s, &signature, sizeof(signature)); + if (r) goto ERROR; - } - // Sign is now released and we should not do this again below - sign = NULL; - - // Because GPGME could be using its internal allocator, we need to copy the signature - // and release the memory that we got from GPGME using gpgme_free(). - *signature = malloc(*signature_length); - if (!*signature) + // Write the signature + r = fprintf(f, "%s\n", s); + if (r < 0) { + ERROR(key->pakfire, "Could not write the signature: %m\n"); + r = 1; goto ERROR; + } - memcpy(*signature, __signature, *signature_length); - - // Success + // Success! r = 0; ERROR: - if (__signature) - gpgme_free(__signature); - if (data) - gpgme_data_release(data); - if (sign) - gpgme_data_release(sign); + if (s) + free(s); return r; } diff --git a/src/libpakfire/keystore.c b/src/libpakfire/keystore.c index bb55e2fa2..4343ac39c 100644 --- a/src/libpakfire/keystore.c +++ b/src/libpakfire/keystore.c @@ -85,8 +85,10 @@ static int pakfire_keystore_import(struct pakfire* pakfire, gpgme_ctx_t ctx) { continue; } +#if 0 // Import keys from file r = pakfire_key_import(pakfire, f, NULL); +#endif fclose(f); // End if key import was unsuccessful diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index c5f99922d..57931cf72 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -32,7 +32,6 @@ global: pakfire_get_repo; pakfire_get_repos; pakfire_install; - pakfire_list_keys; pakfire_ref; pakfire_refresh; pakfire_search; @@ -133,19 +132,9 @@ global: pakfire_key_export; pakfire_key_generate; pakfire_key_get; - pakfire_key_get_created; - pakfire_key_get_email; - pakfire_key_get_expires; - pakfire_key_get_fingerprint; - pakfire_key_get_name; - pakfire_key_get_pubkey_algo; - pakfire_key_get_pubkey_length; - pakfire_key_get_public_key; - pakfire_key_get_secret_key; - pakfire_key_get_uid; - pakfire_key_has_secret; + pakfire_key_get_algo; + pakfire_key_get_id; pakfire_key_import; - pakfire_key_is_revoked; pakfire_key_ref; pakfire_key_unref; diff --git a/src/libpakfire/pakfire.c b/src/libpakfire/pakfire.c index 4f28310a6..5094bb360 100644 --- a/src/libpakfire/pakfire.c +++ b/src/libpakfire/pakfire.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -48,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -64,7 +62,6 @@ #include #include -#define KEYSTORE_DIR "/etc/pakfire/trusted.keys.d" #define LOCK_PATH PAKFIRE_PRIVATE_DIR "/.lock" struct pakfire { @@ -74,7 +71,6 @@ struct pakfire { char lock_path[PATH_MAX]; char cache_path[PATH_MAX]; char arch[ARCH_MAX]; - char keystore_path[PATH_MAX]; int flags; @@ -126,9 +122,6 @@ struct pakfire { char tag[40]; } distro; - // GPG Context - gpgme_ctx_t gpgctx; - // Magic Context magic_t magic; @@ -406,10 +399,6 @@ static void pakfire_free(struct pakfire* pakfire) { if (pakfire->magic) magic_close(pakfire->magic); - // Release GPGME context - if (pakfire->gpgctx) - pakfire_keystore_destroy(pakfire, &pakfire->gpgctx); - // Release lock (if not already done so) pakfire_release_lock(pakfire); @@ -959,13 +948,6 @@ PAKFIRE_EXPORT int pakfire_create(struct pakfire** pakfire, const char* path, goto ERROR; } - // Set keystore path - r = pakfire_path(p, p->keystore_path, "%s", KEYSTORE_DIR); - if (r) { - ERROR(p, "Could not set keystore path: %m\n"); - goto ERROR; - } - // Make path for private files r = pakfire_path(p, private_dir, "%s", PAKFIRE_PRIVATE_DIR); if (r) @@ -978,11 +960,6 @@ PAKFIRE_EXPORT int pakfire_create(struct pakfire** pakfire, const char* path, goto ERROR; } - // Initialize keystore - r = pakfire_keystore_init(p, &p->gpgctx); - if (r) - goto ERROR; - // Populate pool r = pakfire_populate_pool(p); if (r) @@ -1088,10 +1065,6 @@ void pakfire_release_lock(struct pakfire* pakfire) { unlink(pakfire->lock_path); } -const char* pakfire_get_keystore_path(struct pakfire* pakfire) { - return pakfire->keystore_path; -} - int __pakfire_path(struct pakfire* pakfire, char* path, const size_t length, const char* format, ...) { char buffer[PATH_MAX]; @@ -1134,10 +1107,6 @@ int __pakfire_cache_path(struct pakfire* pakfire, char* path, size_t length, return __pakfire_path_join(path, length, pakfire->cache_path, buffer); } -gpgme_ctx_t pakfire_get_gpgctx(struct pakfire* pakfire) { - return pakfire->gpgctx; -} - magic_t pakfire_get_magic(struct pakfire* pakfire) { int r; @@ -1171,64 +1140,6 @@ ERROR: return NULL; } -PAKFIRE_EXPORT int pakfire_list_keys(struct pakfire* pakfire, struct pakfire_key*** keys) { - // Reset keys - *keys = NULL; - - // Fetch GPGME context - gpgme_ctx_t gpgctx = pakfire_get_gpgctx(pakfire); - if (!gpgctx) - return 1; - - struct pakfire_key* key = NULL; - gpgme_key_t gpgkey = NULL; - size_t length = 0; - int r = 1; - - // Iterate over all keys and import them to the list - gpgme_error_t e = gpgme_op_keylist_start(gpgctx, NULL, 0); - if (e) - goto ERROR; - - while (!e) { - e = gpgme_op_keylist_next(gpgctx, &gpgkey); - if (e) - break; - - // Create key - r = pakfire_key_create(&key, pakfire, gpgkey); - gpgme_key_unref(gpgkey); - if (r) - goto ERROR; - - // Append to keys - *keys = reallocarray(*keys, length + 2, sizeof(**keys)); - if (!*keys) { - r = 1; - goto ERROR; - } - - // Store key in array - (*keys)[length++] = key; - - // Terminate the array - (*keys)[length] = NULL; - } - - // Done - return 0; - -ERROR: - if (*keys) { - for (struct pakfire_key** _key = *keys; *_key; _key++) - pakfire_key_unref(*_key); - free(*keys); - keys = NULL; - } - - return r; -} - int pakfire_repo_walk(struct pakfire* pakfire, pakfire_repo_walk_callback callback, void* p) { struct pakfire_repo* repo = NULL; diff --git a/src/libpakfire/repo.c b/src/libpakfire/repo.c index a61e207dd..600d9d080 100644 --- a/src/libpakfire/repo.c +++ b/src/libpakfire/repo.c @@ -58,8 +58,8 @@ struct pakfire_repo_appdata { char* description; char* baseurl; - // Key fingerprint - char key[PAKFIRE_KEY_FPR_MAXLEN]; + // Key + char* key; // Mirrorlist char* mirrorlist_url; @@ -77,6 +77,8 @@ struct pakfire_repo { struct pakfire_repo_appdata* appdata; struct pakfire_mirrorlist* mirrorlist; + + struct pakfire_key* key; }; int pakfire_repo_is_internal(struct pakfire_repo* repo) { @@ -165,46 +167,35 @@ static int pakfire_repo_retrieve( return r; } -static int pakfire_repo_import_key(struct pakfire_repo* repo, FILE* f) { - struct pakfire_key** keys = NULL; +static int pakfire_repo_import_key(struct pakfire_repo* repo, const char* data) { + struct pakfire_key* key = NULL; int r; - // Import any keys from the file descriptor - r = pakfire_key_import(repo->pakfire, f, &keys); - if (r) - return r; - - /* - XXX It can happen, that more than one repository are using the same - key which can only be imported once. The second time, the key won't - be returned which lets us end up with that repository having no key. - */ - - for (struct pakfire_key** key = keys; *key; key++) { - char* dump = pakfire_key_dump(*key); - - if (dump) - DEBUG(repo->pakfire, "Imported key:\n%s\n", dump); + // Free any formerly imported keys (this should not happen) + if (repo->key) { + pakfire_key_unref(repo->key); + repo->key = NULL; + } - // Fetch the key's fingerprint - const char* fingerprint = pakfire_key_get_fingerprint(*key); - if (!fingerprint) { - r = 1; - goto ERROR; - } + // Import the key + r = pakfire_key_import_from_string(&repo->key, repo->pakfire, data, strlen(data)); + if (r) { + ERROR(repo->pakfire, "Could not import key for repository '%s': %m\n", + pakfire_repo_get_name(repo)); + goto ERROR; + } - // Store the fingerprint - r = pakfire_string_set(repo->appdata->key, fingerprint); - if (r) - goto ERROR; + // If the key could be successfully imported, we will store it in the appdata + repo->appdata->key = strdup(data); + if (repo->appdata->key) { + ERROR(repo->pakfire, "Could not copy the key to appdata: %m\n"); + r = 1; + goto ERROR; } ERROR: - if (keys) { - for (struct pakfire_key** key = keys; *key; key++) - pakfire_key_unref(*key); - free(keys); - } + if (key) + pakfire_key_unref(key); return r; } @@ -263,7 +254,7 @@ int pakfire_repo_import(struct pakfire* pakfire, struct pakfire_config* config) pakfire_repo_set_mirrorlist_url(repo, mirrors); // Key - FILE* key = pakfire_config_get_fopen(config, *section, "key"); + const char* key = pakfire_config_get(config, *section, "key", NULL); if (key) { r = pakfire_repo_import_key(repo, key); if (r) { @@ -524,6 +515,9 @@ static void free_repo_appdata(struct pakfire_repo_appdata* appdata) { if (!appdata) return; + if (appdata->key) + free(appdata->key); + if (appdata->description) free(appdata->description); @@ -539,6 +533,10 @@ static void pakfire_repo_free(struct pakfire_repo* repo, const int free_repo) { repo_free(repo->repo, 0); } + // Free the key + if (repo->key) + pakfire_key_unref(repo->key); + if (repo->mirrorlist) pakfire_mirrorlist_unref(repo->mirrorlist); pakfire_unref(repo->pakfire); @@ -817,7 +815,20 @@ const char* pakfire_repo_get_path(struct pakfire_repo* repo) { } PAKFIRE_EXPORT struct pakfire_key* pakfire_repo_get_key(struct pakfire_repo* repo) { - return pakfire_key_get(repo->pakfire, repo->appdata->key); + int r; + + if (!repo->key && repo->appdata->key) { + r = pakfire_key_import_from_string(&repo->key, repo->pakfire, + repo->appdata->key, strlen(repo->appdata->key)); + if (r) + goto ERROR; + } + + if (repo->key) + return pakfire_key_ref(repo->key); + +ERROR: + return NULL; } PAKFIRE_EXPORT const char* pakfire_repo_get_mirrorlist_url(struct pakfire_repo* repo) { @@ -902,9 +913,9 @@ PAKFIRE_EXPORT int pakfire_repo_write_config(struct pakfire_repo* repo, FILE* f) // Key key = pakfire_repo_get_key(repo); if (key) { - r = pakfire_key_get_public_key(key, &buffer, &length); + r = pakfire_key_export(key, f, PAKFIRE_KEY_EXPORT_MODE_PUBLIC); if (r) { - ERROR(repo->pakfire, "Could not fetch public key: %m\n"); + ERROR(repo->pakfire, "Could not export the key: %m\n"); goto ERROR; } diff --git a/src/libpakfire/util.c b/src/libpakfire/util.c index 79cd196b1..74606f7a0 100644 --- a/src/libpakfire/util.c +++ b/src/libpakfire/util.c @@ -38,6 +38,11 @@ #include #include +// OpenSSL +#include +#include +#include + #define PCRE2_CODE_UNIT_WIDTH 8 #include @@ -941,3 +946,77 @@ int pakfire_compile_regex(struct pakfire* pakfire, pcre2_code** regex, const cha return 0; } + +// Base64 + +#define OPENSSL_ERROR_MAX 1024 + +int pakfire_b64encode(struct pakfire* pakfire, char** output, + const void* buffer, const size_t length) { + char error[OPENSSL_ERROR_MAX]; + BIO* b64 = NULL; + BIO* bio = NULL; + char* p = NULL; + int r; + + // Initialize the base64 encoder + b64 = BIO_new(BIO_f_base64()); + if (!b64) { + ERR_error_string_n(ERR_get_error(), error, sizeof(error)); + + ERROR(pakfire, "Could not initialize the base64 encoder: %s\n", error); + r = 1; + goto ERROR; + } + + // Disable line breaks and a trailing newline + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + // Initialize a memory buffer + bio = BIO_new(BIO_s_mem()); + if (!bio) { + ERR_error_string_n(ERR_get_error(), error, sizeof(error)); + + ERROR(pakfire, "Could not initialize memory buffer: %s\n", error); + r = 1; + goto ERROR; + } + + // Connect both things + b64 = BIO_push(b64, bio); + + // Write the input + r = BIO_write(b64, buffer, length); + if (r < 1) { + ERR_error_string_n(ERR_get_error(), error, sizeof(error)); + + ERROR(pakfire, "%s\n", error); + r = 1; + goto ERROR; + } + + // Flush + BIO_flush(b64); + + // Fetch a pointer to the output and determine its length + const size_t l = BIO_get_mem_data(b64, &p); + + // Copy the output to the heap + *output = strndup(p, l); + if (!*output) { + ERROR(pakfire, "Could not copy base64 encoded string to heap: %m\n"); + r = 1; + goto ERROR; + } + + // Success + r = 0; + +ERROR: + if (bio) + BIO_free(bio); + if (b64) + BIO_free(b64); + + return r; +} diff --git a/tests/data/keys/key1.pub b/tests/data/keys/key1.pub new file mode 100644 index 000000000..e2f7c87ee --- /dev/null +++ b/tests/data/keys/key1.pub @@ -0,0 +1,2 @@ +untrusted comment: Pakfire Test Key public key +RWTAZap9ohW221+ZFLwJKs9l9uSbHyJ6ht+bvE6BsJWRF/VC3pRBXxD8 diff --git a/tests/data/keys/key1.sec b/tests/data/keys/key1.sec new file mode 100644 index 000000000..595a985eb --- /dev/null +++ b/tests/data/keys/key1.sec @@ -0,0 +1,2 @@ +untrusted comment: Pakfire Test Key secret key +RWRCSwAAAACp4FboBK3u+pmhh0rTr0F3NWpyMsbUPt7AZap9ohW228SoHTfMv0XDN6XqHElAQ3bmgPGyyYMLlRVbd2FJabNMX5kUvAkqz2X25JsfInqG35u8ToGwlZEX9ULelEFfEPw= diff --git a/tests/libpakfire/key.c b/tests/libpakfire/key.c index 5678c9213..8752d821e 100644 --- a/tests/libpakfire/key.c +++ b/tests/libpakfire/key.c @@ -25,48 +25,53 @@ #include #include "../testsuite.h" -#include "key.h" -static int test_init(const struct test* t) { - struct pakfire_key** keys = NULL; +static int test_generate(const struct test* t) { + struct pakfire_key* key = NULL; int r = EXIT_FAILURE; - // Try loading any keys & delete them all - ASSERT_SUCCESS(pakfire_list_keys(t->pakfire, &keys)); - while (keys && *keys) { - struct pakfire_key* key = *keys++; + // Try to call pakfire_key_generate() with some invalid inputs + ASSERT_ERRNO(pakfire_key_generate(&key, t->pakfire, PAKFIRE_KEY_ALGO_NULL), EINVAL); - pakfire_key_delete(key); - pakfire_key_unref(key); - } + // Generate a new key using ed25519 + ASSERT_SUCCESS(pakfire_key_generate(&key, t->pakfire, PAKFIRE_KEY_ALGO_ED25519)); - // Load list of keys again - ASSERT_SUCCESS(pakfire_list_keys(t->pakfire, &keys)); + // Write the public key to the console + ASSERT_SUCCESS(pakfire_key_export(key, stdout, PAKFIRE_KEY_EXPORT_MODE_PUBLIC)); - // Must be empty now - ASSERT(keys == NULL); + // Write the private key to the console + ASSERT_SUCCESS(pakfire_key_export(key, stdout, PAKFIRE_KEY_EXPORT_MODE_PRIVATE)); // Everything passed r = EXIT_SUCCESS; FAIL: + if (key) + pakfire_key_unref(key); + return r; } -static int test_generate_key(const struct test* t, const char* algo, const char* userid) { +static int test_sign(const struct test* t) { struct pakfire_key* key = NULL; - char* dump = NULL; int r = EXIT_FAILURE; - // Generate a new key - ASSERT_SUCCESS(pakfire_key_generate(&key, t->pakfire, algo, userid)); + const char* data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const size_t length = strlen(data); + + char* signature = NULL; + size_t signature_length = 0; + + // Generate a new key using ed25519 + ASSERT_SUCCESS(pakfire_key_generate(&key, t->pakfire, PAKFIRE_KEY_ALGO_ED25519)); - // Export the key - ASSERT_SUCCESS(pakfire_key_export(key, stdout, PAKFIRE_KEY_EXPORT_MODE_SECRET)); + // Write the public key to the console + ASSERT_SUCCESS(pakfire_key_export(key, stdout, PAKFIRE_KEY_EXPORT_MODE_PUBLIC)); - // Dump the key details - ASSERT(dump = pakfire_key_dump(key)); - printf("%s\n", dump); + // Write the private key to the console + ASSERT_SUCCESS(pakfire_key_export(key, stdout, PAKFIRE_KEY_EXPORT_MODE_PRIVATE)); + + ASSERT_SUCCESS(pakfire_key_sign(key, stdout, data, length, "UNTRUSTED COMMENT")); // Everything passed r = EXIT_SUCCESS; @@ -74,29 +79,23 @@ static int test_generate_key(const struct test* t, const char* algo, const char* FAIL: if (key) pakfire_key_unref(key); - if (dump) - free(dump); return r; } -static int test_generate(const struct test* t) { +static int test_import_public(const struct test* t) { struct pakfire_key* key = NULL; + FILE* f = NULL; int r = EXIT_FAILURE; - // Try to call pakfire_key_generate() with some invalid inputs - ASSERT_ERRNO(pakfire_key_generate(&key, t->pakfire, NULL, NULL), EINVAL); - ASSERT_ERRNO(pakfire_key_generate(&key, t->pakfire, "rsa2048", NULL), EINVAL); - ASSERT_ERRNO(pakfire_key_generate(&key, t->pakfire, NULL, "Invalid Test Key"), EINVAL); - - // Generate a new key using RSA2048 - ASSERT_SUCCESS(test_generate_key(t, "rsa2048", "Test Key #1")); + // Open the public key + ASSERT(f = fopen(TEST_DATA_DIR "/keys/key1.pub", "r")); - // Generate a new key using ed25519 - ASSERT_SUCCESS(test_generate_key(t, "ed25519", "Test Key #2")); + // Try to import the key + ASSERT_SUCCESS(pakfire_key_import(&key, t->pakfire, f)); - // Try to generate a key with the same ID - ASSERT_ERRNO(pakfire_key_generate(&key, t->pakfire, "rsa2048", "Test Key #1"), EINVAL); + // Write the imported key to the console + ASSERT_SUCCESS(pakfire_key_export(key, stdout, PAKFIRE_KEY_EXPORT_MODE_PUBLIC)); // Everything passed r = EXIT_SUCCESS; @@ -104,58 +103,43 @@ static int test_generate(const struct test* t) { FAIL: if (key) pakfire_key_unref(key); + if (f) + fclose(f); return r; } -static int test_import_export(const struct test* t) { - // Try to delete the key just in case it - // has been imported before - struct pakfire_key* key = pakfire_key_get(t->pakfire, TEST_KEY_FINGERPRINT); - if (key) { - pakfire_key_delete(key); - pakfire_key_unref(key); - } - -#if 0 - // Import a key - struct pakfire_key** keys = pakfire_key_import(t->pakfire, TEST_KEY_DATA); - - // We should have a list with precisely one key object - ASSERT(keys); - ASSERT(keys[0] != NULL); - ASSERT(keys[1] == NULL); - - // Get the imported key - key = *keys; +static int test_import_secret(const struct test* t) { + struct pakfire_key* key = NULL; + FILE* f = NULL; + int r = EXIT_FAILURE; - // Check the fingerprint - const char* fingerprint = pakfire_key_get_fingerprint(key); - ASSERT(strcmp(fingerprint, TEST_KEY_FINGERPRINT) == 0); + // Open the public key + ASSERT(f = fopen(TEST_DATA_DIR "/keys/key1.sec", "r")); - // Dump key description - char* dump = pakfire_key_dump(key); - ASSERT(dump); - LOG("%s\n", dump); - free(dump); + // Try to import the key + ASSERT_SUCCESS(pakfire_key_import(&key, t->pakfire, f)); - // Export the key - char* data = pakfire_key_export(key, 0); - ASSERT(data); + // Write the imported key to the console + ASSERT_SUCCESS(pakfire_key_export(key, stdout, PAKFIRE_KEY_EXPORT_MODE_PRIVATE)); - LOG("Exported key:\n%s\n", data); - free(data); + // Everything passed + r = EXIT_SUCCESS; - pakfire_key_unref(key); -#endif +FAIL: + if (key) + pakfire_key_unref(key); + if (f) + fclose(f); - return EXIT_SUCCESS; + return r; } int main(int argc, const char* argv[]) { - testsuite_add_test(test_init); testsuite_add_test(test_generate); - testsuite_add_test(test_import_export); + testsuite_add_test(test_sign); + testsuite_add_test(test_import_public); + testsuite_add_test(test_import_secret); return testsuite_run(argc, argv); } diff --git a/tests/libpakfire/key.h b/tests/libpakfire/key.h deleted file mode 100644 index 95d285c33..000000000 --- a/tests/libpakfire/key.h +++ /dev/null @@ -1,47 +0,0 @@ -/*############################################################################# -# # -# Pakfire - The IPFire package management system # -# Copyright (C) 2017 Pakfire development team # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see . # -# # -#############################################################################*/ - -const char* TEST_KEY_FINGERPRINT = "E63B4976A575A3B2544AC15E726D8B0B0889B04E"; - -const char* TEST_KEY_DATA = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n" -"mQINBE/ndRQBEAC5ykX6wgPdR42ZkTdrcVS9fIACn/n/ed7K/dWlUtANnAtoH27Qp+I/vKy9\n" -"DwGUjDe5ST8l4td+gzZNwWowTnLr6zULG+dBDPNL1SZrL7sxLfjuEyOAAFcMTI8hKqwCQfSz\n" -"OJVX4X7mfSDgewqFjDO1a1gkJUXnq8xMNJa6fTH61qVPXmwBpR4JgzrtH4FmvuXjocKZ4+/B\n" -"NwD80ChfiwwNjwTv0ykdXhV6aEtqg9sfFRB/BGUIBDUOlG6i8VCNQ0X1rAcyO2waj6cAfYVE\n" -"HbD4POMIWhaBvfKnYUuUyPoSDjcgIWIrHmdBHuM/zbLjAfIoh/Lk16UnU6DBjsMdtq6d9HWD\n" -"OWRQOXigwKHiRZD9QQDPxTb8w6EAu/UFzHNUCD7O0rS2KmugZMk/Q0ijhVCfC6MXTu7Vjg3c\n" -"tjf7ZE2kvhKs5I6j3lTCLm23WYcRefKJQ/9Ab1d6bYoOwNpQFdP0duYyP2TC1cSC5Cs8h7pE\n" -"nI1yB9B+Fu6fqNyIhgo9fbh29+F8K/KYT0UifsTvBNTv2bf+23IbFR3EC3WWEdvars1h9mTK\n" -"g8bbyKNxXrWXrPUb+TWovaTpzpRNqOYDa5tqh9Q/0e1mkNcjJbBK/2HxAT4hi69Dfswr0cYh\n" -"IwpH3fTwlZPpBjEOVz5VyAaZyjjJHweRhz5YJUgPt7J9/tTmGQARAQABtEVJUEZpcmUgQnVp\n" -"bGRzZXJ2ZXIgY29ybmVsaXVzLmlwZmlyZS5vcmcgPHBha2ZpcmUtYnVpbGRlcnNAaXBmaXJl\n" -"Lm9yZz6JAjgEEwECACIFAk/ndRQCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEHJt\n" -"iwsIibBOdqsP/1EVKVgFxiMVcRTP5VYV2+EV/CaiaqMzC488AGRq8LYMzq/hqj0w+lbCl6AG\n" -"25Aqf6UX8VMgkPr5pIy/IZqZgQ0N7fX6Vw0mhR/2zAHItvuff8zCM2Sp682CRahn1SB9oWjl\n" -"bJZwHJPVkLVqAxs5f1EyXstl8NNrVJQ0rZKWvfTKJL6kCYitnNuat4BB/uv2aNB8MiMlwJj6\n" -"DtO6uGagw3lkR9w+PL0lW2auQqE6Ia6CIdOT43qQ/Is7SnmL5uS5/uwNgdZ1ayCMPM+xeJrH\n" -"A7MTQKVDcyTmkIriO7qRaaPsPkhqfD/vjurWQ+Hx9XTUUk3QeCpZfXLGB+ZNLg2+kxanSoQ0\n" -"JbB8V7OMOi7Z8y0U0vXKTn1cKIzrXB1/GvwpYPZAmFgcOqXoNF3Qs7ilud3bxomG8nBHWNBA\n" -"1w+rzMYQbwCow7GkknniaB+ZzkPB+8+1jul4U5rtGeFyloyHy6WO2WKk7nsou/i3vfpVHRzh\n" -"9XVkEYesGrAIJqrpfJYgAbzRSUyPoFoIBhC7p8emKr/TTzzc90s5EPlqkxE/BRPvkqW+4HjS\n" -"ybOFv4fii7qGdpNrnXTACB2v06Y+TpUGXVA5+Ac+5Zn5F/++tUnvZ9eCT1VmUhw+wDV7qQtq\n" -"gVwRjTWnu8cc9uoZbKK1Qifehl11xi4hp+YZmv/7eOg1LWeR\n" -"=XdHO\n\n" -"-----END PGP PUBLIC KEY BLOCK-----\n";