]> git.ipfire.org Git - pakfire.git/commitdiff
key: Add function that can sign data
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 11 Jul 2021 15:02:16 +0000 (15:02 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 11 Jul 2021 15:02:16 +0000 (15:02 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/include/pakfire/key.h
src/libpakfire/key.c

index f7f99307859a0f1699eff056f4e4fab31a6eaae7..57f4a198c3db7c2b06741cbd8c84fb032081af63 100644 (file)
@@ -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 */
index 7651612064a693c8ba9b72cdfb33a54da07eaaf2..5d6b205c4dfa827d577d6a1d2f224095a10054d7 100644 (file)
@@ -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;
+}