summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Ball <nullspoon@oper.io>2018-10-24 17:52:07 -0600
committerAaron Ball <nullspoon@oper.io>2018-10-24 17:58:32 -0600
commit25378d03e6fe81321952ca8e41580027f71943ed (patch)
tree29c0e2df47ad4d891884ed7584260f1b9401c344
parent02d9ba096937a3f931080233bcd73c99ef9c612a (diff)
downloadgpgedit-25378d03e6fe81321952ca8e41580027f71943ed.tar.gz
gpgedit-25378d03e6fe81321952ca8e41580027f71943ed.tar.xz
Implement re-encrypt support
gpg.c: Add new init_gpg function that more closely mimicks that defined in the gpgme tests. This however initializes the passed-in context object, reducing duplicate code. Removed old gpg_init. Clean up linked library dependencies. Implemented gpg_keyids_to_key_t() to convert arrays of key id strings to an array of key objects (don't forget to free the array!). Implemented gpg_recip_count, which counts the number of recipients for the given gpg_op_decrypt_result_t object. Implemented gpg_dump_key, which dumps all of the human-readable information in a gpgme_key_t object to stdout. This is for debugging key issues.
-rw-r--r--src/gpg.c244
-rw-r--r--src/gpg.h15
-rw-r--r--src/main.c48
3 files changed, 238 insertions, 69 deletions
diff --git a/src/gpg.c b/src/gpg.c
index 9c25a0d..6509f45 100644
--- a/src/gpg.c
+++ b/src/gpg.c
@@ -21,12 +21,50 @@
#define READSIZE 256
+gpgme_error_t init_gpg(gpgme_ctx_t* ctx, gpgme_protocol_t proto) {
+ gpgme_error_t err;
+
+ gpgme_check_version (NULL);
+ setlocale (LC_ALL, "");
+ gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
+
+ err = gpgme_engine_check_version (proto);
+
+ err = gpgme_new(ctx);
+ if(err != GPG_ERR_NO_ERROR) {
+ printf("ERROR: ");
+ if(err == GPG_ERR_INV_VALUE) {
+ printf("GPG context is not valid pointer\n");
+ } else if(err == GPG_ERR_ENOMEM) {
+ printf("Insufficient memory to allocate GPG context\n");
+ } else if(err == GPG_ERR_ENOMEM) {
+ printf("Insufficient memory to allocate GPG context\n");
+ } else if(err == GPG_ERR_NOT_OPERATIONAL) {
+ printf("GPGME not initialized\n");
+ } else {
+ printf("Unknown\n");
+ }
+ return err;
+ }
+
+ gpgme_set_protocol(*ctx, proto);
+ gpgme_set_armor(*ctx, 1);
-int gpgme_data_fwrite(gpgme_data_t dh, FILE* out) {
+ return err;
+}
+
+
+int gpg_data_fwrite(gpgme_data_t dh, FILE* out) {
char buf[READSIZE];
size_t total = 0;
size_t size = 0;
+ gpgme_data_seek(dh, 0, SEEK_SET);
+ if(gpgme_data_read(dh, buf, 1) < 1) {
+ printf("Error: GPG data struct is empty. Nothing to write.\n");
+ return -1;
+ }
+
// Set seek to beginning of file
gpgme_data_seek(dh, 0, SEEK_SET);
@@ -40,44 +78,182 @@ int gpgme_data_fwrite(gpgme_data_t dh, FILE* out) {
}
-int gpg_init(gpgme_ctx_t* ctx) {
+int gpg_recip_count(gpgme_recipient_t firstrecip) {
+ gpgme_recipient_t recip; // Current recipient object
+ int count = 0; // Count of recipients
+
+ // Get recipient list
+ recip = firstrecip;
+ while(recip != NULL) {
+ //printf("-- recipient: %s\n", recip->keyid);
+ recip = recip->next;
+ count++;
+ }
+
+ return count;
+}
+
+
+char** gpg_recip_get_keyids(gpgme_recipient_t firstrecip) {
+ gpgme_recipient_t recip; // Current recipient object
+ int count = 0; // Number of recipients
+ int i = 0; // Key index
+ char** keyids = NULL;
+
+ count = gpg_recip_count(firstrecip);
+ keyids = (char**) malloc(sizeof(char*) * count + 1);
+
+ // Write each recipient key id to the char array
+ recip = firstrecip;
+ while(recip != NULL) {
+ // For debugging purposes
+ //printf("Getting key for %s\n", recip->keyid);
+ keyids[i] = malloc(strlen(recip->keyid) + 1);
+ strcpy(keyids[i], recip->keyid);
+
+ i++;
+ recip = recip->next;
+ }
+
+ keyids[i] = NULL;
+ return keyids;
+}
+
+
+gpgme_key_t* gpg_keyids_to_key_t(gpgme_ctx_t ctx, char** keyids) {
+ gpgme_key_t* out;
gpgme_error_t err;
- // Initialize
- setlocale(LC_ALL, "");
- gpgme_check_version(NULL);
- // Create context and check if anything failed
- err = gpgme_new(ctx);
+ int count = 0; // Number of recipients
+ int i = 0;
+
+ // Count the keys
+ while(keyids[count] != NULL)
+ count++;
+
+ // Allocate the gpgme_key_t pointer array
+ out = malloc(sizeof(gpgme_key_t) * (count + 1));
+
+ // Loop over the keys back to zero
+ while(i < count) {
+ err = gpgme_get_key(ctx, keyids[i], &out[i], 0);
+ if(err != GPG_ERR_NO_ERROR) {
+ printf("Ooops! Something went wrong getting key %s\n", keyids[i]);
+ }
+ i++;
+ }
+ out[i] = NULL;
+ return out;
+}
+
+
+void gpg_keyids_release(char** keyids) {
+ int i = 0;
+ while(keyids[i] != NULL) {
+ free(keyids[i]);
+ i++;
+ }
+ free(keyids);
+}
+
+
+void gpg_dump_key(gpgme_key_t key) {
+ printf("Recipient: %s\n", key->fpr);
+ printf(" protocol: %d\n", key->protocol);
+ printf(" revoked: %d\n", key->revoked);
+ printf(" expired: %d\n", key->expired);
+ printf(" disabled: %d\n", key->disabled);
+ printf(" invalid: %d\n", key->invalid);
+ printf(" can_encrypt: %d\n", key->can_encrypt);
+ printf(" can_sign: %d\n", key->can_sign);
+ printf(" can_certify: %d\n", key->can_certify);
+ printf(" can_auth: %d\n", key->can_authenticate);
+ printf(" qualified: %d\n", key->is_qualified);
+ printf(" secret: %d\n", key->secret);
+ printf(" origin: %d\n", key->origin);
+ printf(" issuer_serial: %s\n", key->issuer_serial);
+ printf(" issuer_name: %s\n", key->issuer_name);
+ printf(" chain_id: %s\n", key->chain_id);
+ printf(" last_update: %ld\n", key->last_update);
+}
+
+
+size_t gpg_encrypt_file(char* infile, char* outfile, char** keyids) {
+ gpgme_ctx_t ctx;
+ gpgme_data_t indata;
+ gpgme_data_t outdata;
+ gpgme_error_t err;
+ gpgme_key_t* keys = NULL;
+
+ err = init_gpg(&ctx, GPGME_PROTOCOL_OPENPGP);
if(err != GPG_ERR_NO_ERROR) {
- printf("ERROR: ");
- if(err == GPG_ERR_INV_VALUE) {
- printf("GPG context is not valid pointer\n");
- } else if(err == GPG_ERR_ENOMEM) {
- printf("Insufficient memory to allocate GPG context\n");
- } else if(err == GPG_ERR_ENOMEM) {
- printf("Insufficient memory to allocate GPG context\n");
- } else if(err == GPG_ERR_NOT_OPERATIONAL) {
- printf("GPGME not initialized\n");
+ printf("Error: %s\n", gpgme_strerror(err));
+ return -1;
+ }
+
+ // For debugging purposes
+ // printf("Reading updated data from memory\n");
+ // Initialize data structures
+ err = gpgme_data_new_from_file(&indata, infile, 1);
+ if(err != GPG_ERR_NO_ERROR)
+ printf("Error: %s\n", gpgme_strerror(err));
+
+ err = gpgme_data_new(&outdata);
+ if(err != GPG_ERR_NO_ERROR)
+ printf("Error: %s\n", gpgme_strerror(err));
+
+ // Get key id objects from keyids char array
+ keys = gpg_keyids_to_key_t(ctx, keyids);
+ // For debugging purposes
+ // int i = 0;
+ // while(keys[i] != NULL) {
+ // gpg_dump_key(keys[i]);
+ // i++;
+ // }
+
+ // Encrypt!
+ err = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, indata, outdata);
+
+ if(err != GPG_ERR_NO_ERROR) {
+ if(err == GPG_ERR_UNUSABLE_PUBKEY) {
+ printf("One or more public keys unusable\n");
+ } else if(err == GPG_ERR_INV_VALUE) {
+ printf("Invalid data structure\n");
+ } else if(err == GPG_ERR_BAD_PASSPHRASE) {
+ printf("Incorrect passphrase\n");
} else {
- printf("Unknown\n");
+ printf("Unknown error: %d\n", err);
+ printf("Message:\n %s\n", gpgme_strerror(err));
}
- return -1;
}
+ // For debugging purposes
+ // printf("No errors detecting during encryption.\n");
- gpgme_set_protocol(*ctx, GPGME_PROTOCOL_OpenPGP);
- gpgme_set_armor(*ctx, 1);
+ // For debugging purposes
+ // printf("Writing to disk\n");
+ // Write to disk!
+ FILE* refd = fopen(outfile, "w");
+ gpg_data_fwrite(outdata, refd);
+ fclose(refd);
+
+ // cleanup
+ gpg_keyids_release(keyids);
+ gpgme_data_release(indata);
+ gpgme_data_release(outdata);
+ gpgme_release(ctx);
return 0;
}
-size_t gpg_decrypt(char* file, gpgme_ctx_t* ctx, gpgme_data_t plain) {
+gpgme_decrypt_result_t
+gpg_decrypt_file(char* infile, char* outfile, gpgme_ctx_t ctx) {
gpgme_error_t err;
- gpgme_data_t intxt;
- //gpgme_decrypt_result_t* res;
-
+ gpgme_data_t indata = NULL;
+ gpgme_data_t outdata = NULL;
// Read ciphertext file into gpgme data struct, and fail if any errors
// returned.
- err = gpgme_data_new_from_file(&intxt, file, 1);
+ gpgme_data_new(&outdata);
+ err = gpgme_data_new_from_file(&indata, infile, 1);
if(err != GPG_ERR_NO_ERROR) {
printf("ERROR: ");
if(err == GPG_ERR_INV_VALUE) {
@@ -87,11 +263,11 @@ size_t gpg_decrypt(char* file, gpgme_ctx_t* ctx, gpgme_data_t plain) {
} else if(err == GPG_ERR_ENOMEM) {
printf("Insufficient memory to allocate data struct\n");
}
- return err;
+ return NULL;
}
// Attempt to decrypt
- err = gpgme_op_decrypt(*ctx, intxt, plain);
+ err = gpgme_op_decrypt(ctx, indata, outdata);
if(err != GPG_ERR_NO_ERROR) {
printf("ERROR: ");
if(err == GPG_ERR_INV_VALUE) {
@@ -103,15 +279,19 @@ size_t gpg_decrypt(char* file, gpgme_ctx_t* ctx, gpgme_data_t plain) {
} else if(err == GPG_ERR_BAD_PASSPHRASE) {
printf("Passphrase is incorrect\n");
} else {
- printf("Unknown\n");
+ printf("Unhandled error\n %s\n", gpgme_strerror(err));
}
- return err;
+ return NULL;
}
+ // Write decrypted data to outfile
+ FILE* outfd = fopen(outfile, "w");
+ gpg_data_fwrite(outdata, outfd);
- //res = gpgme_op_decrypt_result(ctx);
// Clean up
- gpgme_data_release(intxt);
- return GPG_ERR_NO_ERROR;
+ fclose(outfd);
+ gpgme_data_release(indata);
+ gpgme_data_release(outdata);
+ return gpgme_op_decrypt_result(ctx);
}
#endif
diff --git a/src/gpg.h b/src/gpg.h
index 959c3f5..38ae4b2 100644
--- a/src/gpg.h
+++ b/src/gpg.h
@@ -17,12 +17,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include <gpgme.h>
#include <locale.h>
-int gpgme_data_fwrite(gpgme_data_t, FILE*);
+int gpg_data_fwrite(gpgme_data_t, FILE*);
-int gpg_init(gpgme_ctx_t*);
-size_t gpg_decrypt(char*, gpgme_ctx_t*, gpgme_data_t);
+gpgme_error_t init_gpg(gpgme_ctx_t*, gpgme_protocol_t);
+gpgme_decrypt_result_t gpg_decrypt_file(char*, char*, gpgme_ctx_t);
+
+char** gpg_recip_get_keyids(gpgme_recipient_t);
+
+void gpg_keyids_release(char**);
+
+gpgme_key_t* gpg_keyids_to_key_t(gpgme_ctx_t, char**);
+
+size_t gpg_encrypt_file(char*, char*, char**);
diff --git a/src/main.c b/src/main.c
index cb82676..162982a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -19,10 +19,8 @@
#include <string.h>
#include <unistd.h>
#include <gpgme.h>
-#include <locale.h>
#include "gpg.h"
-
void system_edit(char* file) {
char cmd[256]; // Buffer for editor command
sprintf(cmd, "%s %s\n", "vim", file);
@@ -31,51 +29,35 @@ void system_edit(char* file) {
int main(int argc, char* argv[]) {
- char tmpfile[64] = "/tmp/gpgedit-XXXXXX";
- FILE* fd;
- gpgme_data_t plain;
- gpgme_ctx_t ctx;
+ char tmpfile[32] = "/tmp/gpgedit-XXXXXX";
+ gpgme_ctx_t decctx;
+ gpgme_error_t err;
if(argc == 1) {
printf("Please specify a gpg encrypted file to edit\n");
return 1;
}
- if(gpg_init(&ctx) != 0) {
- printf("ERROR\n");
+ // Initialize decryption context, create tmp file to write decrypted contents
+ // to, and run decryption operation.
+ err = init_gpg(&decctx, GPGME_PROTOCOL_OPENPGP);
+ if(err != GPG_ERR_NO_ERROR) {
+ printf("Error: %s\n", gpgme_strerror(err));
return 1;
}
- // Create empty initialized gpgme data struct for output
- gpgme_data_new(&plain);
- // Decrypt file
- gpg_decrypt(argv[1], &ctx, plain);
- // Get decryption result
- gpgme_decrypt_result_t res = gpgme_op_decrypt_result(ctx);
-
- // Get recipient list
- gpgme_recipient_t recip;
- recip = res->recipients;
- while(recip != NULL) {
- printf("-- recipient: %s\n", recip->keyid);
- recip = recip->next;
- }
- // Create tmp file to write decrypted contents to
mkstemp(tmpfile);
- fd = fopen(tmpfile, "w");
-
- // Write to stdout
- gpgme_data_fwrite(plain, fd);
-
- // Cleanup
- fclose(fd); // close output file descriptor
- gpgme_data_release(plain); // Release gpgme_data_t plain object
- gpgme_release(ctx);
+ gpgme_decrypt_result_t res = gpg_decrypt_file(argv[1], tmpfile, decctx);
+ // Get keyids array from recipients list
+ char** keyids = gpg_recip_get_keyids(res->recipients);
+ // Freedom!
+ gpgme_release(decctx);
// Open the system editor
system_edit(tmpfile);
- // TODO: Encrypt and Write tmpfile to storage
+ // Re-encrypt the plaintext tmp file
+ gpg_encrypt_file(tmpfile, argv[1], keyids);
// Clean up tmpfile
unlink(tmpfile);

Generated by cgit