Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:Communication Layer #50

Open
wants to merge 46 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
49daaee
Added key to crypto predicates along the usages
fabian-hk Dec 5, 2024
134c6a6
Proof optimization
fabian-hk Dec 6, 2024
b137b35
Improve proofs and code cleanup
fabian-hk Dec 6, 2024
17b31e3
Make key in crypto predicates not dependent on the key usage
fabian-hk Dec 20, 2024
88cf697
Simplified Sign bytes_invariant
fabian-hk Dec 20, 2024
a277cb6
First draft of a confidential send function
fabian-hk Jul 20, 2024
38f9cdf
Confidential send and receive function and example protocol
fabian-hk Jul 29, 2024
e11ad00
Authenticated send and receive function; first draft of events that c…
fabian-hk Aug 5, 2024
13188db
Improved events that can be extended by a higher layer
fabian-hk Aug 7, 2024
106c001
Cleanup code; documentation
fabian-hk Aug 9, 2024
03eddb2
Fixed issue with initialization method for debug run; Code cleanup
fabian-hk Aug 10, 2024
31f0379
Introduced comm_higher_layer_event_preds_later function to improve co…
fabian-hk Aug 19, 2024
93f1747
First draft of confidential and authenticated send and receive functions
fabian-hk Aug 20, 2024
0719149
Updated version of the confidential and authenticated send and receiv…
fabian-hk Oct 24, 2024
8c1efed
Cleanup decrypt_message_proof post condition and signature predicate
fabian-hk Oct 28, 2024
85a711e
Updated communication layer to be compatible with label changes
fabian-hk Oct 30, 2024
eadbb82
Conf-auth proof with pk_enc extract function
fabian-hk Nov 7, 2024
8faf365
Cleanup
fabian-hk Nov 11, 2024
c8282c1
Cleanup; Separate file for core extension
fabian-hk Nov 12, 2024
7d9e3a8
Define later for comm_higher_layer_event_preds
fabian-hk Nov 14, 2024
96f2e30
First draft of request-response functions
fabian-hk Nov 20, 2024
f8644a4
Request-response functions with state on the server side
fabian-hk Nov 27, 2024
b605ff9
Use comm_meta_data for the request-response functions; Added last pro…
fabian-hk Nov 29, 2024
261d091
Clean up states and events
fabian-hk Dec 5, 2024
57a3500
Removed id and client from request response pairs
fabian-hk Dec 5, 2024
3271ca2
Updated com layer README
fabian-hk Dec 5, 2024
cfe081c
Tried to replace reveal by showing the property with pkenc_input but …
fabian-hk Nov 5, 2024
db61f53
Conf auth proof without reveal but with pk_receiver in message
fabian-hk Nov 8, 2024
5167191
Only encrypt payload
fabian-hk Nov 10, 2024
94ac9aa
Cleanup
fabian-hk Nov 10, 2024
4f9becd
Sign predicate cleanup
fabian-hk Dec 6, 2024
18f4c4f
Fixed issues after rebase on feature/add-key-to-crypto-preds
fabian-hk Dec 10, 2024
a2f4d14
Automatically serialize and parse messages
fabian-hk Dec 16, 2024
7492439
Cleanup
fabian-hk Dec 16, 2024
28e6207
Added SMTPats to request response lemmas
fabian-hk Dec 17, 2024
5033826
Changed post condition of receive_request_proof
fabian-hk Dec 18, 2024
11e0d2a
Removed communication_keys_sess_ids from send response and receive re…
fabian-hk Dec 20, 2024
23b45cb
Add function to generate a communication layer response nonce with an…
fabian-hk Jan 8, 2025
b625d4a
Add trace printing functions; Cleanup
fabian-hk Jan 9, 2025
a3539be
Encapsulate all com messages in com_message_t type. This is needed fo…
fabian-hk Jan 10, 2025
8d4f779
Improve printing of communication messages
fabian-hk Jan 22, 2025
7deb02c
Feedback
fabian-hk Jan 22, 2025
3d927a0
Feedback
fabian-hk Jan 28, 2025
7499ea7
Using False as default in event predicates extension by higher layer;…
fabian-hk Jan 30, 2025
40ba5f5
Update URL to communication layer examples
fabian-hk Jan 30, 2025
14504c8
Adjust request/confidential message postconditions (#101)
qaphla Feb 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 18 additions & 22 deletions src/lib/communication/DY.Lib.Communication.Core.Invariants.fst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open DY.Lib.Crypto.AEAD.Split
open DY.Lib.Event.Typed
open DY.Lib.State.PrivateKeys
open DY.Lib.State.Tagged
open DY.Lib.Comparse.DYUtils

open DY.Lib.Communication.Data
open DY.Lib.Communication.Core
Expand Down Expand Up @@ -128,34 +129,29 @@ let default_comm_higher_layer_event_preds (a:Type) {| parseable_serializeable by
}

#push-options "--ifuel 1 --fuel 0"
let event_predicate_communication_layer
let event_predicate_communication_layer
{|cinvs:crypto_invariants|}
(#a:Type) {| parseable_serializeable bytes a |}
(higher_layer_preds:comm_higher_layer_event_preds a) :
(higher_layer_preds:comm_higher_layer_event_preds a) :
event_predicate communication_event =
fun tr prin e ->
(match e with
| CommConfSendMsg sender receiver payload -> (
is_knowable_by (comm_label sender receiver) tr payload /\
(match parse a payload with
| None -> False
| Some payload_p -> higher_layer_preds.send_conf tr sender receiver payload_p
)
parse_and_pred (higher_layer_preds.send_conf tr sender receiver) payload
)
| CommConfReceiveMsg receiver payload -> (
exists sender.
(
event_triggered tr sender (CommConfSendMsg sender receiver payload) \/
is_publishable tr payload
)
Some? (parse a payload) /\
(
(exists sender. event_triggered tr sender (CommConfSendMsg sender receiver payload)) \/
is_publishable tr payload
)
)
| CommAuthSendMsg sender payload -> (
(match parse a payload with
| None -> False
| Some payload_p -> higher_layer_preds.send_auth tr sender payload_p
)
parse_and_pred (higher_layer_preds.send_auth tr sender) payload
)
| CommAuthReceiveMsg sender receiver payload -> (
Some? (parse a payload) /\
is_publishable tr payload /\
(
event_triggered tr sender (CommAuthSendMsg sender payload) \/
Expand All @@ -164,10 +160,7 @@ let event_predicate_communication_layer
)
| CommConfAuthSendMsg sender receiver payload -> (
is_knowable_by (comm_label sender receiver) tr payload /\
(match parse a payload with
| None -> False
| Some payload_p -> higher_layer_preds.send_conf_auth tr sender receiver payload_p
)
parse_and_pred (higher_layer_preds.send_conf_auth tr sender receiver) payload
)
| CommConfAuthReceiveMsg sender receiver payload -> (
// We can only show the following about the decrypted ciphertext (payload):
Expand All @@ -180,13 +173,16 @@ let event_predicate_communication_layer
// 2. The corrupted sender takes a ciphertext from an honest principal.
// Since the crypto predicates apply to this ciphertext, the
// decrypted payload flows to the receiver and some unknown sender'.
event_triggered tr sender (CommConfAuthSendMsg sender receiver payload) \/
is_corrupt tr (long_term_key_label sender)
Some? (parse a payload) /\
(
event_triggered tr sender (CommConfAuthSendMsg sender receiver payload) \/
is_corrupt tr (long_term_key_label sender)
)
)
)
#pop-options

val event_predicate_communication_layer_and_tag:
val event_predicate_communication_layer_and_tag:
{|cinvs:crypto_invariants|} ->
#a:Type -> {| parseable_serializeable bytes a |} ->
comm_higher_layer_event_preds a ->
Expand Down
22 changes: 4 additions & 18 deletions src/lib/communication/DY.Lib.Communication.Core.Lemmas.fst
Original file line number Diff line number Diff line change
Expand Up @@ -123,32 +123,18 @@ val receive_confidential_proof:
receiver:principal -> msg_id:timestamp ->
Lemma
(requires
trace_invariant tr /\
trace_invariant tr /\
has_private_keys_invariant /\
has_communication_layer_crypto_predicates /\
has_communication_layer_event_predicates higher_layer_preds
)
(ensures (
match receive_confidential #a comm_keys_ids receiver msg_id tr with
| (None, tr_out) -> trace_invariant tr_out
| (Some payload, tr_out) -> (
| (Some payload, tr_out) ->
trace_invariant tr_out /\
(
(exists sender.
is_well_formed a (is_knowable_by (comm_label sender receiver) tr) payload /\
// We explicitly do not use `event_triggered tr receiver
// (CommConfReceiveMsg receiver (serialize a payload))` as a
// post-condition here. The reason for the following form of the
// post-condition is that it allows us on the higher layer to assert a
// statement `b` contained in the `higher_layer_preds` that depends on
// some field `field1` of the payload in the following way: `b
// payload.field1 \/ is_publishable tr payload.field1`.
event_triggered tr sender (CommConfSendMsg sender receiver (serialize a payload))
) \/ (
is_well_formed a (is_publishable tr) payload
)
)
)
event_triggered tr_out receiver (CommConfReceiveMsg receiver (serialize a payload)) /\
is_well_formed a (is_knowable_by (principal_label receiver) tr) payload
))
let receive_confidential_proof #invs #a tr higher_layer_preds comm_keys_ids receiver msg_id =
match receive_confidential #a comm_keys_ids receiver msg_id tr with
Expand Down
47 changes: 47 additions & 0 deletions src/lib/communication/DY.Lib.Communication.Core.Properties.fst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open DY.Lib.Event.Typed
open DY.Lib.State.PKI
open DY.Lib.State.PrivateKeys
open DY.Lib.State.Typed
open DY.Lib.Comparse.DYUtils

open DY.Lib.Communication.Core
open DY.Lib.Communication.Core.Invariants
Expand All @@ -18,6 +19,52 @@ open DY.Lib.Communication.Core.Lemmas
/// This module contains security properties that can be proven from the
/// communication layer guarantees.

(*** Confidential Messages Properties ***)

val conf_message_secrecy:
{|protocol_invariants|} ->
#a:Type -> {| parseable_serializeable bytes a |} ->
tr:trace -> i:timestamp ->
higher_layer_preds:comm_higher_layer_event_preds a ->
receiver:principal ->
payload:bytes ->
Lemma
(requires
trace_invariant tr /\
has_communication_layer_event_predicates higher_layer_preds /\
event_triggered_at tr i receiver (CommConfReceiveMsg receiver payload)
)
(ensures
is_knowable_by (principal_label receiver) (prefix tr i) payload /\

parse_and_pred (fun payload_parsed ->
(exists sender. higher_layer_preds.send_conf (prefix tr i) sender receiver payload_parsed) \/
is_well_formed a (is_publishable (prefix tr i)) payload_parsed
) payload
)
let conf_message_secrecy #invs #a tr i higher_layer_preds receiver payload =
let send_event sender = CommConfSendMsg sender receiver payload in
let tr_i = prefix tr i in
eliminate (exists sender. event_triggered tr_i sender (send_event sender)) \/
is_publishable tr_i payload
returns
is_knowable_by (principal_label receiver) tr_i payload /\
parse_and_pred (fun payload_parsed ->
(exists sender. higher_layer_preds.send_conf (prefix tr i) sender receiver payload_parsed) \/
is_well_formed a (is_publishable (prefix tr i)) payload_parsed
) payload
with _. eliminate exists sender. event_triggered tr_i sender (send_event sender)
returns _
with _. (
let j = find_event_triggered_at_timestamp tr sender (send_event sender) in
find_event_triggered_at_timestamp_later tr_i tr sender (send_event sender);

serialize_parse_inv_lemma a payload;
higher_layer_preds.send_conf_later (prefix tr j) tr_i sender receiver (Some?.v (parse a payload))
)
and _. parse_wf_lemma a (is_publishable (prefix tr i)) payload


(*** Authenticated Messages Properties ***)

val sender_authentication:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ open DY.Lib.Event.Typed
open DY.Lib.State.PrivateKeys
open DY.Lib.State.Tagged
open DY.Lib.State.Typed
open DY.Lib.Comparse.DYUtils

open DY.Lib.Communication.Data
open DY.Lib.Communication.Core
Expand Down Expand Up @@ -70,10 +71,7 @@ let state_predicates_communication_layer {|crypto_invariants|}: local_state_pred
let server = prin in
is_knowable_by (principal_label server) tr key /\
is_knowable_by (get_label tr key) tr request /\
(
key `has_usage tr` (AeadKey comm_layer_aead_tag empty) \/
is_publishable tr key
)
key `has_usage tr` (AeadKey comm_layer_aead_tag empty)
)
| ClientReceiveResponse {server; response; key} -> (
let client = prin in
Expand Down Expand Up @@ -152,23 +150,21 @@ let event_predicate_communication_layer_reqres
is_knowable_by (get_label tr key) tr request /\
is_secret (comm_label client server) tr key /\
key `has_usage tr` (AeadKey comm_layer_aead_tag empty) /\
(match parse a request with
| None -> False
| Some request -> higher_layer_resreq_preds.send_request tr client server request (get_label tr key))
parse_and_pred (fun request -> higher_layer_resreq_preds.send_request tr client server request (get_label tr key)) request
)
| CommServerReceiveRequest server request key -> (
is_knowable_by (principal_label server) tr request /\
(exists client. event_triggered tr client (CommClientSendRequest client server request key) \/
is_publishable tr request)
is_knowable_by (principal_label server) tr key /\
is_knowable_by (get_label tr key) tr request /\
key `has_usage tr` (AeadKey comm_layer_aead_tag empty) /\
(
(exists client. event_triggered tr client (CommClientSendRequest client server request key)) \/
is_publishable tr key
)
)
| CommServerSendResponse server request response -> (
(match parse a response with
| None -> False
| Some response -> (
match parse a request with
| None -> False
| Some request -> higher_layer_resreq_preds.send_response tr server request response)
)
match parse a request, parse a response with
| Some request, Some response -> higher_layer_resreq_preds.send_response tr server request response
| _ -> False
)
| CommClientReceiveResponse client server response key -> (
(exists request. event_triggered tr server (CommServerSendResponse server request response)) \/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ open DY.Lib.Communication.Data
open DY.Lib.Communication.Core
open DY.Lib.Communication.Core.Invariants
open DY.Lib.Communication.Core.Lemmas
open DY.Lib.Communication.Core.Properties
open DY.Lib.Communication.RequestResponse
open DY.Lib.Communication.RequestResponse.Invariants

Expand Down Expand Up @@ -117,15 +118,12 @@ val receive_request_proof:
| (Some (payload, req_meta_data), tr_out) -> (
let payload_bytes = serialize a payload in
trace_invariant tr_out /\
// See comment on `receive_confidential_proof` for the reason of this form
// of the post-condition.
(exists client. event_triggered tr_out client (CommClientSendRequest client server payload_bytes req_meta_data.key) \/
is_well_formed a (is_publishable tr_out) payload) /\
event_triggered tr_out server (CommServerReceiveRequest server payload_bytes req_meta_data.key) /\
is_well_formed a (is_knowable_by (principal_label server) tr_out) payload /\
is_well_formed a (is_knowable_by (get_response_label tr req_meta_data) tr) payload
is_well_formed a (is_knowable_by (get_response_label tr_out req_meta_data) tr_out) payload
)
))
[SMTPat (trace_invariant tr);
[SMTPat (trace_invariant tr);
SMTPat (apply_com_layer_lemmas higher_layer_preds);
SMTPat (receive_request #a comm_keys_ids server msg_id tr)]
let receive_request_proof #invs #a tr comm_keys_ids higher_layer_preds server msg_id =
Expand All @@ -136,13 +134,36 @@ let receive_request_proof #invs #a tr comm_keys_ids higher_layer_preds server ms
let (Some req_msg_t, tr') = receive_confidential #com_message_t comm_keys_ids server msg_id tr in
let RequestMessage req_msg = req_msg_t in

let req_msg_bytes = serialize com_message_t req_msg_t in
let req_send_event client = CommClientSendRequest client server req_msg.request req_msg.key in

let i = find_event_triggered_at_timestamp tr' server (CommConfReceiveMsg server req_msg_bytes) in
conf_message_secrecy tr' i request_response_event_preconditions server req_msg_bytes;

// Properties that can be proved uniformly in both the honest and corrupt case
eliminate (exists client. event_triggered tr' client (req_send_event client)) \/
(is_publishable tr' req_msg.request /\ is_publishable tr' req_msg.key)
returns (
is_knowable_by (get_response_label tr' req_meta_data) tr' req_msg.request /\
req_msg.key `has_usage tr'` (AeadKey comm_layer_aead_tag empty)
)
with _. eliminate exists client. event_triggered tr' client (req_send_event client)
returns _
with _. (
let i = find_event_triggered_at_timestamp tr' client (req_send_event client) in
// Triggers event_triggered_at_implies_pred
assert(event_triggered_at tr' i client (req_send_event client))
)
and _. has_usage_publishable tr' req_msg.key (AeadKey comm_layer_aead_tag empty);

// Relating knowledge of the request to knowledge of its fields
serialize_parse_inv_lemma #bytes a req_msg.request;
assert(is_comm_response_payload tr_out server req_meta_data payload);
assert(is_comm_response_payload tr' server req_meta_data payload);

let ((), tr') = trigger_event server (CommServerReceiveRequest server req_msg.request req_msg.key) tr' in
let (sid', tr') = new_session_id server tr' in
let ((), tr') = set_state server sid' (ServerReceiveRequest {request=req_msg.request; key=req_msg.key} <: communication_states) tr' in
assert(tr' == tr_out);
assert(tr' == tr_out);
assert(trace_invariant tr_out);
()
)
Expand Down Expand Up @@ -182,9 +203,7 @@ val compute_response_message_proof:
is_knowable_by (principal_label server) tr key /\
is_well_formed a (is_knowable_by (get_label tr key) tr) response /\
is_publishable tr nonce /\
(key `has_usage tr` (AeadKey comm_layer_aead_tag empty) \/
is_publishable tr key
) /\
key `has_usage tr` (AeadKey comm_layer_aead_tag empty) /\
event_triggered tr server (CommServerSendResponse server request (serialize a response))
)
(ensures
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,13 @@ val receive_request:
principal -> timestamp ->
traceful (option (a & comm_meta_data))
let receive_request #a comm_keys_ids server msg_id =
let*? req_msg_t:com_message_t = receive_confidential #com_message_t comm_keys_ids server msg_id in
let*? req_msg_t:com_message_t = receive_confidential #com_message_t comm_keys_ids server msg_id in
guard_tr (RequestMessage? req_msg_t);*?
let RequestMessage req_msg = req_msg_t in
let*? request = return (parse a req_msg.request) in
trigger_event server (CommServerReceiveRequest server req_msg.request req_msg.key);*
let* sid = new_session_id server in
set_state server sid (ServerReceiveRequest {request=req_msg.request; key=req_msg.key} <: communication_states);*
let*? request = return (parse a req_msg.request) in
let req_meta_data = {key=req_msg.key; server; sid; request=req_msg.request} in
return (Some (request, req_meta_data))

Expand Down
2 changes: 1 addition & 1 deletion src/lib/communication/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ The request-response pairs are implemented with the same structure in the
`DY.Lib.Communication.RequstResponse.*` namespace.

Examples for how to use the communication layer functions
in a higher layer protocol can be found in this [repository](https://github.com/fabian-hk/dolev-yao-star-communication-layer-examples).
in a higher layer protocol can be found in this [repository](https://github.com/REPROSEC/dolev-yao-star-communication-layer-examples).
23 changes: 23 additions & 0 deletions src/lib/comparse/DY.Lib.Comparse.DYUtils.fst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module DY.Lib.Comparse.DYUtils

open Comparse
open DY.Core

open DY.Lib.Comparse.Glue
open DY.Lib.Comparse.Parsers

/// This module provides some utility functions for working more simply
/// with parseable bytes (e.g., lifting predicates from abstract types to
/// their serialized bytes counterparts).

#set-options "--fuel 0 --ifuel 0"

unfold
val parse_and_pred:
#a:Type -> {| parseable_serializeable bytes a |} ->
(p:a -> Type0) -> (bytes -> Type0)
let parse_and_pred #a p = (fun b ->
match parse a b with
| None -> False
| Some x -> p x
)
Comment on lines +16 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels to me like a generally good utility function, which we probably do want to have (and which could probably also be used more broadly) --- I also introduced it for that reason. That said, I see a few possible problems with it:

  • This may not be the right place for it. It doesn't seem to fit in exactly with the other comparse glue, but it also feels strange to have this utils file with only a single function. Maybe this is less relevant if we have more useful functions of this form. Maybe also it belongs in the main Comparse repo (in a more general form, using an arbitrary bytes_like), rather than here.
  • I'm not sure if the use of this will be bad for the SMT solver, in particular since it does often require a lambda to define the input predicate p. My sense is that as long as we don't want to talk about equivalence of these predicates that shouldn't be too big of a problem, but I am far from an expert on the encoding used.