Skip to content

Commit

Permalink
Deniability (#2)
Browse files Browse the repository at this point in the history
* Add real versus simulated KEMTLS SAUTH for deniability

* Deniability for all variants

* Conditional full versions for deniability

* Fix bug in m4 macro

* Give long-term secret keys to deniability adversary

* Missing message in KEMTLS PDK MUTUAL deniability

* Add comments/documentation about deniability

* Add results from deniability runs

* Reorganize output files
  • Loading branch information
dstebila authored Jan 31, 2022
1 parent 24c37bd commit b00ecd9
Show file tree
Hide file tree
Showing 25 changed files with 26,377 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/deniability/generated*
/generated_corekt.spthy
/generated_corekt_pdk.spthy
client_session_key.aes
36 changes: 36 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ all: prove

preprocess:
m4 corekt.spthy > generated_corekt.spthy
cd deniability && m4 kemtls_sauth.spthy > generated_kemtls_sauth.spthy
cd deniability && m4 kemtls_mutual.spthy > generated_kemtls_mutual.spthy
cd deniability && m4 kemtls_pdk_sauth.spthy > generated_kemtls_pdk_sauth.spthy
cd deniability && m4 kemtls_pdk_mutual.spthy > generated_kemtls_pdk_mutual.spthy
cd deniability && m4 --define=FULL kemtls_sauth.spthy > generated_kemtls_sauth_full.spthy
cd deniability && m4 --define=FULL kemtls_mutual.spthy > generated_kemtls_mutual_full.spthy
cd deniability && m4 --define=FULL kemtls_pdk_sauth.spthy > generated_kemtls_pdk_sauth_full.spthy
cd deniability && m4 --define=FULL kemtls_pdk_mutual.spthy > generated_kemtls_pdk_mutual_full.spthy

prove-sauth: preprocess
tamarin-prover -DINCLUDE_KEMTLS_SAUTH_OR_MUTUAL -DINCLUDE_KEMTLS_SAUTH --quit-on-warning generated_corekt.spthy
Expand Down Expand Up @@ -31,5 +39,33 @@ prove-all: preprocess
tamarin-prover -DINCLUDE_KEMTLS_SAUTH_OR_MUTUAL -DINCLUDE_KEMTLS_SAUTH -DINCLUDE_KEMTLS_MUTUAL -DINCLUDE_KEMTLS_PDK_SAUTH -DINCLUDE_KEMTLS_PDK_SAUTH -DINCLUDE_KEMTLS_PDK_MUTUAL --quit-on-warning generated_corekt.spthy
tamarin-prover -DINCLUDE_KEMTLS_SAUTH_OR_MUTUAL -DINCLUDE_KEMTLS_SAUTH -DINCLUDE_KEMTLS_MUTUAL -DINCLUDE_KEMTLS_PDK_SAUTH -DINCLUDE_KEMTLS_PDK_SAUTH -DINCLUDE_KEMTLS_PDK_MUTUAL $(if $(PROVE), --prove=$(PROVE), --prove) --output --Output=output generated_corekt.spthy

deniability-sauth: preprocess
tamarin-prover --quit-on-warning --diff --prove --output --Output=output deniability/generated_kemtls_sauth.spthy

deniability-sauth-full: preprocess
tamarin-prover --quit-on-warning --diff --prove --output --Output=output deniability/generated_kemtls_sauth_full.spthy

deniability-mutual: preprocess
tamarin-prover --quit-on-warning --diff --prove --output --Output=output deniability/generated_kemtls_mutual.spthy

deniability-mutual-full: preprocess
tamarin-prover --quit-on-warning --diff --prove --output --Output=output deniability/generated_kemtls_mutual_full.spthy

deniability-pdk-sauth: preprocess
tamarin-prover --quit-on-warning --diff --prove --output --Output=output deniability/generated_kemtls_pdk_sauth.spthy

deniability-pdk-sauth-full: preprocess
tamarin-prover --quit-on-warning --diff --prove --output --Output=output deniability/generated_kemtls_pdk_sauth_full.spthy

deniability-pdk-mutual: preprocess
tamarin-prover --quit-on-warning --diff --prove --output --Output=output deniability/generated_kemtls_pdk_mutual.spthy

deniability-pdk-mutual-full: preprocess
tamarin-prover --quit-on-warning --diff --prove --output --Output=output deniability/generated_kemtls_pdk_mutual_full.spthy

deniability-all: deniability-sauth deniability-mutual deniability-pdk-sauth deniability-pdk-mutual

deniability-full-all: deniability-sauth-full deniability-mutual-full deniability-pdk-sauth-full deniability-pdk-mutual-full

clean:
$(RM) -f generated_* */generated_*
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# Tamarin model for Core KEMTLS ("CoreKT")

This repository contains a Tamarin model for the "core cryptographic version" of the KEMTLS protocol. Roughly speaking, this means the version of KEMTLS as specified in Figures 3 and 7 of https://eprint.iacr.org/2020/534.pdf, without any additional the framing from the TLS protocol, such as extra TLS message fields, pre-shared key / resumption, or handshake / application layer encryption.
This repository contains a Tamarin model for the "core cryptographic version" of the KEMTLS and KEMTLS-PDK protocol. Roughly speaking, this means the version of KEMTLS as specified in Figures 3 and 7 of https://eprint.iacr.org/2020/534.pdf, and the version of KEMTLS-PDK as specified in https://eprint.iacr.org/2021/779.pdf, without any additional the framing from the TLS protocol, such as extra TLS message fields, pre-shared key / resumption, or handshake / application layer encryption.

The goal of this modelling exercise is to very closely follow the pen-and-paper security model and properties as specified in the multi-stage key exchange security model of the original paper (https://eprint.iacr.org/2020/534.pdf).
The goal of this modelling exercise is to very closely follow the pen-and-paper security model and properties as specified in the multi-stage key exchange security model of the KEMTLS papers (https://eprint.iacr.org/2020/534.pdf and https://eprint.iacr.org/2021/779.pdf).

## Organization of the code base

The code base uses the M4 macro language to combine multiple source files into Tamarin files, as well as using macros to generate code and select different segments of code (M4 ifdef's). The code base also uses Tamarin #ifdef's to selectively run different segments of code.

- `glossary.md` summarizes the primitives, state facts, and action facts used throughout the protocol, model, and lemmas.

- The `protocol` folder contains the formulation of the KEMTLS protocol in Tamarin. In fact it includes two KEMTLS protocol modes: server-only authentication and mutual authentication.
- The `protocol` folder contains the formulation of the KEMTLS protocol in Tamarin. In fact it includes four KEMTLS protocol modes: server-only authentication and mutual authentication from the original paper (https://eprint.iacr.org/2020/534.pdf), and server-only authentication and mutual authentication when server public keys are predistributed ("PDK mode") (https://eprint.iacr.org/2021/779.pdf).

- The `model` folder contains oracles that are accessible to the adversary for compromising secret keys.

Expand All @@ -20,15 +22,28 @@ The goal of this modelling exercise is to very closely follow the pen-and-paper
- `lemmas/sk_security.spthy` contains lemmas that model session key security. There are separate lemmas checking keys that are intended to have "weak forward secrecy 1", "weak forward secrecy 2", or "(full) forward secrecy". This is a codification of the freshness conditions in Definition B.3 of https://eprint.iacr.org/2020/534.pdf.
- `lemmas/malicious_acceptance.spthy` contains a lemma that models authentication security of KEMTLS: for session stages that believe they have authenticated their peer, there really is a matching session. This is a codification of Definition B.4 in https://eprint.iacr.org/2020/534.pdf.

- `corekt.spthy` uses m4 macros to pull all the above Tamarin source code into a single file. Run the command `make preprocess` to generate the resulting file `generated_corekt.spthy`, which is the file you should actually have Tamarin run.
- The `deniability` folder contains protocol specifications and lemmas for modelling offline deniability of KEMTLS via Tamarin's observational equivalence feature. For each variant {sauth, mutual, pdk_sauth, pdk_mutual}:

- `deniability/variant_real.spthy` contains a rule that generates the transcript using parties' secret keys to decapsulate.
- `deniability/variant_simulated.spthy` contains a rule that generates the transcript using only parties' public keys.
- `deniability/variant.spthy` contains a lemma checking that the transcripts generated by the `real` and `simulated` rules are indistinguishable.

- `corekt.spthy` uses m4 macros to pull all the above Tamarin source code (except deniability) into a single file. Run the command `make preprocess` to generate the resulting file `generated_corekt.spthy`, which is the file you should actually have Tamarin run.

- The `output` folder contains output from having run the model.

## Getting started

1. You'll need to have a working version of [Tamarin prover](https://tamarin-prover.github.io) installed.
2. Run `make preprocess` to generate a single Tamarin file `generated_corekt.spthy` from all the above sources.
3. Run `make prove` to have Tamarin try to prove all the above lemmas. The output will be shown on the screen and stored in the `output` directory. On a 16-core machine with lots of RAM, it takes about 7 minutes of wall clock time to prove all the lemmas (using Tamarin version 1.6.1).
2. Run `make preprocess` to run the M4 preprocessor to generate various combined Tamarin files.

### To run deniability lemmas:

- Run `time make deniability-variant` or `time make deniability-variant-full`, for variant in {`sauth`, `mutual`, `pdk-sauth`, `pdk-mutual`} to check the offline deniability property for the given variant. Without `-full`, some messages are omitted, and these take between 1 and 15 minutes each to run on a 16-core machine with 32 GB of RAM. With `-full`, all messages are included, and these take between TODO and TODO minutes each to run on 16-cores of a large machine with 180 GB of RAM. See the documentation in `deniability/kemtls_variant.spthy` for a more detailed explanation of the security property and message omission/inclusion.

### To run all other lemmas: (TODO: update documentation)

- Run `make prove` to have Tamarin try to prove all the above lemmas (except for deniability). The output will be shown on the screen and stored in the `output` directory. On a 16-core machine with lots of RAM, it takes about 7 minutes of wall clock time to prove all the lemmas (using Tamarin version 1.6.1).
- You can prove a specific lemma with `make prove PROVE=sk_security_wfs1` (for example).
- You can also use the Tamarin web UI: `tamarin-prover interactive .`

42 changes: 42 additions & 0 deletions deniability/kemtls_mutual.spthy
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* This file models the offline deniability of KEMTLS in mutual authentication mode. */

changequote(<!,!>)

theory corekt_deniability_mutual
begin

include(../protocol/primitives.spthy)

include(../protocol/kemtls_keygen.spthy)

include(../protocol/kemtls_mutual_defines.spthy)
include(kemtls_mutual_real.spthy)
include(kemtls_mutual_simulated.spthy)

/* This lemma captures the offline deniability of KEMTLS in mutual authentication mode.
* Offline deniability means that a judge, when given a protocol transcript and all of the
* keys involved, cannot tell whether the transcript is genuine or forged.
*
* This is modelled in Tamarin by having one rule that generates real transcripts
* uses real secret keys to decapsulate, and another rule that generates simulated
* transcripts only using public keys. The adversary is given the transcripts,
* as well as derived session keys and the parties' long-term public and private keys.
*
* If the M4 macro FULL is defined, then the transcript covers the full protocol
* run and all session keys are given to the adversary.
* If the M4 macro FULL is not defined, then the transcript only covers up until
* the last calculation involving either a real or simulated key, and then all
* subsequent messages and keys that can clearly be publicly computed are omitted
* to make things easier for Tamarin to prove.
*/
rule real_vs_simulated:
[
RealTranscript(transcript_real, session_keys_real, long_term_keys),
FakeTranscript(transcript_simulated, session_keys_simulated, long_term_keys)
]
--[]->
[
Out(diff(<transcript_real, session_keys_real, long_term_keys>, <transcript_simulated, session_keys_simulated, long_term_keys>))
]

end
68 changes: 68 additions & 0 deletions deniability/kemtls_mutual_real.spthy
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* This rule generates a *real* transcript for KEMTLS in mutual
* authentication mode, using the client's and server's long-term secret keys
* to decapsulate.
*/
rule KEMTLS_MUTUAL_real:
let
pk_e = KEM_e_PK(~sk_e)
CLIENT_HELLO = <'ClientHello', pk_e, ~r_c>
ct_e = KEM_e_Encaps_ct(pk_e, ~coins_e)
ss_e = KEM_e_Encaps_ss(pk_e, ~coins_e)
SERVER_HELLO = <'ServerHello', ct_e, ~r_s>
ES = HKDFExtract('0', '0')
dES = HKDFExpand(ES, 'derived', '0')
HS = HKDFExtract(dES, ss_e)
ifdef(<!FULL!>, <!
CHTS = HKDFExpand(HS, 'c_hs_traffic', M_KEMTLS_MUTUAL_STAGE1_TRANSCRIPT)
SHTS = HKDFExpand(HS, 's_hs_traffic', M_KEMTLS_MUTUAL_STAGE2_TRANSCRIPT)
!>)
dHS = HKDFExpand(HS, 'derived', '0')
CERTIFICATE_REQUEST = <'CertificateRequest'>
SERVER_CERTIFICATE = <'ServerCertificate', pk_S>
ct_S = KEM_s_Encaps_ct(pk_S, ~coins_S)
ss_S = KEM_s_Decaps(ct_S, sk_S)
CLIENT_KEM_CIPHERTEXT = <'ClientKEMCiphertext', ct_S>
AHS = HKDFExtract(dHS, ss_S)
ifdef(<!FULL!>, <!
CAHTS = HKDFExpand(AHS, 'c_ahs_traffic', M_KEMTLS_MUTUAL_STAGE3_TRANSCRIPT)
SAHTS = HKDFExpand(AHS, 's_ahs_traffic', M_KEMTLS_MUTUAL_STAGE4_TRANSCRIPT)
!>)
dAHS = HKDFExpand(AHS, 'derived', '0')
CLIENT_CERTIFICATE = <'ClientCertificate', pk_C>
ct_C = KEM_c_Encaps_ct(pk_C, ~coins_C)
ss_C = KEM_c_Decaps(ct_C, sk_C)
SERVER_KEM_CIPHERTEXT = <'ServerKEMCiphertext', ct_C>
MS = HKDFExtract(dAHS, ss_C)
ifdef(<!FULL!>, <!
fk_c = HKDFExpand(MS, 'c_finished', '0')
fk_s = HKDFExpand(MS, 's_finished', '0')
CF = HMAC(fk_c, M_KEMTLS_MUTUAL_CF_TRANSCRIPT)
CLIENT_FINISHED = <'ClientFinished', CF>
CATS = HKDFExpand(MS, 'c_ap_traffic', M_KEMTLS_MUTUAL_STAGE5_TRANSCRIPT)
SF = HMAC(fk_s, M_KEMTLS_MUTUAL_SF_TRANSCRIPT)
SERVER_FINISHED = <'ServerFinished', SF>
SATS = HKDFExpand(MS, 's_ap_traffic', M_KEMTLS_MUTUAL_STAGE6_TRANSCRIPT)
!>)
in
[
!Ltk($C, pk_C, sk_C, 'KEM_c'),
!Ltk($S, pk_S, sk_S, 'KEM_s'),
Fr(~sk_e),
Fr(~r_c),
Fr(~r_s),
Fr(~coins_e),
Fr(~coins_C),
Fr(~coins_S)
]
--[]->
[
RealTranscript(
<CLIENT_HELLO, SERVER_HELLO, CERTIFICATE_REQUEST, SERVER_CERTIFICATE, CLIENT_KEM_CIPHERTEXT, CLIENT_CERTIFICATE, SERVER_KEM_CIPHERTEXT
ifdef(<!FULL!>, <!, CLIENT_FINISHED, SERVER_FINISHED!>)
>,
<HS, AHS, MS
ifdef(<!FULL!>, <!, CHTS, SHTS, CAHTS, SAHTS, CATS, SATS!>)
>,
<pk_C, sk_C, pk_S, sk_S>
)
]
67 changes: 67 additions & 0 deletions deniability/kemtls_mutual_simulated.spthy
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* This rule generates a *simulated* transcript for KEMTLS in mutual
* authentication mode, without using any party's long-term secret keys.
*/
rule KEMTLS_MUTUAL_simulated:
let
pk_e = KEM_e_PK(~sk_e)
CLIENT_HELLO = <'ClientHello', pk_e, ~r_c>
ct_e = KEM_e_Encaps_ct(pk_e, ~coins_e)
ss_e = KEM_e_Encaps_ss(pk_e, ~coins_e)
SERVER_HELLO = <'ServerHello', ct_e, ~r_s>
ES = HKDFExtract('0', '0')
dES = HKDFExpand(ES, 'derived', '0')
HS = HKDFExtract(dES, ss_e)
ifdef(<!FULL!>, <!
CHTS = HKDFExpand(HS, 'c_hs_traffic', M_KEMTLS_MUTUAL_STAGE1_TRANSCRIPT)
SHTS = HKDFExpand(HS, 's_hs_traffic', M_KEMTLS_MUTUAL_STAGE2_TRANSCRIPT)
!>)
dHS = HKDFExpand(HS, 'derived', '0')
CERTIFICATE_REQUEST = <'CertificateRequest'>
SERVER_CERTIFICATE = <'ServerCertificate', pk_S>
ct_S = KEM_s_Encaps_ct(pk_S, ~coins_S)
ss_S = KEM_s_Encaps_ss(pk_S, ~coins_S)
CLIENT_KEM_CIPHERTEXT = <'ClientKEMCiphertext', ct_S>
AHS = HKDFExtract(dHS, ss_S)
ifdef(<!FULL!>, <!
CAHTS = HKDFExpand(AHS, 'c_ahs_traffic', M_KEMTLS_MUTUAL_STAGE3_TRANSCRIPT)
SAHTS = HKDFExpand(AHS, 's_ahs_traffic', M_KEMTLS_MUTUAL_STAGE4_TRANSCRIPT)
!>)
dAHS = HKDFExpand(AHS, 'derived', '0')
CLIENT_CERTIFICATE = <'ClientCertificate', pk_C>
ct_C = KEM_c_Encaps_ct(pk_C, ~coins_C)
ss_C = KEM_c_Encaps_ss(pk_C, ~coins_C)
SERVER_KEM_CIPHERTEXT = <'ServerKEMCiphertext', ct_C>
MS = HKDFExtract(dAHS, ss_C)
ifdef(<!FULL!>, <!
fk_c = HKDFExpand(MS, 'c_finished', '0')
fk_s = HKDFExpand(MS, 's_finished', '0')
CF = HMAC(fk_c, M_KEMTLS_MUTUAL_CF_TRANSCRIPT)
CLIENT_FINISHED = <'ClientFinished', CF>
CATS = HKDFExpand(MS, 'c_ap_traffic', M_KEMTLS_MUTUAL_STAGE5_TRANSCRIPT)
SF = HMAC(fk_s, M_KEMTLS_MUTUAL_SF_TRANSCRIPT)
SERVER_FINISHED = <'ServerFinished', SF>
SATS = HKDFExpand(MS, 's_ap_traffic', M_KEMTLS_MUTUAL_STAGE6_TRANSCRIPT)
!>)
in
[
!Ltk($C, pk_C, sk_C, 'KEM_c'),
!Ltk($S, pk_S, sk_S, 'KEM_s'),
Fr(~sk_e),
Fr(~r_c),
Fr(~r_s),
Fr(~coins_e),
Fr(~coins_C),
Fr(~coins_S)
]
--[]->
[
FakeTranscript(
<CLIENT_HELLO, SERVER_HELLO, CERTIFICATE_REQUEST, SERVER_CERTIFICATE, CLIENT_KEM_CIPHERTEXT, CLIENT_CERTIFICATE, SERVER_KEM_CIPHERTEXT
ifdef(<!FULL!>, <!, CLIENT_FINISHED, SERVER_FINISHED!>)
>,
<HS, AHS, MS
ifdef(<!FULL!>, <!, CHTS, SHTS, CAHTS, SAHTS, CATS, SATS!>)
>,
<pk_C, sk_C, pk_S, sk_S>
)
]
42 changes: 42 additions & 0 deletions deniability/kemtls_pdk_mutual.spthy
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* This file models the offline deniability of KEMTLS-PDK in mutual authentication mode. */

changequote(<!,!>)

theory corekt_deniability_pdk_mutual
begin

include(../protocol/primitives.spthy)

include(../protocol/kemtls_keygen.spthy)

include(../protocol/kemtls_pdk_mutual_defines.spthy)
include(kemtls_pdk_mutual_real.spthy)
include(kemtls_pdk_mutual_simulated.spthy)

/* This lemma captures the offline deniability of KEMTLS-PDK in mutual authentication mode.
* Offline deniability means that a judge, when given a protocol transcript and all of the
* keys involved, cannot tell whether the transcript is genuine or forged.
*
* This is modelled in Tamarin by having one rule that generates real transcripts
* uses real secret keys to decapsulate, and another rule that generates simulated
* transcripts only using public keys. The adversary is given the transcripts,
* as well as derived session keys and the parties' long-term public and private keys.
*
* If the M4 macro FULL is defined, then the transcript covers the full protocol
* run and all session keys are given to the adversary.
* If the M4 macro FULL is not defined, then the transcript only covers up until
* the last calculation involving either a real or simulated key, and then all
* subsequent messages and keys that can clearly be publicly computed are omitted
* to make things easier for Tamarin to prove.
*/
rule real_vs_simulated:
[
RealTranscript(transcript_real, session_keys_real, long_term_keys),
FakeTranscript(transcript_simulated, session_keys_simulated, long_term_keys)
]
--[]->
[
Out(diff(<transcript_real, session_keys_real, long_term_keys>, <transcript_simulated, session_keys_simulated, long_term_keys>))
]

end
Loading

0 comments on commit b00ecd9

Please sign in to comment.