ENGINE-74: merged into default
authorKrista Grothoff <krista@pep-project.org>
Wed, 23 Nov 2016 21:10:38 +0100
changeset 14321b16e94e76a9
parent 1425 74ee50b89619
parent 1431 66ddf4c4274f
child 1434 a6f131891ac9
child 1435 838db6c0b04f
ENGINE-74: merged into default
     1.1 --- a/src/bloblist.c	Wed Nov 23 17:36:02 2016 +0100
     1.2 +++ b/src/bloblist.c	Wed Nov 23 21:10:38 2016 +0100
     1.3 @@ -166,3 +166,16 @@
     1.4      return len;
     1.5  }
     1.6  
     1.7 +bloblist_t* consume_bloblist_head(bloblist_t *bloblist_head) {
     1.8 +    if (!bloblist_head)
     1.9 +        return NULL;
    1.10 +    
    1.11 +    bloblist_t* next = bloblist_head->next;
    1.12 +        
    1.13 +    free(bloblist_head->value);
    1.14 +    free(bloblist_head->mime_type);
    1.15 +    free(bloblist_head->filename);
    1.16 +    free(bloblist_head);
    1.17 +    
    1.18 +    return next;
    1.19 +}
     2.1 --- a/src/bloblist.h	Wed Nov 23 17:36:02 2016 +0100
     2.2 +++ b/src/bloblist.h	Wed Nov 23 21:10:38 2016 +0100
     2.3 @@ -91,6 +91,17 @@
     2.4  
     2.5  DYNAMIC_API int bloblist_length(const bloblist_t *bloblist);
     2.6  
     2.7 +// consume_bloblist_head() - internal function to delete head of the bloblist
     2.8 +//
     2.9 +//  parameters:
    2.10 +//      bloblist (in)   bloblist to delete head from
    2.11 +//
    2.12 +//  return value:
    2.13 +//      new head of the bloblist 
    2.14 +//
    2.15 +
    2.16 +bloblist_t* consume_bloblist_head(bloblist_t *bloblist_head);
    2.17 +
    2.18  
    2.19  #ifdef __cplusplus
    2.20  }
     3.1 --- a/src/cryptotech.h	Wed Nov 23 17:36:02 2016 +0100
     3.2 +++ b/src/cryptotech.h	Wed Nov 23 21:10:38 2016 +0100
     3.3 @@ -1,6 +1,7 @@
     3.4  #pragma once
     3.5  
     3.6  #include "pEpEngine.h"
     3.7 +#include "bloblist.h"
     3.8  
     3.9  typedef enum _PEP_cryptotech {
    3.10      PEP_crypt_none = 0,
    3.11 @@ -14,6 +15,7 @@
    3.12  
    3.13  typedef PEP_STATUS (*decrypt_and_verify_t)(
    3.14          PEP_SESSION session, const char *ctext, size_t csize,
    3.15 +        const char *dsigtext, size_t dsigsize,
    3.16          char **ptext, size_t *psize, stringlist_t **keylist
    3.17      );
    3.18  
     4.1 --- a/src/message_api.c	Wed Nov 23 17:36:02 2016 +0100
     4.2 +++ b/src/message_api.c	Wed Nov 23 21:10:38 2016 +0100
     4.3 @@ -44,7 +44,7 @@
     4.4  static bool is_fileending(const bloblist_t *bl, const char *fe)
     4.5  {
     4.6      assert(fe);
     4.7 -    
     4.8 +
     4.9      if (bl == NULL || bl->filename == NULL || fe == NULL)
    4.10          return false;
    4.11  
    4.12 @@ -99,7 +99,7 @@
    4.13              return result;
    4.14          }
    4.15      }
    4.16 -        
    4.17 +
    4.18      if (longmsg == NULL)
    4.19          longmsg = "";
    4.20  
    4.21 @@ -130,7 +130,7 @@
    4.22      assert(src);
    4.23      assert(shortmsg);
    4.24      assert(longmsg);
    4.25 -    
    4.26 +
    4.27      if (src == NULL || shortmsg == NULL || longmsg == NULL)
    4.28          return -1;
    4.29  
    4.30 @@ -385,7 +385,7 @@
    4.31      assert(status == PEP_STATUS_OK);
    4.32      if (status != PEP_STATUS_OK)
    4.33          goto pep_error;
    4.34 -    
    4.35 +
    4.36      if (free_ptext){
    4.37          free(ptext);
    4.38          free_ptext=0;
    4.39 @@ -652,7 +652,7 @@
    4.40      assert(msg);
    4.41  
    4.42      add_opt_field(msg, "X-pEp-Version", PEP_VERSION);
    4.43 -    
    4.44 +
    4.45      if (rating != PEP_rating_undefined)
    4.46          add_opt_field(msg, "X-EncStatus", rating_to_string(rating));
    4.47  
    4.48 @@ -667,16 +667,16 @@
    4.49  {
    4.50      if (ct == PEP_ct_unknown)
    4.51          return PEP_rating_undefined;
    4.52 -    
    4.53 +
    4.54      else if (ct == PEP_ct_key_not_found)
    4.55          return PEP_rating_have_no_key;
    4.56 -        
    4.57 +
    4.58      else if (ct == PEP_ct_compromized)
    4.59          return PEP_rating_under_attack;
    4.60  
    4.61      else if (ct == PEP_ct_mistrusted)
    4.62          return PEP_rating_mistrust;
    4.63 -    
    4.64 +
    4.65      if (rating == PEP_rating_unencrypted_for_some)
    4.66          return PEP_rating_unencrypted_for_some;
    4.67  
    4.68 @@ -712,7 +712,7 @@
    4.69  
    4.70      if (blob == NULL || blob->filename == NULL)
    4.71          return false;
    4.72 -    
    4.73 +
    4.74      ext = strrchr(blob->filename, '.');
    4.75      if (ext == NULL)
    4.76          return false;
    4.77 @@ -751,7 +751,7 @@
    4.78      assert(filename);
    4.79      if (filename == NULL)
    4.80          return NULL;
    4.81 -    
    4.82 +
    4.83      char *ext = strrchr(filename, '.');
    4.84      if (ext == NULL)
    4.85          return NULL;
    4.86 @@ -794,7 +794,7 @@
    4.87  
    4.88      assert(session);
    4.89      assert(fpr);
    4.90 -    
    4.91 +
    4.92      if (session == NULL || fpr == NULL)
    4.93          return PEP_rating_undefined;
    4.94  
    4.95 @@ -857,7 +857,7 @@
    4.96  
    4.97      if (max_comm_type == PEP_ct_compromized)
    4.98          return PEP_ct_compromized;
    4.99 -    
   4.100 +
   4.101      if (max_comm_type == PEP_ct_mistrusted)
   4.102          return PEP_ct_mistrusted;
   4.103  
   4.104 @@ -894,7 +894,7 @@
   4.105                is_mime_type(bl, "application/octet-stream")) &&
   4.106               (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
   4.107                      is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
   4.108 -            // explicit mime type 
   4.109 +            // explicit mime type
   4.110              is_mime_type(bl, "application/pgp-keys") ||
   4.111              // as text, by file name
   4.112              (is_mime_type(bl, "text/plain") &&
   4.113 @@ -928,14 +928,14 @@
   4.114  }
   4.115  
   4.116  bool import_attached_keys(
   4.117 -        PEP_SESSION session, 
   4.118 +        PEP_SESSION session,
   4.119          const message *msg,
   4.120          identity_list **private_idents
   4.121      )
   4.122  {
   4.123      assert(session);
   4.124      assert(msg);
   4.125 -    
   4.126 +
   4.127      if (session == NULL || msg == NULL)
   4.128          return false;
   4.129  
   4.130 @@ -944,10 +944,10 @@
   4.131      bloblist_t *bl;
   4.132      int i = 0;
   4.133      for (bl = msg->attachments; i < MAX_KEYS_TO_IMPORT && bl && bl->value;
   4.134 -            bl = bl->next, i++) 
   4.135 +            bl = bl->next, i++)
   4.136      {
   4.137          if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
   4.138 -                && is_key(bl)) 
   4.139 +                && is_key(bl))
   4.140          {
   4.141              import_key(session, bl->value, bl->size, private_idents);
   4.142              remove = true;
   4.143 @@ -968,10 +968,10 @@
   4.144      if (status != PEP_STATUS_OK)
   4.145          return status;
   4.146      assert(size);
   4.147 -    
   4.148 +
   4.149      bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
   4.150                        "pEpkey.asc");
   4.151 -    
   4.152 +
   4.153      if (msg->attachments == NULL && bl)
   4.154          msg->attachments = bl;
   4.155  
   4.156 @@ -984,7 +984,7 @@
   4.157  {
   4.158      assert(session);
   4.159      assert(msg);
   4.160 -    
   4.161 +
   4.162      if (msg->dir == PEP_dir_incoming)
   4.163          return;
   4.164  
   4.165 @@ -994,16 +994,16 @@
   4.166  
   4.167      if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
   4.168          return;
   4.169 -    
   4.170 +
   4.171      char *revoked_fpr = NULL;
   4.172      uint64_t revocation_date = 0;
   4.173 -    
   4.174 +
   4.175      if(get_revoked(session, msg->from->fpr,
   4.176                     &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
   4.177         revoked_fpr != NULL)
   4.178      {
   4.179          time_t now = time(NULL);
   4.180 -        
   4.181 +
   4.182          if (now < (time_t)revocation_date + ONE_WEEK)
   4.183          {
   4.184              _attach_key(session, revoked_fpr, msg);
   4.185 @@ -1015,7 +1015,7 @@
   4.186  PEP_cryptotech determine_encryption_format(message *msg)
   4.187  {
   4.188      assert(msg);
   4.189 -    
   4.190 +
   4.191      if (is_PGP_message_text(msg->longmsg)) {
   4.192          msg->enc_format = PEP_enc_pieces;
   4.193          return PEP_crypt_OpenPGP;
   4.194 @@ -1056,7 +1056,7 @@
   4.195  
   4.196      if (src->dir == PEP_dir_incoming)
   4.197          return PEP_ILLEGAL_VALUE;
   4.198 -    
   4.199 +
   4.200      determine_encryption_format(src);
   4.201      if (src->enc_format != PEP_enc_none)
   4.202          return PEP_ILLEGAL_VALUE;
   4.203 @@ -1083,25 +1083,25 @@
   4.204      PEP_comm_type max_comm_type = PEP_ct_pEp;
   4.205  
   4.206      identity_list * _il;
   4.207 -    
   4.208 +
   4.209      if ((_il = src->bcc) && _il->ident)
   4.210      {
   4.211          // BCC limited support:
   4.212          //     - App splits mails with BCC in multiple mails.
   4.213          //     - Each email is encrypted separately
   4.214 -        
   4.215 +
   4.216          if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
   4.217          {
   4.218              // Only one Bcc with no other recipient allowed for now
   4.219              return PEP_ILLEGAL_VALUE;
   4.220          }
   4.221 -        
   4.222 +
   4.223          PEP_STATUS _status = update_identity(session, _il->ident);
   4.224          if (_status != PEP_STATUS_OK) {
   4.225              status = _status;
   4.226              goto pep_error;
   4.227          }
   4.228 -        
   4.229 +
   4.230          if (_il->ident->fpr && _il->ident->fpr[0]) {
   4.231              _k = stringlist_add(_k, _il->ident->fpr);
   4.232              if (_k == NULL)
   4.233 @@ -1112,7 +1112,7 @@
   4.234          else {
   4.235              dest_keys_found = false;
   4.236              status = PEP_KEY_NOT_FOUND;
   4.237 -        }        
   4.238 +        }
   4.239      }
   4.240      else
   4.241      {
   4.242 @@ -1157,7 +1157,7 @@
   4.243              }
   4.244          }
   4.245      }
   4.246 -    
   4.247 +
   4.248      if (!dest_keys_found ||
   4.249          stringlist_length(keys) == 0 ||
   4.250          _rating(max_comm_type,
   4.251 @@ -1194,10 +1194,10 @@
   4.252              status = PEP_ILLEGAL_VALUE;
   4.253              goto pep_error;
   4.254          }
   4.255 -        
   4.256 +
   4.257          if (status == PEP_OUT_OF_MEMORY)
   4.258              goto enomem;
   4.259 -        
   4.260 +
   4.261          if (status != PEP_STATUS_OK)
   4.262              goto pep_error;
   4.263      }
   4.264 @@ -1249,7 +1249,7 @@
   4.265  
   4.266      if (src->dir == PEP_dir_incoming)
   4.267          return PEP_ILLEGAL_VALUE;
   4.268 -    
   4.269 +
   4.270      determine_encryption_format(src);
   4.271      if (src->enc_format != PEP_enc_none)
   4.272          return PEP_ILLEGAL_VALUE;
   4.273 @@ -1260,7 +1260,7 @@
   4.274  
   4.275      *dst = NULL;
   4.276  
   4.277 -    
   4.278 +
   4.279      PEP_STATUS _status = update_identity(session, target_id);
   4.280      if (_status != PEP_STATUS_OK) {
   4.281          status = _status;
   4.282 @@ -1270,10 +1270,10 @@
   4.283      char* target_fpr = target_id->fpr;
   4.284      if (!target_fpr)
   4.285          return PEP_KEY_NOT_FOUND; // FIXME: Error condition
   4.286 -        
   4.287 +
   4.288      keys = new_stringlist(target_fpr);
   4.289  
   4.290 -    
   4.291 +
   4.292      msg = clone_to_empty_message(src);
   4.293      if (msg == NULL)
   4.294          goto enomem;
   4.295 @@ -1297,10 +1297,10 @@
   4.296              status = PEP_ILLEGAL_VALUE;
   4.297              goto pep_error;
   4.298      }
   4.299 -        
   4.300 +
   4.301      if (status == PEP_OUT_OF_MEMORY)
   4.302          goto enomem;
   4.303 -    
   4.304 +
   4.305      if (status != PEP_STATUS_OK)
   4.306          goto pep_error;
   4.307  
   4.308 @@ -1357,13 +1357,88 @@
   4.309      return PEP_ILLEGAL_VALUE;
   4.310  }
   4.311  
   4.312 +
   4.313 +PEP_STATUS _get_detached_signature(message* msg, bloblist_t** signature_blob) {
   4.314 +    bloblist_t* attach_curr = msg->attachments;
   4.315 +
   4.316 +    *signature_blob = NULL;
   4.317 +
   4.318 +    while (attach_curr) {
   4.319 +        if (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0) {
   4.320 +            *signature_blob = attach_curr;
   4.321 +            break;
   4.322 +        }
   4.323 +        attach_curr = attach_curr->next;
   4.324 +    }
   4.325 +
   4.326 +    return PEP_STATUS_OK;
   4.327 +}
   4.328 +
   4.329 +PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
   4.330 +                            char** stext, size_t* ssize) {
   4.331 +
   4.332 +    char* signed_boundary = NULL;
   4.333 +    char* signpost = strstr(ptext, "Content-Type: multipart/signed");
   4.334 +
   4.335 +    *ssize = 0;
   4.336 +    *stext = NULL;
   4.337 +
   4.338 +    if (!signpost)
   4.339 +        return PEP_UNKNOWN_ERROR;
   4.340 +
   4.341 +    char* curr_line = signpost;
   4.342 +//    const char* end_text = ptext + psize;
   4.343 +    const char* boundary_key = "boundary=\"";
   4.344 +    const size_t BOUNDARY_KEY_SIZE = 10;
   4.345 +
   4.346 +    char* start_boundary = strstr(curr_line, boundary_key);
   4.347 +    if (!start_boundary)
   4.348 +        return PEP_UNKNOWN_ERROR;
   4.349 +
   4.350 +    start_boundary += BOUNDARY_KEY_SIZE;
   4.351 +
   4.352 +    char* end_boundary = strstr(start_boundary, "\"");
   4.353 +
   4.354 +    if (!end_boundary)
   4.355 +        return PEP_UNKNOWN_ERROR;
   4.356 +
   4.357 +    size_t boundary_strlen = (end_boundary - start_boundary) + 2;
   4.358 +
   4.359 +    signed_boundary = calloc(1, boundary_strlen + 1);
   4.360 +    strlcpy(signed_boundary, "--", boundary_strlen + 1);
   4.361 +    strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
   4.362 +
   4.363 +    start_boundary = strstr(end_boundary, signed_boundary);
   4.364 +
   4.365 +    if (!start_boundary)
   4.366 +        return PEP_UNKNOWN_ERROR;
   4.367 +
   4.368 +    start_boundary += boundary_strlen;
   4.369 +
   4.370 +    while (*start_boundary == '\n')
   4.371 +        start_boundary++;
   4.372 +
   4.373 +    end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
   4.374 +
   4.375 +    if (!end_boundary)
   4.376 +        return PEP_UNKNOWN_ERROR;
   4.377 +
   4.378 +    end_boundary--; // See RFC3156 section 5...
   4.379 +
   4.380 +    *ssize = end_boundary - start_boundary;
   4.381 +    *stext = start_boundary;
   4.382 +    free(signed_boundary);
   4.383 +
   4.384 +    return PEP_STATUS_OK;
   4.385 +}
   4.386 +
   4.387  DYNAMIC_API PEP_STATUS _decrypt_message(
   4.388          PEP_SESSION session,
   4.389          message *src,
   4.390          message **dst,
   4.391          stringlist_t **keylist,
   4.392          PEP_rating *rating,
   4.393 -        PEP_decrypt_flags_t *flags, 
   4.394 +        PEP_decrypt_flags_t *flags,
   4.395          identity_list **private_il
   4.396      )
   4.397  {
   4.398 @@ -1397,12 +1472,50 @@
   4.399      if(status != PEP_STATUS_OK)
   4.400          return status;
   4.401  
   4.402 +    // IF longmsg and longmsg_formatted are empty, we MAY have an encrypted body
   4.403 +    // that's an attachment instead.
   4.404 +    // Check for encryption stuck in the first 2 attachments instead of the body
   4.405 +    // (RFC3156)
   4.406 +    //
   4.407 +    if (!src->longmsg && !src->longmsg_formatted) {
   4.408 +        bloblist_t* attached_head = src->attachments;
   4.409 +        if (attached_head && strcasecmp(attached_head->mime_type, "application/pgp-encrypted")) {
   4.410 +            bloblist_t* enc_att_txt = attached_head->next;
   4.411 +            if (enc_att_txt && strcasecmp(enc_att_txt->mime_type, "application/octet-stream")) {
   4.412 +                size_t enc_att_len = enc_att_txt->size;
   4.413 +                char* newlongmsg = calloc(1, enc_att_len + 1);
   4.414 +                if (newlongmsg == NULL)
   4.415 +                    goto enomem;
   4.416 +
   4.417 +                memcpy(newlongmsg, enc_att_txt, enc_att_len);
   4.418 +                newlongmsg[enc_att_len] = '\0';
   4.419 +
   4.420 +                src->longmsg = newlongmsg;
   4.421 +
   4.422 +                // delete attachments here
   4.423 +                src->attachments = enc_att_txt->next;
   4.424 +                consume_bloblist_head(attached_head);
   4.425 +                consume_bloblist_head(attached_head);
   4.426 +            }
   4.427 +        }
   4.428 +    }
   4.429 +
   4.430 +    // Get detached signature, if any
   4.431 +    bloblist_t* detached_sig = NULL;
   4.432 +    char* dsig_text = NULL;
   4.433 +    size_t dsig_size = 0;
   4.434 +    status = _get_detached_signature(src, &detached_sig);
   4.435 +    if (detached_sig) {
   4.436 +        dsig_text = detached_sig->value;
   4.437 +        dsig_size = detached_sig->size;
   4.438 +    }
   4.439 +
   4.440      PEP_cryptotech crypto = determine_encryption_format(src);
   4.441  
   4.442      *dst = NULL;
   4.443      *keylist = NULL;
   4.444      *rating = PEP_rating_undefined;
   4.445 - 
   4.446 +
   4.447      switch (src->enc_format) {
   4.448          case PEP_enc_none:
   4.449              *rating = PEP_rating_unencrypted;
   4.450 @@ -1410,7 +1523,7 @@
   4.451                  remove_attached_keys(src);
   4.452              if(session->inject_sync_msg){
   4.453                  status = receive_DeviceState_msg(session, src, *rating, *keylist);
   4.454 -                if (status == PEP_MESSAGE_CONSUME || 
   4.455 +                if (status == PEP_MESSAGE_CONSUME ||
   4.456                      status == PEP_MESSAGE_IGNORE) {
   4.457                      free_message(msg);
   4.458                      msg = NULL;
   4.459 @@ -1438,7 +1551,8 @@
   4.460              NOT_IMPLEMENTED
   4.461      }
   4.462      status = cryptotech[crypto].decrypt_and_verify(session, ctext,
   4.463 -                                                   csize, &ptext, &psize, &_keylist);
   4.464 +                                                   csize, dsig_text, dsig_size,
   4.465 +                                                   &ptext, &psize, &_keylist);
   4.466      if (status > PEP_CANNOT_DECRYPT_UNKNOWN){
   4.467          goto pep_error;
   4.468      }
   4.469 @@ -1453,7 +1567,7 @@
   4.470          }
   4.471      }
   4.472  
   4.473 -    bool imported_private_key_address = false; 
   4.474 +    bool imported_private_key_address = false;
   4.475  
   4.476      if (ptext) {
   4.477          switch (src->enc_format) {
   4.478 @@ -1461,6 +1575,26 @@
   4.479                  status = mime_decode_message(ptext, psize, &msg);
   4.480                  if (status != PEP_STATUS_OK)
   4.481                      goto pep_error;
   4.482 +                status = _get_detached_signature(msg, &detached_sig);
   4.483 +                if (decrypt_status == PEP_DECRYPTED && detached_sig) {
   4.484 +                    dsig_text = detached_sig->value;
   4.485 +                    dsig_size = detached_sig->size;
   4.486 +                    size_t ssize = 0;
   4.487 +                    char* stext = NULL;
   4.488 +
   4.489 +                    status = _get_signed_text(ptext, psize, &stext, &ssize);
   4.490 +                    stringlist_t *_verify_keylist = NULL;
   4.491 +
   4.492 +                    if (ssize > 0 && stext) {
   4.493 +                        status = cryptotech[crypto].verify_text(session, stext,
   4.494 +                                                                ssize, dsig_text, dsig_size,
   4.495 +                                                                &_verify_keylist);
   4.496 +
   4.497 +                        if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
   4.498 +                            decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
   4.499 +                    }
   4.500 +                }
   4.501 +
   4.502                  break;
   4.503  
   4.504              case PEP_enc_pieces:
   4.505 @@ -1493,8 +1627,10 @@
   4.506                          free(ptext);
   4.507                          ptext = NULL;
   4.508  
   4.509 +                        // FIXME: What about attachments with separate sigs???
   4.510                          status = decrypt_and_verify(session, attctext, attcsize,
   4.511 -                                &ptext, &psize, &_keylist);
   4.512 +                                                    NULL, 0,
   4.513 +                                                    &ptext, &psize, &_keylist);
   4.514                          free_stringlist(_keylist);
   4.515  
   4.516                          if (ptext) {
   4.517 @@ -1550,7 +1686,7 @@
   4.518                  // BUG: must implement more
   4.519                  NOT_IMPLEMENTED
   4.520          }
   4.521 -        
   4.522 +
   4.523          switch (src->enc_format) {
   4.524              case PEP_enc_PGP_MIME:
   4.525              case PEP_enc_pieces:
   4.526 @@ -1586,11 +1722,11 @@
   4.527                  // BUG: must implement more
   4.528                  NOT_IMPLEMENTED
   4.529          }
   4.530 -       
   4.531 +
   4.532          // check for private key in decrypted message attachement while inporting
   4.533          identity_list *_private_il = NULL;
   4.534          imported_keys = import_attached_keys(session, msg, &_private_il);
   4.535 -        if (_private_il && 
   4.536 +        if (_private_il &&
   4.537              identity_list_length(_private_il) == 1 &&
   4.538              _private_il->ident->address)
   4.539          {
   4.540 @@ -1602,11 +1738,11 @@
   4.541          }else{
   4.542              free_identity_list(_private_il);
   4.543          }
   4.544 -         
   4.545 +
   4.546          if(decrypt_status == PEP_DECRYPTED){
   4.547  
   4.548              // TODO optimize if import_attached_keys didn't import any key
   4.549 -            
   4.550 +
   4.551              // In case message did decrypt, but no valid signature could be found
   4.552              // then retry decrypt+verify after importing key.
   4.553  
   4.554 @@ -1616,32 +1752,32 @@
   4.555              status = _update_identity_for_incoming_message(session, src);
   4.556              if(status != PEP_STATUS_OK)
   4.557                  goto pep_error;
   4.558 -            
   4.559 +
   4.560              char *re_ptext = NULL;
   4.561              size_t re_psize;
   4.562 -            
   4.563 +
   4.564              free_stringlist(_keylist);
   4.565              _keylist = NULL;
   4.566  
   4.567              status = cryptotech[crypto].decrypt_and_verify(session, ctext,
   4.568 -                csize, &re_ptext, &re_psize, &_keylist);
   4.569 -            
   4.570 +                csize, dsig_text, dsig_size, &re_ptext, &re_psize, &_keylist);
   4.571 +
   4.572              free(re_ptext);
   4.573 -            
   4.574 +
   4.575              if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
   4.576                  goto pep_error;
   4.577 -            
   4.578 +
   4.579              decrypt_status = status;
   4.580          }
   4.581 -        
   4.582 +
   4.583          *rating = decrypt_rating(decrypt_status);
   4.584 -        
   4.585 +
   4.586          if (*rating > PEP_rating_mistrust) {
   4.587              PEP_rating kl_rating = PEP_rating_undefined;
   4.588 -            
   4.589 +
   4.590              if (_keylist)
   4.591                  kl_rating = keylist_rating(session, _keylist);
   4.592 -            
   4.593 +
   4.594              if (kl_rating <= PEP_rating_mistrust) {
   4.595                  *rating = kl_rating;
   4.596              }
   4.597 @@ -1679,13 +1815,13 @@
   4.598      }
   4.599  
   4.600      // Case of own key imported from own trusted message
   4.601 -    if (// Message have been reliably decrypted 
   4.602 +    if (// Message have been reliably decrypted
   4.603          msg &&
   4.604          *rating >= PEP_rating_trusted &&
   4.605          imported_private_key_address &&
   4.606          // to is [own]
   4.607          msg->to->ident->user_id &&
   4.608 -        strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0 
   4.609 +        strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0
   4.610          )
   4.611      {
   4.612          *flags |= PEP_decrypt_flag_own_private_key;
   4.613 @@ -1697,7 +1833,7 @@
   4.614              remove_attached_keys(msg);
   4.615          if (*rating >= PEP_rating_reliable && session->inject_sync_msg) {
   4.616              status = receive_DeviceState_msg(session, msg, *rating, _keylist);
   4.617 -            if (status == PEP_MESSAGE_CONSUME || 
   4.618 +            if (status == PEP_MESSAGE_CONSUME ||
   4.619                  status == PEP_MESSAGE_IGNORE) {
   4.620                  free_message(msg);
   4.621                  msg = NULL;
   4.622 @@ -1735,7 +1871,7 @@
   4.623          message **dst,
   4.624          stringlist_t **keylist,
   4.625          PEP_rating *rating,
   4.626 -        PEP_decrypt_flags_t *flags 
   4.627 +        PEP_decrypt_flags_t *flags
   4.628      )
   4.629  {
   4.630      return _decrypt_message( session, src, dst, keylist, rating, flags, NULL );
   4.631 @@ -1744,7 +1880,7 @@
   4.632  DYNAMIC_API PEP_STATUS own_message_private_key_details(
   4.633          PEP_SESSION session,
   4.634          message *msg,
   4.635 -        pEp_identity **ident 
   4.636 +        pEp_identity **ident
   4.637      )
   4.638  {
   4.639      assert(session);
   4.640 @@ -1754,10 +1890,10 @@
   4.641      if (!(session && msg && ident))
   4.642          return PEP_ILLEGAL_VALUE;
   4.643  
   4.644 -    message *dst = NULL; 
   4.645 +    message *dst = NULL;
   4.646      stringlist_t *keylist = NULL;
   4.647      PEP_rating rating;
   4.648 -    PEP_decrypt_flags_t flags; 
   4.649 +    PEP_decrypt_flags_t flags;
   4.650  
   4.651      *ident = NULL;
   4.652  
   4.653 @@ -1780,7 +1916,7 @@
   4.654  }
   4.655  
   4.656  static void _max_comm_type_from_identity_list(
   4.657 -        identity_list *identities, 
   4.658 +        identity_list *identities,
   4.659          PEP_SESSION session,
   4.660          PEP_comm_type *max_comm_type,
   4.661          bool *comm_type_determined
   4.662 @@ -1829,7 +1965,7 @@
   4.663  
   4.664      _max_comm_type_from_identity_list(msg->cc, session,
   4.665                                        &max_comm_type, &comm_type_determined);
   4.666 -        
   4.667 +
   4.668      _max_comm_type_from_identity_list(msg->bcc, session,
   4.669                                        &max_comm_type, &comm_type_determined);
   4.670  
   4.671 @@ -1909,46 +2045,46 @@
   4.672  static bool _is_valid_hex(const char* hexstr) {
   4.673      if (!hexstr)
   4.674          return false;
   4.675 -    
   4.676 +
   4.677      const char* curr = hexstr;
   4.678      char currchar;
   4.679 -    
   4.680 +
   4.681      for (currchar = *curr; currchar != '\0'; currchar = *(++curr)) {
   4.682          if ((currchar >= '0' && currchar <= '9') ||
   4.683              (currchar >= 'a' && currchar <= 'f') ||
   4.684 -            (currchar >= 'A' && currchar <= 'F')) 
   4.685 +            (currchar >= 'A' && currchar <= 'F'))
   4.686          {
   4.687              continue;
   4.688          }
   4.689          return false;
   4.690      }
   4.691 -    return true;        
   4.692 +    return true;
   4.693  }
   4.694  
   4.695  // Returns, in comparison: 1 if fpr1 > fpr2, 0 if equal, -1 if fpr1 < fpr2
   4.696  static PEP_STATUS _compare_fprs(const char* fpr1, const char* fpr2, int* comparison) {
   4.697 -    
   4.698 +
   4.699      const int _FULL_FINGERPRINT_LENGTH = 40;
   4.700      const int _ASCII_LOWERCASE_OFFSET = 32;
   4.701  
   4.702      size_t fpr1_len = strlen(fpr1);
   4.703      size_t fpr2_len = strlen(fpr2);
   4.704 -    
   4.705 +
   4.706      if (fpr1_len != _FULL_FINGERPRINT_LENGTH || fpr2_len != _FULL_FINGERPRINT_LENGTH)
   4.707          return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
   4.708 -    
   4.709 +
   4.710      if (!_is_valid_hex(fpr1) || !_is_valid_hex(fpr2))
   4.711          return PEP_ILLEGAL_VALUE;
   4.712 -    
   4.713 +
   4.714      const char* fpr1_curr = fpr1;
   4.715      const char* fpr2_curr = fpr2;
   4.716 -    
   4.717 +
   4.718      char current;
   4.719  
   4.720      // Advance past leading zeros.
   4.721      for (current = *fpr1_curr; current != '0' && current != '\0'; current = *(++fpr1_curr), fpr1_len--);
   4.722      for (current = *fpr2_curr; current != '0' && current != '\0'; current = *(++fpr2_curr), fpr2_len--);
   4.723 -    
   4.724 +
   4.725      if (fpr1_len == fpr2_len) {
   4.726          char digit1;
   4.727          char digit2;
   4.728 @@ -1962,7 +2098,7 @@
   4.729                  digit1 -= _ASCII_LOWERCASE_OFFSET;
   4.730              if (digit2 >= 'a' && digit2 <= 'f')
   4.731                  digit2 -= _ASCII_LOWERCASE_OFFSET;
   4.732 -                        
   4.733 +
   4.734              // We take advantage of the fact that 'a'-'f' are larger
   4.735              // integer values in the ASCII table than '0'-'9'.
   4.736              // This allows us to compare digits directly.
   4.737 @@ -1973,7 +2109,7 @@
   4.738                  *comparison = -1;
   4.739                  return PEP_STATUS_OK;
   4.740              }
   4.741 -            
   4.742 +
   4.743              // pointers already advanced above. Keep going.
   4.744          }
   4.745          *comparison = 0;
   4.746 @@ -2000,28 +2136,28 @@
   4.747      assert(id2->fpr);
   4.748      assert(words);
   4.749      assert(wsize);
   4.750 -    
   4.751 +
   4.752      if (!(session && id1 && id2 && words && wsize) ||
   4.753          !(id1->fpr) || (!id2->fpr))
   4.754          return PEP_ILLEGAL_VALUE;
   4.755 -    
   4.756 +
   4.757      const char *source1 = id1->fpr;
   4.758      const char *source2 = id2->fpr;
   4.759 -    
   4.760 +
   4.761      *words = NULL;
   4.762      *wsize = 0;
   4.763  
   4.764      const size_t SHORT_NUM_TWORDS = 5;
   4.765 -    
   4.766 +
   4.767      // N.B. THIS will have to be changed once we start checking trustword entropy.
   4.768      // For now, full is ALL, and otherwise it's 5-per-id.
   4.769      size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
   4.770 -    
   4.771 +
   4.772      char* first_set = NULL;
   4.773      char* second_set = NULL;
   4.774      size_t first_wsize = 0;
   4.775      size_t second_wsize = 0;
   4.776 -    
   4.777 +
   4.778      int fpr_comparison = -255;
   4.779      PEP_STATUS status = _compare_fprs(source1, source2, &fpr_comparison);
   4.780      if (status != PEP_STATUS_OK)
   4.781 @@ -2034,32 +2170,32 @@
   4.782              status = trustwords(session, source2, lang, &first_set, &first_wsize, max_words_per_id);
   4.783              if (status != PEP_STATUS_OK)
   4.784                  goto error_release;
   4.785 -            status = trustwords(session, source1, lang, &second_set, &second_wsize, max_words_per_id); 
   4.786 +            status = trustwords(session, source1, lang, &second_set, &second_wsize, max_words_per_id);
   4.787              if (status != PEP_STATUS_OK)
   4.788                  goto error_release;
   4.789              break;
   4.790 -        case 0: 
   4.791 +        case 0:
   4.792          case -1: // source1 <= source2
   4.793              status = trustwords(session, source1, lang, &first_set, &first_wsize, max_words_per_id);
   4.794              if (status != PEP_STATUS_OK)
   4.795                  goto error_release;
   4.796 -            status = trustwords(session, source2, lang, &second_set, &second_wsize, max_words_per_id); 
   4.797 +            status = trustwords(session, source2, lang, &second_set, &second_wsize, max_words_per_id);
   4.798              if (status != PEP_STATUS_OK)
   4.799                  goto error_release;
   4.800              break;
   4.801          default:
   4.802              return PEP_UNKNOWN_ERROR; // shouldn't be possible
   4.803      }
   4.804 -    
   4.805 +
   4.806      size_t _wsize = first_wsize + second_wsize;
   4.807 -    
   4.808 +
   4.809      bool needs_space = (first_set[first_wsize - 1] != ' ');
   4.810 -    
   4.811 +
   4.812      if (needs_space)
   4.813          _wsize++;
   4.814 -    
   4.815 +
   4.816      _retstr = calloc(1, _wsize + 1);
   4.817 -    
   4.818 +
   4.819      size_t len = strlcpy(_retstr, first_set, _wsize);
   4.820      if (len >= _wsize) {
   4.821          status = PEP_UNKNOWN_ERROR;
   4.822 @@ -2077,16 +2213,16 @@
   4.823          status = PEP_UNKNOWN_ERROR;
   4.824          goto error_release;
   4.825      }
   4.826 -    
   4.827 +
   4.828      *words = _retstr;
   4.829      *wsize = _wsize;
   4.830      status = PEP_STATUS_OK;
   4.831 -    
   4.832 +
   4.833      goto the_end;
   4.834 -    
   4.835 +
   4.836      error_release:
   4.837      free(_retstr);
   4.838 -    
   4.839 +
   4.840      the_end:
   4.841      free(first_set);
   4.842      free(second_set);
   4.843 @@ -2102,16 +2238,16 @@
   4.844      stringlist_t **keylist,
   4.845      PEP_rating *rating,
   4.846      PEP_decrypt_flags_t *flags
   4.847 -) 
   4.848 +)
   4.849  {
   4.850      PEP_STATUS status = PEP_STATUS_OK;
   4.851      message* tmp_msg = NULL;
   4.852      message* dec_msg = NULL;
   4.853 -    
   4.854 +
   4.855      status = mime_decode_message(mimetext, size, &tmp_msg);
   4.856      if (status != PEP_STATUS_OK)
   4.857          goto pep_error;
   4.858 -    
   4.859 +
   4.860      status = decrypt_message(session,
   4.861                               tmp_msg,
   4.862                               &dec_msg,
   4.863 @@ -2120,13 +2256,13 @@
   4.864                               flags);
   4.865      if (status != PEP_STATUS_OK)
   4.866          goto pep_error;
   4.867 -    
   4.868 +
   4.869      status = mime_encode_message(dec_msg, false, mime_plaintext);
   4.870 -    
   4.871 +
   4.872  pep_error:
   4.873      free_message(tmp_msg);
   4.874      free_message(dec_msg);
   4.875 -    
   4.876 +
   4.877      return status;
   4.878  }
   4.879  
   4.880 @@ -2138,16 +2274,16 @@
   4.881      char** mime_ciphertext,
   4.882      PEP_enc_format enc_format,
   4.883      PEP_encrypt_flags_t flags
   4.884 -) 
   4.885 +)
   4.886  {
   4.887      PEP_STATUS status = PEP_STATUS_OK;
   4.888      message* tmp_msg = NULL;
   4.889      message* enc_msg = NULL;
   4.890 -    
   4.891 +
   4.892      status = mime_decode_message(mimetext, size, &tmp_msg);
   4.893      if (status != PEP_STATUS_OK)
   4.894          goto pep_error;
   4.895 -    
   4.896 +
   4.897      // This isn't incoming, though... so we need to reverse the direction
   4.898      tmp_msg->dir = PEP_dir_outgoing;
   4.899      status = encrypt_message(session,
   4.900 @@ -2158,9 +2294,9 @@
   4.901                               flags);
   4.902      if (status != PEP_STATUS_OK)
   4.903          goto pep_error;
   4.904 -        
   4.905 +
   4.906      status = mime_encode_message(enc_msg, false, mime_ciphertext);
   4.907 -    
   4.908 +
   4.909  pep_error:
   4.910      free_message(tmp_msg);
   4.911      free_message(enc_msg);
   4.912 @@ -2168,5 +2304,3 @@
   4.913      return status;
   4.914  
   4.915  }
   4.916 -
   4.917 -
     5.1 --- a/src/pEpEngine.c	Wed Nov 23 17:36:02 2016 +0100
     5.2 +++ b/src/pEpEngine.c	Wed Nov 23 21:10:38 2016 +0100
     5.3 @@ -1392,6 +1392,7 @@
     5.4  
     5.5  DYNAMIC_API PEP_STATUS decrypt_and_verify(
     5.6      PEP_SESSION session, const char *ctext, size_t csize,
     5.7 +    const char *dsigtext, size_t dsigsize,
     5.8      char **ptext, size_t *psize, stringlist_t **keylist
     5.9      )
    5.10  {
    5.11 @@ -1406,7 +1407,7 @@
    5.12          return PEP_ILLEGAL_VALUE;
    5.13  
    5.14      return session->cryptotech[PEP_crypt_OpenPGP].decrypt_and_verify(
    5.15 -            session, ctext, csize, ptext, psize, keylist);
    5.16 +            session, ctext, csize, dsigtext, dsigsize, ptext, psize, keylist);
    5.17  }
    5.18  
    5.19  DYNAMIC_API PEP_STATUS encrypt_and_sign(
     6.1 --- a/src/pEpEngine.h	Wed Nov 23 17:36:02 2016 +0100
     6.2 +++ b/src/pEpEngine.h	Wed Nov 23 21:10:38 2016 +0100
     6.3 @@ -185,6 +185,10 @@
     6.4  //        session (in)    session handle
     6.5  //        ctext (in)      cipher text to decrypt and/or verify
     6.6  //        csize (in)      size of cipher text
     6.7 +//        dsigtext (in)   if extant, *detached* signature text for this
     6.8 +//                        message (or NULL if not)
     6.9 +//        dsize (in)      size of *detached* signature text for this
    6.10 +//                        message (0, if no detached sig exists)
    6.11  //        ptext (out)     pointer to internal buffer with plain text
    6.12  //        psize (out)     size of plain text
    6.13  //        keylist (out)   list of key ids which where used to encrypt
    6.14 @@ -208,6 +212,7 @@
    6.15  
    6.16  DYNAMIC_API PEP_STATUS decrypt_and_verify(
    6.17          PEP_SESSION session, const char *ctext, size_t csize,
    6.18 +        const char *dsigtext, size_t dsigsize,
    6.19          char **ptext, size_t *psize, stringlist_t **keylist
    6.20      );
    6.21  
     7.1 --- a/src/pgp_gpg.c	Wed Nov 23 17:36:02 2016 +0100
     7.2 +++ b/src/pgp_gpg.c	Wed Nov 23 21:10:38 2016 +0100
     7.3 @@ -39,10 +39,10 @@
     7.4                length <= sizeof(unsigned int) * CHAR_BIT)) {
     7.5              r = Fclose(f);
     7.6              assert(r == 0);
     7.7 -        
     7.8 +
     7.9              return false;
    7.10          }
    7.11 -        
    7.12 +
    7.13          do {
    7.14              char * s;
    7.15  
    7.16 @@ -98,7 +98,7 @@
    7.17      PEP_STATUS status = PEP_STATUS_OK;
    7.18      gpgme_error_t gpgme_error;
    7.19      bool bResult;
    7.20 -    
    7.21 +
    7.22      if (in_first) {
    7.23          stringlist_t *conf_keys   = new_stringlist("keyserver");
    7.24          stringlist_t *conf_values = new_stringlist("hkp://keys.gnupg.net");
    7.25 @@ -338,7 +338,7 @@
    7.26          assert(gpg.gpgme_io_write);
    7.27  
    7.28          gpg.version = gpg.gpgme_check(NULL);
    7.29 -        
    7.30 +
    7.31          const char * const cLocal = setlocale(LC_ALL, NULL);
    7.32          if (!cLocal || (strcmp(cLocal, "C") == 0))
    7.33              setlocale(LC_ALL, "");
    7.34 @@ -349,6 +349,7 @@
    7.35  #endif
    7.36      }
    7.37  
    7.38 +    gpg.gpgme_check(NULL);
    7.39      gpgme_error = gpg.gpgme_new(&session->ctx);
    7.40      gpgme_error = _GPGERR(gpgme_error);
    7.41      if (gpgme_error != GPG_ERR_NO_ERROR) {
    7.42 @@ -384,6 +385,7 @@
    7.43  
    7.44  PEP_STATUS pgp_decrypt_and_verify(
    7.45      PEP_SESSION session, const char *ctext, size_t csize,
    7.46 +    const char *dsigtext, size_t dsigsize,
    7.47      char **ptext, size_t *psize, stringlist_t **keylist
    7.48      )
    7.49  {
    7.50 @@ -434,8 +436,13 @@
    7.51  #endif
    7.52      case GPGME_DATA_TYPE_PGP_SIGNED:
    7.53      case GPGME_DATA_TYPE_PGP_OTHER:
    7.54 -        gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
    7.55 -            plain);
    7.56 +        if (dsigtext) {
    7.57 +            gpgme_error = gpg.gpgme_op_decrypt(session->ctx, cipher, plain);
    7.58 +        }
    7.59 +        else {
    7.60 +            gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
    7.61 +                plain);
    7.62 +        }
    7.63          gpgme_error = _GPGERR(gpgme_error);
    7.64          assert(gpgme_error != GPG_ERR_INV_VALUE);
    7.65          assert(gpgme_error != GPG_ERR_NO_DATA);
    7.66 @@ -467,11 +474,31 @@
    7.67                  reading = gpg.gpgme_data_read(plain, _buffer, length);
    7.68                  assert(length == reading);
    7.69  
    7.70 +                if (dsigtext) {  // Is this safe to do?
    7.71 +                    gpgme_data_t sigdata;
    7.72 +                    // FIXME: replace with verify_text?
    7.73 +                    gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
    7.74 +                                                dsigsize, 0);
    7.75 +                    gpgme_op_verify(session->ctx, sigdata, plain, NULL);
    7.76 +                    gpg.gpgme_data_release(sigdata);
    7.77 +                }
    7.78 +
    7.79                  gpgme_verify_result =
    7.80                      gpg.gpgme_op_verify_result(session->ctx);
    7.81                  assert(gpgme_verify_result);
    7.82                  gpgme_signature = gpgme_verify_result->signatures;
    7.83  
    7.84 +                // if (!gpgme_signature && dsigtext) {
    7.85 +                //     gpgme_data_t sigdata;
    7.86 +                //     gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
    7.87 +                //                                 dsigsize, 0);
    7.88 +                //     gpgme_op_verify(session->ctx, sigdata, plain, NULL);
    7.89 +                //     gpgme_verify_result_t result2 =
    7.90 +                //         gpg.gpgme_op_verify_result(session->ctx);
    7.91 +                //     assert(result2);
    7.92 +                //     gpgme_signature = result2->signatures;
    7.93 +                // }
    7.94 +
    7.95                  if (gpgme_signature) {
    7.96                      stringlist_t *k;
    7.97                      _keylist = new_stringlist(NULL);
    7.98 @@ -485,14 +512,15 @@
    7.99                      k = _keylist;
   7.100  
   7.101                      result = PEP_DECRYPTED_AND_VERIFIED;
   7.102 +                    gpg.gpgme_check(NULL);
   7.103                      do {
   7.104                          switch (_GPGERR(gpgme_signature->status)) {
   7.105                          case GPG_ERR_NO_ERROR:
   7.106                          {
   7.107 -                            // Some versions of gpg returns signer's 
   7.108 +                            // Some versions of gpg returns signer's
   7.109                              // signing subkey fingerprint instead of
   7.110                              // signer's primary key fingerprint.
   7.111 -                            // This is meant to get signer's primary 
   7.112 +                            // This is meant to get signer's primary
   7.113                              // key fingerprint, using subkey's.
   7.114  
   7.115                              gpgme_key_t key = NULL;
   7.116 @@ -509,8 +537,8 @@
   7.117                                  return PEP_OUT_OF_MEMORY;
   7.118                              }
   7.119                              // Primary key is given as the first subkey
   7.120 -                            if (gpgme_error == GPG_ERR_NO_ERROR &&  
   7.121 -                                key && key->subkeys && key->subkeys->fpr 
   7.122 +                            if (gpgme_error == GPG_ERR_NO_ERROR &&
   7.123 +                                key && key->subkeys && key->subkeys->fpr
   7.124                                  && key->subkeys->fpr[0])
   7.125                              {
   7.126                                  k = stringlist_add(k, key->subkeys->fpr);
   7.127 @@ -525,7 +553,7 @@
   7.128                                      return PEP_OUT_OF_MEMORY;
   7.129                                  }
   7.130                              }
   7.131 -                            else 
   7.132 +                            else
   7.133                              {
   7.134                                  result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   7.135                                  break;
   7.136 @@ -693,7 +721,7 @@
   7.137                  gpgme_key_t key;
   7.138                  memset(&key,0,sizeof(key));
   7.139  
   7.140 -                // GPGME may give subkey's fpr instead of primary key's fpr. 
   7.141 +                // GPGME may give subkey's fpr instead of primary key's fpr.
   7.142                  // Therefore we ask for the primary fingerprint instead
   7.143                  // we assume that gpgme_get_key can find key by subkey's fpr
   7.144                  gpgme_error = gpg.gpgme_get_key(session->ctx,
   7.145 @@ -707,8 +735,8 @@
   7.146                      return PEP_OUT_OF_MEMORY;
   7.147                  }
   7.148                  // Primary key is given as the first subkey
   7.149 -                if (gpgme_error == GPG_ERR_NO_ERROR &&  
   7.150 -                    key && key->subkeys && key->subkeys->fpr 
   7.151 +                if (gpgme_error == GPG_ERR_NO_ERROR &&
   7.152 +                    key && key->subkeys && key->subkeys->fpr
   7.153                      && key->subkeys->fpr[0])
   7.154                  {
   7.155                      k = stringlist_add(k, key->subkeys->fpr);
   7.156 @@ -1059,8 +1087,8 @@
   7.157  
   7.158      assert(session);
   7.159      assert(key_data);
   7.160 -   
   7.161 -    if(private_idents) 
   7.162 +
   7.163 +    if(private_idents)
   7.164          *private_idents = NULL;
   7.165  
   7.166      gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
   7.167 @@ -1085,7 +1113,7 @@
   7.168      gpgme_error = _GPGERR(gpgme_error);
   7.169      switch (gpgme_error) {
   7.170      case GPG_ERR_NO_ERROR:
   7.171 -        if(private_idents) 
   7.172 +        if(private_idents)
   7.173          {
   7.174              gpgme_import_result =
   7.175                  gpg.gpgme_op_import_result(session->ctx);
   7.176 @@ -1096,8 +1124,8 @@
   7.177              }
   7.178  
   7.179              gpgme_import_status_t import;
   7.180 -            for (import = gpgme_import_result->imports; 
   7.181 -                 import; 
   7.182 +            for (import = gpgme_import_result->imports;
   7.183 +                 import;
   7.184                   import = import->next)
   7.185               {
   7.186                  if (import &&
   7.187 @@ -1114,9 +1142,9 @@
   7.188                          gpg.gpgme_data_release(dh);
   7.189                          return PEP_OUT_OF_MEMORY;
   7.190                      }
   7.191 -                    
   7.192 -                    if (gpgme_error == GPG_ERR_NO_ERROR &&  
   7.193 -                        key && key->uids && 
   7.194 +
   7.195 +                    if (gpgme_error == GPG_ERR_NO_ERROR &&
   7.196 +                        key && key->uids &&
   7.197                          key->uids->email && key->uids->name)
   7.198                      {
   7.199                          pEp_identity *ident = new_identity(
   7.200 @@ -1136,7 +1164,7 @@
   7.201                              return PEP_OUT_OF_MEMORY;
   7.202                          }
   7.203                      }
   7.204 -                    else 
   7.205 +                    else
   7.206                      {
   7.207                          gpg.gpgme_key_unref(key);
   7.208                          gpg.gpgme_data_release(dh);
   7.209 @@ -1242,21 +1270,21 @@
   7.210      return PEP_STATUS_OK;
   7.211  }
   7.212  
   7.213 -PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern, 
   7.214 +PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern,
   7.215                              stringpair_list_t** keyinfo_list)
   7.216 -{    
   7.217 +{
   7.218      gpgme_error_t gpgme_error;
   7.219      assert(session);
   7.220      assert(keyinfo_list);
   7.221 -    
   7.222 +
   7.223      if (!session || !keyinfo_list)
   7.224          return PEP_ILLEGAL_VALUE;
   7.225 -    
   7.226 +
   7.227      *keyinfo_list = NULL;
   7.228 -    
   7.229 +
   7.230      gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
   7.231      gpgme_error = _GPGERR(gpgme_error);
   7.232 -    
   7.233 +
   7.234      switch(gpgme_error) {
   7.235          case GPG_ERR_NO_ERROR:
   7.236              break;
   7.237 @@ -1265,18 +1293,18 @@
   7.238              return PEP_UNKNOWN_ERROR;
   7.239          default:
   7.240              gpg.gpgme_op_keylist_end(session->ctx);
   7.241 -            return PEP_GET_KEY_FAILED;        
   7.242 +            return PEP_GET_KEY_FAILED;
   7.243      };
   7.244 -    
   7.245 +
   7.246      gpgme_key_t key;
   7.247      stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
   7.248      stringpair_list_t* list_curr = _keyinfo_list;
   7.249      stringpair_t* pair = NULL;
   7.250 -        
   7.251 -    do { 
   7.252 +
   7.253 +    do {
   7.254          gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
   7.255          gpgme_error = _GPGERR(gpgme_error);
   7.256 -      
   7.257 +
   7.258          switch(gpgme_error) {
   7.259              case GPG_ERR_EOF:
   7.260                  break;
   7.261 @@ -1294,18 +1322,18 @@
   7.262                  assert(uid);
   7.263                  if (!fpr)
   7.264                      return PEP_GET_KEY_FAILED;
   7.265 -                
   7.266 +
   7.267                  if (key->subkeys->revoked)
   7.268                      continue;
   7.269 -                
   7.270 +
   7.271                  pair = new_stringpair(fpr, uid);
   7.272  
   7.273                  assert(pair);
   7.274 -                
   7.275 +
   7.276                  if (pair) {
   7.277                      list_curr = stringpair_list_add(list_curr, pair);
   7.278                      pair = NULL;
   7.279 -                    
   7.280 +
   7.281                      assert(list_curr);
   7.282                      if (list_curr != NULL)
   7.283                          break;
   7.284 @@ -1322,14 +1350,14 @@
   7.285                  return PEP_UNKNOWN_ERROR;
   7.286          }
   7.287      } while (gpgme_error != GPG_ERR_EOF);
   7.288 -    
   7.289 +
   7.290      if (_keyinfo_list->value == NULL) {
   7.291          free_stringpair_list(_keyinfo_list);
   7.292          _keyinfo_list = NULL;
   7.293      }
   7.294 -    
   7.295 +
   7.296      *keyinfo_list = _keyinfo_list;
   7.297 -    
   7.298 +
   7.299      return PEP_STATUS_OK;
   7.300  }
   7.301  
   7.302 @@ -1424,13 +1452,13 @@
   7.303                              int private_only) {
   7.304      gpgme_error_t gpgme_error;
   7.305      gpgme_key_t key;
   7.306 -    
   7.307 +
   7.308      assert(session);
   7.309      assert(pattern);
   7.310      assert(keylist);
   7.311 -    
   7.312 +
   7.313      *keylist = NULL;
   7.314 -    
   7.315 +
   7.316      gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
   7.317      gpgme_error = _GPGERR(gpgme_error);
   7.318      switch (gpgme_error) {
   7.319 @@ -1443,10 +1471,10 @@
   7.320              gpg.gpgme_op_keylist_end(session->ctx);
   7.321              return PEP_GET_KEY_FAILED;
   7.322      };
   7.323 -    
   7.324 +
   7.325      stringlist_t *_keylist = new_stringlist(NULL);
   7.326      stringlist_t *_k = _keylist;
   7.327 -    
   7.328 +
   7.329      do {
   7.330          gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
   7.331          gpgme_error = _GPGERR(gpgme_error);
   7.332 @@ -1472,7 +1500,7 @@
   7.333                  return PEP_UNKNOWN_ERROR;
   7.334          };
   7.335      } while (gpgme_error != GPG_ERR_EOF);
   7.336 -    
   7.337 +
   7.338      gpg.gpgme_op_keylist_end(session->ctx);
   7.339      if (_keylist->value == NULL) {
   7.340          free_stringlist(_keylist);
   7.341 @@ -1487,7 +1515,7 @@
   7.342      )
   7.343  {
   7.344      return _pgp_search_keys(session, pattern, keylist, 0);
   7.345 -}    
   7.346 +}
   7.347  
   7.348  PEP_STATUS pgp_find_private_keys(
   7.349      PEP_SESSION session, const char *pattern, stringlist_t **keylist
   7.350 @@ -2166,4 +2194,3 @@
   7.351      }
   7.352      return status;
   7.353  }
   7.354 -
     8.1 --- a/src/pgp_gpg.h	Wed Nov 23 17:36:02 2016 +0100
     8.2 +++ b/src/pgp_gpg.h	Wed Nov 23 21:10:38 2016 +0100
     8.3 @@ -7,6 +7,7 @@
     8.4  
     8.5  PEP_STATUS pgp_decrypt_and_verify(
     8.6          PEP_SESSION session, const char *ctext, size_t csize,
     8.7 +        const char *dsigtext, size_t dsigsize,
     8.8          char **ptext, size_t *psize, stringlist_t **keylist
     8.9      );
    8.10  
     9.1 --- a/test/pEpEngineTest.cc	Wed Nov 23 17:36:02 2016 +0100
     9.2 +++ b/test/pEpEngineTest.cc	Wed Nov 23 21:10:38 2016 +0100
     9.3 @@ -120,7 +120,7 @@
     9.4      stringlist_t *keylist;
     9.5  
     9.6      cout << "calling decrypt_and_verify()\n";
     9.7 -    PEP_STATUS decrypt_result = decrypt_and_verify(session, cipher_buffer.data(), cipher_buffer.size(), &buf_text, &buf_size, &keylist);
     9.8 +    PEP_STATUS decrypt_result = decrypt_and_verify(session, cipher_buffer.data(), cipher_buffer.size(), NULL, 0, &buf_text, &buf_size, &keylist);
     9.9  
    9.10      cout << "returning from decrypt_and_verify() with result == 0x" << std::hex << decrypt_result << "\n";
    9.11      assert(decrypt_result == PEP_DECRYPTED_AND_VERIFIED);