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;
+}