Compare commits

...

15 Commits

@ -1,14 +1,12 @@
syntax: regexp
^asn\.1/.*\.(c|h)$
^asn\.1/libasn1\.a$
.*xcuserdata/
^build/
^local.conf
^test_home/
syntax: glob
asn.1/Makefile.am.*
asn.1/converter-example.mk
asn.1/libasn1.a
local.conf
build/
test_home/
asn.1/*.c
asn.1/*.h
xcuserdata/
*.orig
*.old
*.d

@ -20,7 +20,7 @@ libasn1.a: $(ALL_OBJECTS)
$(CC) $(CPPFLAGS) $(CFLAGS) $(OPTIMIZE) $(ASN1C_INC) -c $< -o $@
Sync.c: sync.asn1 keysync.asn1 pEp.asn1
$(ASN1C) -gen-PER -fincludes-quoted -fcompound-names -pdu=auto pEp.asn1 keysync.asn1 $<
$(ASN1C) -gen-PER -fincludes-quoted -fcompound-names -pdu=auto pEp.asn1 keysync.asn1 trustsync.asn1 $<
rm -f converter-sample.c
touch Sync.c

@ -89,7 +89,7 @@ libpEpEngine.a: $(ALL_OBJECTS)
clean:
rm -f *.d *.o *.a $(TARGET) *.dll *.so *.zip *.d.* *.def *~
rm -Rf $(TARGET).dSYM
rm -f KeySync_fsm.* Sync_actions.c Sync_event.* Sync_func.* Sync_impl.* sync_codec.* distribution_codec.*
rm -f KeySync_fsm.* TrustSync_fsm.* Sync_actions.c Sync_event.* Sync_func.* Sync_impl.* sync_codec.* distribution_codec.*
# CAVEAT:
# install_headers is needed for building pEp MIME

@ -368,6 +368,8 @@ action showBeingInGroup
timeout KeySync
call "show_handshake" with "type" > SYNC_NOTIFY_TIMEOUT
timeout TrustSync;
action prepareOwnKeys
||
stringlist_t *own_keys;

@ -1,6 +1,6 @@
// This file is under BSD License 2.0
// KeyReset protocol for p≡p
// Distribution protocol for p≡p
// Copyright (c) 2019, p≡p foundation
// Written by Volker Birk

@ -9,7 +9,7 @@ def "func:distinctName" {
when "not($nodes)"
result "/..";
otherwise
result "$nodes[1] | func:distinctName($nodes[position() > 1])[@name != $nodes[1]/@name]";
result "$nodes[1] | func:distinctName($nodes[@name != $nodes[1]/@name])";
}
}
@ -19,7 +19,7 @@ def "func:distinctType" {
when "not($nodes)"
result "/..";
otherwise
result "$nodes[1] | func:distinctType($nodes[position() > 1])[@type != $nodes[1]/@type]";
result "$nodes[1] | func:distinctType($nodes[@type != $nodes[1]/@type]";
}
}

@ -99,6 +99,7 @@ tstylesheet {
template "condition" | #error condition «@name» not implemented\n
template "action" | #error action «@name» not implemented\n
template "fsm" | #error timeout handler for «@name» not implemented\n
function "condition" {
param "content";

@ -45,7 +45,7 @@ tstylesheet {
BEGIN
`` for "fsm" | IMPORTS «@name» FROM «yml:ucase(@name)»;
IMPORTS `apply "fsm", mode=imports`;
«@name» ::= CHOICE {
`` for "fsm" |> «yml:lcase(@name)» [APPLICATION «@id»] «@name»`if "position()!=last()" > , `
@ -56,6 +56,11 @@ tstylesheet {
||
}
template "fsm", mode=imports {
> «@name» FROM «yml:ucase(@name)»
if "position()!=last()" >
}
template "fsm", mode=individual
document "generated/{yml:lcase(@name)}.asn1", "text" {

@ -487,67 +487,91 @@ tstylesheet {
}
}
switch (message_type) {
// these messages are being broadcasted
`` for "fsm/message[@type='broadcast']" |>> case «../@name»_PR_«yml:mixedCase(@name)»:
status = _own_identities_retrieve(session, &channels, PEP_idf_not_for_«yml:lcase(@name)»);
if (status)
goto the_end;
switch (fsm) {
||
for "fsm" {
||
case Sync_PR_«yml:lcase(@name)»:
switch (message_type) {
`` for "message[@type='broadcast']" |>>>> case «../@name»_PR_«yml:mixedCase(@name)»:
||
if "message[@type='broadcast']"
||
// these messages are being broadcasted
status = _own_identities_retrieve(session, &channels, PEP_idf_not_for_«yml:lcase(../@name)»);
if (status)
goto the_end;
if (!(channels && channels->ident)) {
// status = PEP_«yml:ucase(@name)»_NO_CHANNEL;
// we don't check for having a channel, because if
// this is initial setup before having an own
// identity we're fine
goto the_end;
}
break;
if (!(channels && channels->ident)) {
// status = PEP_«yml:ucase(../@name)»_NO_CHANNEL;
// we don't check for having a channel, because if
// this is initial setup before having an own
// identity we're fine
goto the_end;
}
break;
// these go anycast; previously used address is sticky (unicast)
`` for "fsm/message[@type='anycast']" |>> case «../@name»_PR_«yml:mixedCase(@name)»:
// if we have a comm_partner fixed send it there
if (session->«yml:lcase(@name)»_state.comm_partner.identity) {
pEp_identity *channel = identity_dup(session->«yml:lcase(@name)»_state.comm_partner.identity);
if (!channel) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
||
||
`` for "message[@type='anycast']" |>>>> case «../@name»_PR_«yml:mixedCase(@name)»:
||
if "message[@type='anycast']"
||
// these go anycast; previously used address is sticky (unicast)
// if we have a comm_partner fixed send it there
if (session->«yml:lcase(../@name)»_state.comm_partner.identity) {
pEp_identity *channel = identity_dup(session->«yml:lcase(../@name)»_state.comm_partner.identity);
if (!channel) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
channels = new_identity_list(channel);
if (!channels) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
}
// if we can reply just do
else if (session->«yml:lcase(@name)»_state.transport.from) {
pEp_identity *channel = identity_dup(session->«yml:lcase(@name)»_state.transport.from);
if (!channel) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
channels = new_identity_list(channel);
if (!channels) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
}
// if we can reply just do
else if (session->«yml:lcase(../@name)»_state.transport.from) {
pEp_identity *channel = identity_dup(session->«yml:lcase(../@name)»_state.transport.from);
if (!channel) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
channels = new_identity_list(channel);
if (!channels) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
}
// real anycast, send it to the first matching
else {
status = _own_identities_retrieve(session, &channels, PEP_idf_not_for_«yml:lcase(@name)»);
if (status)
goto the_end;
if (!channels)
goto the_end;
channels = new_identity_list(channel);
if (!channels) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
}
// real anycast, send it to the first matching
else {
status = _own_identities_retrieve(session, &channels, PEP_idf_not_for_«yml:lcase(../@name)»);
if (status)
goto the_end;
if (!channels)
goto the_end;
if (channels->next) {
free_identity_list(channels->next);
channels->next = NULL;
}
}
break;
if (channels->next) {
free_identity_list(channels->next);
channels->next = NULL;
}
||
||
default:
status = PEP_«yml:ucase(../@name)»_ILLEGAL_MESSAGE;
goto the_end;
}
break;
||
}
||
default:
status = PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
goto the_end;
@ -565,380 +589,410 @@ tstylesheet {
}
memcpy(_data, data, size);
switch (message_type) {
`` for "fsm/message[@security='unencrypted' and ../@name!='KeySync']" | #error unencrypted only allowed with KeySync
`` for "fsm/message[@security='unencrypted' and ../@name='KeySync']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
li->ident->fpr,
&_m
);
if (status) {
free(_data);
goto the_end;
}
attach_own_key(session, _m);
decorate_message(_m, PEP_rating_undefined, NULL, true, true);
m = _m;
break;
`` for "fsm/message[@security='untrusted' and ../@name!='KeySync']" | #error untrusted only allowed with KeySync
`` for "fsm/message[@security='untrusted' and ../@name='KeySync']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
// add fpr of key of comm partner
assert(session->«yml:lcase(@name)»_state.transport.sender_fpr);
if (!session->«yml:lcase(@name)»_state.transport.sender_fpr) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
if (fsm == Sync_PR_keysync) {
switch (message_type) {
`` for "fsm/message[@security='unencrypted' and ../@name!='KeySync']" | #error unencrypted only allowed with KeySync
`` for "fsm/message[@security='unencrypted' and ../@name='KeySync']" |>>>> case «../@name»_PR_«yml:mixedCase(@name)»:
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
li->ident->fpr,
&_m
);
if (status) {
free(_data);
goto the_end;
}
attach_own_key(session, _m);
decorate_message(_m, PEP_rating_undefined, NULL, true, true);
m = _m;
break;
extra = new_stringlist(session->«yml:lcase(@name)»_state.transport.sender_fpr);
if (!extra) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
NULL,
&_m
);
if (status) {
free(_data);
goto the_end;
}
`` for "fsm/message[@security='untrusted' and ../@name!='KeySync']" | #error untrusted only allowed with KeySync
`` for "fsm/message[@security='untrusted' and ../@name='KeySync']" |>>>> case «../@name»_PR_«yml:mixedCase(@name)»:
// add fpr of key of comm partner
status = encrypt_message(session, _m, extra, &m, PEP_enc_PEP, 0);
if (status) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
add_opt_field(m, "pEp-auto-consume", "yes");
m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
free_message(_m);
break;
// attach own keys for new member
`` for "fsm/message[@security='attach_own_keys_for_new_member']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
// check if we had a former negotiation
transaction = false;
for (int i=0; i < session->«yml:lcase(@name)»_state.own.negotiation.size; i++) {
if (session->«yml:lcase(@name)»_state.own.negotiation.buf[i]) {
transaction = true;
break;
}
}
// if it is a former negotiation check if the key
// is fully trusted and the sender key of this
// transaction; if so add the sender key to extra
// keys allowing this new partner to read the
// secret keys
if (transaction) {
assert(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr &&
session->«yml:lcase(@name)»_state.transport.from &&
session->«yml:lcase(@name)»_state.transport.from->user_id);
if (!(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr &&
session->«yml:lcase(@name)»_state.transport.from &&
session->«yml:lcase(@name)»_state.transport.from->user_id))
{
assert(session->«yml:lcase(@name)»_state.transport.sender_fpr);
if (!session->«yml:lcase(@name)»_state.transport.sender_fpr) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
// test if this is a green channel
pEp_identity *ident = new_identity(NULL,
session->«yml:lcase(@name)»_state.comm_partner.sender_fpr,
session->«yml:lcase(@name)»_state.transport.from->user_id,
NULL
);
if (!ident) {
extra = new_stringlist(session->«yml:lcase(@name)»_state.transport.sender_fpr);
if (!extra) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
status = get_trust(session, ident);
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
NULL,
&_m
);
if (status) {
free_identity(ident);
free(_data);
goto the_end;
}
assert(ident->comm_type == PEP_ct_pEp); // we don't deliver otherwise
if (ident->comm_type != PEP_ct_pEp) {
free_identity(ident);
status = encrypt_message(session, _m, extra, &m, PEP_enc_PEP, 0);
if (status) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
free_identity(ident);
add_opt_field(m, "pEp-auto-consume", "yes");
m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
free_message(_m);
break;
// test if we accepted this as own key already
// attach own keys for new member
`` for "fsm/message[@security='attach_own_keys_for_new_member' and ../@name!='KeySync']" | #error attach_own_keys_for_new_member only allowed with KeySync
`` for "fsm/message[@security='attach_own_keys_for_new_member']" |>>>> case «../@name»_PR_«yml:mixedCase(@name)»:
// check if we had a former negotiation
bool is_own_key = false;
status = own_key_is_listed(session,
session->«yml:lcase(@name)»_state.comm_partner.sender_fpr,
&is_own_key);
assert(!status);
if (status)
goto the_end;
assert(is_own_key);
if (!is_own_key) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
transaction = false;
for (int i=0; i < session->«yml:lcase(@name)»_state.own.negotiation.size; i++) {
if (session->«yml:lcase(@name)»_state.own.negotiation.buf[i]) {
transaction = true;
break;
}
}
// if it is a former negotiation check if the key
// is fully trusted and the sender key of this
// transaction; if so add the sender key to extra
// keys allowing this new partner to read the
// secret keys
if (transaction) {
assert(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr &&
session->«yml:lcase(@name)»_state.transport.from &&
session->«yml:lcase(@name)»_state.transport.from->user_id);
if (!(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr &&
session->«yml:lcase(@name)»_state.transport.from &&
session->«yml:lcase(@name)»_state.transport.from->user_id))
{
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
// test if this is a green channel
pEp_identity *ident = new_identity(NULL,
session->«yml:lcase(@name)»_state.comm_partner.sender_fpr,
session->«yml:lcase(@name)»_state.transport.from->user_id,
NULL
);
if (!ident) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
status = get_trust(session, ident);
if (status) {
free_identity(ident);
goto the_end;
}
assert(ident->comm_type == PEP_ct_pEp); // we don't deliver otherwise
if (ident->comm_type != PEP_ct_pEp) {
free_identity(ident);
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
free_identity(ident);
// if so add key of comm partner to extra keys
// test if we accepted this as own key already
extra = new_stringlist(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr);
if (!extra) {
status = PEP_OUT_OF_MEMORY;
bool is_own_key = false;
status = own_key_is_listed(session,
session->«yml:lcase(@name)»_state.comm_partner.sender_fpr,
&is_own_key);
assert(!status);
if (status)
goto the_end;
assert(is_own_key);
if (!is_own_key) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
// if so add key of comm partner to extra keys
extra = new_stringlist(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr);
if (!extra) {
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
}
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
NULL,
&_m
);
if (status) {
free(_data);
goto the_end;
}
}
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
NULL,
&_m
);
if (status) {
free(_data);
goto the_end;
}
// export secret keys into memory
// export secret keys into memory
key_data = strdup("");
assert(key_data);
if (!key_data) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data_size = 1; // N.B. If null termination makes us happy for debugging, fine, but
// if we include this in the size, libetpan will null terminate and
// go bananas. We can't have a NUL in the mime text.
for (stringlist_t *sl = session->«yml:lcase(@name)»_state.own.keys;
sl && sl->value ; sl = sl->next)
{
char *_key_data = NULL;
size_t _size = 0;
status = export_secret_key(session, sl->value, &_key_data, &_size);
if (status && status != PEP_KEY_NOT_FOUND) {
key_data = strdup("");
assert(key_data);
if (!key_data) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data_size = 1; // N.B. If null termination makes us happy for debugging, fine, but
// if we include this in the size, libetpan will null terminate and
// go bananas. We can't have a NUL in the mime text.
if (status != PEP_KEY_NOT_FOUND) {
assert(_key_data && _size);
char *n = realloc(key_data, key_data_size + _size);
if (!n) {
for (stringlist_t *sl = session->«yml:lcase(@name)»_state.own.keys;
sl && sl->value ; sl = sl->next)
{
char *_key_data = NULL;
size_t _size = 0;
status = export_secret_key(session, sl->value, &_key_data, &_size);
if (status && status != PEP_KEY_NOT_FOUND) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = n;
key_data_size += _size;
strlcat(key_data, _key_data, key_data_size);
free(_key_data);
_key_data = NULL;
}
status = export_key(session, sl->value, &_key_data, &_size);
if (status && status != PEP_KEY_NOT_FOUND) {
free(_data);
free_message(_m);
goto the_end;
}
if (status != PEP_KEY_NOT_FOUND) {
assert(_key_data && _size);
char *n = realloc(key_data, key_data_size + _size);
if (!n) {
if (status != PEP_KEY_NOT_FOUND) {
assert(_key_data && _size);
char *n = realloc(key_data, key_data_size + _size);
if (!n) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = n;
key_data_size += _size;
strlcat(key_data, _key_data, key_data_size);
free(_key_data);
_key_data = NULL;
}
status = export_key(session, sl->value, &_key_data, &_size);
if (status && status != PEP_KEY_NOT_FOUND) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = n;
key_data_size += _size;
strlcat(key_data, _key_data, key_data_size);
free(_key_data);
_key_data = NULL;
if (status != PEP_KEY_NOT_FOUND) {
assert(_key_data && _size);
char *n = realloc(key_data, key_data_size + _size);
if (!n) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = n;
key_data_size += _size;
strlcat(key_data, _key_data, key_data_size);
free(_key_data);
_key_data = NULL;
}
}
}
// add secret key data as attachment
// add secret key data as attachment
// N.B. The -1 makes sure we do NOT add a NUL into the mime stream!
bloblist_t *bl = bloblist_add(_m->attachments, key_data, key_data_size - 1,
"application/octet-stream", "file://own.key");
if (!bl) {
free(_data);
// N.B. The -1 makes sure we do NOT add a NUL into the mime stream!
bloblist_t *bl = bloblist_add(_m->attachments, key_data, key_data_size - 1,
"application/octet-stream", "file://own.key");
if (!bl) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = NULL;
status = encrypt_message(session, _m, extra, &m, PEP_enc_PEP, 0);
if (status) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
add_opt_field(m, "pEp-auto-consume", "yes");
m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = NULL;
break;
status = encrypt_message(session, _m, extra, &m, PEP_enc_PEP, 0);
if (status) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
add_opt_field(m, "pEp-auto-consume", "yes");
m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
free_message(_m);
break;
// attach own keys for group
`` for "fsm/message[@security='attach_own_keys_for_group']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
NULL,
&_m
);
if (status) {
free(_data);
goto the_end;
}
// attach own keys for group
`` for "fsm/message[@security='attach_own_keys_for_group' and ../@name!='KeySync']" | #error attach_own_keys_for_group only allowed with KeySync
`` for "fsm/message[@security='attach_own_keys_for_group']" |>>>> case «../@name»_PR_«yml:mixedCase(@name)»:
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
NULL,
&_m
);
if (status) {
free(_data);
goto the_end;
}
// export secret keys into memory
// export secret keys into memory
key_data = strdup("");
assert(key_data);
if (!key_data) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data_size = 1; // N.B. If null termination makes us happy for debugging, fine, but
// if we include this in the size, libetpan will null terminate and
// go bananas. We can't have a NUL in the mime text.
for (stringlist_t *sl = session->«yml:lcase(@name)»_state.own.keys;
sl && sl->value ; sl = sl->next)
{
char *_key_data = NULL;
size_t _size = 0;
status = export_secret_key(session, sl->value, &_key_data, &_size);
if (status && status != PEP_KEY_NOT_FOUND) {
key_data = strdup("");
assert(key_data);
if (!key_data) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data_size = 1; // N.B. If null termination makes us happy for debugging, fine, but
// if we include this in the size, libetpan will null terminate and
// go bananas. We can't have a NUL in the mime text.
if (status != PEP_KEY_NOT_FOUND) {
assert(_key_data && _size);
char *n = realloc(key_data, key_data_size + _size);
if (!n) {
for (stringlist_t *sl = session->«yml:lcase(@name)»_state.own.keys;
sl && sl->value ; sl = sl->next)
{
char *_key_data = NULL;
size_t _size = 0;
status = export_secret_key(session, sl->value, &_key_data, &_size);
if (status && status != PEP_KEY_NOT_FOUND) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = n;
key_data_size += _size;
strlcat(key_data, _key_data, key_data_size);
free(_key_data);
_key_data = NULL;
}
status = export_key(session, sl->value, &_key_data, &_size);
if (status && status != PEP_KEY_NOT_FOUND) {
free(_data);
free_message(_m);
goto the_end;
}
if (status != PEP_KEY_NOT_FOUND) {
assert(_key_data && _size);
char *n = realloc(key_data, key_data_size + _size);
if (!n) {
if (status != PEP_KEY_NOT_FOUND) {
assert(_key_data && _size);
char *n = realloc(key_data, key_data_size + _size);
if (!n) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = n;
key_data_size += _size;
strlcat(key_data, _key_data, key_data_size);
free(_key_data);
_key_data = NULL;
}
status = export_key(session, sl->value, &_key_data, &_size);
if (status && status != PEP_KEY_NOT_FOUND) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = n;
key_data_size += _size;
strlcat(key_data, _key_data, key_data_size);
free(_key_data);
_key_data = NULL;
if (status != PEP_KEY_NOT_FOUND) {
assert(_key_data && _size);
char *n = realloc(key_data, key_data_size + _size);
if (!n) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = n;
key_data_size += _size;
strlcat(key_data, _key_data, key_data_size);
free(_key_data);
_key_data = NULL;
}
}
}
// add secret key data as attachment
// add secret key data as attachment
// N.B. The -1 makes sure we do NOT add a NUL into the mime stream!
bl = bloblist_add(_m->attachments, key_data, key_data_size - 1,
"application/octet-stream", "file://own.key");
if (!bl) {
free(_data);
// N.B. The -1 makes sure we do NOT add a NUL into the mime stream!
bl = bloblist_add(_m->attachments, key_data, key_data_size - 1,
"application/octet-stream", "file://own.key");
if (!bl) {
free(_data);
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = NULL;
// we do not support extra keys here and will only encrypt to ourselves
status = encrypt_message(session, _m, NULL, &m, PEP_enc_PEP, 0);
if (status) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
add_opt_field(m, "pEp-auto-consume", "yes");
m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
free_message(_m);
status = PEP_OUT_OF_MEMORY;
goto the_end;
}
key_data = NULL;
break;
// we do not support extra keys here and will only encrypt to ourselves
status = encrypt_message(session, _m, NULL, &m, PEP_enc_PEP, 0);
if (status) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
add_opt_field(m, "pEp-auto-consume", "yes");
m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
free_message(_m);
break;
default: // security=trusted only
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
NULL,
&_m
);
if (status) {
free(_data);
goto the_end;
}
default: // security=trusted only
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
NULL,
&_m
);
if (status) {
free(_data);
goto the_end;
}
status = encrypt_message(session, _m, NULL, &m, PEP_enc_PEP, 0);
if (status) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
add_opt_field(m, "pEp-auto-consume", "yes");
m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
free_message(_m);
status = encrypt_message(session, _m, NULL, &m, PEP_enc_PEP, 0);
if (status) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
add_opt_field(m, "pEp-auto-consume", "yes");
m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
free_message(_m);
}
}
else {
// for other protocols than KeySync security=trusted only
status = base_prepare_message(
session,
li->ident,
li->ident,
BASE_SYNC,
_data,
size,
NULL,
&_m
);
if (status) {
free(_data);
goto the_end;
}
status = encrypt_message(session, _m, NULL, &m, PEP_enc_PEP, 0);
if (status) {
status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
goto the_end;
}
add_opt_field(m, "pEp-auto-consume", "yes");
m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
free_message(_m);
}
status = session->messageToSend(m);
@ -1112,7 +1166,7 @@ tstylesheet {
case «../@name»_PR_«yml:lcase(@name)»: {
int state = session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state;
switch (state) {
`` for "state[@name!='InitState' and @timeout != 'off']" |>>> case «@name»:
`` for "state[@name!='InitState' and @timeout != 'off']" |>>> case «../@name»_state_«@name»:
if (_«@name»_timeout(state)) {
session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state = Init;
event = Init;
@ -1253,8 +1307,8 @@ tstylesheet {
«@name»_state_None = None,
«@name»_state_Init = Init,
||
for "func:distinctName(state[not(@name='InitState')])"
|> «@name»`if "position()!=last()" > , `
for "state[not(@name='InitState')]"
|> «../@name»_state_«@name»`if "position()!=last()" > , `
||
} «@name»_state;
@ -1325,9 +1379,9 @@ tstylesheet {
case Init:
return "InitState";
||
for "func:distinctName(state[not(@name='InitState')])" {
|>> case «@name»:
|>>> return "«@name»";
for "state[not(@name='InitState')]" {
|>> case «../@name»_state_«@name»:
|>>> return "«../@name»_state_«@name»";
}
||
default:
@ -1420,7 +1474,7 @@ tstylesheet {
template "state", mode=fsm {
choose {
when "@name='InitState'" | case «../@name»_state_Init:
otherwise | case «@name»:
otherwise | case «../@name»_state_«@name»:
}
||
«../@name»_SERVICE_LOG("in state", "«@name»");
@ -1474,9 +1528,14 @@ tstylesheet {
const "fsm", "ancestor::fsm";
||
«$fsm/@name»_SERVICE_LOG("transition to state", "«@target»");
return «@target»;
«$fsm/@name»_SERVICE_LOG("transition to state", "«$fsm/@name»_state_«@target»");
||
choose {
when "@target='InitState' or @target='End'"
| return «@target»;
otherwise
| return «$fsm/@name»_state_«@target»;
}
}
template "send" {

@ -673,4 +673,55 @@ protocol Sync 1 {
message SynchronizeGroupKeys 21, ratelimit=60 {
}
}
fsm TrustSync 2, threshold=300 {
version 1, 0;
state InitState {
on Init {
if deviceGrouped
go Grouped;
go Sole;
}
}
// recheck for being grouped regulary
state Sole timeout=on;
// leave device group is shutting down sync so no check needed
state Grouped timeout=off {
// UpdateTrust is an event being triggered:
// - when new Key material arrives
// - when a default key was set for a Communication Partner
// - when the Trust status is chaning for a Communication Partner
on UpdateTrust {
send TrustUpdate;
}
on TrustUpdate {
if sameChallenge {
// we'll ignore our own TrustUpdates
}
else {
}
}
}