sync/cond_act_sync.yml2
author Volker Birk <vb@pep-project.org>
Thu, 08 Aug 2019 13:38:56 +0200
branchsync
changeset 3971 8b2d20579b85
parent 3856 8a23d954fd74
child 4053 a1b219054c9b
permissions -rw-r--r--
Forming Group intermediate state and UI notification
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 // generate conditions and actions
     5 
     6 // Copyleft (c) 2017-2019, p≡p foundation
     7 
     8 // Written by Volker Birk
     9 
    10 
    11 include ./sql_func.yml2
    12 
    13 // condition: PEP_STATUS «@name»(PEP_SESSION session, bool *result)
    14 
    15 condition deviceGrouped {
    16     call "exec_sql_int" with "sql"
    17         > "select count(*) from identity where is_own = 1 and (flags & 0x100) = 0x100;"
    18     |> *result = _result > 0;
    19 }
    20 
    21 condition weAreOfferer
    22 ||
    23     TID_t *t1 = &session->sync_state.keysync.challenge;
    24     TID_t *t2 = &session->sync_state.own.challenge;
    25 
    26     *result = _TID_greater(t1, t2);
    27 ||
    28 
    29 condition partnerIsGrouped
    30 |> *result = session->sync_state.keysync.is_group;
    31 
    32 condition sameChallenge
    33 ||
    34     TID_t *t1 = &session->sync_state.keysync.challenge;
    35     TID_t *t2 = &session->sync_state.own.challenge;
    36 
    37     *result = t1->size == t2->size && memcmp(t1->buf, t2->buf, t1->size) == 0;
    38 ||
    39 
    40 condition sameNegotiation
    41 ||
    42     TID_t *t1 = &session->sync_state.keysync.negotiation;
    43     TID_t *t2 = &session->sync_state.comm_partner.negotiation;
    44 
    45     // test if TID is identical
    46     *result = t1->size == t2->size && memcmp(t1->buf, t2->buf, t1->size) == 0;
    47 ||
    48 
    49 condition sameNegotiationAndPartner
    50 ||
    51     TID_t *t1 = &session->sync_state.keysync.negotiation;
    52     TID_t *t2 = &session->sync_state.comm_partner.negotiation;
    53 
    54     const char *s1 = session->sync_state.comm_partner.sender_fpr;
    55     const char *s2 = session->sync_state.transport.sender_fpr;
    56 
    57     // test if TID is identical
    58     *result = t1->size == t2->size && memcmp(t1->buf, t2->buf, t1->size) == 0
    59     // and test if we're talking to the same sender
    60             && s1 && s2 && strcmp(s1, s2) == 0;
    61 ||
    62 
    63 condition keyElectionWon
    64 ||
    65     pEp_identity *from = session->sync_state.transport.from;
    66     char *sender_fpr = session->sync_state.comm_partner.sender_fpr;
    67 
    68     assert(from && from->address && from->address[0] && from->user_id &&
    69             from->user_id[0]);
    70     if (!(from && from->address && from->address[0] && from->user_id &&
    71             from->user_id[0]))
    72         return PEP_ILLEGAL_VALUE;
    73 
    74     pEp_identity *me = NULL;
    75     PEP_STATUS status = get_identity(session, from->address, from->user_id, &me);
    76     assert(status == PEP_STATUS_OK);
    77     if (status)
    78         return status;
    79 
    80     assert(me->fpr && me->fpr[0]);
    81     if (!(me->fpr && me->fpr[0])) {
    82         free_identity(me);
    83         return PEP_ILLEGAL_VALUE;
    84     }
    85 
    86     size_t len = MIN(strlen(sender_fpr), strlen(me->fpr));
    87     *result = strncasecmp(sender_fpr, me->fpr, len) > 0;
    88     free_identity(me);
    89 ||
    90 
    91 // action: PEP_STATUS «@name»(PEP_SESSION session)
    92 
    93 function "new_UUID" {
    94     param "dst";
    95     ||
    96         {
    97             pEpUUID c;
    98             uuid_generate_random(c);
    99 
   100             OCTET_STRING_fromBuf(«$dst», (char *) c, 16);
   101         }
   102     ||
   103 }
   104 
   105 function "copy_UUID" {
   106     param "src", param "dst";
   107     ||
   108         {
   109             TID_t *src = «$src»;
   110             TID_t *dst = «$dst»;
   111 
   112             assert(src->size == 16);
   113             if (!(src->size == 16))
   114                 return PEP_UNKNOWN_ERROR;
   115 
   116             OCTET_STRING_fromBuf(dst, (char *) src->buf, src->size);
   117         }
   118     ||
   119 }
   120 
   121 function "xor_UUID" {
   122     param "src", param "dst";
   123     ||
   124         {
   125             TID_t *src = «$src»;
   126             TID_t *dst = «$dst»;
   127 
   128             assert(src->size == 16 && dst->size == 16);
   129             if (!(src->size == 16 && dst->size == 16))
   130                 return PEP_UNKNOWN_ERROR;
   131 
   132             for (int i=0; i < src->size; ++i)
   133                 dst->buf[i] ^= src->buf[i];
   134         }
   135     ||
   136 }
   137 
   138 action newChallengeAndNegotiationBase {
   139     // random new challenge
   140     call "new_UUID" with "dst" > &session->sync_state.own.challenge
   141     call "copy_UUID" {
   142         with "src" > &session->sync_state.own.challenge
   143         with "dst" > &session->sync_state.keysync.challenge
   144     }
   145 
   146     // this is the random data we are using as a base
   147     call "new_UUID" with "dst" > &session->sync_state.own.negotiation
   148 ||
   149     memset(session->sync_state.keysync.negotiation.buf, 0,
   150             session->sync_state.keysync.negotiation.size);
   151     memset(session->sync_state.comm_partner.negotiation.buf, 0,
   152             session->sync_state.comm_partner.negotiation.size);
   153 ||
   154 }
   155 
   156 action useOwnChallenge call "copy_UUID" {
   157     with "src" > &session->sync_state.own.challenge
   158     with "dst" > &session->sync_state.keysync.challenge
   159 }
   160 
   161 action openNegotiation {
   162 ||
   163     // sender key must be stable while transaction
   164 
   165     // we take the actual signature of the last message and store it in our
   166     // state for the comm partner
   167     assert(session->sync_state.transport.sender_fpr);
   168 
   169     free(session->sync_state.comm_partner.sender_fpr);
   170 
   171     session->sync_state.comm_partner.sender_fpr
   172             = strdup(session->sync_state.transport.sender_fpr);
   173     assert(session->sync_state.comm_partner.sender_fpr);
   174     if (!session->sync_state.comm_partner.sender_fpr)
   175         return PEP_OUT_OF_MEMORY;
   176 
   177     // we need a unique TID for the Negotiation with each single comm_partner
   178     // we identify the comm_partners by their Challenge
   179     // we derive the actual Negotiation TID by having random data and XORing it
   180     // with comm_partner's Challenge
   181 
   182     // copy Negotiation base into buffer
   183 
   184 ||
   185     call "copy_UUID" {
   186         with "src" > &session->sync_state.own.negotiation
   187         with "dst" > &session->sync_state.keysync.negotiation
   188     }
   189 ||
   190 
   191     // we're XORing this with the challenge of the comm_partner, which is in
   192     // the buffer already
   193 
   194 ||
   195     call "xor_UUID" {
   196         with "src" > &session->sync_state.keysync.challenge
   197         with "dst" > &session->sync_state.keysync.negotiation
   198     }
   199 ||
   200 
   201     // this is the Negotiation's TID for this comm_partner
   202 
   203 ||
   204     call "copy_UUID" {
   205         with "src" > &session->sync_state.keysync.negotiation
   206         with "dst" > &session->sync_state.comm_partner.negotiation
   207     }
   208 }
   209 
   210 action storeNegotiation {
   211 ||
   212     // sender key must be stable while transaction
   213 
   214     // we take the actual signature of the last message and store it in our
   215     // state for the comm partner
   216     assert(session->sync_state.transport.sender_fpr);
   217 
   218     free(session->sync_state.comm_partner.sender_fpr);
   219 
   220     session->sync_state.comm_partner.sender_fpr
   221             = strdup(session->sync_state.transport.sender_fpr);
   222     assert(session->sync_state.comm_partner.sender_fpr);
   223     if (!session->sync_state.comm_partner.sender_fpr)
   224         return PEP_OUT_OF_MEMORY;
   225 
   226 ||
   227     call "copy_UUID" {
   228         with "src" > &session->sync_state.keysync.negotiation
   229         with "dst" > &session->sync_state.comm_partner.negotiation
   230     }
   231 }
   232 
   233 function "show_handshake" {
   234     param "type";
   235     ||
   236         assert(session->notifyHandshake);
   237         if (!session->notifyHandshake)
   238             return PEP_SYNC_NO_NOTIFY_CALLBACK;
   239      
   240     ||
   241     choose {
   242     when "$type = 'SYNC_NOTIFY_INIT_ADD_OUR_DEVICE' or $type = 'SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE' or $type = 'SYNC_NOTIFY_INIT_FORM_GROUP'"
   243     ||
   244         assert(session->sync_state.transport.from);
   245         if (!session->sync_state.transport.from)
   246             return PEP_ILLEGAL_VALUE;
   247 
   248         pEp_identity *from = session->sync_state.transport.from;
   249         pEp_identity *me = NULL;
   250         PEP_STATUS status = get_identity(session, from->address, from->user_id, &me);
   251         assert(status == PEP_STATUS_OK);
   252         if (status)
   253             return status;
   254         assert(strcmp(me->fpr, session->sync_state.comm_partner.sender_fpr) != 0);
   255         
   256         assert(me->fpr && me->fpr[0]);
   257         if (!(me->fpr && me->fpr[0])) {
   258             free_identity(me);
   259             return PEP_ILLEGAL_VALUE;
   260         }
   261 
   262         pEp_identity *partner = identity_dup(from);
   263         if (!partner) {
   264             free_identity(me);
   265             return PEP_OUT_OF_MEMORY;
   266         }
   267 
   268         assert(session->sync_state.comm_partner.sender_fpr);
   269         if (session->sync_state.comm_partner.sender_fpr) {
   270             free(partner->fpr);
   271             partner->fpr = strdup(session->sync_state.comm_partner.sender_fpr);
   272             assert(partner->fpr);
   273             if (!partner->fpr) {
   274                 free_identity(me);
   275                 free_identity(partner);
   276                 return PEP_OUT_OF_MEMORY;
   277             }
   278         }
   279 
   280         free(partner->user_id);
   281         partner->user_id = strdup("#NV");
   282         assert(partner->user_id);
   283         if (!partner->user_id) {
   284             free_identity(me);
   285             free_identity(partner);
   286             return PEP_OUT_OF_MEMORY;
   287         }
   288 
   289         assert(strcmp(me->fpr, partner->fpr) != 0);
   290         status = session->notifyHandshake(me, partner, «$type»);
   291         if (status)
   292             return status;
   293     ||
   294     otherwise
   295     ||
   296         pEp_identity *me = new_identity(NULL, NULL, NULL, NULL);
   297         pEp_identity *partner = new_identity(NULL, NULL, NULL, NULL);
   298         assert(me && partner);
   299         if (!(me && partner)) {
   300             free_identity(me);
   301             free_identity(partner);
   302             return PEP_OUT_OF_MEMORY;
   303         }
   304 
   305         PEP_STATUS status = session->notifyHandshake(me, partner, «$type»);
   306         if (status)
   307             return status;
   308     ||
   309     }
   310 }
   311 
   312 action showSoleHandshake
   313     call "show_handshake" with "type" > SYNC_NOTIFY_INIT_FORM_GROUP
   314 
   315 action showJoinGroupHandshake
   316     call "show_handshake" with "type" > SYNC_NOTIFY_INIT_ADD_OUR_DEVICE
   317 
   318 action showGroupedHandshake
   319     call "show_handshake" with "type" > SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE
   320 
   321 action hideHandshakeDialog
   322     call "show_handshake" with "type" > SYNC_NOTIFY_OVERTAKEN
   323 
   324 action showDeviceAdded
   325     call "show_handshake" with "type" > SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED
   326 
   327 action showFormingGroup
   328     call "show_handshake" with "type" > SYNC_NOTIFY_FORMING_GROUP
   329     
   330 action showGroupCreated
   331     call "show_handshake" with "type" > SYNC_NOTIFY_ACCEPTED_GROUP_CREATED
   332 
   333 action showBeingSole
   334     call "show_handshake" with "type" > SYNC_NOTIFY_SOLE
   335 
   336 action showBeingInGroup
   337     call "show_handshake" with "type" > SYNC_NOTIFY_IN_GROUP
   338 
   339 timeout KeySync
   340     call "show_handshake" with "type" > SYNC_NOTIFY_TIMEOUT
   341 
   342 action prepareOwnKeys
   343 ||
   344     stringlist_t *own_keys;
   345     PEP_STATUS status = _own_keys_retrieve(session, &own_keys, PEP_idf_not_for_sync, true);
   346     if (status)
   347         return status;
   348 
   349     if (session->sync_state.own.keys)
   350         free_stringlist(session->sync_state.own.keys);
   351     session->sync_state.own.keys = own_keys;
   352 
   353     identity_list *il;
   354     status = _own_identities_retrieve(session, &il, PEP_idf_not_for_sync);
   355     if (status)
   356         return status;
   357 
   358     IdentityList_from_identity_list(il, &session->sync_state.keysync.ownIdentities);
   359     free_identity_list(il);
   360 ||
   361 
   362 action saveGroupKeys
   363 ||
   364     char *user_id = NULL;
   365     PEP_STATUS status = get_default_own_userid(session, &user_id);
   366     if (status)
   367         return status;
   368 
   369     identity_list *il = IdentityList_to_identity_list(&session->sync_state.keysync.ownIdentities, NULL);
   370     if (!il) {
   371         free(user_id);
   372         return PEP_OUT_OF_MEMORY;
   373     }
   374     
   375     identity_list *oil = session->sync_state.own.identities;
   376 
   377     // BUG: this should be a transaction and been rolled back completely on error
   378     for (identity_list *_il = il; _il && _il->ident; _il = _il->next) {
   379         pEp_identity *ident = _il->ident;
   380         bool is_own_already = false;
   381 
   382         status = is_own_address(session, ident->address, &is_own_already);
   383         if (status) {
   384             free_identity_list(il);
   385             free(user_id);
   386             return status;
   387         }
   388 
   389         free(ident->user_id);
   390         ident->user_id = strdup(user_id);
   391         assert(ident->user_id);
   392         if (!ident->user_id) {
   393             free_identity_list(il);
   394             free(user_id);
   395             return PEP_OUT_OF_MEMORY;
   396         }
   397 
   398         if (is_own_already) {
   399             ident->comm_type = PEP_ct_pEp;
   400             status = set_trust(session, ident);
   401         }
   402         else {
   403             oil = identity_list_add(oil, ident);
   404             if (!oil) {
   405                 free_identity_list(il);
   406                 free(user_id);
   407                 return PEP_OUT_OF_MEMORY;
   408             }
   409             status = myself(session, ident);
   410         }
   411         if (status) {
   412             free_identity_list(il);
   413             free(user_id);
   414             return status;
   415         }
   416     }
   417 
   418     free(user_id);
   419     free_identity_list(il);
   420 ||
   421 
   422 action ownKeysAreDefaultKeys
   423 ||
   424     PEP_STATUS status = PEP_STATUS_OK;
   425 
   426     // set flag for all keys; don't change anything else
   427     for (identity_list *il = session->sync_state.own.identities; il && il->ident ; il = il->next) {
   428         if (!(il->ident->flags && PEP_idf_not_for_sync)) {
   429             status = set_identity_flags(session, il->ident, PEP_idf_devicegroup);
   430             if (status)
   431                 return status;
   432         }
   433     }
   434 ||
   435 
   436 action receivedKeysAreDefaultKeys
   437 ||
   438     PEP_STATUS status = PEP_STATUS_OK;
   439     // set flag for all keys
   440     for (identity_list *il = session->sync_state.own.identities; il && il->ident ; il = il->next) {
   441         if (!(il->ident->flags && PEP_idf_not_for_sync)) {
   442             
   443             status = set_identity_flags(session, il->ident, PEP_idf_devicegroup);
   444             if (status)
   445                 return status;
   446         }
   447     }
   448 
   449     char *user_id = NULL;
   450     status = get_default_own_userid(session, &user_id);
   451     if (status)
   452         return status;
   453 
   454     identity_list *il = IdentityList_to_identity_list(&session->sync_state.keysync.ownIdentities, NULL);
   455     if (!il)
   456         return PEP_OUT_OF_MEMORY;
   457 
   458     for (identity_list *_il = il; _il && _il->ident ; _il = _il->next) {
   459         // replace partner's user_id with own user_id
   460         free(_il->ident->user_id);
   461         _il->ident->user_id = strdup(user_id);
   462         assert(_il->ident->user_id);
   463         if (!_il->ident->user_id) {
   464             free_identity_list(il);
   465             free(user_id);
   466             return PEP_OUT_OF_MEMORY;
   467         }
   468     
   469         const char *own_key = _il->ident->fpr;
   470         _il->ident->fpr = NULL;
   471         status = set_own_key(session, _il->ident, own_key);
   472         if (status) {
   473             free_identity_list(il);
   474             free(user_id);
   475             return status;
   476         }
   477     }
   478 
   479     free_identity_list(il);
   480     free(user_id);
   481 ||
   482 
   483 action trustThisKey
   484 ||
   485     assert(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr);
   486     if (!(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr))
   487         return PEP_ILLEGAL_VALUE;
   488 
   489     pEp_identity *ident = identity_dup(session->sync_state.transport.from);
   490     if (!ident)
   491         return PEP_OUT_OF_MEMORY;
   492     free(ident->fpr);
   493     ident->fpr = strdup(session->sync_state.comm_partner.sender_fpr);
   494     assert(ident->fpr);
   495     if (!ident->fpr) {
   496         free_identity(ident);
   497         return PEP_OUT_OF_MEMORY;
   498     }
   499 
   500     PEP_STATUS status = trust_own_key(session, ident);
   501     if (status) {
   502         free_identity(ident);
   503         return status;
   504     }
   505 
   506     OCTET_STRING_fromBuf(&session->sync_state.keysync.key, ident->fpr, strlen(ident->fpr));
   507     free_identity(ident);
   508 ||
   509 
   510 action untrustThisKey
   511 ||
   512     assert(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr);
   513     if (!(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr))
   514         return PEP_ILLEGAL_VALUE;
   515 
   516     pEp_identity *ident = session->sync_state.transport.from;
   517     free(ident->fpr);
   518     ident->fpr = strdup(session->sync_state.comm_partner.sender_fpr);
   519     assert(ident->fpr);
   520     if (!ident->fpr)
   521         return PEP_OUT_OF_MEMORY;
   522 
   523     PEP_STATUS status = key_reset_trust(session, ident);
   524     if (status)
   525         return status;
   526 
   527     OCTET_STRING_fromBuf(&session->sync_state.keysync.key, "", 0);
   528 ||
   529 
   530 action tellWeAreGrouped
   531 ||
   532     session->sync_state.keysync.is_group = true;
   533 ||
   534 
   535 action tellWeAreNotGrouped
   536 ||
   537     session->sync_state.keysync.is_group = false;
   538 ||
   539 
   540 action disable;