sync/cond_act_sync.yml2
author Krista 'DarthMama' Bennett <krista@pep.foundation>
Sat, 18 Jan 2020 23:15:45 +0100
branchsync
changeset 4352 69ac22b40ac7
parent 4346 38fb52d3c608
permissions -rw-r--r--
now ignoring own key resets in non-grouped keys
     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-2020, 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 sameResponse
    41 ||
    42     TID_t *t1 = &session->sync_state.keysync.response;
    43     TID_t *t2 = &session->sync_state.own.response;
    44 
    45     *result = t1->size == t2->size && memcmp(t1->buf, t2->buf, t1->size) == 0;
    46 ||
    47 
    48 condition sameNegotiation
    49 ||
    50     TID_t *t1 = &session->sync_state.keysync.negotiation;
    51     TID_t *t2 = &session->sync_state.comm_partner.negotiation;
    52 
    53     // test if TID is identical
    54     *result = t1->size == t2->size && memcmp(t1->buf, t2->buf, t1->size) == 0;
    55 ||
    56 
    57 condition sameNegotiationAndPartner
    58 ||
    59     TID_t *t1 = &session->sync_state.keysync.negotiation;
    60     TID_t *t2 = &session->sync_state.comm_partner.negotiation;
    61 
    62     const char *s1 = session->sync_state.comm_partner.sender_fpr;
    63     const char *s2 = session->sync_state.transport.sender_fpr;
    64 
    65     // test if TID is identical
    66     *result = t1->size == t2->size && memcmp(t1->buf, t2->buf, t1->size) == 0
    67     // and test if we're talking to the same sender
    68             && s1 && s2 && strcmp(s1, s2) == 0;
    69 ||
    70 
    71 condition fromGroupMember
    72 ||
    73     const char *sender_fpr = session->sync_state.comm_partner.sender_fpr;
    74     return is_own_key(session, sender_fpr, result);
    75 ||
    76 
    77 condition keyElectionWon
    78 ||
    79     pEp_identity *from = session->sync_state.transport.from;
    80     char *sender_fpr = session->sync_state.comm_partner.sender_fpr;
    81 
    82     assert(from && from->address && from->address[0] && from->user_id &&
    83             from->user_id[0]);
    84     if (!(from && from->address && from->address[0] && from->user_id &&
    85             from->user_id[0]))
    86         return PEP_ILLEGAL_VALUE;
    87 
    88     pEp_identity *me = NULL;
    89     PEP_STATUS status = get_identity(session, from->address, from->user_id, &me);
    90     assert(status == PEP_STATUS_OK);
    91     if (status)
    92         return status;
    93 
    94     assert(me->fpr && me->fpr[0]);
    95     if (!(me->fpr && me->fpr[0])) {
    96         free_identity(me);
    97         return PEP_ILLEGAL_VALUE;
    98     }
    99 
   100     size_t len = MIN(strlen(sender_fpr), strlen(me->fpr));
   101     *result = strncasecmp(sender_fpr, me->fpr, len) > 0;
   102     free_identity(me);
   103 ||
   104 
   105 // action: PEP_STATUS «@name»(PEP_SESSION session)
   106 
   107 function "new_UUID" {
   108     param "dst";
   109     ||
   110         {
   111             pEpUUID c;
   112             uuid_generate_random(c);
   113 
   114             OCTET_STRING_fromBuf(«$dst», (char *) c, 16);
   115         }
   116     ||
   117 }
   118 
   119 function "copy_UUID" {
   120     param "src", param "dst";
   121     ||
   122         {
   123             TID_t *src = «$src»;
   124             TID_t *dst = «$dst»;
   125 
   126             assert(src->size == 16);
   127             if (!(src->size == 16))
   128                 return PEP_UNKNOWN_ERROR;
   129 
   130             OCTET_STRING_fromBuf(dst, (char *) src->buf, src->size);
   131         }
   132     ||
   133 }
   134 
   135 function "xor_UUID" {
   136     param "src", param "dst";
   137     ||
   138         {
   139             TID_t *src = «$src»;
   140             TID_t *dst = «$dst»;
   141 
   142             assert(src->size == 16 && dst->size == 16);
   143             if (!(src->size == 16 && dst->size == 16))
   144                 return PEP_UNKNOWN_ERROR;
   145 
   146             for (int i=0; i < src->size; ++i)
   147                 dst->buf[i] ^= src->buf[i];
   148         }
   149     ||
   150 }
   151 
   152 action newChallengeAndNegotiationBase {
   153     // random new challenge
   154     call "new_UUID" with "dst" > &session->sync_state.own.challenge
   155     call "copy_UUID" {
   156         with "src" > &session->sync_state.own.challenge
   157         with "dst" > &session->sync_state.keysync.challenge
   158     }
   159 
   160     // random new response
   161     call "new_UUID" with "dst" > &session->sync_state.own.response
   162     call "copy_UUID" {
   163         with "src" > &session->sync_state.own.response
   164         with "dst" > &session->sync_state.keysync.response
   165     }
   166 
   167     // this is the random data we are using as a base
   168     call "new_UUID" with "dst" > &session->sync_state.own.negotiation
   169 ||
   170     memset(session->sync_state.keysync.negotiation.buf, 0,
   171             session->sync_state.keysync.negotiation.size);
   172     memset(session->sync_state.comm_partner.negotiation.buf, 0,
   173             session->sync_state.comm_partner.negotiation.size);
   174 ||
   175 }
   176 
   177 action useOwnChallenge call "copy_UUID" {
   178     with "src" > &session->sync_state.own.challenge
   179     with "dst" > &session->sync_state.keysync.challenge
   180 }
   181 
   182 action useOwnResponse call "copy_UUID" {
   183     with "src" > &session->sync_state.own.response
   184     with "dst" > &session->sync_state.keysync.response
   185 }
   186 
   187 action openNegotiation {
   188 ||
   189     // sender key must be stable while transaction
   190 
   191     // we take the actual signature of the last message and store it in our
   192     // state for the comm partner
   193     assert(session->sync_state.transport.sender_fpr);
   194 
   195     free(session->sync_state.comm_partner.sender_fpr);
   196 
   197     session->sync_state.comm_partner.sender_fpr
   198             = strdup(session->sync_state.transport.sender_fpr);
   199     assert(session->sync_state.comm_partner.sender_fpr);
   200     if (!session->sync_state.comm_partner.sender_fpr)
   201         return PEP_OUT_OF_MEMORY;
   202 
   203     // we need a unique TID for the Negotiation with each single comm_partner
   204     // we identify the comm_partners by their Challenge
   205     // we derive the actual Negotiation TID by having random data and XORing it
   206     // with comm_partner's Challenge
   207 
   208     // copy Negotiation base into buffer
   209 
   210 ||
   211     call "copy_UUID" {
   212         with "src" > &session->sync_state.own.negotiation
   213         with "dst" > &session->sync_state.keysync.negotiation
   214     }
   215 ||
   216 
   217     // we're XORing this with the challenge of the comm_partner, which is in
   218     // the buffer already
   219 
   220 ||
   221     call "xor_UUID" {
   222         with "src" > &session->sync_state.keysync.challenge
   223         with "dst" > &session->sync_state.keysync.negotiation
   224     }
   225 ||
   226 
   227     // this is the Negotiation's TID for this comm_partner
   228 
   229 ||
   230     call "copy_UUID" {
   231         with "src" > &session->sync_state.keysync.negotiation
   232         with "dst" > &session->sync_state.comm_partner.negotiation
   233     }
   234 }
   235 
   236 action storeNegotiation {
   237 ||
   238     // sender key must be stable while transaction
   239 
   240     // we take the actual signature of the last message and store it in our
   241     // state for the comm partner
   242     assert(session->sync_state.transport.sender_fpr);
   243 
   244     free(session->sync_state.comm_partner.sender_fpr);
   245 
   246     session->sync_state.comm_partner.sender_fpr
   247             = strdup(session->sync_state.transport.sender_fpr);
   248     assert(session->sync_state.comm_partner.sender_fpr);
   249     if (!session->sync_state.comm_partner.sender_fpr)
   250         return PEP_OUT_OF_MEMORY;
   251 
   252 ||
   253     call "copy_UUID" {
   254         with "src" > &session->sync_state.keysync.negotiation
   255         with "dst" > &session->sync_state.comm_partner.negotiation
   256     }
   257 }
   258 
   259 function "show_handshake" {
   260     param "type";
   261     ||
   262         assert(session->notifyHandshake);
   263         if (!session->notifyHandshake)
   264             return PEP_SYNC_NO_NOTIFY_CALLBACK;
   265 
   266     ||
   267     choose {
   268     when "$type = 'SYNC_NOTIFY_INIT_ADD_OUR_DEVICE' or $type = 'SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE' or $type = 'SYNC_NOTIFY_INIT_FORM_GROUP'"
   269     ||
   270         assert(session->sync_state.transport.from);
   271         if (!session->sync_state.transport.from)
   272             return PEP_ILLEGAL_VALUE;
   273 
   274         pEp_identity *from = session->sync_state.transport.from;
   275         pEp_identity *me = NULL;
   276         PEP_STATUS status = get_identity(session, from->address, from->user_id, &me);
   277         assert(status == PEP_STATUS_OK);
   278         if (status)
   279             return status;
   280         assert(strcmp(me->fpr, session->sync_state.comm_partner.sender_fpr) != 0);
   281 
   282         assert(me->fpr && me->fpr[0]);
   283         if (!(me->fpr && me->fpr[0])) {
   284             free_identity(me);
   285             return PEP_ILLEGAL_VALUE;
   286         }
   287 
   288         pEp_identity *partner = identity_dup(from);
   289         if (!partner) {
   290             free_identity(me);
   291             return PEP_OUT_OF_MEMORY;
   292         }
   293 
   294         assert(session->sync_state.comm_partner.sender_fpr);
   295         if (session->sync_state.comm_partner.sender_fpr) {
   296             free(partner->fpr);
   297             partner->fpr = strdup(session->sync_state.comm_partner.sender_fpr);
   298             assert(partner->fpr);
   299             if (!partner->fpr) {
   300                 free_identity(me);
   301                 free_identity(partner);
   302                 return PEP_OUT_OF_MEMORY;
   303             }
   304         }
   305 
   306         free(partner->user_id);
   307         partner->user_id = strdup("#NV");
   308         assert(partner->user_id);
   309         if (!partner->user_id) {
   310             free_identity(me);
   311             free_identity(partner);
   312             return PEP_OUT_OF_MEMORY;
   313         }
   314 
   315         assert(strcmp(me->fpr, partner->fpr) != 0);
   316         status = session->notifyHandshake(me, partner, «$type»);
   317         if (status)
   318             return status;
   319     ||
   320     otherwise
   321     ||
   322         pEp_identity *me = new_identity(NULL, NULL, NULL, NULL);
   323         pEp_identity *partner = new_identity(NULL, NULL, NULL, NULL);
   324         assert(me && partner);
   325         if (!(me && partner)) {
   326             free_identity(me);
   327             free_identity(partner);
   328             return PEP_OUT_OF_MEMORY;
   329         }
   330 
   331         PEP_STATUS status = session->notifyHandshake(me, partner, «$type»);
   332         if (status)
   333             return status;
   334     ||
   335     }
   336 }
   337 
   338 action showSoleHandshake
   339     call "show_handshake" with "type" > SYNC_NOTIFY_INIT_FORM_GROUP
   340 
   341 action showJoinGroupHandshake
   342     call "show_handshake" with "type" > SYNC_NOTIFY_INIT_ADD_OUR_DEVICE
   343 
   344 action showGroupedHandshake
   345     call "show_handshake" with "type" > SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE
   346 
   347 action showDeviceAdded
   348     call "show_handshake" with "type" > SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED
   349 
   350 action showDeviceAccepted
   351     call "show_handshake" with "type" > SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED
   352 
   353 action showGroupCreated
   354     call "show_handshake" with "type" > SYNC_NOTIFY_ACCEPTED_GROUP_CREATED
   355 
   356 action showBeingSole
   357     call "show_handshake" with "type" > SYNC_NOTIFY_SOLE
   358 
   359 action showBeingInGroup
   360     call "show_handshake" with "type" > SYNC_NOTIFY_IN_GROUP
   361 
   362 timeout KeySync
   363     call "show_handshake" with "type" > SYNC_NOTIFY_TIMEOUT
   364 
   365 action prepareOwnKeys
   366 ||
   367     stringlist_t *own_keys;
   368     PEP_STATUS status = _own_keys_retrieve(session, &own_keys, PEP_idf_not_for_sync, true);
   369     if (status)
   370         return status;
   371 
   372     if (session->sync_state.own.keys)
   373         free_stringlist(session->sync_state.own.keys);
   374     session->sync_state.own.keys = own_keys;
   375 
   376     identity_list *il;
   377     status = _own_identities_retrieve(session, &il, PEP_idf_not_for_sync);
   378     if (status)
   379         return status;
   380 
   381     IdentityList_from_identity_list(il, &session->sync_state.keysync.ownIdentities);
   382     free_identity_list(il);
   383 ||
   384 
   385 action saveGroupKeys
   386 ||
   387     char *user_id = NULL;
   388     PEP_STATUS status = get_default_own_userid(session, &user_id);
   389     if (status)
   390         return status;
   391 
   392     identity_list *il = IdentityList_to_identity_list(&session->sync_state.keysync.ownIdentities, NULL);
   393     if (!il) {
   394         free(user_id);
   395         return PEP_OUT_OF_MEMORY;
   396     }
   397     status = set_all_userids_to_own(session, il);
   398     if (status != PEP_STATUS_OK) {
   399         free(user_id);
   400         return status;
   401     }
   402 
   403     identity_list *oil = session->sync_state.own.identities;
   404 
   405     // BUG: this should be a transaction and been rolled back completely on error
   406     for (identity_list *_il = il; _il && _il->ident; _il = _il->next) {
   407         pEp_identity *ident = _il->ident;
   408         bool is_own_already = false;
   409 
   410         status = is_own_address(session, ident->address, &is_own_already);
   411         if (status) {
   412             free_identity_list(il);
   413             free(user_id);
   414             return status;
   415         }
   416 
   417         free(ident->user_id);
   418         ident->user_id = strdup(user_id);
   419         assert(ident->user_id);
   420         if (!ident->user_id) {
   421             free_identity_list(il);
   422             free(user_id);
   423             return PEP_OUT_OF_MEMORY;
   424         }
   425 
   426         if (is_own_already) {
   427             ident->comm_type = PEP_ct_pEp;
   428             status = set_trust(session, ident);
   429         }
   430         else {
   431             oil = identity_list_add(oil, ident);
   432             if (!oil) {
   433                 free_identity_list(il);
   434                 free(user_id);
   435                 return PEP_OUT_OF_MEMORY;
   436             }
   437             status = myself(session, ident);
   438         }
   439         if (status) {
   440             free_identity_list(il);
   441             free(user_id);
   442             return status;
   443         }
   444     }
   445 
   446     free(user_id);
   447     // NO! This contains the references we add above and belongs to
   448     // session->sync_state.own.identities!
   449     // free_identity_list(il);
   450 ||
   451 
   452 action ownKeysAreDefaultKeys
   453 ||
   454     PEP_STATUS status = PEP_STATUS_OK;
   455 
   456     // set flag for all keys; don't change anything else
   457     for (identity_list *il = session->sync_state.own.identities; il && il->ident ; il = il->next) {
   458         if (!(il->ident->flags && PEP_idf_not_for_sync)) {
   459             status = set_identity_flags(session, il->ident, PEP_idf_devicegroup);
   460             if (status)
   461                 return status;
   462         }
   463     }
   464 ||
   465 
   466 action receivedKeysAreDefaultKeys
   467 ||
   468     PEP_STATUS status = PEP_STATUS_OK;
   469     // set flag for all keys
   470     for (identity_list *il = session->sync_state.own.identities; il && il->ident ; il = il->next) {
   471         if (!(il->ident->flags && PEP_idf_not_for_sync)) {
   472 
   473             status = set_identity_flags(session, il->ident, PEP_idf_devicegroup);
   474             if (status)
   475                 return status;
   476         }
   477     }
   478 
   479     char *user_id = NULL;
   480     status = get_default_own_userid(session, &user_id);
   481     if (status)
   482         return status;
   483 
   484     identity_list *il = IdentityList_to_identity_list(&session->sync_state.keysync.ownIdentities, NULL);
   485     if (!il)
   486         return PEP_OUT_OF_MEMORY;
   487 
   488     status = set_all_userids_to_own(session, il);
   489     if (status != PEP_STATUS_OK) {
   490         free(user_id);
   491         return status;
   492     }
   493 
   494     for (identity_list *_il = il; _il && _il->ident ; _il = _il->next) {
   495         // replace partner's user_id with own user_id
   496         free(_il->ident->user_id);
   497         _il->ident->user_id = strdup(user_id);
   498         assert(_il->ident->user_id);
   499         if (!_il->ident->user_id) {
   500             free_identity_list(il);
   501             free(user_id);
   502             return PEP_OUT_OF_MEMORY;
   503         }
   504 
   505         const char *own_key = _il->ident->fpr;
   506         _il->ident->fpr = NULL;
   507         status = set_own_key(session, _il->ident, own_key);
   508         if (status) {
   509             free_identity_list(il);
   510             free(user_id);
   511             return status;
   512         }
   513     }
   514 
   515     free_identity_list(il);
   516     free(user_id);
   517 ||
   518 
   519 action useThisKey
   520 ||
   521     assert(session->sync_state.comm_partner.sender_fpr);
   522     if (!session->sync_state.comm_partner.sender_fpr)
   523         return PEP_ILLEGAL_VALUE;
   524 
   525     const char *fpr = session->sync_state.comm_partner.sender_fpr;
   526     OCTET_STRING_fromBuf(&session->sync_state.keysync.key, fpr, strlen(fpr));
   527 ||
   528 
   529 action storeThisKey
   530 ||
   531     assert(session->sync_state.keysync.key.size);
   532     if (!session->sync_state.keysync.key.size)
   533         return PEP_ILLEGAL_VALUE;
   534 
   535     char *fpr = strndup((const char *) session->sync_state.keysync.key.buf, session->sync_state.keysync.key.size);
   536     assert(fpr);
   537     if (!fpr)
   538         return PEP_OUT_OF_MEMORY;
   539 
   540     free(session->sync_state.comm_partner.sender_fpr);
   541     session->sync_state.comm_partner.sender_fpr = fpr;
   542 ||
   543 
   544 action trustThisKey
   545 ||
   546     assert(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr);
   547     if (!(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr))
   548         return PEP_ILLEGAL_VALUE;
   549 
   550     pEp_identity *ident = identity_dup(session->sync_state.transport.from);
   551     if (!ident)
   552         return PEP_OUT_OF_MEMORY;
   553     free(ident->fpr);
   554     ident->fpr = strdup(session->sync_state.comm_partner.sender_fpr);
   555     assert(ident->fpr);
   556     if (!ident->fpr) {
   557         free_identity(ident);
   558         return PEP_OUT_OF_MEMORY;
   559     }
   560 
   561     PEP_STATUS status = trust_own_key(session, ident);
   562     if (status) {
   563         free_identity(ident);
   564         return status;
   565     }
   566 
   567     OCTET_STRING_fromBuf(&session->sync_state.keysync.key, ident->fpr, strlen(ident->fpr));
   568     free_identity(ident);
   569 ||
   570 
   571 action untrustThisKey
   572 ||
   573     assert(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr);
   574     if (!(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr))
   575         return PEP_ILLEGAL_VALUE;
   576 
   577     pEp_identity *ident = session->sync_state.transport.from;
   578     free(ident->fpr);
   579     ident->fpr = strdup(session->sync_state.comm_partner.sender_fpr);
   580     assert(ident->fpr);
   581     if (!ident->fpr)
   582         return PEP_OUT_OF_MEMORY;
   583 
   584     PEP_STATUS status = key_reset_trust(session, ident);
   585     if (status)
   586         return status;
   587 
   588     OCTET_STRING_fromBuf(&session->sync_state.keysync.key, "", 0);
   589 ||
   590 
   591 action tellWeAreGrouped
   592 ||
   593     session->sync_state.keysync.is_group = true;
   594 ||
   595 
   596 action tellWeAreNotGrouped
   597 ||
   598     session->sync_state.keysync.is_group = false;
   599 ||
   600 
   601 action disable
   602 ||
   603     disable_sync(session);
   604 ||
   605 
   606 action resetOwnGroupedKeys
   607 ||
   608     return key_reset_own_grouped_keys(session);
   609 ||