src/sync_impl.c
author Volker Birk <vb@pep.foundation>
Wed, 31 Aug 2016 12:10:26 +0200
branchkeysync
changeset 1104 81cabcd37300
parent 1102 9fdf0e11bf18
child 1105 3fbdd80f0e52
permissions -rw-r--r--
adding secret keys on demand
     1 #include "../asn.1/DeviceGroup-Protocol.h"
     2 #include "sync_impl.h"
     3 #include "pEp_internal.h"
     4 #include "keymanagement.h"
     5 #include "message_api.h"
     6 #include "map_asn1.h"
     7 #include "baseprotocol.h"
     8 
     9 #define SYNC_VERSION_MAJOR 1
    10 #define SYNC_VERSION_MINOR 0
    11 
    12 PEP_STATUS receive_sync_msg(
    13         PEP_SESSION session,
    14         DeviceGroup_Protocol_t *msg
    15     )
    16 {
    17     assert(session && msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING);
    18     if (!(session && msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING))
    19         return PEP_ILLEGAL_VALUE;
    20 
    21     void *extra = NULL;
    22     Identity partner = NULL;
    23     DeviceState_event event = DeviceState_event_NONE;
    24 
    25     switch (msg->payload.present) {
    26         case DeviceGroup_Protocol__payload_PR_beacon:
    27             partner = Identity_to_Struct(&msg->header.me, NULL);
    28             if (!partner)
    29                 return PEP_OUT_OF_MEMORY;
    30             event = Beacon;
    31             break;
    32 
    33         case DeviceGroup_Protocol__payload_PR_handshakeRequest:
    34             partner = Identity_to_Struct(&msg->header.me, NULL);
    35             if (!partner)
    36                 return PEP_OUT_OF_MEMORY;
    37             event = HandshakeRequest;
    38             break;
    39 
    40         case DeviceGroup_Protocol__payload_PR_groupKeys:
    41             partner = Identity_to_Struct(&msg->header.me, NULL);
    42             if (!partner)
    43                 return PEP_OUT_OF_MEMORY;
    44             identity_list *group_keys = IdentityList_to_identity_list(
    45                     &msg->payload.choice.groupKeys.ownIdentities, NULL);
    46             if (!group_keys) {
    47                 free_identity(partner);
    48                 return PEP_OUT_OF_MEMORY;
    49             }
    50             extra = (void *) group_keys;
    51             event = GroupKeys;
    52             break;
    53 
    54         default:
    55             return PEP_SYNC_ILLEGAL_MESSAGE;
    56     }
    57 
    58     return fsm_DeviceState_inject(session, event, partner, extra);
    59 }
    60 
    61 PEP_STATUS receive_DeviceState_msg(PEP_SESSION session, message *src, PEP_rating rating)
    62 {
    63     assert(session && src);
    64     if (!(session && src))
    65         return PEP_ILLEGAL_VALUE;
    66 
    67     bool found = false;
    68     
    69     bloblist_t *last = NULL;
    70     for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
    71         if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp") == 0
    72                 && bl->size) {
    73             DeviceGroup_Protocol_t *msg = NULL;
    74             uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **)
    75                     &msg, bl->value, bl->size);
    76             if (msg) {
    77                 switch (msg->payload.present) {
    78                     // HandshakeRequest needs encryption
    79                     case DeviceGroup_Protocol__payload_PR_handshakeRequest:
    80                         if (rating < PEP_rating_reliable) {
    81                             ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    82                             goto skip;
    83                         }
    84                     // accepting GroupKeys needs trust
    85                     case DeviceGroup_Protocol__payload_PR_groupKeys:
    86                         if (rating < PEP_rating_trusted) {
    87                             ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    88                             goto skip;
    89                         }
    90                     default:
    91                         break;
    92                 }
    93 
    94                 found = true;
    95 
    96                 int32_t value = (int32_t) msg->header.sequence;
    97                 char *user_id = strndup((char *) msg->header.me.user_id->buf,
    98                         msg->header.me.user_id->size);
    99                 assert(user_id);
   100                 if (!user_id) {
   101                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   102                     return PEP_OUT_OF_MEMORY;
   103                 }
   104 
   105                 PEP_STATUS status = sequence_value(session, (char *) user_id,
   106                         &value);
   107 
   108                 if (status == PEP_STATUS_OK) {
   109                     status = session->inject_sync_msg(msg, session->sync_obj);
   110                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   111                     if (status != PEP_STATUS_OK)
   112                         return status;
   113                 }
   114             }
   115 
   116             bloblist_t *blob = bl;
   117             if (last)
   118                 last->next = bl->next;
   119             else
   120                 src->attachments = bl->next;
   121 
   122             blob->next = NULL;
   123             free_bloblist(blob);
   124         }
   125         else {
   126 skip:
   127             last = bl;
   128         }
   129     }
   130 
   131     if (found) {
   132         for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
   133                 spl = spl->next) {
   134             if (spl->value->key &&
   135                     strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
   136                 if (spl->value->value &&
   137                         strcasecmp(spl->value->value, "yes") == 0)
   138                     return PEP_MESSAGE_CONSUMED;
   139             }
   140         }
   141     }
   142 
   143     return PEP_STATUS_OK;
   144 }
   145 
   146 DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type)
   147 {
   148     DeviceGroup_Protocol_t *msg = (DeviceGroup_Protocol_t *)
   149             calloc(1, sizeof(DeviceGroup_Protocol_t));
   150     assert(msg);
   151     if (!msg)
   152         return NULL;
   153     msg->payload.present = type;
   154     return msg;
   155 }
   156 
   157 void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg)
   158 {
   159     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   160 }
   161 
   162 PEP_STATUS unicast_msg(
   163         PEP_SESSION session,
   164         const Identity partner,
   165         DeviceState_state state,
   166         DeviceGroup_Protocol_t *msg,
   167         bool encrypted
   168     )
   169 {
   170     PEP_STATUS status = PEP_STATUS_OK;
   171     char *payload = NULL;
   172     message *_message = NULL;
   173     pEp_identity *me = NULL;
   174     pEp_identity *_me = NULL;
   175 
   176     assert(session && partner && state && msg);
   177     if (!(session && partner && state && msg))
   178         return PEP_ILLEGAL_VALUE;
   179 
   180     assert(session->messageToSend);
   181     if (!session->messageToSend) {
   182         status = PEP_SEND_FUNCTION_NOT_REGISTERED;
   183         goto error;
   184     }
   185 
   186     msg->header.version.major = SYNC_VERSION_MAJOR;
   187     msg->header.version.minor = SYNC_VERSION_MINOR;
   188 
   189     status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
   190     if (status != PEP_STATUS_OK)
   191         goto error;
   192     
   193     int32_t seq = 0;
   194 
   195     status = sequence_value(session, sync_uuid, &seq);
   196     if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK)
   197         goto error;
   198 
   199     msg->header.sequence = (long) seq;
   200 
   201     _me = identity_dup(me);
   202     if (!_me)
   203         goto enomem;
   204 
   205     free(_me->user_id);
   206     _me->user_id = strndup(sync_uuid, 36);
   207     assert(_me->user_id);
   208     if (!_me->user_id)
   209         goto enomem;
   210 
   211     if (Identity_from_Struct(_me, &msg->header.me) == NULL)
   212         goto enomem;
   213 
   214     free_identity(_me);
   215     _me = NULL;
   216 
   217     msg->header.state = (long) state;
   218 
   219     bool devicegroup = storedGroupKeys(session);
   220     if (devicegroup)
   221         msg->header.devicegroup = 1;
   222     else
   223         msg->header.devicegroup = 0;
   224 
   225     if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) {
   226         status = PEP_CONTRAINTS_VIOLATED;
   227         goto error;
   228     }
   229 
   230     ssize_t size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol,
   231             NULL, msg, (void **) &payload);
   232     if (size == -1) {
   233         status = PEP_CANNOT_ENCODE;
   234         goto error;
   235     }
   236 
   237     status = prepare_message(me, partner, payload, size, &_message);
   238     if (status != PEP_STATUS_OK)
   239         goto error;
   240     payload = NULL;
   241     free_identity(me);
   242     me = NULL;
   243 
   244     if (encrypted) {
   245         if (msg->payload.present == DeviceGroup_Protocol__payload_PR_groupKeys) {
   246             PEP_rating rating = PEP_rating_undefined;
   247             status = outgoing_message_rating(session, _message, &rating);
   248             if (status != PEP_STATUS_OK)
   249                 goto error;
   250             if (rating < PEP_rating_trusted) {
   251                 status = PEP_SYNC_NO_TRUST;
   252                 goto error;
   253             }
   254             
   255             IdentityList_t *list = &msg->payload.choice.groupKeys.ownIdentities;
   256             for (int i=0; i<list->list.count; i++) {
   257                 Identity_t *ident = list->list.array[i];
   258                 bloblist_t *bl = bloblist_add(_message->attachments,
   259                         (char *) ident->fpr.buf, ident->fpr.size,
   260                         "application/pgp-keys", "");
   261                 if (!bl)
   262                     goto enomem;
   263                 if (!_message->attachments)
   264                     _message->attachments = bl;
   265             }
   266         }
   267 
   268         message *_encrypted = NULL;
   269         status = encrypt_message(session, _message, NULL, &_encrypted, PEP_enc_PEP, 0);
   270         if (status != PEP_STATUS_OK)
   271             goto error;
   272         free_message(_message);
   273         _message = _encrypted;
   274     }
   275 
   276     status = session->messageToSend(session->sync_obj, _message);
   277     return status;
   278 
   279 enomem:
   280     status = PEP_OUT_OF_MEMORY;
   281 error:
   282     free_identity(_me);
   283     free(payload);
   284     free_message(_message);
   285     free_identity(me);
   286     return status;
   287 }
   288 
   289 PEP_STATUS multicast_self_msg(
   290         PEP_SESSION session,
   291         DeviceState_state state,
   292         DeviceGroup_Protocol_t *msg,
   293         bool encrypted
   294     )
   295 {
   296     PEP_STATUS status = PEP_STATUS_OK;
   297 
   298     assert(session && state && msg);
   299     if (!(session && state && msg))
   300         return PEP_ILLEGAL_VALUE;
   301 
   302     identity_list *own_identities = NULL;
   303     status = own_identities_retrieve(session, &own_identities);
   304     if (status != PEP_STATUS_OK)
   305         return status;
   306 
   307     for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
   308         pEp_identity *me = _i->ident;
   309 
   310         // FIXME: no deep copy for multicast supported yet
   311         DeviceGroup_Protocol_t *_msg = malloc(sizeof(DeviceGroup_Protocol_t));
   312         assert(_msg);
   313         if (_msg == NULL)
   314             goto enomem;
   315         memcpy(_msg, msg, sizeof(DeviceGroup_Protocol_t));
   316         status = unicast_msg(session, me, state, _msg, encrypted);
   317         free_DeviceGroup_Protocol_msg(_msg);
   318     }
   319 
   320     free_identity_list(own_identities);
   321     return PEP_STATUS_OK;
   322 
   323 enomem:
   324     free_identity_list(own_identities);
   325     return PEP_OUT_OF_MEMORY;
   326 }
   327