summaryrefslogtreecommitdiff
path: root/src/gpg.c
blob: 3656084e737d1c3c3d238948cf2eb5a6a8715e37 (plain)
    1 // GPGEdit edits GPG encrypted files
    2 // Copyright (C) 2018  Aaron Ball <nullspoon@oper.io>
    3 //
    4 // This program is free software: you can redistribute it and/or modify
    5 // it under the terms of the GNU General Public License as published by
    6 // the Free Software Foundation, either version 3 of the License, or
    7 // (at your option) any later version.
    8 //
    9 // This program is distributed in the hope that it will be useful,
   10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12 // GNU General Public License for more details.
   13 //
   14 // You should have received a copy of the GNU General Public License
   15 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
   16 #include "gpg.h"
   17 
   18 
   19 int gpg_failiferr(gpgme_error_t err) {
   20   if(err != GPG_ERR_NO_ERROR) {
   21     if(err == GPG_ERR_INV_VALUE) {
   22       logger(LOG_FATAL, "Invalid data structure\n");
   23     } else if(err == GPG_ERR_NO_DATA) {
   24       logger(LOG_FATAL, "Data struct contains no encrypted data\n");
   25     } else if(err == GPG_ERR_DECRYPT_FAILED) {
   26       logger(LOG_FATAL, "Could not decrypt file\n");
   27     } else if(err == GPG_ERR_ENOMEM) {
   28       logger(LOG_FATAL, "Insufficient memory to allocate GPG context\n");
   29     } else if(err == GPG_ERR_NOT_OPERATIONAL) {
   30       logger(LOG_FATAL, "GPGME not initialized\n");
   31     } else if(err == GPG_ERR_UNUSABLE_PUBKEY) {
   32       logger(LOG_FATAL, "One or more public keys unusable\n");
   33     } else if(err == GPG_ERR_BAD_PASSPHRASE) {
   34       logger(LOG_FATAL, "Incorrect passphrase\n");
   35     } else if(err == GPG_ERR_NOT_IMPLEMENTED) {
   36       logger(LOG_FATAL, "Not implemented\n");
   37     } else {
   38       logger(LOG_ERROR, "Unknown error: %d\n", err);
   39     }
   40     logger(LOG_ERROR, "  %s\n", gpgme_strerror(err));
   41     return err;
   42   }
   43   return 0;
   44 }
   45 
   46 
   47 gpgme_error_t init_gpg(gpgme_ctx_t* ctx, gpgme_protocol_t proto) {
   48   gpgme_error_t err;
   49 
   50   gpgme_check_version (NULL);
   51   setlocale (LC_ALL, "");
   52   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
   53 
   54   err = gpgme_engine_check_version (proto);
   55   gpg_failiferr(err);
   56 
   57   err = gpgme_new(ctx);
   58   gpg_failiferr(err);
   59 
   60   gpgme_set_protocol(*ctx, proto);
   61   gpgme_set_armor(*ctx, 1);
   62 
   63   return err;
   64 }
   65 
   66 
   67 int gpg_data_fwrite(gpgme_data_t dh, FILE* out) {
   68   char buf[READSIZE];
   69   size_t total = 0;
   70   size_t size = 0;
   71 
   72   gpgme_data_seek(dh, 0, SEEK_SET);
   73   if(gpgme_data_read(dh, buf, 1) < 1) {
   74     logger(LOG_ERROR, "GPG data struct is empty. Nothing to write.\n");
   75     return -1;
   76   }
   77 
   78   // Set seek to beginning of file
   79   gpgme_data_seek(dh, 0, SEEK_SET);
   80 
   81   while((size = gpgme_data_read(dh, buf, READSIZE)) > 0) {
   82     total += size;
   83     buf[size] = '\0';        // Ensure string terminates at the correct length
   84     fprintf(out, "%s", buf); // Write to file descriptor
   85   }
   86 
   87   return total;
   88 }
   89 
   90 
   91 int gpg_recip_count(gpgme_recipient_t firstrecip) {
   92   gpgme_recipient_t recip; // Current recipient object
   93   int count = 0;           // Count of recipients
   94 
   95   // Get recipient list
   96   recip = firstrecip;
   97   while(recip != NULL) {
   98     // printf("-- recipient: %s\n", recip->keyid);
   99     recip = recip->next;
  100     count++;
  101   }
  102 
  103   return count;
  104 }
  105 
  106 
  107 // gpg_strll_to_key_t:
  108 // Converts a string linked list containing keyids (multiple identifier types
  109 // are supported) into an array of gpgme_key_t objects.
  110 //
  111 // @ctx        GPGME context (already initialized)
  112 // @firstrecip First linkedlist recipient item
  113 //
  114 // @return gpgme_key_t* Array of gpgme_key_t objects, one for each keyid string
  115 gpgme_key_t* gpg_strll_to_key_t(gpgme_ctx_t ctx, struct strll* firstrecip) {
  116   gpgme_key_t* out;
  117   gpgme_error_t err;
  118   int i               = 0;
  119   struct strll* recip = firstrecip;
  120 
  121   // Initialize the gpgme_key_t pointer array
  122   out = (gpgme_key_t*) malloc(1);
  123   out = NULL;
  124 
  125   // Loop over the keys back to zero
  126   while(recip != NULL) {
  127     out = realloc(out, sizeof(gpgme_key_t) * (i + 1));
  128     err = gpgme_get_key(ctx, recip->str, &out[i], 0);
  129     gpg_failiferr(err);
  130     recip = recip->next;
  131     i++;
  132   }
  133   out[i] = NULL;
  134   return out;
  135 }
  136 
  137 
  138 void gpg_key_dump(gpgme_key_t key) {
  139   printf("Recipient: %s\n", key->fpr);
  140   printf("  protocol:      %d\n", key->protocol);
  141   printf("  revoked:       %d\n", key->revoked);
  142   printf("  expired:       %d\n", key->expired);
  143   printf("  disabled:      %d\n", key->disabled);
  144   printf("  invalid:       %d\n", key->invalid);
  145   printf("  can_encrypt:   %d\n", key->can_encrypt);
  146   printf("  can_sign:      %d\n", key->can_sign);
  147   printf("  can_certify:   %d\n", key->can_certify);
  148   printf("  can_auth:      %d\n", key->can_authenticate);
  149   printf("  qualified:     %d\n", key->is_qualified);
  150   printf("  secret:        %d\n", key->secret);
  151   printf("  issuer_serial: %s\n", key->issuer_serial);
  152   printf("  issuer_name:   %s\n", key->issuer_name);
  153   printf("  chain_id:      %s\n", key->chain_id);
  154 }
  155 
  156 
  157 size_t gpg_encrypt_file(char* infile, char* outfile, struct strll* recipll) {
  158   gpgme_ctx_t   ctx;
  159   gpgme_data_t  indata;
  160   gpgme_data_t  outdata;
  161   gpgme_error_t err;
  162   gpgme_key_t*  keys = NULL;
  163 
  164   err = init_gpg(&ctx, GPGME_PROTOCOL_OPENPGP);
  165   gpg_failiferr(err);
  166 
  167   // For debugging purposes
  168   logger(LOG_DEBUG, "Reading updated data from memory\n");
  169   // Initialize data structures
  170   err = gpgme_data_new_from_file(&indata, infile, 1);
  171   gpg_failiferr(err);
  172 
  173   err = gpgme_data_new(&outdata);
  174   gpg_failiferr(err);
  175 
  176   // Get key id objects from keyids char array
  177   keys = gpg_strll_to_key_t(ctx, recipll);
  178 
  179   // For debugging purposes
  180   // int i = 0;
  181   // while(keys[i] != NULL) {
  182   //   gpg_key_dump(keys[i]);
  183   //   i++;
  184   // }
  185 
  186   // Encrypt!
  187   err = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, indata, outdata);
  188   gpg_failiferr(err);
  189 
  190 
  191   // For debugging purposes
  192   logger(LOG_DEBUG, "No errors detecting during encryption. Writing to disk\n");
  193 
  194   // Write to disk!
  195   FILE* refd = fopen(outfile, "w");
  196   gpg_data_fwrite(outdata, refd);
  197   fclose(refd);
  198 
  199   // cleanup
  200   gpgme_data_release(indata);
  201   gpgme_data_release(outdata);
  202   gpgme_release(ctx);
  203   return 0;
  204 }
  205 
  206 
  207 gpgme_decrypt_result_t
  208 gpg_decrypt_file(char* infile, char* outfile, gpgme_ctx_t ctx) {
  209   gpgme_error_t err;
  210   gpgme_data_t indata = NULL;
  211   gpgme_data_t outdata = NULL;
  212 
  213   // Read ciphertext file into gpgme data struct, and fail if any errors
  214   // returned.
  215   gpgme_data_new(&outdata);
  216   err = gpgme_data_new_from_file(&indata, infile, 1);
  217   gpg_failiferr(err);
  218 
  219   // Attempt to decrypt
  220   err = gpgme_op_decrypt(ctx, indata, outdata);
  221   gpg_failiferr(err);
  222 
  223   // Write decrypted data to outfile
  224   FILE* outfd = fopen(outfile, "w");
  225   gpg_data_fwrite(outdata, outfd);
  226 
  227   // Clean up
  228   fclose(outfd);
  229   gpgme_data_release(indata);
  230   gpgme_data_release(outdata);
  231   return gpgme_op_decrypt_result(ctx);
  232 }

Generated by cgit