sync/cond_act_sync.yml2
author Roker <roker@pep-project.org>
Wed, 16 Sep 2020 18:14:33 +0200
changeset 5065 d6d23b414a93
parent 4672 9f99a202f9b9
child 4687 f0bdf6dffd23
permissions -rw-r--r--
also "install" libpEpEngine.a into $PREFIX/lib
     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.transport.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     // clear comm_partner's key until we have decided
   190 
   191     free(session->sync_state.comm_partner.sender_fpr);
   192     session->sync_state.comm_partner.sender_fpr = NULL;
   193 
   194     // clear comm_partner's identity
   195 
   196     free_identity(session->sync_state.comm_partner.identity);
   197     session->sync_state.comm_partner.identity = NULL;
   198 
   199     // we need a unique TID for the Negotiation with each single comm_partner
   200     // we identify the comm_partners by their Challenge
   201     // we derive the actual Negotiation TID by having random data and XORing it
   202     // with comm_partner's Challenge
   203 
   204     // copy Negotiation base into buffer
   205 
   206 ||
   207     call "copy_UUID" {
   208         with "src" > &session->sync_state.own.negotiation
   209         with "dst" > &session->sync_state.keysync.negotiation
   210     }
   211 ||
   212 
   213     // we're XORing this with the challenge of the comm_partner, which is in
   214     // the buffer already
   215 
   216 ||
   217     call "xor_UUID" {
   218         with "src" > &session->sync_state.keysync.challenge
   219         with "dst" > &session->sync_state.keysync.negotiation
   220     }
   221 ||
   222 
   223     // this is the Negotiation's TID for this comm_partner
   224 
   225 ||
   226     call "copy_UUID" {
   227         with "src" > &session->sync_state.keysync.negotiation
   228         with "dst" > &session->sync_state.comm_partner.negotiation
   229     }
   230 }
   231 
   232 action storeNegotiation {
   233 ||
   234     // comm_partner must be stable from now on
   235 
   236     // we take the actual signature of the last message and store it in our
   237     // state for the comm_partner
   238 
   239     assert(session->sync_state.transport.sender_fpr);
   240 
   241     free(session->sync_state.comm_partner.sender_fpr);
   242 
   243     session->sync_state.comm_partner.sender_fpr
   244             = strdup(session->sync_state.transport.sender_fpr);
   245     assert(session->sync_state.comm_partner.sender_fpr);
   246     if (!session->sync_state.comm_partner.sender_fpr)
   247         return PEP_OUT_OF_MEMORY;
   248 
   249     // we store the comm_partner's identity
   250     
   251     assert(session->sync_state.transport.from);
   252 
   253     free_identity(session->sync_state.comm_partner.identity);
   254 
   255     session->sync_state.comm_partner.identity
   256             = identity_dup(session->sync_state.transport.from);
   257     if (!session->sync_state.comm_partner.identity)
   258         return PEP_OUT_OF_MEMORY;
   259 
   260 ||
   261     call "copy_UUID" {
   262         with "src" > &session->sync_state.keysync.negotiation
   263         with "dst" > &session->sync_state.comm_partner.negotiation
   264     }
   265 }
   266 
   267 function "show_handshake" {
   268     param "type";
   269     ||
   270         assert(session->notifyHandshake);
   271         if (!session->notifyHandshake)
   272             return PEP_SYNC_NO_NOTIFY_CALLBACK;
   273 
   274     ||
   275     choose {
   276     when "$type = 'SYNC_NOTIFY_INIT_ADD_OUR_DEVICE' or $type = 'SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE' or $type = 'SYNC_NOTIFY_INIT_FORM_GROUP'"
   277     ||
   278         assert(session->sync_state.transport.from);
   279         if (!session->sync_state.transport.from)
   280             return PEP_ILLEGAL_VALUE;
   281 
   282         pEp_identity *from = session->sync_state.transport.from;
   283         pEp_identity *me = NULL;
   284         PEP_STATUS status = get_identity(session, from->address, from->user_id, &me);
   285         assert(status == PEP_STATUS_OK);
   286         if (status)
   287             return status;
   288 
   289         assert(me->fpr && me->fpr[0]);
   290         if (!(me->fpr && me->fpr[0])) {
   291             free_identity(me);
   292             return PEP_ILLEGAL_VALUE;
   293         }
   294 
   295         pEp_identity *partner = identity_dup(from);
   296         if (!partner) {
   297             free_identity(me);
   298             return PEP_OUT_OF_MEMORY;
   299         }
   300 
   301         assert(session->sync_state.comm_partner.sender_fpr);
   302         if (session->sync_state.comm_partner.sender_fpr) {
   303             free(partner->fpr);
   304             partner->fpr = strdup(session->sync_state.comm_partner.sender_fpr);
   305             assert(partner->fpr);
   306             if (!partner->fpr) {
   307                 free_identity(me);
   308                 free_identity(partner);
   309                 return PEP_OUT_OF_MEMORY;
   310             }
   311         }
   312 
   313         free(partner->user_id);
   314         partner->user_id = strdup("#NV");
   315         assert(partner->user_id);
   316         if (!partner->user_id) {
   317             free_identity(me);
   318             free_identity(partner);
   319             return PEP_OUT_OF_MEMORY;
   320         }
   321 
   322         status = session->notifyHandshake(me, partner, «$type»);
   323         if (status)
   324             return status;
   325     ||
   326     otherwise
   327     ||
   328         pEp_identity *me = new_identity(NULL, NULL, NULL, NULL);
   329         pEp_identity *partner = new_identity(NULL, NULL, NULL, NULL);
   330         assert(me && partner);
   331         if (!(me && partner)) {
   332             free_identity(me);
   333             free_identity(partner);
   334             return PEP_OUT_OF_MEMORY;
   335         }
   336 
   337         PEP_STATUS status = session->notifyHandshake(me, partner, «$type»);
   338         if (status)
   339             return status;
   340     ||
   341     }
   342 }
   343 
   344 action showSoleHandshake
   345     call "show_handshake" with "type" > SYNC_NOTIFY_INIT_FORM_GROUP
   346 
   347 action showJoinGroupHandshake
   348     call "show_handshake" with "type" > SYNC_NOTIFY_INIT_ADD_OUR_DEVICE
   349 
   350 action showGroupedHandshake
   351     call "show_handshake" with "type" > SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE
   352 
   353 action showDeviceAdded
   354     call "show_handshake" with "type" > SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED
   355 
   356 action showDeviceAccepted
   357     call "show_handshake" with "type" > SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED
   358 
   359 action showGroupCreated
   360     call "show_handshake" with "type" > SYNC_NOTIFY_ACCEPTED_GROUP_CREATED
   361 
   362 action showBeingSole
   363     call "show_handshake" with "type" > SYNC_NOTIFY_SOLE
   364 
   365 action showBeingInGroup
   366     call "show_handshake" with "type" > SYNC_NOTIFY_IN_GROUP
   367 
   368 timeout KeySync
   369     call "show_handshake" with "type" > SYNC_NOTIFY_TIMEOUT
   370 
   371 action prepareOwnKeys
   372 ||
   373     stringlist_t *own_keys;
   374     PEP_STATUS status = _own_keys_retrieve(session, &own_keys, PEP_idf_not_for_sync, true);
   375     if (status)
   376         return status;
   377 
   378     if (session->sync_state.own.keys)
   379         free_stringlist(session->sync_state.own.keys);
   380     session->sync_state.own.keys = own_keys;
   381 
   382     identity_list *il;
   383     status = _own_identities_retrieve(session, &il, PEP_idf_not_for_sync);
   384     if (status)
   385         return status;
   386 
   387     IdentityList_from_identity_list(il, &session->sync_state.keysync.ownIdentities);
   388     free_identity_list(il);
   389 ||
   390 
   391 action saveGroupKeys
   392 ||
   393     char *user_id = NULL;
   394     PEP_STATUS status = get_default_own_userid(session, &user_id);
   395     if (status)
   396         return status;
   397 
   398     identity_list *il = IdentityList_to_identity_list(&session->sync_state.keysync.ownIdentities, NULL);
   399     if (!il) {
   400         free(user_id);
   401         return PEP_OUT_OF_MEMORY;
   402     }
   403     status = set_all_userids_to_own(session, il);
   404     if (status != PEP_STATUS_OK) {
   405         free(user_id);
   406         return status;
   407     }
   408 
   409     // if own identities are not yet fetched from the database do this now
   410     if (!session->sync_state.own.identities) {
   411         identity_list *il;
   412         status = _own_identities_retrieve(session, &il, PEP_idf_not_for_sync);
   413         if (status) {
   414             free(user_id);
   415             return status;
   416         }
   417         session->sync_state.own.identities = il;
   418     }
   419 
   420     identity_list *oil = session->sync_state.own.identities;
   421 
   422     // FIXME: this should be a transaction and been rolled back completely on error
   423     for (identity_list *_il = il; _il && _il->ident; _il = _il->next) {
   424         bool found = false;
   425         status = _have_identity_in(oil, _il->ident, &found);
   426         if (status)
   427             break;
   428 
   429         if (!found) {
   430             _il->ident->me = true;
   431 
   432             status = set_identity(session, _il->ident);
   433             if (status)
   434                 break;
   435         }
   436     }
   437 
   438     free(user_id);
   439     free_identity_list(il);
   440 ||
   441 
   442 action ownKeysAreDefaultKeys
   443 ||
   444     PEP_STATUS status = PEP_STATUS_OK;
   445 
   446     // set flag for all keys; don't change anything else
   447     for (identity_list *il = session->sync_state.own.identities; il && il->ident ; il = il->next) {
   448         if (!(il->ident->flags & PEP_idf_not_for_sync)) {
   449             status = set_identity_flags(session, il->ident, PEP_idf_devicegroup);
   450             if (status)
   451                 return status;
   452         }
   453     }
   454 ||
   455 
   456 action backupOwnKeys
   457 ||
   458     if (session->sync_state.own.backup)
   459         free_stringlist(session->sync_state.own.backup);
   460 
   461     session->sync_state.own.backup = stringlist_dup(session->sync_state.own.keys);
   462     if (session->sync_state.own.backup == NULL)
   463         return PEP_OUT_OF_MEMORY;
   464 ||
   465 
   466 action prepareOwnKeysFromBackup
   467 ||
   468     if (session->sync_state.own.keys)
   469         free_stringlist(session->sync_state.own.keys);
   470 
   471     session->sync_state.own.keys = stringlist_dup(session->sync_state.own.backup);
   472     if (session->sync_state.own.keys == NULL)
   473         return PEP_OUT_OF_MEMORY;
   474 ||
   475 
   476 action receivedKeysAreDefaultKeys
   477 ||
   478     PEP_STATUS status = PEP_STATUS_OK;
   479     // set flag for all keys
   480     for (identity_list *il = session->sync_state.own.identities; il && il->ident ; il = il->next) {
   481         if (!(il->ident->flags & PEP_idf_not_for_sync)) {
   482 
   483             status = set_identity_flags(session, il->ident, PEP_idf_devicegroup);
   484             if (status)
   485                 return status;
   486         }
   487     }
   488 
   489     char *user_id = NULL;
   490     status = get_default_own_userid(session, &user_id);
   491     if (status)
   492         return status;
   493 
   494     identity_list *il = IdentityList_to_identity_list(&session->sync_state.keysync.ownIdentities, NULL);
   495     if (!il)
   496         return PEP_OUT_OF_MEMORY;
   497 
   498     status = set_all_userids_to_own(session, il);
   499     if (status != PEP_STATUS_OK) {
   500         free(user_id);
   501         return status;
   502     }
   503 
   504     for (identity_list *_il = il; _il && _il->ident ; _il = _il->next) {
   505         status = set_own_key(session, _il->ident, _il->ident->fpr);
   506         if (status != PEP_STATUS_OK && status != PEP_KEY_UNSUITABLE)
   507             break;
   508     }
   509 
   510     free_identity_list(il);
   511     free(user_id);
   512 
   513     if (status == PEP_KEY_UNSUITABLE)
   514         status = PEP_STATUS_OK;
   515 ||
   516 
   517 action useThisKey
   518 ||
   519     assert(session->sync_state.comm_partner.sender_fpr);
   520     if (!session->sync_state.comm_partner.sender_fpr)
   521         return PEP_ILLEGAL_VALUE;
   522 
   523     const char *fpr = session->sync_state.comm_partner.sender_fpr;
   524     OCTET_STRING_fromBuf(&session->sync_state.keysync.key, fpr, strlen(fpr));
   525 ||
   526 
   527 action storeThisKey
   528 ||
   529     assert(session->sync_state.keysync.key.size);
   530     if (!session->sync_state.keysync.key.size)
   531         return PEP_ILLEGAL_VALUE;
   532 
   533     char *fpr = strndup((const char *) session->sync_state.keysync.key.buf, session->sync_state.keysync.key.size);
   534     assert(fpr);
   535     if (!fpr)
   536         return PEP_OUT_OF_MEMORY;
   537 
   538     free(session->sync_state.comm_partner.sender_fpr);
   539     session->sync_state.comm_partner.sender_fpr = fpr;
   540 ||
   541 
   542 action trustThisKey
   543 ||
   544     assert(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr);
   545     if (!(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr))
   546         return PEP_ILLEGAL_VALUE;
   547 
   548     pEp_identity *ident = identity_dup(session->sync_state.transport.from);
   549     if (!ident)
   550         return PEP_OUT_OF_MEMORY;
   551     free(ident->fpr);
   552     ident->fpr = strdup(session->sync_state.comm_partner.sender_fpr);
   553     assert(ident->fpr);
   554     if (!ident->fpr) {
   555         free_identity(ident);
   556         return PEP_OUT_OF_MEMORY;
   557     }
   558 
   559     PEP_STATUS status = trust_own_key(session, ident);
   560     if (status) {
   561         free_identity(ident);
   562         return status;
   563     }
   564 
   565     OCTET_STRING_fromBuf(&session->sync_state.keysync.key, ident->fpr, strlen(ident->fpr));
   566     free_identity(ident);
   567 ||
   568 
   569 action untrustThisKey
   570 ||
   571     assert(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr);
   572     if (!(session->sync_state.transport.from && session->sync_state.comm_partner.sender_fpr))
   573         return PEP_ILLEGAL_VALUE;
   574 
   575     pEp_identity *ident = session->sync_state.transport.from;
   576     free(ident->fpr);
   577     ident->fpr = strdup(session->sync_state.comm_partner.sender_fpr);
   578     assert(ident->fpr);
   579     if (!ident->fpr)
   580         return PEP_OUT_OF_MEMORY;
   581 
   582     PEP_STATUS status = key_reset_trust(session, ident);
   583     if (status)
   584         return status;
   585 
   586     OCTET_STRING_fromBuf(&session->sync_state.keysync.key, "", 0);
   587 ||
   588 
   589 action tellWeAreGrouped
   590 ||
   591     session->sync_state.keysync.is_group = true;
   592 ||
   593 
   594 action tellWeAreNotGrouped
   595 ||
   596     session->sync_state.keysync.is_group = false;
   597 ||
   598 
   599 action disable
   600 ||
   601     disable_sync(session);
   602 ||
   603 
   604 action resetOwnGroupedKeys
   605 ||
   606     return key_reset_own_grouped_keys(session);
   607 ||
   608 
   609 action resetOwnKeysUngrouped
   610 ||
   611     return key_reset_all_own_keys(session);
   612 ||