From: Michael Tremer Date: Sun, 11 Jul 2021 15:02:16 +0000 (+0000) Subject: key: Add function that can sign data X-Git-Tag: 0.9.28~1053 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a5276fd71597d1e0b4a62b31b52e952f12ba7cda;p=pakfire.git key: Add function that can sign data Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/include/pakfire/key.h b/src/libpakfire/include/pakfire/key.h index f7f993078..57f4a198c 100644 --- a/src/libpakfire/include/pakfire/key.h +++ b/src/libpakfire/include/pakfire/key.h @@ -65,6 +65,9 @@ char* pakfire_key_dump(struct pakfire_key* key); int pakfire_key_create(struct pakfire_key** key, struct pakfire* pakfire, gpgme_key_t gpgkey); +int pakfire_key_sign(struct pakfire_key* key, const char* buffer, const size_t buffer_length, + char** signature, size_t* signature_length); + #endif #endif /* PAKFIRE_KEY_H */ diff --git a/src/libpakfire/key.c b/src/libpakfire/key.c index 765161206..5d6b205c4 100644 --- a/src/libpakfire/key.c +++ b/src/libpakfire/key.c @@ -575,3 +575,106 @@ PAKFIRE_EXPORT char* pakfire_key_dump(struct pakfire_key* key) { return s; } + +int pakfire_key_sign(struct pakfire_key* key, const char* buffer, const size_t buffer_length, + char** signature, size_t* signature_length) { + // Fetch GPGME context + gpgme_ctx_t gpgctx = pakfire_get_gpgctx(key->pakfire); + if (!gpgctx) + return 1; + + // Remove any previous signers + gpgme_signers_clear(gpgctx); + + gpgme_data_t data = NULL; + gpgme_data_t sign = NULL; + gpgme_error_t e; + char* __signature = NULL; + int r = 1; + + // 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)); + 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)); + 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)); + 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; + + default: + ERROR(key->pakfire, "Could not sign: %s\n", gpgme_strerror(e)); + + // Set errno to something useful + errno = gpgme_err_code_to_errno(e); + goto ERROR; + } + +#ifdef ENABLE_DEBUG + // 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); + } + + gpgme_result_unref(result); + } +#endif + + // 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"); + 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) + goto ERROR; + + memcpy(*signature, __signature, *signature_length); + + // Success + r = 0; + +ERROR: + if (__signature) + gpgme_free(__signature); + if (data) + gpgme_data_release(data); + if (sign) + gpgme_data_release(sign); + + return r; +}