├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── client_example ├── client_example.owl └── extraction │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── run_verus.sh │ └── src │ ├── execlib.rs │ ├── lib.rs │ ├── owl_aead.rs │ ├── owl_const_bytes.rs │ ├── owl_dhke.rs │ ├── owl_hkdf.rs │ ├── owl_hmac.rs │ ├── owl_pke.rs │ ├── owl_util.rs │ ├── server.rs │ └── speclib.rs ├── docs ├── 1-intro-to-owl.md ├── 2-indices.md ├── crypto-ops.md ├── encrypted_key_basic.owl └── internals │ └── kdf.md ├── extraction ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── preamble.rs ├── run_verus.sh └── src │ ├── execlib.rs │ ├── owl_aead.rs │ ├── owl_const_bytes.rs │ ├── owl_dhke.rs │ ├── owl_hkdf.rs │ ├── owl_hmac.rs │ ├── owl_pke.rs │ ├── owl_util.rs │ └── speclib.rs ├── hpke ├── owl-hpke │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── execlib.rs │ │ ├── lib.rs │ │ ├── owl_aead.rs │ │ ├── owl_const_bytes.rs │ │ ├── owl_dhke.rs │ │ ├── owl_hkdf.rs │ │ ├── owl_hmac.rs │ │ ├── owl_pke.rs │ │ ├── owl_util.rs │ │ └── speclib.rs ├── rust-hpke │ ├── .clippy.toml │ ├── .gitignore │ ├── CHANGELOG.md │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── benches │ │ └── benches.rs │ ├── examples │ │ ├── agility.rs │ │ └── client_server.rs │ ├── src │ │ ├── aead.rs │ │ ├── aead │ │ │ ├── aes_gcm.rs │ │ │ ├── chacha20_poly1305.rs │ │ │ └── export_only.rs │ │ ├── dhkex.rs │ │ ├── dhkex │ │ │ ├── ecdh_nistp.rs │ │ │ └── x25519.rs │ │ ├── kat_tests.rs │ │ ├── kdf.rs │ │ ├── kem.rs │ │ ├── kem │ │ │ └── dhkem.rs │ │ ├── lib.rs │ │ ├── op_mode.rs │ │ ├── setup.rs │ │ ├── single_shot.rs │ │ ├── test_util.rs │ │ └── util.rs │ └── test-vectors-5f503c5.json └── test_bench_hpke │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── bench_hpke.py │ └── src │ └── main.rs ├── old.cabal.project.local ├── owl.cabal ├── prelude.smt2 ├── src ├── AST.hs ├── CmdArgs.hs ├── Extraction │ ├── ConcreteAST.hs │ ├── Concretify.hs │ ├── ExtractionBase.hs │ ├── ExtractionTop.hs │ ├── GenVerus.hs │ ├── LowerBufOpt.hs │ ├── LowerImmut.hs │ ├── PrettyVerus.hs │ ├── SpecExtraction.hs │ └── Verus.hs ├── LabelChecking.hs ├── Main.hs ├── Parse.hs ├── Pass │ ├── ANFPass.hs │ ├── ModuleFlattening.hs │ └── PathResolution.hs ├── Pretty.hs ├── SMT.hs ├── SMTBase.hs ├── Test.hs ├── Typing.hs └── TypingBase.hs ├── tests ├── failure │ ├── bad_locality.owl │ ├── corr_enc_bad.owl │ ├── duplicateDef.owl │ ├── inconclusive.owl │ ├── parse_lengths_unparsable.owl │ ├── pcCheck1.owl │ └── wrong_name.owl ├── should_fail │ └── types.owl ├── should_succeed │ ├── basic_hash.owl │ ├── dangling_path_var.owl │ ├── lak-indexed.owl │ ├── lak.owl │ ├── mod_alias.owl │ ├── mw-indexed.owl │ ├── mw.owl │ ├── struct_resolution.owl │ └── subtyping.owl ├── success │ ├── abstract_ty.owl │ ├── abstractdefs.owl │ ├── aead_ctr.owl │ ├── apex_example.owl │ ├── arith.owl │ ├── basic_auth.owl │ ├── basic_hash-indexed.owl │ ├── basics.owl │ ├── bool.owl │ ├── call.owl │ ├── checknonce.owl │ ├── corr_enc.owl │ ├── corrdecl.owl │ ├── crh.owl │ ├── debug.owl │ ├── denning-sacco.owl │ ├── dep_enum.owl │ ├── dhke.owl │ ├── double_index.owl │ ├── easy_call.owl │ ├── encrypted_key.owl │ ├── encrypted_key_indexed.owl │ ├── encrypted_key_struct.owl │ ├── enum_parsing_example.owl │ ├── enumlength.owl │ ├── enums.owl │ ├── fancy_struct.owl │ ├── feldhofer-indexed.owl │ ├── guard.owl │ ├── hash-lock.owl │ ├── idx_locality.owl │ ├── ifcond.owl │ ├── indices │ │ ├── indices.owl │ │ └── mac_indices.owl │ ├── infer.owl │ ├── kdf-corr.owl │ ├── kdf-enc.owl │ ├── kdf-self.owl │ ├── ke │ │ ├── dh_ke.owl │ │ ├── full_protocol.owl │ │ ├── ke.owli │ │ ├── psk_ke.owl │ │ ├── transp.owl │ │ └── transp.owli │ ├── ke_mod │ │ ├── dh_ke.owl │ │ ├── full_protocol.owl │ │ ├── ke.owli │ │ ├── params.owli │ │ ├── psk_ke.owl │ │ ├── transp.owl │ │ └── transp.owli │ ├── kerberos.owl │ ├── kerberos │ │ ├── kerberos.owli │ │ ├── kerberos_2_3.owl │ │ ├── kerberos_ASE_pkinit.owl │ │ ├── kerberos_ASE_standard.owl │ │ ├── kerberos_full_pkinit.owl │ │ └── kerberos_full_standard.owl │ ├── kerberos_mod │ │ ├── kerberos_pkinit.owl │ │ ├── kerberos_skinit.owl │ │ ├── kerberos_stage1.owli │ │ └── kerberos_stage23.owl │ ├── lengths.owl │ ├── let_sugar.owl │ ├── mac.owl │ ├── mod_alias.owl │ ├── mods │ │ ├── functor.owl │ │ ├── mods.owl │ │ └── spec.owl │ ├── mw-indexed.owl │ ├── nested_and.owl │ ├── ns-sym-indexed.owl │ ├── ns-sym.owl │ ├── nsl.owl │ ├── odh.owl │ ├── option.owl │ ├── option_refine.owl │ ├── otwayrees-indexed.owl │ ├── otwayrees-simple.owl │ ├── otwayrees.owl │ ├── parse_lengths.owl │ ├── parse_lengths_nested.owl │ ├── parse_refinement.owl │ ├── pke.owl │ ├── predicates.owl │ ├── private_authentication.owl │ ├── private_authentication_hybrid.owl │ ├── running_example.owl │ ├── singleton-type.owl │ ├── ssh.owl │ ├── struct.owl │ ├── struct_eta.owl │ ├── struct_ext.owl │ ├── toy_examples │ │ ├── basic_hash-indexed.owl │ │ ├── denning-sacco.owl │ │ ├── dhke.owl │ │ ├── feldhofer-indexed.owl │ │ ├── hash-lock.owl │ │ ├── kerberos.owl │ │ ├── lak-indexed.owl │ │ ├── mw-indexed.owl │ │ ├── ns-sym-indexed.owl │ │ ├── nsl.owl │ │ ├── otwayrees-indexed.owl │ │ ├── private_authentication_hybrid.owl │ │ ├── ssh.owl │ │ └── yahalom-indexed.owl │ ├── unauth_dh.owl │ └── yahalom-indexed.owl └── wip │ ├── hpke │ ├── defs.owl │ ├── full.owl │ ├── receiver.owl │ └── sender.owl │ ├── unauth_hash.owl │ ├── wg │ ├── defs.owl │ ├── full.owl │ ├── init.owl │ ├── resp.owl │ └── transp.owl │ ├── wireguard-indexed.owl │ └── wireguard.owl ├── vim ├── ftdetect │ └── owl.vim └── syntax │ └── owl.vim ├── vscode └── owl-support-for-vscode │ ├── .vscode │ └── launch.json │ ├── .vscodeignore │ ├── CHANGELOG.md │ ├── README.md │ ├── language-configuration.json │ ├── package.json │ ├── syntaxes │ └── owl.tmLanguage.json │ └── vsc-extension-quickstart.md └── wg ├── .gitignore ├── cleanup-netconfig.sh ├── jq_dump.sh ├── run-iperf-test.sh ├── run-linedelay-test.sh ├── run_all_benches.sh ├── setup-netconfig.sh ├── wg1.conf ├── wg1n.conf ├── wireguard-go ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── conn │ ├── bind_std.go │ ├── bind_std_test.go │ ├── bind_windows.go │ ├── bindtest │ │ └── bindtest.go │ ├── boundif_android.go │ ├── conn.go │ ├── conn_test.go │ ├── controlfns.go │ ├── controlfns_linux.go │ ├── controlfns_unix.go │ ├── controlfns_windows.go │ ├── default.go │ ├── errors_default.go │ ├── errors_linux.go │ ├── features_default.go │ ├── features_linux.go │ ├── gso_default.go │ ├── gso_linux.go │ ├── mark_default.go │ ├── mark_unix.go │ ├── sticky_default.go │ ├── sticky_linux.go │ ├── sticky_linux_test.go │ └── winrio │ │ └── rio_windows.go ├── device │ ├── allowedips.go │ ├── allowedips_rand_test.go │ ├── allowedips_test.go │ ├── bind_test.go │ ├── channels.go │ ├── constants.go │ ├── cookie.go │ ├── cookie_test.go │ ├── device.go │ ├── device_test.go │ ├── devicestate_string.go │ ├── endpoint_test.go │ ├── indextable.go │ ├── ip.go │ ├── kdf_test.go │ ├── keypair.go │ ├── logger.go │ ├── mobilequirks.go │ ├── noise-helpers.go │ ├── noise-protocol.go │ ├── noise-types.go │ ├── noise_test.go │ ├── peer.go │ ├── pools.go │ ├── pools_test.go │ ├── queueconstants_android.go │ ├── queueconstants_default.go │ ├── queueconstants_ios.go │ ├── queueconstants_windows.go │ ├── race_disabled_test.go │ ├── race_enabled_test.go │ ├── receive.go │ ├── send.go │ ├── sticky_default.go │ ├── sticky_linux.go │ ├── timers.go │ ├── tun.go │ └── uapi.go ├── format_test.go ├── go.mod ├── go.sum ├── ipc │ ├── namedpipe │ │ ├── file.go │ │ ├── namedpipe.go │ │ └── namedpipe_test.go │ ├── uapi_bsd.go │ ├── uapi_linux.go │ ├── uapi_unix.go │ ├── uapi_wasm.go │ └── uapi_windows.go ├── lib │ ├── .gitignore │ ├── owl_wireguard.h │ └── owl_wireguard │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── rust_toolchain.toml │ │ └── src │ │ ├── execlib.rs │ │ ├── lib.rs │ │ ├── owl_aead.rs │ │ ├── owl_const_bytes.rs │ │ ├── owl_dhke.rs │ │ ├── owl_hkdf.rs │ │ ├── owl_hmac.rs │ │ ├── owl_pke.rs │ │ ├── owl_util.rs │ │ ├── owl_wireguard.rs │ │ └── speclib.rs ├── main.go ├── main_windows.go ├── ratelimiter │ ├── ratelimiter.go │ └── ratelimiter_test.go ├── replay │ ├── replay.go │ └── replay_test.go ├── rwcancel │ ├── rwcancel.go │ └── rwcancel_stub.go ├── tai64n │ ├── tai64n.go │ └── tai64n_test.go ├── tests │ └── netns.sh ├── tun │ ├── alignment_windows_test.go │ ├── checksum.go │ ├── checksum_test.go │ ├── errors.go │ ├── netstack │ │ ├── examples │ │ │ ├── http_client.go │ │ │ ├── http_server.go │ │ │ └── ping_client.go │ │ └── tun.go │ ├── offload_linux.go │ ├── offload_linux_test.go │ ├── operateonfd.go │ ├── tun.go │ ├── tun_darwin.go │ ├── tun_freebsd.go │ ├── tun_linux.go │ ├── tun_openbsd.go │ ├── tun_windows.go │ └── tuntest │ │ └── tuntest.go └── version.go └── wireguard-rs ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── architecture.svg ├── bench_end_to_end.py ├── bench_handshake.py ├── bench_send_recv.py ├── netns.sh ├── rust-toolchain.toml └── src ├── configuration ├── config.rs ├── error.rs ├── mod.rs └── uapi │ ├── get.rs │ ├── mod.rs │ └── set.rs ├── main.rs ├── platform ├── dummy │ ├── endpoint.rs │ ├── mod.rs │ ├── tun │ │ ├── dummy.rs │ │ ├── mod.rs │ │ └── void.rs │ └── udp.rs ├── endpoint.rs ├── linux │ ├── mod.rs │ ├── tun.rs │ ├── uapi.rs │ └── udp.rs ├── mod.rs ├── tun.rs ├── uapi.rs └── udp.rs ├── util.rs └── wireguard ├── constants.rs ├── handshake ├── device.rs ├── macs.rs ├── messages.rs ├── mod.rs ├── noise.rs ├── peer.rs ├── ratelimiter.rs ├── tests.rs ├── timestamp.rs └── types.rs ├── mod.rs ├── owl_wg ├── execlib.rs ├── mod.rs ├── owl_aead.rs ├── owl_const_bytes.rs ├── owl_dhke.rs ├── owl_hkdf.rs ├── owl_hmac.rs ├── owl_pke.rs ├── owl_util.rs ├── owl_wireguard.rs └── speclib.rs ├── peer.rs ├── queue.rs ├── router ├── anti_replay.rs ├── constants.rs ├── device.rs ├── ip.rs ├── messages.rs ├── mod.rs ├── peer.rs ├── queue.rs ├── receive.rs ├── route.rs ├── send.rs ├── tests │ ├── bench.rs │ ├── bench_new.rs │ ├── mod.rs │ └── tests.rs ├── types.rs └── worker.rs ├── tests.rs ├── timers.rs ├── types.rs ├── wireguard.rs └── workers.rs /.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | dist-newstyle/ 3 | temp.rs 4 | hie.yaml 5 | stack.yaml.lock 6 | .vscode/ 7 | main 8 | *.owl_config 9 | .owl-log/ 10 | .z3log/ 11 | *.smtcache 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Secure Foundations Lab 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cabal build owl 3 | -------------------------------------------------------------------------------- /client_example/client_example.owl: -------------------------------------------------------------------------------- 1 | locality Client 2 | locality Server 3 | name message : nonce @ Client 4 | name kC2S : enckey Name(message) @ Client, Server 5 | name kS2C : enckey (if sec(kC2S) then Name(message) else Data) @ Client, Server 6 | 7 | struct EncMsg { 8 | version_num: Const(0x01), 9 | cipher: Data 10 | } 11 | 12 | enum ServerResult { 13 | | SROk (if sec(kC2S) then Name(message) else Data) 14 | | SRErr 15 | } 16 | 17 | def server_recv() @ Server : ServerResult = 18 | input p in 19 | parse p as EncMsg(_, ctxt) in { 20 | let recv_key = get(kC2S) in 21 | corr_case kC2S in 22 | case adec(recv_key, ctxt) { 23 | | Some ptxt => SROk(ptxt) 24 | | None => SRErr() 25 | } 26 | } otherwise SRErr() 27 | 28 | def server_send(m: if sec(kC2S) then Name(message) else Data) @ Server : Unit = 29 | let send_key = get(kS2C) in 30 | let enc_msg = aenc(send_key, m) in 31 | let msg = EncMsg(0x01, enc_msg) in 32 | output msg to endpoint(Client) 33 | 34 | def echo_server() @ Server : Unit = 35 | let s_result = call server_recv() in 36 | corr_case kC2S in 37 | case s_result { 38 | | SROk m => call server_send(m) 39 | | SRErr => () 40 | } 41 | -------------------------------------------------------------------------------- /client_example/extraction/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | rust-toolchain.toml -------------------------------------------------------------------------------- /client_example/extraction/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "extraction" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "extraction" 8 | path = "src/lib.rs" 9 | 10 | # [[bin]] 11 | # name = "extraction" 12 | # path = "src/main.rs" 13 | 14 | [dependencies] 15 | aead = {version = "0.5.1"} # , optional = true} 16 | aes-gcm = {version = "0.10.1"} # , optional = true} 17 | chacha20poly1305 = {version = "0.10.1"} # , optional = true} 18 | blake2 = {version = "0.10.6"} # , optional = true} 19 | crypto = "0.4.0" 20 | digest = "0.10.5" 21 | hkdf = "0.12.3" 22 | hmac = "0.12.1" 23 | p256 = { version = "0.11.1", features = ["ecdh", "bits", "serde"] } 24 | rand = "0.8.5" 25 | rsa = "0.7.2" 26 | sha1 = "0.10.5" 27 | sha2 = "0.10.6" 28 | libcrux = { git = "https://github.com/cryspen/libcrux", features = ["rand"] } 29 | serde = { version = "1.0", features = ["derive"] } 30 | serde_json = "1.0" 31 | x25519-dalek = { version = "2.0.0", features = ["static_secrets"] } 32 | builtin = { git = "https://github.com/verus-lang/verus", branch = "main" } 33 | builtin_macros = { git = "https://github.com/verus-lang/verus", branch = "main" } 34 | vstd = { git = "https://github.com/verus-lang/verus", branch = "main" } 35 | vest = { git = "https://github.com/secure-foundations/vest", branch = "main" } 36 | 37 | [features] 38 | default = [] # ["nonverif-crypto"] 39 | nonverif-crypto = [] 40 | 41 | [package.metadata.verus] 42 | verify = true 43 | -------------------------------------------------------------------------------- /client_example/extraction/run_verus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | function usage() { 6 | echo "Usage: ${0} [-n] [-v ]" 7 | echo " -n: Do not format the code" 8 | echo " -v : Additional arguments to pass to verus" 9 | echo "You must have verus and verusfmt in your path" 10 | exit 2 11 | } 12 | 13 | format="true" 14 | ext_dir_path=$(realpath .) 15 | verus_args="" 16 | 17 | # Parse command line options 18 | while getopts "v:n" opt; do 19 | case "${opt}" in 20 | n) format="false" ;; 21 | v) verus_args="${OPTARG}" ;; 22 | \? ) usage ;; 23 | : ) usage ;; 24 | esac 25 | done 26 | shift $((OPTIND -1)) 27 | 28 | 29 | src_path=$ext_dir_path/src 30 | 31 | main_file=$src_path/lib.rs 32 | 33 | if [ $format = "true" ]; then 34 | echo "" 35 | echo "FORMATTING" 36 | verusfmt $main_file 37 | fi 38 | 39 | echo "" 40 | echo "CARGO VERUS BUILD" 41 | pushd $ext_dir_path 42 | cargo verus verify -- --rlimit=100 $verus_args 43 | popd 44 | 45 | 46 | if [ -z $verus_args ]; then 47 | echo "" 48 | echo "Done!" 49 | else 50 | echo "" 51 | echo "" 52 | echo "WARNING: using the following extra verus args: $verus_args" 53 | echo "" 54 | fi 55 | 56 | -------------------------------------------------------------------------------- /client_example/extraction/src/owl_dhke.rs: -------------------------------------------------------------------------------- 1 | use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; 2 | use vstd::prelude::*; 3 | use libcrux::ecdh::*; 4 | use libcrux::drbg::*; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_ecdh_key_pair() -> (Vec, Vec) { 10 | #[cfg(feature = "nonverif-crypto")] 11 | { 12 | let mut rng = rand::thread_rng(); 13 | let secret = StaticSecret::random_from_rng(&mut rng); 14 | let public = PublicKey::from(&secret); 15 | let sk_bytes = secret.to_bytes().to_vec(); 16 | let pk_bytes = public.to_bytes().to_vec(); 17 | (sk_bytes, pk_bytes) 18 | } 19 | #[cfg(not(feature = "nonverif-crypto"))] 20 | { 21 | let mut rng = Drbg::new(libcrux::digest::Algorithm::Sha256).unwrap(); 22 | let (pk, sk) = x25519_key_gen(&mut rng).unwrap(); 23 | let pk_bytes = pk.0.to_vec(); 24 | let sk_bytes = sk.0.to_vec(); 25 | (sk_bytes, pk_bytes) 26 | } 27 | } 28 | 29 | #[verifier(external_body)] 30 | pub fn ecdh_dhpk(sk: &[u8]) -> Vec { 31 | #[cfg(feature = "nonverif-crypto")] 32 | { 33 | use std::convert::TryInto; 34 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 35 | let sk_decoded = StaticSecret::from(sk_length_checked); 36 | let pk = PublicKey::from(&sk_decoded); 37 | pk.to_bytes().to_vec() 38 | } 39 | #[cfg(not(feature = "nonverif-crypto"))] 40 | { 41 | secret_to_public(Algorithm::X25519, sk).unwrap() 42 | } 43 | } 44 | 45 | #[verifier(external_body)] 46 | pub fn ecdh_combine(sk: &[u8], others_pk: &[u8]) -> Vec { 47 | #[cfg(feature = "nonverif-crypto")] 48 | { 49 | use std::convert::TryInto; 50 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 51 | let pk_length_checked: [u8; 32] = others_pk.try_into().unwrap(); 52 | let sk_decoded = StaticSecret::from(sk_length_checked); 53 | let pk_decoded = PublicKey::from(pk_length_checked); 54 | let shared_secret = sk_decoded.diffie_hellman(&pk_decoded); 55 | shared_secret.as_bytes().to_vec() 56 | } 57 | #[cfg(not(feature = "nonverif-crypto"))] 58 | { 59 | derive(Algorithm::X25519, others_pk, sk).unwrap() 60 | } 61 | } 62 | 63 | } // verus! 64 | -------------------------------------------------------------------------------- /client_example/extraction/src/owl_hkdf.rs: -------------------------------------------------------------------------------- 1 | use hkdf::Hkdf; 2 | use sha2::Sha256; 3 | use vstd::prelude::*; 4 | 5 | use libcrux::hkdf::*; 6 | 7 | verus! { 8 | 9 | pub open spec fn spec_kdfkey_size() -> usize { 32 } 10 | pub const fn kdfkey_size() -> (r:usize) ensures r == spec_kdfkey_size() { 32 } 11 | 12 | #[verifier(external_body)] 13 | pub fn gen_rand_kdf_key() -> Vec { 14 | crate::owl_util::gen_rand_bytes(kdfkey_size()) 15 | } 16 | 17 | #[verifier(external_body)] 18 | pub fn extract_expand_to_len(ikm: &[u8], salt: &[u8], info: &[u8], len: usize) -> Vec { 19 | #[cfg(feature = "nonverif-crypto")] 20 | { 21 | let h = Hkdf::::new(Some(salt), ikm); 22 | let mut okm = vec![0u8; len]; 23 | h.expand(info, &mut okm).expect("failed to expand"); 24 | okm 25 | } 26 | #[cfg(not(feature = "nonverif-crypto"))] 27 | { 28 | // support other algorithms here? 29 | libcrux::hkdf::hkdf(Algorithm::Sha256, salt, ikm, info, len).unwrap() 30 | } 31 | } 32 | 33 | 34 | } // verus! 35 | -------------------------------------------------------------------------------- /client_example/extraction/src/owl_util.rs: -------------------------------------------------------------------------------- 1 | use rand::{distributions::Uniform, Rng}; 2 | use vstd::prelude::*; 3 | use libcrux::drbg::*; 4 | use libcrux::digest::Algorithm; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_rand_bytes(len: usize) -> Vec { 10 | let mut rng = Drbg::new(Algorithm::Sha256).unwrap(); 11 | rng.generate_vec(len).unwrap() 12 | } 13 | 14 | } // verus! 15 | -------------------------------------------------------------------------------- /docs/2-indices.md: -------------------------------------------------------------------------------- 1 | TODO -------------------------------------------------------------------------------- /docs/encrypted_key_basic.owl: -------------------------------------------------------------------------------- 1 | /* 2 | A, B already have key k 3 | 4 | A -> B : {k_data}_k 5 | 6 | B -> A : {x}_(k_data) 7 | 8 | A : retrieve x 9 | */ 10 | 11 | locality alice 12 | locality bob 13 | 14 | name x : nonce @ bob 15 | name k_data : enckey Name(x) @ alice 16 | name psk : enckey Name(k_data) @ alice, bob 17 | 18 | enum Result { 19 | | SomeResult Name(x) 20 | | NoResult 21 | } 22 | 23 | def alice_main () @ alice 24 | : if sec(k_data) then Result else Data = 25 | let c = aenc(get(psk), get(k_data)) in 26 | output c to endpoint(bob); 27 | input i in 28 | corr_case k_data in 29 | let res = adec(get(k_data), i) in 30 | case res { 31 | | Some j => SomeResult(j) 32 | | None => NoResult() 33 | } 34 | 35 | def bob_main () @ bob : Unit = 36 | input i in // i : Data 37 | corr_case psk in 38 | case adec(get(psk), i) { 39 | | Some k => 40 | let c = aenc(k, get(x)) in 41 | output c to endpoint(alice) 42 | | None => () 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /extraction/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | src/main.rs 3 | src/lib.rs 4 | *.owl_config 5 | parse_serialize.vest 6 | parse_serialize.rs 7 | rust-toolchain.toml -------------------------------------------------------------------------------- /extraction/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "extraction" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "extraction" 8 | path = "src/lib.rs" 9 | 10 | # [[bin]] 11 | # name = "extraction" 12 | # path = "src/main.rs" 13 | 14 | [dependencies] 15 | aead = {version = "0.5.1"} # , optional = true} 16 | aes-gcm = {version = "0.10.1"} # , optional = true} 17 | chacha20poly1305 = {version = "0.10.1"} # , optional = true} 18 | blake2 = {version = "0.10.6"} # , optional = true} 19 | crypto = "0.4.0" 20 | digest = "0.10.5" 21 | hkdf = "0.12.3" 22 | hmac = "0.12.1" 23 | p256 = { version = "0.11.1", features = ["ecdh", "bits", "serde"] } 24 | rand = "0.8.5" 25 | rsa = "0.7.2" 26 | sha1 = "0.10.5" 27 | sha2 = "0.10.6" 28 | libcrux = { git = "https://github.com/cryspen/libcrux", features = ["rand"] } 29 | serde = { version = "1.0", features = ["derive"] } 30 | serde_json = "1.0" 31 | x25519-dalek = { version = "2.0.0", features = ["static_secrets"] } 32 | builtin = { git = "https://github.com/verus-lang/verus", branch = "main" } 33 | builtin_macros = { git = "https://github.com/verus-lang/verus", branch = "main" } 34 | vstd = { git = "https://github.com/verus-lang/verus", branch = "main" } 35 | vest = { git = "https://github.com/secure-foundations/vest", rev = "39876557b9776b17dabcbbf0385742c94d038597" } 36 | 37 | [features] 38 | default = [] # ["nonverif-crypto"] 39 | nonverif-crypto = [] 40 | 41 | [package.metadata.verus] 42 | verify = true 43 | -------------------------------------------------------------------------------- /extraction/run_verus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | function usage() { 6 | echo "Usage: ${0} [-n] [-v ] " 7 | echo " -n: Do not format the code" 8 | echo " -v : Additional arguments to pass to verus" 9 | echo "You must have verus and verusfmt in your path" 10 | exit 2 11 | } 12 | 13 | format="true" 14 | ext_dir_path="" 15 | verus_args="" 16 | 17 | # Parse command line options 18 | while getopts "v:n" opt; do 19 | case "${opt}" in 20 | n) format="false" ;; 21 | v) verus_args="${OPTARG}" ;; 22 | \? ) usage ;; 23 | : ) usage ;; 24 | esac 25 | done 26 | shift $((OPTIND -1)) 27 | 28 | # Check if there's a required argument provided 29 | if [[ -n $1 ]]; then 30 | ext_dir_path=$(realpath "$1") 31 | else 32 | echo "Path to extraction dir is missing." 1>&2 33 | exit 1 34 | fi 35 | 36 | src_path=$ext_dir_path/src 37 | 38 | main_file=$src_path/lib.rs 39 | 40 | if [ $format = "true" ]; then 41 | echo "" 42 | echo "FORMATTING" 43 | verusfmt $main_file 44 | fi 45 | 46 | echo "" 47 | echo "CARGO VERUS BUILD" 48 | pushd $ext_dir_path 49 | cargo verus verify -- --rlimit=100 $verus_args 50 | popd 51 | 52 | if [ -z $verus_args ]; then 53 | echo "" 54 | echo "Done!" 55 | else 56 | echo "" 57 | echo "" 58 | echo "WARNING: using the following extra verus args: $verus_args" 59 | echo "" 60 | fi 61 | 62 | -------------------------------------------------------------------------------- /extraction/src/owl_dhke.rs: -------------------------------------------------------------------------------- 1 | use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; 2 | use vstd::prelude::*; 3 | use libcrux::ecdh::*; 4 | use libcrux::drbg::*; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_ecdh_key_pair() -> (Vec, Vec) { 10 | #[cfg(feature = "nonverif-crypto")] 11 | { 12 | let mut rng = rand::thread_rng(); 13 | let secret = StaticSecret::random_from_rng(&mut rng); 14 | let public = PublicKey::from(&secret); 15 | let sk_bytes = secret.to_bytes().to_vec(); 16 | let pk_bytes = public.to_bytes().to_vec(); 17 | (sk_bytes, pk_bytes) 18 | } 19 | #[cfg(not(feature = "nonverif-crypto"))] 20 | { 21 | let mut rng = Drbg::new(libcrux::digest::Algorithm::Sha256).unwrap(); 22 | let (pk, sk) = x25519_key_gen(&mut rng).unwrap(); 23 | let pk_bytes = pk.0.to_vec(); 24 | let sk_bytes = sk.0.to_vec(); 25 | (sk_bytes, pk_bytes) 26 | } 27 | } 28 | 29 | #[verifier(external_body)] 30 | pub fn ecdh_dhpk(sk: &[u8]) -> Vec { 31 | #[cfg(feature = "nonverif-crypto")] 32 | { 33 | use std::convert::TryInto; 34 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 35 | let sk_decoded = StaticSecret::from(sk_length_checked); 36 | let pk = PublicKey::from(&sk_decoded); 37 | pk.to_bytes().to_vec() 38 | } 39 | #[cfg(not(feature = "nonverif-crypto"))] 40 | { 41 | secret_to_public(Algorithm::X25519, sk).unwrap() 42 | } 43 | } 44 | 45 | #[verifier(external_body)] 46 | pub fn ecdh_combine(sk: &[u8], others_pk: &[u8]) -> Vec { 47 | #[cfg(feature = "nonverif-crypto")] 48 | { 49 | use std::convert::TryInto; 50 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 51 | let pk_length_checked: [u8; 32] = others_pk.try_into().unwrap(); 52 | let sk_decoded = StaticSecret::from(sk_length_checked); 53 | let pk_decoded = PublicKey::from(pk_length_checked); 54 | let shared_secret = sk_decoded.diffie_hellman(&pk_decoded); 55 | shared_secret.as_bytes().to_vec() 56 | } 57 | #[cfg(not(feature = "nonverif-crypto"))] 58 | { 59 | derive(Algorithm::X25519, others_pk, sk).unwrap() 60 | } 61 | } 62 | 63 | } // verus! 64 | -------------------------------------------------------------------------------- /extraction/src/owl_hkdf.rs: -------------------------------------------------------------------------------- 1 | use hkdf::Hkdf; 2 | use sha2::Sha256; 3 | use vstd::prelude::*; 4 | 5 | use libcrux::hkdf::*; 6 | 7 | verus! { 8 | 9 | pub open spec fn spec_kdfkey_size() -> usize { 32 } 10 | pub const fn kdfkey_size() -> (r:usize) ensures r == spec_kdfkey_size() { 32 } 11 | 12 | #[verifier(external_body)] 13 | pub fn gen_rand_kdf_key() -> Vec { 14 | crate::owl_util::gen_rand_bytes(kdfkey_size()) 15 | } 16 | 17 | #[verifier(external_body)] 18 | pub fn extract_expand_to_len(ikm: &[u8], salt: &[u8], info: &[u8], len: usize) -> Vec { 19 | #[cfg(feature = "nonverif-crypto")] 20 | { 21 | let h = Hkdf::::new(Some(salt), ikm); 22 | let mut okm = vec![0u8; len]; 23 | h.expand(info, &mut okm).expect("failed to expand"); 24 | okm 25 | } 26 | #[cfg(not(feature = "nonverif-crypto"))] 27 | { 28 | // support other algorithms here? 29 | libcrux::hkdf::hkdf(Algorithm::Sha256, salt, ikm, info, len).unwrap() 30 | } 31 | } 32 | 33 | 34 | } // verus! 35 | -------------------------------------------------------------------------------- /extraction/src/owl_util.rs: -------------------------------------------------------------------------------- 1 | use rand::{distributions::Uniform, Rng}; 2 | use vstd::prelude::*; 3 | use libcrux::drbg::*; 4 | use libcrux::digest::Algorithm; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_rand_bytes(len: usize) -> Vec { 10 | let mut rng = Drbg::new(Algorithm::Sha256).unwrap(); 11 | rng.generate_vec(len).unwrap() 12 | } 13 | 14 | } // verus! 15 | -------------------------------------------------------------------------------- /hpke/owl-hpke/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | *.owl_config 4 | rust-toolchain.toml -------------------------------------------------------------------------------- /hpke/owl-hpke/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "owl-hpke" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | aead = {version = "0.5.1"} # , optional = true} 8 | aes-gcm = {version = "0.10.1"} # , optional = true} 9 | chacha20poly1305 = {version = "0.10.1"} # , optional = true} 10 | blake2 = {version = "0.10.6"} # , optional = true} 11 | crypto = "0.4.0" 12 | digest = "0.10.5" 13 | hkdf = "0.12.3" 14 | hmac = "0.12.1" 15 | p256 = { version = "0.11.1", features = ["ecdh", "bits", "serde"] } 16 | rand = "0.8.5" 17 | rsa = "0.7.2" 18 | sha1 = "0.10.5" 19 | sha2 = "0.10.6" 20 | libcrux = { git = "https://github.com/cryspen/libcrux", features = ["rand"] } 21 | serde = { version = "1.0", features = ["derive"] } 22 | serde_json = "1.0" 23 | x25519-dalek = { version = "2.0.0", features = ["static_secrets"] } 24 | vest = { git = "https://github.com/secure-foundations/vest", rev = "74bf5a7" } 25 | builtin = { git = "https://github.com/verus-lang/verus", branch = "main" } 26 | builtin_macros = { git = "https://github.com/verus-lang/verus", branch = "main" } 27 | vstd = { git = "https://github.com/verus-lang/verus", branch = "main" } 28 | hex = "0.4" 29 | 30 | [features] 31 | default = [] # ["nonverif-crypto"] 32 | nonverif-crypto = [] 33 | -------------------------------------------------------------------------------- /hpke/owl-hpke/src/owl_dhke.rs: -------------------------------------------------------------------------------- 1 | use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; 2 | use vstd::prelude::*; 3 | use libcrux::ecdh::*; 4 | use libcrux::drbg::*; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_ecdh_key_pair() -> (Vec, Vec) { 10 | #[cfg(feature = "nonverif-crypto")] 11 | { 12 | let mut rng = rand::thread_rng(); 13 | let secret = StaticSecret::random_from_rng(&mut rng); 14 | let public = PublicKey::from(&secret); 15 | let sk_bytes = secret.to_bytes().to_vec(); 16 | let pk_bytes = public.to_bytes().to_vec(); 17 | (sk_bytes, pk_bytes) 18 | } 19 | #[cfg(not(feature = "nonverif-crypto"))] 20 | { 21 | let mut rng = Drbg::new(libcrux::digest::Algorithm::Sha256).unwrap(); 22 | let (pk, sk) = x25519_key_gen(&mut rng).unwrap(); 23 | let pk_bytes = pk.0.to_vec(); 24 | let sk_bytes = sk.0.to_vec(); 25 | (sk_bytes, pk_bytes) 26 | } 27 | } 28 | 29 | #[verifier(external_body)] 30 | pub fn ecdh_dhpk(sk: &[u8]) -> Vec { 31 | #[cfg(feature = "nonverif-crypto")] 32 | { 33 | use std::convert::TryInto; 34 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 35 | let sk_decoded = StaticSecret::from(sk_length_checked); 36 | let pk = PublicKey::from(&sk_decoded); 37 | pk.to_bytes().to_vec() 38 | } 39 | #[cfg(not(feature = "nonverif-crypto"))] 40 | { 41 | secret_to_public(Algorithm::X25519, sk).unwrap() 42 | } 43 | } 44 | 45 | #[verifier(external_body)] 46 | pub fn ecdh_combine(sk: &[u8], others_pk: &[u8]) -> Vec { 47 | #[cfg(feature = "nonverif-crypto")] 48 | { 49 | use std::convert::TryInto; 50 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 51 | let pk_length_checked: [u8; 32] = others_pk.try_into().unwrap(); 52 | let sk_decoded = StaticSecret::from(sk_length_checked); 53 | let pk_decoded = PublicKey::from(pk_length_checked); 54 | let shared_secret = sk_decoded.diffie_hellman(&pk_decoded); 55 | shared_secret.as_bytes().to_vec() 56 | } 57 | #[cfg(not(feature = "nonverif-crypto"))] 58 | { 59 | derive(Algorithm::X25519, others_pk, sk).unwrap() 60 | } 61 | } 62 | 63 | } // verus! 64 | -------------------------------------------------------------------------------- /hpke/owl-hpke/src/owl_hkdf.rs: -------------------------------------------------------------------------------- 1 | use hkdf::Hkdf; 2 | use sha2::Sha256; 3 | use vstd::prelude::*; 4 | 5 | use libcrux::hkdf::*; 6 | 7 | verus! { 8 | 9 | pub open spec fn spec_kdfkey_size() -> usize { 32 } 10 | pub const fn kdfkey_size() -> (r:usize) ensures r == spec_kdfkey_size() { 32 } 11 | 12 | #[verifier(external_body)] 13 | pub fn gen_rand_kdf_key() -> Vec { 14 | crate::owl_util::gen_rand_bytes(kdfkey_size()) 15 | } 16 | 17 | #[verifier(external_body)] 18 | pub fn extract_expand_to_len(ikm: &[u8], salt: &[u8], info: &[u8], len: usize) -> Vec { 19 | #[cfg(feature = "nonverif-crypto")] 20 | { 21 | let h = Hkdf::::new(Some(salt), ikm); 22 | let mut okm = vec![0u8; len]; 23 | h.expand(info, &mut okm).expect("failed to expand"); 24 | okm 25 | } 26 | #[cfg(not(feature = "nonverif-crypto"))] 27 | { 28 | // support other algorithms here? 29 | libcrux::hkdf::hkdf(Algorithm::Sha256, salt, ikm, info, len).unwrap() 30 | } 31 | } 32 | 33 | 34 | } // verus! 35 | -------------------------------------------------------------------------------- /hpke/owl-hpke/src/owl_pke.rs: -------------------------------------------------------------------------------- 1 | use digest::Digest; 2 | use rsa::{ 3 | pkcs8::DecodePrivateKey, pkcs8::DecodePublicKey, pkcs8::EncodePrivateKey, 4 | pkcs8::EncodePublicKey, PaddingScheme, PublicKey, RsaPrivateKey, RsaPublicKey, 5 | }; 6 | use vstd::prelude::*; 7 | 8 | verus! { 9 | 10 | /* For PKE, we always use OAEP with SHA256 as the padding scheme, 11 | * and use PKCS#8 DER to encode/decode keys as byte vectors 12 | */ 13 | 14 | pub const PRIVATE_KEY_BITS: usize = 2048; 15 | 16 | #[verifier(external_body)] 17 | pub fn gen_rand_keys() -> (Vec, Vec) { 18 | let mut rng = rand::thread_rng(); 19 | let privkey = RsaPrivateKey::new(&mut rng, PRIVATE_KEY_BITS).unwrap(); 20 | let pubkey = RsaPublicKey::from(&privkey); 21 | let privkey_encoded: Vec = privkey.to_pkcs8_der().unwrap().as_bytes().to_vec(); 22 | let pubkey_encoded = pubkey.to_public_key_der().unwrap().to_vec(); 23 | (privkey_encoded, pubkey_encoded) 24 | } 25 | 26 | #[verifier(external_body)] 27 | pub fn encrypt(pubkey: &[u8], msg: &[u8]) -> Vec { 28 | let mut rng = rand::thread_rng(); 29 | let padding = PaddingScheme::new_oaep::(); 30 | let pubkey_decoded = RsaPublicKey::from_public_key_der(pubkey).unwrap(); 31 | pubkey_decoded.encrypt(&mut rng, padding, &msg[..]).unwrap() 32 | } 33 | 34 | #[verifier(external_body)] 35 | pub fn decrypt(privkey: &[u8], ctxt: &[u8]) -> Vec { 36 | let padding = PaddingScheme::new_oaep::(); 37 | let privkey_decoded = RsaPrivateKey::from_pkcs8_der(privkey).unwrap(); 38 | privkey_decoded.decrypt(padding, &ctxt[..]).unwrap() 39 | } 40 | 41 | #[verifier(external_body)] 42 | pub fn sign(privkey: &[u8], msg: &[u8]) -> Vec { 43 | let mut rng = rand::thread_rng(); 44 | let padding = PaddingScheme::new_pss::(); 45 | let privkey_decoded = RsaPrivateKey::from_pkcs8_der(privkey).unwrap(); 46 | privkey_decoded 47 | .sign_with_rng(&mut rng, padding, &sha2::Sha256::digest(&msg)) 48 | .unwrap() 49 | } 50 | 51 | #[verifier(external_body)] 52 | pub fn verify(pubkey: &[u8], signature: &[u8], msg: &[u8]) -> bool { 53 | let padding = PaddingScheme::new_pss::(); 54 | let pubkey_decoded = RsaPublicKey::from_public_key_der(pubkey).unwrap(); 55 | match pubkey_decoded.verify(padding, &sha2::Sha256::digest(&msg), &signature) { 56 | Ok(_) => true, 57 | Err(_) => false, 58 | } 59 | } 60 | 61 | } // verus! 62 | -------------------------------------------------------------------------------- /hpke/owl-hpke/src/owl_util.rs: -------------------------------------------------------------------------------- 1 | use rand::{distributions::Uniform, Rng}; 2 | use vstd::prelude::*; 3 | use libcrux::drbg::*; 4 | use libcrux::digest::Algorithm; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_rand_bytes(len: usize) -> Vec { 10 | let mut rng = Drbg::new(Algorithm::Sha256).unwrap(); 11 | rng.generate_vec(len).unwrap() 12 | } 13 | 14 | } // verus! 15 | -------------------------------------------------------------------------------- /hpke/rust-hpke/.clippy.toml: -------------------------------------------------------------------------------- 1 | type-complexity-threshold = 320 2 | -------------------------------------------------------------------------------- /hpke/rust-hpke/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /hpke/rust-hpke/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## Pending 8 | 9 | * Added `Serializable::write_exact` so serialization requires less stack space 10 | * Removed all impls of `serde::{Serialize, Deserailize}` from crate 11 | * Added support for the P-521 curve 12 | 13 | ## [0.11.0] - 2023-10-11 14 | 15 | ### Removals 16 | 17 | * Removed the redundant re-export of the first encapsulated key type as `kem::EncappedKey` 18 | 19 | ### Changes 20 | 21 | * Updated `x25519-dalek` to 2.0 22 | * Updated `subtle` to 2.5 23 | 24 | ## [0.10.0] - 2022-10-01 25 | 26 | ### Additions 27 | * Added `alloc` feature and feature-gated the `open()` and `seal()` methods behind it 28 | 29 | ### Changes 30 | * Bumped MSRV from 1.56.1 (`59eed8a2a` 2021-11-01) to 1.57.0 (`f1edd0429` 2021-11-29) 31 | * Updated dependencies and weakened `zeroize` dependency from `>=1.3` to just `^1` 32 | * Improved documentation for the AEAD `export()` method and the KDF `labeled_expand()` method 33 | 34 | ## [0.9.0] - 2022-05-04 35 | 36 | ### Additions 37 | * Refactored some internals so end users can theoretically define their own KEMs. See PR [#27](https://github.com/rozbb/rust-hpke/pull/27). 38 | 39 | ### Changes 40 | * Bumped MSRV from 1.51.0 (`2fd73fabe` 2021-03-23) to 1.56.1 (`59eed8a2a` 2021-11-01) 41 | * Updated dependencies 42 | -------------------------------------------------------------------------------- /hpke/rust-hpke/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Michael Rosenberg 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in 4 | compliance with the License. You may obtain a copy of the License at 5 | 6 | https://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 10 | implied. See the License for the specific language governing permissions and limitations under the 11 | License. 12 | -------------------------------------------------------------------------------- /hpke/rust-hpke/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Michael Rosenberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 6 | associated documentation files (the "Software"), to deal in the Software without restriction, 7 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 8 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial 12 | portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 15 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 16 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 17 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /hpke/rust-hpke/src/aead/aes_gcm.rs: -------------------------------------------------------------------------------- 1 | use crate::aead::Aead; 2 | 3 | /// The implementation of AES-128-GCM 4 | pub struct AesGcm128; 5 | 6 | impl Aead for AesGcm128 { 7 | type AeadImpl = aes_gcm::Aes128Gcm; 8 | 9 | // RFC 9180 §7.3: AES-128-GCM 10 | const AEAD_ID: u16 = 0x0001; 11 | } 12 | 13 | /// The implementation of AES-256-GCM 14 | pub struct AesGcm256 {} 15 | 16 | impl Aead for AesGcm256 { 17 | type AeadImpl = aes_gcm::Aes256Gcm; 18 | 19 | // RFC 9180 §7.3: AES-256-GCM 20 | const AEAD_ID: u16 = 0x0002; 21 | } 22 | -------------------------------------------------------------------------------- /hpke/rust-hpke/src/aead/chacha20_poly1305.rs: -------------------------------------------------------------------------------- 1 | use crate::aead::Aead; 2 | 3 | /// The implementation of ChaCha20-Poly1305 4 | pub struct ChaCha20Poly1305; 5 | 6 | impl Aead for ChaCha20Poly1305 { 7 | type AeadImpl = chacha20poly1305::ChaCha20Poly1305; 8 | 9 | // RFC 9180 §7.3: ChaCha20Poly1305 10 | const AEAD_ID: u16 = 0x0003; 11 | } 12 | -------------------------------------------------------------------------------- /hpke/rust-hpke/src/aead/export_only.rs: -------------------------------------------------------------------------------- 1 | use crate::aead::Aead; 2 | 3 | use aead::{ 4 | AeadCore as BaseAeadCore, AeadInPlace as BaseAeadInPlace, KeyInit as BaseKeyInit, 5 | KeySizeUser as BaseKeySizeUser, 6 | }; 7 | use generic_array::typenum; 8 | 9 | /// An inert underlying Aead implementation. The open/seal routines panic. The `new()` function 10 | /// returns an `EmptyAeadImpl`, and that is all of the functionality this struct has. 11 | #[doc(hidden)] 12 | #[derive(Clone)] 13 | pub struct EmptyAeadImpl; 14 | 15 | impl BaseAeadCore for EmptyAeadImpl { 16 | // The nonce size has to be bigger than the sequence size (currently u64), otherwise we get an 17 | // underflow error on seal()/open() before we can even panic 18 | type NonceSize = typenum::U128; 19 | type TagSize = typenum::U0; 20 | type CiphertextOverhead = typenum::U0; 21 | } 22 | 23 | impl BaseAeadInPlace for EmptyAeadImpl { 24 | fn encrypt_in_place_detached( 25 | &self, 26 | _: &aead::Nonce, 27 | _: &[u8], 28 | _: &mut [u8], 29 | ) -> Result, aead::Error> { 30 | panic!("Cannot encrypt with an export-only encryption context!"); 31 | } 32 | 33 | fn decrypt_in_place_detached( 34 | &self, 35 | _: &aead::Nonce, 36 | _: &[u8], 37 | _: &mut [u8], 38 | _: &aead::Tag, 39 | ) -> Result<(), aead::Error> { 40 | panic!("Cannot decrypt with an export-only encryption context!"); 41 | } 42 | } 43 | 44 | impl BaseKeySizeUser for EmptyAeadImpl { 45 | type KeySize = typenum::U0; 46 | } 47 | 48 | impl BaseKeyInit for EmptyAeadImpl { 49 | // Ignore the key, since we can't encrypt or decrypt anything anyway. Just return the object 50 | fn new(_: &aead::Key) -> Self { 51 | EmptyAeadImpl 52 | } 53 | } 54 | 55 | /// An AEAD which can **only** be used for its `export()` function. The `open()` and `seal()` 56 | /// methods on an `AeadCtxR` or `AeadCtxS` which uses this AEAD underlyingly **will panic** if you 57 | /// call them 58 | pub struct ExportOnlyAead; 59 | 60 | impl Aead for ExportOnlyAead { 61 | type AeadImpl = EmptyAeadImpl; 62 | 63 | // RFC 9180 §7.3: Export-only 64 | const AEAD_ID: u16 = 0xFFFF; 65 | } 66 | -------------------------------------------------------------------------------- /hpke/rust-hpke/src/dhkex.rs: -------------------------------------------------------------------------------- 1 | use crate::{kdf::Kdf as KdfTrait, util::KemSuiteId, Deserializable, Serializable}; 2 | 3 | use core::fmt::Debug; 4 | 5 | // This is the maximum value of all of Npk, Ndh, and Nenc. It's achieved by P-521 in RFC 9180 §7.1 6 | // Table 2. 7 | pub(crate) const MAX_PUBKEY_SIZE: usize = 133; 8 | 9 | #[doc(hidden)] 10 | /// Internal error type used to represent `DhKeyExchange::dh()` failing 11 | #[derive(Debug)] 12 | pub struct DhError; 13 | 14 | /// This trait captures the requirements of a Diffie-Hellman key exchange mechanism. It must have a 15 | /// way to generate keypairs, perform the Diffie-Hellman operation, and serialize/deserialize 16 | /// pubkeys. This is built into a KEM in `kem/dhkem.rs`. 17 | pub trait DhKeyExchange { 18 | /// The key exchange's public key type. If you want to generate a keypair, see 19 | /// `Kem::gen_keypair` or `Kem::derive_keypair` 20 | type PublicKey: Clone + Debug + PartialEq + Eq + Serializable + Deserializable; 21 | 22 | /// The key exchange's private key type. If you want to generate a keypair, see 23 | /// `Kem::gen_keypair` or `Kem::derive_keypair` 24 | type PrivateKey: Clone + Serializable + Deserializable; 25 | 26 | /// The result of a DH operation 27 | #[doc(hidden)] 28 | type KexResult: Serializable; 29 | 30 | /// Computes the public key of a given private key 31 | #[doc(hidden)] 32 | fn sk_to_pk(sk: &Self::PrivateKey) -> Self::PublicKey; 33 | 34 | /// Does the Diffie-Hellman operation 35 | #[doc(hidden)] 36 | fn dh(sk: &Self::PrivateKey, pk: &Self::PublicKey) -> Result; 37 | 38 | /// Computes a keypair given key material `ikm` of sufficient entropy. See 39 | /// [`crate::kem::Kem::derive_keypair`] for discussion of entropy. 40 | #[doc(hidden)] 41 | fn derive_keypair( 42 | suite_id: &KemSuiteId, 43 | ikm: &[u8], 44 | ) -> (Self::PrivateKey, Self::PublicKey); 45 | } 46 | 47 | #[cfg(any(feature = "p256", feature = "p384", feature = "p521"))] 48 | pub(crate) mod ecdh_nistp; 49 | 50 | #[cfg(feature = "x25519")] 51 | pub(crate) mod x25519; 52 | -------------------------------------------------------------------------------- /hpke/test_bench_hpke/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /hpke/test_bench_hpke/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_bench_hpke" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | owl-hpke = { path = "../owl-hpke" } 10 | hpke = { path = "../rust-hpke", features = ["std"] } 11 | rand = { version = "0.8", features = ["getrandom", "std_rng"] } 12 | hex = "0.4" 13 | 14 | 15 | [features] 16 | default = [] # ["nonverif-crypto"] 17 | nonverif-crypto = ["owl-hpke/nonverif-crypto"] 18 | 19 | [profile.release] 20 | debug = true 21 | opt-level = 3 22 | lto = "fat" 23 | codegen-units = 1 24 | 25 | [profile.bench] 26 | debug = true 27 | opt-level = 3 28 | lto = "fat" 29 | codegen-units = 1 30 | 31 | 32 | -------------------------------------------------------------------------------- /old.cabal.project.local: -------------------------------------------------------------------------------- 1 | profiling: True 2 | profiling-detail: all-functions 3 | -------------------------------------------------------------------------------- /tests/failure/bad_locality.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob 3 | 4 | name x : nonce @ bob 5 | 6 | def a () @ alice : Unit = 7 | let x = get(x) in 8 | () 9 | -------------------------------------------------------------------------------- /tests/failure/corr_enc_bad.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob 3 | 4 | name x : nonce @ alice 5 | name k : enckey Name(x) @ bob 6 | 7 | name skB : sigkey Name(k) @ bob 8 | 9 | def alice (vkB : vk(skB)) @ alice 10 | : Unit = 11 | input t in 12 | input m in 13 | let k' = m in // Using an adversarial key without verifying the signature 14 | let c = aenc(k', get(x)) in 15 | output c // Leaks x 16 | 17 | -------------------------------------------------------------------------------- /tests/failure/duplicateDef.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | def f1 () @ alice : Unit = () 4 | def f1 () @ alice : Unit = () 5 | -------------------------------------------------------------------------------- /tests/failure/inconclusive.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name n : nonce @ alice 4 | name k : enckey Name(n) @ alice 5 | 6 | def alice_main () @ alice : Unit = 7 | input i in 8 | case adec(get(k), i) { 9 | | Some m => () 10 | | None => () 11 | } 12 | -------------------------------------------------------------------------------- /tests/failure/parse_lengths_unparsable.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | name A : nonce @ alice 3 | name P : nonce @ alice 4 | name V : nonce @ alice 5 | 6 | struct q { 7 | u : Data, 8 | v : Name(V) 9 | } 10 | 11 | enum s { 12 | | P Name(P) 13 | | Q q 14 | | R Data 15 | } 16 | 17 | struct t { 18 | a : Name(A), 19 | b : Data | |enckey| |, 20 | c : Data | 4 |, 21 | s : s 22 | } 23 | 24 | def alice_main() @ alice : Unit = 25 | input i in 26 | parse i as t(a, b, c, s) in { 27 | // debug printTyOf(a); // Data ||nonce|| 28 | // debug printTyOf(s); // Data 29 | assert(length(a) == |nonce|); 30 | assert(length(b) == |enckey|); 31 | assert(length(c) == 4); 32 | case s as s { 33 | | P p => 34 | // debug printTyOf(p); // Data ||nonce|| 35 | assert(length(p) == |nonce|); () 36 | | Q q => 37 | // debug printTyOf(q); // Data 38 | parse q as q(u, v) in { 39 | assert(length(v) == |nonce|); // FAILS, since q is unparsable 40 | () 41 | } otherwise () 42 | | R r => () 43 | otherwise => () 44 | } 45 | } otherwise () -------------------------------------------------------------------------------- /tests/failure/pcCheck1.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name x : nonce @ alice 4 | 5 | enum t { 6 | | A 7 | | B 8 | } 9 | 10 | def alice () @ alice : t = 11 | if get(x) then A() else B() 12 | 13 | -------------------------------------------------------------------------------- /tests/failure/wrong_name.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | name x : DH @ alice 3 | name y : DH @ alice 4 | def alice () @ alice : Unit = 5 | let z : Name(y) = get(x) in 6 | Z () 7 | -------------------------------------------------------------------------------- /tests/should_fail/types.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | // TODO: currently loops 4 | type t 5 | type s = t 6 | 7 | type t = s 8 | 9 | def main(x : t) @ alice : Unit = 10 | let y : t = x in 11 | () 12 | 13 | -------------------------------------------------------------------------------- /tests/should_succeed/basic_hash.owl: -------------------------------------------------------------------------------- 1 | /* 2 | * Basic Hash (without indices - 1 reader and only 1 tag) 3 | * https://www.chatzi.org/papers/rfid_privacy.pdf 4 | * https://github.com/squirrel-prover/squirrel-prover/blob/master/examples/basic-hash.sp 5 | * 6 | * Protocol: 7 | * --------- 8 | * T -> R : 9 | * R -> T : ok 10 | */ 11 | 12 | locality T 13 | locality R 14 | 15 | name NT : nonce @ T 16 | corr adv ==> [NT] 17 | name K : mackey Name(NT) @ T, R 18 | 19 | struct s { 20 | _nT : Name(NT), 21 | _m : Data 22 | } 23 | 24 | def tag () @ T 25 | : Unit = 26 | let nT = get(NT) in 27 | let m = mac(get(K), nT) in 28 | output s(nT, m) 29 | 30 | enum reader_response { 31 | | Ok Name(NT) // don't need to include nT here, but just keeping this consistent with the indexed version 32 | | No 33 | } 34 | 35 | def reader () @ R 36 | : if sec(K) then reader_response else Data = 37 | input i in 38 | corr_case K in 39 | let nT = _nT(i) in 40 | let m = _m(i) in 41 | (case mac_vrfy(get(K), nT, m) 42 | | None => No() 43 | | Some m' => 44 | output Ok(m'); 45 | Ok(m') 46 | ) 47 | -------------------------------------------------------------------------------- /tests/should_succeed/dangling_path_var.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | module type S = { 4 | name x : nonce @ alice 5 | } 6 | 7 | module Srefined = { 8 | name x : nonce @ alice 9 | } 10 | 11 | module M = functor (X : S) => { 12 | module Z = X 13 | def alice_main() @ alice : Name(Z.x) = 14 | get(Z.x) 15 | } 16 | 17 | module Main = M(Srefined) 18 | 19 | // This should work 20 | /* def tst() @ alice : Name(Srefined.x) = 21 | call Main.alice_main() */ 22 | 23 | /* 24 | Expected output: 25 | 26 | 27 | defs = [ 28 | Top_Main_alice_main @ Top.alice : () -> Name(Top.Srefined.x) = 29 | get(Top.Srefined.x) 30 | ] 31 | 32 | nameEnv = [ 33 | Top_Srefined_x : nonce @ Top.alice 34 | ] 35 | 36 | */ 37 | -------------------------------------------------------------------------------- /tests/should_succeed/lak.owl: -------------------------------------------------------------------------------- 1 | /* 2 | * LAK 3 | * https://arxiv.org/pdf/1710.02049.pdf 4 | * https://pdfs.semanticscholar.org/d226/deb2b3b416716e3f5fdfe3083afa33ae8257.pdf 5 | * https://github.com/squirrel-prover/squirrel-prover/blob/master/examples/lak-tags-full-wa.sp 6 | * 7 | * Protocol: 8 | * -------- 9 | * R -> T: nr 10 | * T -> R: nT, h(, k) 11 | * R -> T: h(, k), nr, tag2>, k) 12 | */ 13 | 14 | locality T 15 | locality R 16 | 17 | name nT : nonce @ T 18 | name nR : nonce @ R 19 | 20 | struct m1 { // MAC'd by k 21 | m1_nr : Data, 22 | m1_nt : Data, 23 | m1_tag : Data 24 | } 25 | 26 | struct m2 { 27 | m2_nt : Data, 28 | m2_mac : Data 29 | } 30 | 31 | struct m3 { // MAC'd by k 32 | m3_mac : Data, // change to Data? 33 | // m3_nr : Name(nR), 34 | m3_nr : Data, 35 | m3_tag : Data 36 | } 37 | 38 | enum macd_by_k { 39 | | msg1 m1 40 | | msg2 m3 41 | // | msg2 (__m:m3{happened(tag())}) 42 | } 43 | 44 | name k : mackey macd_by_k @ T, R 45 | 46 | enum reader_response { 47 | | Ok 48 | | No 49 | } 50 | 51 | def reader ( 52 | tag1 : Data, // should be replaced with `exists` + table lookup 53 | tag2 : Data 54 | ) @ R 55 | requires [nR] <= adv 56 | : reader_response = 57 | let _ = output get(nR) in 58 | 59 | input i in 60 | let NT = m2_nt(i) in 61 | let mc = m2_mac(i) in 62 | let NR = get(nR) in 63 | let msg_to_mac_verify = msg1(m1(NR, NT, tag1)) in 64 | corr_case k in 65 | case mac_vrfy(get(k), msg_to_mac_verify, mc) 66 | | None => No() 67 | | Some m => 68 | let msg_to_mac = msg2(m3(i, NR, tag2)) in 69 | let _ = output mac(get(k), msg_to_mac) in 70 | Ok() 71 | 72 | def tag ( 73 | tag1 : Data 74 | ) @ T 75 | requires ([nT] <= adv) 76 | : Unit = 77 | input NR in 78 | let msg_to_mac = msg1(m1(NR, get(nT), tag1)) in 79 | let msg = mac(get(k), msg_to_mac) in 80 | output msg 81 | // let m = mac(get(k), get(nT)) in 82 | // output s(get(nT), m) 83 | -------------------------------------------------------------------------------- /tests/should_succeed/mod_alias.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | module M = { 4 | name k : nonce @ alice 5 | 6 | def alice_main() @ alice : Name(k) = 7 | get(k) 8 | } 9 | 10 | module N = M 11 | 12 | def tst () @ alice : Name(N.k) = 13 | get(N.k) 14 | 15 | /* 16 | Expected output: 17 | 18 | defs = [ 19 | Top_M_alice_main @ alice : () -> Name(Top.M.k) = 20 | get(Top.M.k) 21 | ] 22 | 23 | nameEnv = [ 24 | Top_M_k : nonce @ Top.alice 25 | ] 26 | 27 | */ 28 | -------------------------------------------------------------------------------- /tests/should_succeed/mw.owl: -------------------------------------------------------------------------------- 1 | /* 2 | * Protocol: 3 | * --------- 4 | * R --> T: nr 5 | * T --> R: nt, id + H(,k) 6 | * R --> T: id + H(,k) 7 | */ 8 | 9 | 10 | locality T 11 | locality R 12 | 13 | name NR : nonce @ R 14 | name NT : nonce @ T 15 | 16 | func xor 17 | arity 2 18 | 19 | 20 | struct h1_t { 21 | h1_c : Data, 22 | h1_nr : Data, 23 | h1_nt : Data 24 | } 25 | 26 | name K : mackey h1_t @ T, R 27 | 28 | struct m1_t { 29 | m1_nt : Data, 30 | m1_xormac : Data 31 | } 32 | 33 | // table keys : adv -> (exists i. Name>) @ R 34 | 35 | def reader() @ R 36 | requires [NR] <= adv 37 | : Unit = 38 | let nR = get(NR) in 39 | let _ = output(nR) in 40 | 41 | input inp in 42 | let nT = m1_nt(inp) in 43 | let mc = m1_xormac(inp) in 44 | 45 | () 46 | 47 | def tag (id: Data, c0: Data) @ T 48 | : Unit = 49 | input inp in 50 | let nT = get(NT) in 51 | let msg_to_mac = h1_t(c0, inp, nT) in 52 | let m = mac(get(K), msg_to_mac) in 53 | let x = xor(id, m) in 54 | output m1_t(nT, x) 55 | -------------------------------------------------------------------------------- /tests/should_succeed/struct_resolution.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | module M = { 4 | name k : nonce @ alice 5 | struct s { 6 | _x : Name(k) 7 | } 8 | 9 | def alice_main() @ alice : s = 10 | s(get(k)) 11 | } 12 | 13 | /* 14 | Expected output: 15 | 16 | defs = [ 17 | Top_M_alice_main @ alice : () -> Top.M.s = 18 | Top.M.s(get(Top.M.k)) 19 | ] 20 | 21 | nameEnv = [ 22 | Top_M_k : nonce @ Top.alice 23 | ] 24 | 25 | */ -------------------------------------------------------------------------------- /tests/should_succeed/subtyping.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | def main(b : Bool)@alice : Unit = 4 | if b then 5 | assert(b = true) 6 | else 7 | () 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/success/abstract_ty.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | type t 4 | 5 | name k : enckey t @ alice 6 | 7 | def alice_main() @ alice : Unit = 8 | input inp in 9 | corr_case k in 10 | case adec(get(k), inp) { 11 | | None => () 12 | | Some j => 13 | let r : if sec(k) then t else Data = j in 14 | () 15 | } 16 | -------------------------------------------------------------------------------- /tests/success/abstractdefs.owl: -------------------------------------------------------------------------------- 1 | // Just stealing from encrypted_key.owl 2 | 3 | locality alice 4 | locality bob 5 | 6 | 7 | def alice_main @ alice 8 | def bob_main @ bob 9 | 10 | name x : nonce @ bob 11 | name k_data : enckey (z:Name(x){happened(bob_main())}) @ alice 12 | name shared_key : enckey (z:Name(k_data){happened(alice_main())}) @ alice, bob 13 | 14 | enum Result { 15 | | SomeResult Name(x) 16 | | NoResult 17 | } 18 | 19 | def alice_main () @ alice 20 | : if sec(k_data) then x:Result{(SomeResult?(x) /\ sec(k_data)) ==> happened(bob_main())} else Data 21 | 22 | def bob_main () @ bob 23 | : x:Bool{(x /\ sec(shared_key)) ==> happened(alice_main()) } 24 | 25 | def alice_main () @ alice 26 | : if sec(k_data) then x:Result{(SomeResult?(x) /\ sec(k_data)) ==> happened(bob_main())} else Data = 27 | let c = aenc(get(shared_key), get(k_data)) in 28 | let _ = output c to endpoint(bob) in 29 | input i, _ in 30 | corr_case k_data in 31 | case adec(get(k_data), i) { 32 | | Some j => 33 | assert(sec(k_data) ==> happened(bob_main())); 34 | SomeResult(j) 35 | | None => NoResult() 36 | } 37 | 38 | 39 | def bob_main () @ bob 40 | : x:Bool{(x /\ sec(shared_key)) ==> happened(alice_main()) } = 41 | input i, _ in 42 | // i : Data 43 | corr_case shared_key in 44 | case adec(get(shared_key), i) { 45 | | Some k => 46 | assert (sec(shared_key) ==> happened(alice_main())); 47 | let c = aenc(k, get(x)) in 48 | output c to endpoint(alice); 49 | true 50 | | None => false 51 | } 52 | 53 | -------------------------------------------------------------------------------- /tests/success/aead_ctr.owl: -------------------------------------------------------------------------------- 1 | locality alice : 1 2 | locality bob : 1 3 | 4 | // func f 5 | // arity 0 6 | 7 | name X<@i> : nonce @ alice 8 | name aad_val<@i> : nonce @ alice 9 | corr adv ==> [aad_val<@i>] 10 | counter N<@i> @ alice 11 | counter M<@i> @ bob 12 | name k<@i> : st_aead Name(X<@i>) 13 | aad x. (x == get(aad_val<@i>)) 14 | nonce N 15 | @ alice 16 | 17 | struct dummy_struct { 18 | _dummy_tag : Const(0xdeadbeef) 19 | , _dummy_val : Data 20 | } 21 | 22 | func get_dummy_tag() = 0xdeadbeef 23 | 24 | def alice_main<@i>() @ alice : Unit = 25 | inc_counter N<@i>; 26 | let x = get_counter N<@i> in 27 | assert (aad(k<@i>)[get(aad_val<@i>)]); 28 | let c = st_aead_enc>(get(k<@i>), get(X<@i>), get(aad_val<@i>)) in 29 | let hash_something = crh(0xdeadbeef) in 30 | let dummy_tag = get_dummy_tag() in 31 | let hash_something_else = crh(0xfeedface) in 32 | let dummy = dummy_struct(dummy_tag, c) in 33 | let hash_yet_something_else = crh(0xfeedfacedeadbeef) in 34 | output dummy to endpoint(alice); 35 | corr_case k<@i> in 36 | input h in 37 | case st_aead_dec(get(k<@i>), c, h, x) { 38 | | None => () 39 | | Some _y => 40 | let y : if sec(k<@i>) then (_:Name(X<@i>){h == get(aad_val<@i>)}) else Data = _y in 41 | () 42 | } 43 | 44 | def bob_main<@i>() @ bob : Unit = () 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /tests/success/apex_example.owl: -------------------------------------------------------------------------------- 1 | locality Alice 2 | locality Bob 3 | name channel_secret : nonce 4 | type plaintext = Data<[channel_secret] /\ adv, |adv|> 5 | counter ACtr @ Alice 6 | counter BCtr @ Bob 7 | def alice_send(m : plaintext) @ Alice : Unit 8 | def bob_send(m : plaintext) @ Bob : Unit 9 | name kA2B : st_aead (x:plaintext{happened(alice_send(x))}) 10 | aad x. true 11 | nonce ACtr @ Alice, Bob 12 | name kB2A : st_aead (x:plaintext{happened(bob_send(x))}) 13 | aad x. true 14 | nonce BCtr @ Alice, Bob 15 | 16 | struct EncMsg { 17 | ctr : Data ||counter||, 18 | cipher : Data 19 | } 20 | 21 | def alice_send(m : plaintext) @ Alice : Unit = { 22 | let send_key = get(kA2B) in 23 | let ctr = get_counter ACtr in 24 | let c = st_aead_enc(send_key, m, 0x) in 25 | output EncMsg(ctr, c) to endpoint(Bob) 26 | } 27 | 28 | 29 | def alice_recv() @ Alice : Option (if sec(kB2A) then (m:plaintext{happened(bob_send(m))}) else Data) = { 30 | input i in 31 | parse i as EncMsg(ctr, c) in { 32 | let recv_key = get(kB2A) in 33 | corr_case kB2A in 34 | st_aead_dec(recv_key, c, 0x, ctr) 35 | } 36 | otherwise { None() } 37 | } 38 | -------------------------------------------------------------------------------- /tests/success/arith.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | struct t { 4 | x : Data | |nonce| |, 5 | y : Data | |nonce| |, 6 | z : Data | |nonce| | 7 | } 8 | 9 | def amain (a : t) @ alice : Unit = 10 | assert |nonce| == |nonce|; 11 | assert 2 + 3 == 5; 12 | assert 2 * (3 + 4) == 14; 13 | assert |nonce| + |nonce| == 2 * |nonce|; 14 | assert zero() == 0; 15 | parse a as t(x', y', z') in 16 | let a' = t(x', y', z') in 17 | assert (length(a') == |nonce| + |nonce| + |nonce|); 18 | assert (length(a') == 3 * |nonce|); 19 | 20 | /* 21 | TODO: the below assertion only works with the above junk 22 | */ 23 | assert (length(a) == 3 * |nonce|); 24 | () 25 | -------------------------------------------------------------------------------- /tests/success/basic_auth.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob 3 | 4 | name nA : nonce @ alice 5 | name k : enckey Name(nA) @ alice, bob 6 | -------------------------------------------------------------------------------- /tests/success/basics.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob 3 | name x : nonce @ alice 4 | name y : nonce @ alice 5 | type t = Name(x) 6 | name k : enckey t @ alice 7 | 8 | name n : nonce @ bob 9 | name skB : sigkey Name(n) @ bob 10 | 11 | func parse 12 | arity 1 13 | 14 | def alice1 () @ alice : Data = 15 | input i, s1 in 16 | let c1 = aenc(get(k), get(x)) in 17 | let _ = output c1 in 18 | corr_case k in 19 | let c : if sec(k) then Option t else Option Data = adec(get(k), parse(i)) in 20 | case c { 21 | | Some x => 22 | let res : Data = () in res 23 | | None => 24 | let res : Data = () in res 25 | } 26 | 27 | def tst_constants() @ alice : Unit = 28 | let x = 0 in 29 | let y = 012 in 30 | let z = 0xabcd in 31 | let w = 0xdeadbeef in 32 | let a = 0x in 33 | () 34 | 35 | def alice2 (vk : vk(skB)) @ alice : Data = 36 | input t, _ in 37 | input m, _ in 38 | corr_case skB in 39 | case vrfy(vk, t, m) { 40 | | None => () 41 | | Some m' => 42 | let m'' : if sec(skB) then Name(n) else Data = m' in 43 | () 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /tests/success/bool.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name n : nonce @ alice 4 | name m : nonce @ alice 5 | // So the below equality checks work 6 | corr adv ==> [n] 7 | corr adv ==> [m] 8 | 9 | func f 10 | arity 0 11 | 12 | def alice(x : Bool) @ alice : Unit = 13 | (if f() then 14 | assert (f () == true); () 15 | else 16 | assert (! (f () == true)); () 17 | ); 18 | (if x then 19 | assert (x == true); () 20 | else 21 | assert (x == false); () 22 | ); 23 | (if eq(get(n), get(m)) then 24 | assert (False); () 25 | else 26 | assert (! (get(n) == get(m))); () 27 | ) 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/success/call.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name d : nonce @ alice 4 | name k : enckey Name(d) @ alice 5 | name blah : nonce @ alice 6 | 7 | def alice1 (b: Name(blah)) @ alice : Name(d) 8 | = get(d) 9 | 10 | def alice2 @ alice 11 | 12 | def alice2 () @ alice : Unit 13 | = 14 | assert (happened(alice2())); 15 | let x = call alice1(get(blah)) in 16 | assert (happened(alice1(get(blah)))); 17 | let c = aenc(get(k), x) in 18 | output c to endpoint(alice) 19 | 20 | def alice_main () @ alice : Unit = 21 | call alice2() -------------------------------------------------------------------------------- /tests/success/checknonce.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name n : nonce @ alice 4 | name m : nonce @ alice 5 | 6 | def alice() @ alice : Unit = 7 | let ni = get(n) in 8 | let nj = get(n) in 9 | pcase (i =idx j) in 10 | let b = checknonce(ni, nj) in 11 | if b then 12 | assert (i =idx j); 13 | let mj : Name(m) = get(m) in 14 | () 15 | else () 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/success/corr_enc.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob 3 | 4 | name x : nonce @ alice 5 | name k : enckey Name(x) @ bob 6 | 7 | name skB : sigkey Name(k) @ bob 8 | 9 | def alice (vkB : vk(skB)) @ alice 10 | : Unit = 11 | input t, _ in 12 | input m, _ in 13 | corr_case skB in 14 | case vrfy(vkB, t, m) { 15 | | Some k' => 16 | let k'' : if sec(skB) then Name(k) else Data = k' in 17 | let c : if sec(skB) then Data else Data = aenc(k'', get(x)) in 18 | output c 19 | | None => () 20 | } 21 | 22 | -------------------------------------------------------------------------------- /tests/success/corrdecl.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name n : nonce @ alice 4 | name m : nonce @ alice 5 | 6 | corr adv ==> [n] 7 | corr adv ==> /\_i [m] 8 | 9 | def alice() @ alice : Unit = 10 | output get(n); 11 | output (get(m)); 12 | () 13 | -------------------------------------------------------------------------------- /tests/success/crh.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | def tst(a : Data, b : Data, c : Data, d : Data) @ alice : Unit = 4 | let h1 = crh(crh(a) ++ b) in 5 | let h2 = crh(crh(c) ++ d) in 6 | crh_lemma(h1, h2); 7 | assert (h1 == h2 ==> a == c /\ b == d) 8 | 9 | -------------------------------------------------------------------------------- /tests/success/debug.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | func f 3 | arity 0 4 | def debugTest (y : (y:Unit{True})) @ alice : Unit = 5 | let z : (x:Unit{x == f()}) = admit in 6 | if f() then 7 | debug printTyContext 8 | else 9 | debug printTyContext 10 | -------------------------------------------------------------------------------- /tests/success/dep_enum.owl: -------------------------------------------------------------------------------- 1 | locality Server 2 | 3 | name X : nonce @ Server 4 | name K : enckey Name(X) @ Server 5 | 6 | enum ServerSt { 7 | | NoEncrypt 8 | | Encrypt Name(K) 9 | } 10 | 11 | def go(st : ServerSt, m : if NoEncrypt?(st) then Data else Name(X)) @ 12 | Server : Unit = 13 | case st { 14 | | NoEncrypt => output m 15 | | Encrypt k => let c = aenc(k, m) in output c 16 | } 17 | -------------------------------------------------------------------------------- /tests/success/double_index.owl: -------------------------------------------------------------------------------- 1 | locality A 2 | 3 | name N : nonce @ A 4 | name M : nonce @ A 5 | 6 | name K : enckey (exists i. exists j. Name(N)) @ A 7 | 8 | 9 | def alice() @ A : Unit = 10 | assert (/\_i /\_j [N] <= /\_j /\_i [N]); 11 | assert (/\_i /\_j [M] <= /\_i [M]); 12 | assert (/\_i /\_j ([N] /\ [M] /\ [M]) 13 | <= 14 | (/\_i /\_j [N]) 15 | /\ 16 | (/\_i [M])); 17 | () 18 | 19 | def bob() @ A 20 | : Unit = 21 | input inp in 22 | let k = get(K) in 23 | corr_case K in 24 | case adec(k, inp) { 25 | | None => () 26 | | Some r => 27 | unpack j1, r' = r in 28 | let x2: if sec(K) then (exists i. Name(N)) else Data = r' in 29 | unpack j2, r'' = r' in 30 | let x3: if sec(K) then Name(N) else Data = r'' in 31 | () 32 | } 33 | -------------------------------------------------------------------------------- /tests/success/easy_call.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name d : nonce @ alice 4 | name k : enckey Name(d) @ alice 5 | name blah : nonce @ alice 6 | corr adv ==> [blah] 7 | 8 | def alice1 (b: Name(blah)) @ alice : Option(Data) = 9 | let k = get(k) in 10 | let d = get(d) in 11 | let c = aenc(k, d) in 12 | Some(c) 13 | 14 | def alice2 @ alice 15 | 16 | def alice2 () @ alice : Unit 17 | = 18 | input i in 19 | if eq(i, get(blah)) then 20 | let x = call alice1(i) in 21 | case x { 22 | | Some y => output y to endpoint(alice) 23 | | None => () 24 | } 25 | else () 26 | 27 | def alice_main () @ alice : Unit = 28 | call alice2() -------------------------------------------------------------------------------- /tests/success/encrypted_key.owl: -------------------------------------------------------------------------------- 1 | /* 2 | A, B already have key k 3 | 4 | A -> B : {k_data}_k 5 | 6 | B -> A : {x}_(k_data) 7 | 8 | A : retrieve x 9 | 10 | 11 | label ::= 12 | [k] | 13 | label /\ label | 14 | public | 15 | adv 16 | 17 | 18 | k 19 | | 20 | | 21 | k_data 22 | | 23 | | 24 | x 25 | 26 | 27 | k : enckey t c : adv [k] !<= adv 28 | ------------------------------- 29 | adec(k, c) : option t 30 | 31 | 32 | 33 | k : enckey t c : adv [k] <= adv 34 | ------------------------------- 35 | adec(k, c) : option adv 36 | 37 | 38 | */ 39 | 40 | locality alice 41 | locality bob 42 | 43 | def bob_main @ bob 44 | 45 | def alice_main @ alice 46 | 47 | name x : nonce @ bob 48 | name k_data : enckey (z:Name(x){happened(bob_main())}) @ alice 49 | name shared_key : enckey (z:Name(k_data){happened(alice_main())}) @ alice, bob 50 | 51 | enum Result { 52 | | SomeResult Name(x) 53 | | NoResult 54 | } 55 | 56 | def alice_main () @ alice 57 | : if sec(k_data) then (x:Result{(SomeResult?(x) /\ sec(k_data)) ==> happened(bob_main())}) else Data = 58 | let c = aenc(get(shared_key), get(k_data)) in 59 | let _ = output c to endpoint(bob) in 60 | input i, _ in 61 | corr_case k_data in 62 | case adec(get(k_data), i) { 63 | | Some j => 64 | assert(sec(k_data) ==> happened(bob_main())); 65 | SomeResult(j) 66 | | None => NoResult() 67 | } 68 | 69 | def bob_main () @ bob 70 | : x:Bool{(x /\ sec(shared_key)) ==> happened(alice_main()) } = 71 | input i, _ in 72 | // i : Data 73 | corr_case shared_key in 74 | case adec(get(shared_key), i) { 75 | | Some k => 76 | assert (sec(shared_key) ==> happened(alice_main())); 77 | let c = aenc(k, get(x)) in 78 | output c to endpoint(alice); 79 | true 80 | | None => false 81 | } 82 | 83 | 84 | -------------------------------------------------------------------------------- /tests/success/encrypted_key_indexed.owl: -------------------------------------------------------------------------------- 1 | /* 2 | A, B already have key k 3 | 4 | On round i: 5 | A -> B : {i, k_data_i}_k 6 | 7 | B -> A : {x_i}_(k_data_i) 8 | 9 | A : retrieve x_i 10 | */ 11 | 12 | locality alice 13 | locality bob 14 | 15 | def bob @ bob 16 | 17 | name x : nonce @ bob 18 | name k_data : enckey (exists i. x:Name(x){happened(bob())}) @ alice 19 | name shared_key : enckey (Name(k_data)) @ alice, bob 20 | 21 | enum Result { 22 | | Ok (exists i. Name(x)) 23 | | Err 24 | } 25 | 26 | def alice () @ alice 27 | : if sec(k_data) then Result else Data = 28 | let c = aenc(get(shared_key), get(k_data)) in 29 | let _ = output c in 30 | input i in 31 | corr_case k_data in 32 | case adec(get(k_data), i) { 33 | | Some j => Ok(j) 34 | | None => Err() 35 | } 36 | 37 | def bob () @ bob 38 | : Unit = 39 | input i in 40 | corr_case shared_key in 41 | case adec(get(shared_key), i) { 42 | | Some k => 43 | let msg : x:Name(x){happened(bob())} = get(x) in 44 | let msg = pack(msg) in 45 | let c = aenc(k, msg) in 46 | output c 47 | | None => () 48 | } 49 | -------------------------------------------------------------------------------- /tests/success/encrypted_key_struct.owl: -------------------------------------------------------------------------------- 1 | /* 2 | A, B already have key k 3 | 4 | A -> B : {k_data}_k 5 | 6 | B -> A : {t}_(k_data) 7 | 8 | A : retrieve t._y 9 | */ 10 | 11 | 12 | locality alice 13 | locality bob 14 | name x : nonce @ bob 15 | name y : nonce @ bob 16 | struct t { 17 | _x: Name(x), 18 | _y: Name(y) 19 | } 20 | name k_data : enckey t @ alice 21 | name shared_key : enckey Name(k_data) @ alice, bob 22 | 23 | enum Result { 24 | | SomeResult Name(y) 25 | | NoResult 26 | } 27 | 28 | def alice_main () @ alice 29 | : if sec(k_data) then Result else Data = 30 | let c = aenc(get(shared_key), get(k_data)) in 31 | let _ = output c to endpoint(bob) in 32 | input i in 33 | corr_case k_data in 34 | case adec(get(k_data), i) { 35 | | Some j => 36 | parse j as t(x, y) in SomeResult(y) 37 | otherwise NoResult() 38 | | None => NoResult() 39 | } 40 | 41 | def bob_main () @ bob 42 | : Unit = 43 | input i, ev in 44 | // i : Data 45 | corr_case shared_key in 46 | case adec(get(shared_key), i) { 47 | | Some k => 48 | let foo = t(get(x), get(y)) in 49 | let c = aenc(k, foo) in 50 | output c to ev 51 | | None => () 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /tests/success/enum_parsing_example.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name A : nonce @ alice 4 | corr adv ==> [A] 5 | name B : nonce @ alice 6 | corr adv ==> [B] 7 | 8 | enum s { 9 | | a Name(A) 10 | | b Name(B) 11 | } 12 | 13 | name k : enckey s @ alice 14 | 15 | def alice_main() @ alice : Unit = 16 | input i in 17 | corr_case k in 18 | case adec(get(k), i) { 19 | | Some p => 20 | case p as s { 21 | | a aa => output aa to endpoint(alice) 22 | | b bb => output bb to endpoint(alice) 23 | otherwise => () 24 | } 25 | | None => () 26 | } 27 | -------------------------------------------------------------------------------- /tests/success/enumlength.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | 4 | enum tst { 5 | | A Data | |nonce| | 6 | | B 7 | } 8 | 9 | name k : enckey tst @ alice 10 | 11 | def alice_main(x : Data | |nonce| |, y : Data | |enckey| |) @ alice : Unit = 12 | let a = A(x) in 13 | assert (length(a) == plus(|nonce|, |tag|)); 14 | let c = aenc(get(k), a) in 15 | assert (length(c) == cipherlen(plus(|nonce|, |tag|))); 16 | () 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/success/enums.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name x : nonce @ alice 4 | name y : nonce @ alice 5 | 6 | enum t { 7 | | A Name(x) 8 | | B Name(y) 9 | | C 10 | } 11 | 12 | def alice (x : t) @ alice : Unit = 13 | assert ((A?(x) == true) \/ (B?(x) == true) \/ (C?(x) == true)); 14 | assert (! (A?(x) == true /\ B?(x) == true)); 15 | assert (! (B?(x) == true /\ C?(x) == true)); 16 | assert (! (A?(x) == true /\ C?(x) == true)); 17 | let z = C() in 18 | assert (C?(z) == true); 19 | // TODO: make the below work 20 | assert (A?(z) == false); 21 | () 22 | 23 | def alice2 (x : Bool) @ alice : Unit = 24 | assert (x == true \/ x == false); 25 | assert (! (x == true /\ x == false)) 26 | 27 | def alice3(x : t) @ alice : Unit = 28 | case x { 29 | | A a => { 30 | assert (A?(x)); 31 | assert (!B?(x)); 32 | () 33 | } 34 | | B b => () 35 | | C => () 36 | } 37 | -------------------------------------------------------------------------------- /tests/success/fancy_struct.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | name X : nonce @ alice 3 | name P : nonce @ alice 4 | name Q : nonce @ alice 5 | name R : nonce @ alice 6 | 7 | enum z_enum { 8 | | P Name(P) 9 | | Q Name(Q) 10 | | R 11 | } 12 | 13 | struct s { 14 | _r : Name(R), 15 | _p : Name(P) 16 | } 17 | 18 | struct t { 19 | _x : Name(X), 20 | _y : Data ||nonce||, 21 | // _z : z_enum, 22 | _s : s 23 | } 24 | 25 | def main(x : t) @ alice : Unit = 26 | assert True 27 | -------------------------------------------------------------------------------- /tests/success/guard.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | name n : nonce @ alice 3 | 4 | def main() @ alice : Option Bool = 5 | input i in 6 | guard eq(i, 1) in 7 | Some(true) 8 | -------------------------------------------------------------------------------- /tests/success/idx_locality.owl: -------------------------------------------------------------------------------- 1 | // A locality parameterized by a party ID 2 | locality alice : 1 3 | locality bob 4 | // A name parameterized by a single session ID 5 | name nB : nonce @ bob 6 | // A name parameterized by a session ID and a party ID. The party ID is in scope 7 | // for the relevant localities 8 | name nA : nonce @ alice 9 | 10 | name nnA<@j> : nonce @ alice 11 | 12 | // The below fails, due to using a session ID as a party ID for alice: 13 | // name nA : nonce @ alice 14 | 15 | // The following typechecks, but bob won't really be able to use m unless 16 | // the def has those as parameters 17 | name m<@j> : nonce @ alice, bob 18 | 19 | // Below, i and j have type Ghost. Ghost indices can be used either as session 20 | // IDs or party IDs 21 | struct t { 22 | _a : Name(nA) 23 | // _b : Data 24 | } 25 | 26 | def sub() @ alice : Unit = () 27 | 28 | // Below, i is a session ID, j is a party ID 29 | def alice_main() @ alice : Unit = 30 | let x = get(nA) in 31 | let xx = get(nA) in 32 | // The below fails: 33 | // let x = get(nA) in 34 | // Both kinds of indices can be quantified over 35 | let t : exists j. Name(nA) = pack(x) in 36 | let t : exists k. Name(nA) = pack(xx) in 37 | input inp in 38 | let y : t = t(x) in 39 | let z = call sub() in 40 | () 41 | 42 | def bob_main<@j>() @ bob : Unit = 43 | // let y = get(m<@j>) in 44 | () -------------------------------------------------------------------------------- /tests/success/ifcond.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name n : nonce @ alice 4 | 5 | def main() @ alice : Unit = 6 | let x = get(n) in 7 | input i in 8 | let b = checknonce(x, i) in 9 | if b then 10 | assert ([n] <= adv); 11 | () 12 | else () 13 | 14 | def main2() @ alice : Unit = 15 | let x = get(n) in 16 | input i in 17 | if checknonce(x, i) then 18 | assert ([n] <= adv); 19 | () 20 | else () 21 | -------------------------------------------------------------------------------- /tests/success/indices/indices.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name d : nonce @ alice 4 | name dk : enckey Data<[d], |static|> @ alice 5 | 6 | name d2 : nonce @ alice 7 | name mk : enckey (exists i. Name(dk)) @ alice 8 | 9 | def alice () @ alice 10 | : Unit = 11 | assert (/\_i [dk] <= [mk]); 12 | assert (/\_i ([dk] /\ [d]) <= (/\_i [dk] ) /\ (/\_i [d])); 13 | let m = pack(get(dk)) in 14 | let c = aenc(get(mk), m) in 15 | output c 16 | 17 | def alice3 () @ alice : Name(dk) = 18 | get(dk) 19 | 20 | def alice2() @ alice 21 | : Unit = 22 | let _ = assume(i =idx j) in 23 | let x : Name(d) = get(d) in () 24 | -------------------------------------------------------------------------------- /tests/success/indices/mac_indices.owl: -------------------------------------------------------------------------------- 1 | locality A 2 | locality B 3 | 4 | name nA : nonce @ A 5 | name k : mackey (exists i. Name(nA)) @ A, B 6 | 7 | def alice () @ A 8 | requires corr(nA) 9 | /\ (/\_i [nA] <= adv) 10 | : Unit = 11 | let nA = get(nA) in 12 | let m = pack(nA) in 13 | let t = mac(get(k), m) in 14 | output concat(nA, t) 15 | -------------------------------------------------------------------------------- /tests/success/infer.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name n : nonce @ alice 4 | name k : enckey Name(n) @ alice 5 | 6 | // Both subtype to unit 7 | def main(b : Bool)@alice : Unit = 8 | if b then 9 | assert(b == true) 10 | else 11 | () 12 | 13 | 14 | def main2(x : Data) @ alice : Option (if sec(k) then Name(n) else Data) = 15 | corr_case k in 16 | adec(get(k), x) 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/success/kdf-corr.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name d : nonce @ alice 4 | name k : kdf {ikm info. 5 | True -> strict kdf {ikm2 info2. 6 | True -> enckey Name(d) 7 | } 8 | } @ alice 9 | 10 | name f : dualkdf {salt info. 11 | True -> strict kdf {ikm2 info2. 12 | True -> enckey Name(d) 13 | } 14 | } @ alice 15 | 16 | corr [k] /\ [f] ==> [d] 17 | 18 | def main() @ alice : (x:Unit{corr(k) /\ corr(f) ==> corr(d)}) = 19 | corr_case k in 20 | corr_case f in 21 | let k2 = kdf<0;0;kdfkey;0>(get(k), get(f), 0x) in 22 | let ek = kdf<0;;enckey;0>(k2, 0x, 0x) in 23 | let c = aenc(ek, get(d)) in 24 | output c 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/success/kdf-enc.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob 3 | 4 | /* 5 | name alice : nonce @ alice 6 | */ 7 | 8 | name alice1 : nonce @ alice 9 | name alice2 : nonce @ alice 10 | name alice3 : nonce @ alice 11 | 12 | // hack so vest doesn't complain 13 | struct s { 14 | _a : Data ||nonce||, 15 | _b : Data ||nonce|| 16 | } 17 | 18 | name k : kdf {ikm info. 19 | (info == 0x01) -> enckey Name(alice1), 20 | (info == 0x02) -> strict kdf {ikm info. 21 | (info == 0x01) -> enckey Name(alice2), 22 | (info == 0x02) -> kdf {ikm info. 23 | (info == 0x01) -> enckey Name(alice3) 24 | } 25 | } 26 | } @ alice, bob 27 | 28 | corr [k] ==> [alice1] 29 | corr [k] ==> [alice2] 30 | 31 | // This is just a hack for extraction to test slicing the KDF output 32 | // It's not supposed to mean anything cryptographically 33 | name kk : kdf {ikm info. 34 | True -> strict (nonce) || nonce 35 | } @ bob 36 | corr adv ==> [kk] 37 | 38 | def alice_main() @ alice : Unit = 39 | // corr_case k in 40 | let ek = kdf<0;;enckey;0>(get(k), 0x, 0x01) in 41 | // assert (corr(k) ==> corr(KDF(0x, 0x01)[0])); 42 | let c = aenc(ek, get(alice1)) in 43 | output c to endpoint(bob); 44 | let k2 = kdf<1;;kdfkey;0>(get(k), 0x, 0x02) in 45 | let ek2 = kdf<0;;enckey;0>(k2, 0x, 0x01) in 46 | let c2 = aenc(ek2, get(alice2)) in 47 | output c2 to endpoint(bob); 48 | () 49 | 50 | def bob_main() @ bob : Unit = 51 | let k1 = kdf<0;; nonce || nonce; 0>(get(kk), 0x, 0x) in 52 | let k2 = kdf<0;; nonce || nonce; 1>(get(kk), 0x, 0x) in 53 | () 54 | 55 | /* 56 | def bob_main() @ bob : Unit = 57 | input c1 in 58 | corr_case k1 in 59 | case adec(get(k1), c1) { 60 | | None => () 61 | | Some m1 => 62 | input c2 in 63 | let k2 = hash(get(k1)) in 64 | corr_case k2 in 65 | case adec(k2, c2) { 66 | | None => () 67 | | Some m2 => 68 | input c3 in 69 | let k3 = hash(k2) in 70 | corr_case k3 in 71 | case adec(k3, c3) { 72 | | None => () 73 | | Some m3 => 74 | assert (sec(k3) ==> sec(k2)); 75 | assert (sec(k2) ==> (m1 == get(alice1) /\ m2 == get(alice2))); 76 | assert (sec(k1) ==> (m1 == get(alice1))); 77 | () 78 | } 79 | } 80 | } 81 | */ 82 | 83 | 84 | -------------------------------------------------------------------------------- /tests/success/kdf-self.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name alice_secret : nonce @ alice 4 | 5 | counter C @ alice 6 | 7 | name k0 : kdf {ikm info self. 8 | info == 0x01 -> public nonce |counter|, 9 | info == 0x02 -> strict st_aead Data<[alice_secret] /\ adv, |adv|> 10 | aad x. true 11 | nonce C 12 | pattern i. xor(i, gkdf(self, ikm, 0x01)) 13 | } @ alice 14 | 15 | corr [k0] ==> [alice_secret] 16 | 17 | def main() @ alice : Unit = 18 | corr_case k0 in 19 | let base_nonce = kdf<0;;nonce |counter|;0>(get(k0), 0x, 0x01) in 20 | let k_enc = kdf<1;;enckey;0>(get(k0), 0x, 0x02) in 21 | let c = st_aead_enc(k_enc, get(alice_secret), 0x) in 22 | output c; 23 | input in_cipher in 24 | input in_ctr in 25 | case st_aead_dec(k_enc, in_cipher, 0x, xor(in_ctr, base_nonce)) as Option Data<[alice_secret] /\ adv, |adv|> { 26 | | Some m => () 27 | | None => () 28 | otherwise => () 29 | } 30 | -------------------------------------------------------------------------------- /tests/success/ke/full_protocol.owl: -------------------------------------------------------------------------------- 1 | include "ke.owli" 2 | include "psk_ke.owl" 3 | // include "dh_ke.owl" // uncomment and comment above to use diffie-hellman 4 | include "transp.owl" 5 | 6 | def Server_main () @ Server 7 | : Option (if sec(data) then Name(data) else Data) 8 | = corr_case data in call server() 9 | 10 | def Client_main () @ Client 11 | : Unit 12 | = call client(get(data)) 13 | -------------------------------------------------------------------------------- /tests/success/ke/ke.owli: -------------------------------------------------------------------------------- 1 | include "transp.owli" 2 | 3 | name k : enckey Name(data) @ Server 4 | def ke_Server() @ Server : Unit 5 | def ke_Client() @ Client : Option (if sec(k) then Name(k) else Data) 6 | -------------------------------------------------------------------------------- /tests/success/ke/psk_ke.owl: -------------------------------------------------------------------------------- 1 | include "ke.owli" 2 | 3 | name shared_key : enckey Name(k) @ Server, Client 4 | 5 | def ke_Server() @ Server : Unit = 6 | let c = aenc(get(shared_key), get(k)) in 7 | output c to endpoint(Client) 8 | 9 | def ke_Client () @ Client : Option (if sec(k) then Name(k) else Data) = 10 | input i in 11 | corr_case shared_key in 12 | corr_case k in 13 | adec(get(shared_key), i) 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/success/ke/transp.owl: -------------------------------------------------------------------------------- 1 | include "transp.owli" 2 | include "ke.owli" 3 | 4 | def server() @ Server : 5 | Option (if sec(data) then Name(data) else Data) = 6 | call ke_Server(); 7 | input i in 8 | corr_case k in 9 | corr_case data in 10 | adec(get(k), i) 11 | 12 | def client(x : Name(data)) @ Client: Unit = 13 | corr_case k in 14 | let o = call ke_Client() in 15 | case o { 16 | | None => () 17 | | Some k => 18 | let c = aenc(k, x) in 19 | output c to endpoint(Server) 20 | } 21 | -------------------------------------------------------------------------------- /tests/success/ke/transp.owli: -------------------------------------------------------------------------------- 1 | locality Server 2 | locality Client 3 | 4 | name data : nonce @ Client 5 | 6 | def server() @ Server : Option (if sec(data) then Name(data) else Data) 7 | def client(x : Name(data)) @ Client : Unit -------------------------------------------------------------------------------- /tests/success/ke_mod/full_protocol.owl: -------------------------------------------------------------------------------- 1 | include "psk_ke.owl" 2 | include "dh_ke.owl" 3 | include "transp.owl" 4 | 5 | module Full(P : Params, K : KE(P)) = { 6 | module T = Transp(P, K) 7 | def Server_main () @ P.Server 8 | : Option (if sec(P.data) then Name(P.data) else Data) 9 | = corr_case P.data in call T.server() 10 | 11 | def Client_main () @ P.Client 12 | : Unit 13 | = call T.client(get(P.data)) 14 | 15 | } 16 | 17 | module tstParams : Params = { 18 | locality Client 19 | locality Server 20 | name data : nonce @ Client 21 | } 22 | 23 | /* 24 | the below type checks but does not extract 25 | 26 | module DHFunctor (P : Params) = Full(P, DH_KE) 27 | 28 | module PSKFunctor (P : Params) = Full(P, PSK_KE) 29 | 30 | module FullDH = DHFunctor(tstParams) 31 | module FullPSK = PSKFunctor(tstParams) 32 | */ 33 | 34 | 35 | module FullDH = { 36 | module Inner_KE = DH_KE(tstParams) 37 | module P = Full(tstParams, Inner_KE) 38 | } 39 | 40 | module FullPSK = { 41 | module Inner_KE = PSK_KE(tstParams) 42 | module P = Full(tstParams, Inner_KE) 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /tests/success/ke_mod/ke.owli: -------------------------------------------------------------------------------- 1 | include "params.owli" 2 | 3 | module type KE (P : Params) = { 4 | name k : enckey Name(P.data) @ P.Server 5 | def ke_Server() @ P.Server : Unit 6 | def ke_Client() @ P.Client : Option (if sec(k) then Name(k) else Data) 7 | } 8 | -------------------------------------------------------------------------------- /tests/success/ke_mod/params.owli: -------------------------------------------------------------------------------- 1 | module type Params = { 2 | locality Client 3 | locality Server 4 | name data : nonce @ Client 5 | } 6 | -------------------------------------------------------------------------------- /tests/success/ke_mod/psk_ke.owl: -------------------------------------------------------------------------------- 1 | include "ke.owli" 2 | 3 | module PSK_KE (P : Params) : KE(P) = { 4 | name k : enckey Name(P.data) @ P.Server 5 | name shared_key : enckey Name(k) @ P.Server, P.Client 6 | 7 | def ke_Server() @ P.Server : Unit = 8 | let c = aenc(get(shared_key), get(k)) in 9 | output c to endpoint(P.Client) 10 | 11 | def ke_Client () @ P.Client : Option (if sec(k) then Name(k) else Data) = 12 | input i in 13 | corr_case shared_key in 14 | corr_case k in 15 | adec(get(shared_key), i) 16 | 17 | } 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/success/ke_mod/transp.owl: -------------------------------------------------------------------------------- 1 | include "transp.owli" 2 | include "ke.owli" 3 | 4 | module Transp (P : Params, K : KE(P)) : TRANSP(P) = { 5 | def server() @ P.Server : 6 | Option (if sec(P.data) then Name(P.data) else Data) = 7 | call K.ke_Server(); 8 | input i in 9 | corr_case K.k in 10 | corr_case P.data in 11 | adec(get(K.k), i) 12 | 13 | def client(x : Name(P.data)) @ P.Client: Unit = 14 | corr_case K.k in 15 | let o = call K.ke_Client() in 16 | case o { 17 | | None => () 18 | | Some k => 19 | let c = aenc(k, x) in 20 | output c to endpoint(P.Server) 21 | } 22 | 23 | } 24 | 25 | -------------------------------------------------------------------------------- /tests/success/ke_mod/transp.owli: -------------------------------------------------------------------------------- 1 | include "params.owli" 2 | 3 | module type TRANSP (P : Params) = { 4 | def server() @ P.Server : Option (if sec(P.data) then Name(P.data) else Data) 5 | def client(x : Name(P.data)) @ P.Client : Unit 6 | } 7 | 8 | -------------------------------------------------------------------------------- /tests/success/kerberos/kerberos_ASE_standard.owl: -------------------------------------------------------------------------------- 1 | include "kerberos.owli" 2 | 3 | // ********************************* 4 | // pre-shared key for STANDARD mode 5 | // ********************************* 6 | 7 | // In previous versions this was called kC 8 | name K : enckey Name(AK) @ authserver, client 9 | 10 | def client_main () @ client 11 | : Unit = 12 | 13 | let username = get(uname) in 14 | let _ = output username to endpoint(authserver) in 15 | 16 | // i = tgt, aenc(K, AK) 17 | input i in 18 | 19 | parse i as authserver_msg(tgt, c) in { 20 | corr_case K in 21 | case adec(get(K), c) { 22 | | None => () 23 | | Some ak => 24 | call client_kerberos(ak, tgt, username) 25 | } 26 | } 27 | otherwise () 28 | 29 | def authserver_main () @ authserver 30 | : Unit = 31 | 32 | // i = client's username 33 | input i, _ in 34 | if eq(i, get(uname)) then 35 | 36 | // make & send TGT = (AK)_kT, m = (AK)_K 37 | let tgt = aenc(get(kT), get(AK)) in 38 | 39 | let m = aenc(get(K), get(AK)) in 40 | let p = authserver_msg(tgt, m) in 41 | 42 | let _ = output p to endpoint(client) in () 43 | else () 44 | -------------------------------------------------------------------------------- /tests/success/kerberos/kerberos_full_pkinit.owl: -------------------------------------------------------------------------------- 1 | include "kerberos.owli" 2 | include "kerberos_ASE_pkinit.owl" 3 | include "kerberos_2_3.owl" 4 | -------------------------------------------------------------------------------- /tests/success/kerberos/kerberos_full_standard.owl: -------------------------------------------------------------------------------- 1 | include "kerberos.owli" 2 | include "kerberos_ASE_standard.owl" 3 | include "kerberos_2_3.owl" 4 | -------------------------------------------------------------------------------- /tests/success/kerberos_mod/kerberos_skinit.owl: -------------------------------------------------------------------------------- 1 | include "kerberos_stage1.owli" 2 | 3 | module Kerberos_SKINIT(P : Params) : Kerberos_Stage1(P) = { 4 | name K : enckey Name(P.AK) @ P.authserver, P.client 5 | 6 | struct client_stage1_t { 7 | _ak : if sec(K) then Name(P.AK) else Data ||enckey||, 8 | _tgt : Data |cipherlen(|enckey|)|, 9 | _username : Data ||nonce|| 10 | } 11 | 12 | def client_stage1 () @ P.client 13 | : Option client_stage1_t = 14 | 15 | let username = get(P.uname) in 16 | let _ = output username to endpoint(P.authserver) in 17 | 18 | // i = tgt, aenc(K, AK) 19 | input i in 20 | 21 | parse i as P.authserver_msg(tgt, c) in { 22 | corr_case K in 23 | case adec(get(K), c) { 24 | | None => None() 25 | | Some ak => 26 | if eq(length(ak), |enckey|) then Some(client_stage1_t(ak, 27 | tgt, username)) else None() 28 | } 29 | } otherwise None() 30 | 31 | def authserver_main () @ P.authserver 32 | : Unit = 33 | 34 | // i = client's username 35 | input i, _ in 36 | if eq(i, get(P.uname)) then 37 | 38 | // make & send TGT = (AK)_kT, m = (AK)_K 39 | let tgt = aenc(get(P.kT), get(P.AK)) in 40 | 41 | let m = aenc(get(K), get(P.AK)) in 42 | let p = P.authserver_msg(tgt, m) in 43 | 44 | let _ = output p to endpoint(P.client) in () 45 | else () 46 | } 47 | 48 | -------------------------------------------------------------------------------- /tests/success/kerberos_mod/kerberos_stage1.owli: -------------------------------------------------------------------------------- 1 | module type Params = { 2 | locality ticketserver // TGS 3 | locality service // S 4 | locality client // C 5 | locality authserver // KAS 6 | 7 | name uname : nonce @ ticketserver, service, client, authserver 8 | corr adv ==> [uname] 9 | 10 | // SK = service key 11 | name SK : enckey Data @ ticketserver 12 | 13 | // messages to/from the ticket server 14 | // encrypted using AK 15 | enum AKEnum { 16 | | ClientRequest 17 | | TicketResponse Name(SK) 18 | } 19 | 20 | // AK = authserver key 21 | name AK : enckey AKEnum @ authserver 22 | 23 | // pre-shared symmetric keys 24 | name kT : enckey Name(AK) @ authserver, ticketserver 25 | name kS : enckey Name(SK) @ ticketserver, service 26 | 27 | // ********************************* 28 | // message formats 29 | // ********************************* 30 | 31 | struct authserver_msg { 32 | _authserver_msg_1 : Data |cipherlen(|enckey|)|, 33 | _authserver_msg_2 : Data |cipherlen(|enckey|)| 34 | } 35 | 36 | struct client_to_ticketserver_msg { 37 | _client_to_ticketserver_msg_1 : Data |cipherlen(|enckey|)|, 38 | _client_to_ticketserver_msg_2 : Data |cipherlen(|tag|)| 39 | } 40 | 41 | struct ticketserver_msg { 42 | _ticketserver_msg_1 : Data |cipherlen(|enckey|)|, 43 | _ticketserver_msg_2 : Data |cipherlen(plus(|tag|, |enckey|))| 44 | } 45 | 46 | struct client_to_service_msg { 47 | _client_to_service_msg_1 : Data |cipherlen(|enckey|)|, 48 | _client_to_service_msg_2 : Data |cipherlen(|nonce|)| 49 | } 50 | } 51 | 52 | module type Kerberos_Stage1 (P : Params) = { 53 | name K 54 | struct client_stage1_t { 55 | _ak : if sec(K) then Name(P.AK) else Data ||enckey||, 56 | _tgt : Data |cipherlen(|enckey|)|, 57 | _username : Data ||nonce|| 58 | } 59 | def client_stage1() @ P.client : Option client_stage1_t 60 | 61 | def authserver_main() @ P.authserver : Unit 62 | } 63 | 64 | -------------------------------------------------------------------------------- /tests/success/lengths.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | name X : nonce @ alice 3 | name K : enckey Name(X) @ alice 4 | 5 | def tst () @ alice : Unit = 6 | assert (length(get(X)) == |nonce| ); 7 | assert (length(get(K)) == |enckey| ); 8 | let k = get(K) in 9 | let x : (w:Name(K){length(w) == |enckey|}) = k in 10 | () 11 | -------------------------------------------------------------------------------- /tests/success/let_sugar.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | struct t { 4 | _x : Data | |nonce| |, 5 | _y : Data | |nonce| |, 6 | _z : Data | |nonce| | 7 | } 8 | 9 | struct s { 10 | _a : Data | |nonce| | 11 | } 12 | 13 | def alice_main() @ alice : Unit = 14 | input i in 15 | parse i as t(x, y, z) in 16 | let s' = s(x) in 17 | output s' 18 | otherwise () 19 | 20 | -------------------------------------------------------------------------------- /tests/success/mac.owl: -------------------------------------------------------------------------------- 1 | locality A 2 | locality B 3 | 4 | name d : nonce @ A 5 | name k : mackey Name(d) @ A, B 6 | 7 | // func p1 8 | // arity 1 9 | // func p2 10 | // arity 1 11 | 12 | // func concat 13 | // arity 2 14 | 15 | def A_main () @ A 16 | requires corr(d) : Unit = 17 | let _ = output get(d) to endpoint(B) in 18 | let t = mac(get(k), get(d)) in 19 | output t to endpoint(B) 20 | 21 | def B_main () @ B : Unit = 22 | input i in 23 | input j in 24 | corr_case k in 25 | case mac_vrfy(get(k), i, j) { 26 | | None => () 27 | | Some m => 28 | let mm : if sec(k) then Name(d) else Data = m in 29 | () 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/success/mod_alias.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | module M = { 4 | name k : nonce @ alice 5 | 6 | def alice_main() @ alice : Name(k) = 7 | get(k) 8 | } 9 | 10 | module N = M 11 | 12 | def tst1 () @ alice : Name(N.k) = get(N.k) 13 | def tst2 () @ alice : Name(M.k) = get(N.k) 14 | def tst3 () @ alice : Name(N.k) = get(M.k) 15 | 16 | /* 17 | Expected output: 18 | 19 | defs = [ 20 | Top_M_alice_main @ alice : () -> Name(Top.M.k) = 21 | get(Top.M.k) 22 | ] 23 | 24 | nameEnv = [ 25 | Top_M_k : nonce @ Top.alice 26 | ] 27 | 28 | */ 29 | -------------------------------------------------------------------------------- /tests/success/mods/functor.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | module type S = { 4 | name x : nonce @ alice 5 | } 6 | 7 | module Srefined = { 8 | name x : nonce @ alice 9 | name z : nonce @ alice 10 | } 11 | 12 | module M = functor (X : S) => { 13 | module Z = X 14 | name k : enckey Name(Z.x) @ alice 15 | def alice_main() @ alice : Name(Z.x) = 16 | let x = get(Z.x) in 17 | x 18 | } 19 | 20 | module Main = M(Srefined) 21 | 22 | 23 | // def blah() @ alice : Name(Srefined.x) = 24 | // let x = call Main.alice_main() in 25 | // x -------------------------------------------------------------------------------- /tests/success/mods/mods.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | module A = { 4 | locality bob 5 | module B = { 6 | name n : nonce @ bob 7 | struct s { 8 | _x : Name(n) 9 | } 10 | } 11 | 12 | def bob_main() @ bob : Unit = () 13 | } 14 | 15 | module X = A.B 16 | 17 | 18 | module M = { 19 | name k : nonce @ alice 20 | name k2 : enckey Name(k) @ alice 21 | struct s { 22 | _x : Name(k) 23 | } 24 | 25 | enum t { 26 | | Ok 27 | | Bad 28 | } 29 | 30 | def foo() @ alice : s = 31 | s(get(k)) 32 | 33 | def bar(x : t) @ alice : Unit = 34 | case x { 35 | | Ok => () 36 | | Bad => () 37 | } 38 | } 39 | 40 | 41 | module N = M 42 | 43 | def foo0() @ A.bob : Unit = 44 | let x : X.s = X.s(get(X.n)) in 45 | () 46 | 47 | def alice_main() @ alice : Unit = 48 | let x = get(N.k) in 49 | let y : N.s = N.s(x) in 50 | let z : N.s = call N.foo() in 51 | let w : N.t = N.Ok() in 52 | call N.bar(w); 53 | case w { 54 | | Ok => () 55 | | Bad => () 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /tests/success/mods/spec.owl: -------------------------------------------------------------------------------- 1 | locality alice : 1 2 | 3 | module type Spec = { 4 | locality bob : 1 5 | name k<@i> : nonce @ bob 6 | } 7 | 8 | module T : Spec = { 9 | locality bob = alice 10 | name k<@i> : nonce @ bob 11 | name k2<@i> : nonce @ bob 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/success/nested_and.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | def this_works() @ alice : Unit = 4 | input A in 5 | input B in 6 | 7 | if eq(length(A), |nonce|) && eq(length(B), |nonce|) then 8 | assert(eq(length(A), |nonce|)); 9 | assert(eq(length(B), |nonce|)); 10 | () 11 | else 12 | () 13 | 14 | def this_should_work_but_doesnt() @ alice : Unit = 15 | input A in 16 | input B in 17 | input C in 18 | 19 | 20 | if eq(length(A), |nonce|) && eq(length(B), |nonce|) && eq(length(C), |nonce|) then 21 | assert(eq(length(A), |nonce|)); 22 | assert(eq(length(B), |nonce|)); 23 | assert(eq(length(C), |nonce|)); 24 | () 25 | else 26 | () 27 | -------------------------------------------------------------------------------- /tests/success/odh.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name X : DH @ alice 4 | name Y : DH @ alice 5 | 6 | name n : nonce @ alice 7 | 8 | odh L : 9 | X, Y -> {salt info. 10 | salt == 0x -> strict enckey Name(n) 11 | } 12 | 13 | corr [X] ==> [n] 14 | corr [Y] ==> [n] 15 | 16 | def main() @ alice : Unit = 17 | corr_case X in 18 | corr_case Y in 19 | let k = kdf<;odh L[0];enckey;0>(0x, dh_combine(dhpk(get(X)), get(Y)) ++ 0x1234, 0x) in 20 | let c = aenc(k, get(n)) in 21 | output c 22 | -------------------------------------------------------------------------------- /tests/success/option.owl: -------------------------------------------------------------------------------- 1 | locality A 2 | 3 | name N : nonce @ A 4 | name M : nonce @ A 5 | 6 | def alice() @ A : Unit = 7 | // Annotation on Some 8 | let tst : Option Name(N) = Some)>(get(N)) in 9 | // No annotation on Some: infers the type 10 | let tst1 : Option Name(N) = Some(get(N)) in 11 | // Subtyping on option 12 | let tst2 : Option Data<[N]> = tst1 in 13 | // Pass in bad data for argument with annotation --> Data with covering 14 | // label 15 | let tst3 : Data<[M]> = Some)>(get(M)) in 16 | // None always requires the option 17 | let tst4 : Option Name(N) = None)>() in 18 | let tst5 : Bool = None?(tst4) in 19 | let tst6 : Bool = Some?(tst4) in 20 | let tst7 : Bool<[M]> = Some?(tst3) in // ill-typed case 21 | () 22 | -------------------------------------------------------------------------------- /tests/success/option_refine.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name secret: nonce @ alice 4 | 5 | def test1(x: Option(Data)) @ alice : 6 | if Some?(x) then Option(Data) else Unit 7 | = 8 | case x { 9 | | Some y => Some(y) 10 | | None => () 11 | } 12 | 13 | def test2(x: Option(Data)) @ alice : 14 | if Some?(x) /\ None?(x) then Name(secret) else Unit 15 | = () 16 | -------------------------------------------------------------------------------- /tests/success/parse_lengths.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name A : nonce @ alice 4 | struct t { 5 | a : Name(A), 6 | b : Data | |enckey| |, 7 | c : Data | 4 |, 8 | d : Data | |pke_pk| | 9 | } 10 | 11 | name P : nonce @ alice 12 | enum s { 13 | | P Name(P) 14 | | Q Data | |pke_sk| | 15 | | R 16 | } 17 | 18 | def alice_main() @ alice : Unit = 19 | input i in 20 | parse i as t(a, b, c, d) in { 21 | // debug printTyOf(a); // Data ||nonce|| 22 | assert(length(a) == |nonce|); 23 | assert(length(b) == |enckey|); 24 | assert(length(c) == 4); 25 | assert(length(d) == |pke_pk|); 26 | input j in 27 | case j as s { 28 | | P p => 29 | // debug printTyOf(p); // Data ||nonce|| 30 | assert(length(p) == |nonce|); () 31 | | Q q => assert(length(q) == |pke_sk|); () 32 | | R => () 33 | otherwise => () 34 | } 35 | } otherwise () -------------------------------------------------------------------------------- /tests/success/parse_lengths_nested.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | name A : nonce @ alice 3 | name P : nonce @ alice 4 | name V : nonce @ alice 5 | 6 | struct q { 7 | u : Data | |pke_pk| |, 8 | v : Name(V) 9 | } 10 | 11 | enum s { 12 | | PP Name(P) 13 | | QQ q 14 | | RR 15 | } 16 | 17 | struct t { 18 | a : Name(A), 19 | b : Data | |enckey| |, 20 | c : Data | 4 |, 21 | s : s 22 | } 23 | 24 | def alice_main() @ alice : Unit = 25 | input i in 26 | parse i as t(a, b, c, s) in { 27 | // debug printTyOf(a); // Data ||nonce|| 28 | // debug printTyOf(s); // Data 29 | assert(length(a) == |nonce|); 30 | assert(length(b) == |enckey|); 31 | assert(length(c) == 4); 32 | case s as s { 33 | | PP p => 34 | // debug printTyOf(p); // Data ||nonce|| 35 | assert(length(p) == |nonce|); () 36 | | QQ q => 37 | // debug printTyOf(q); // Data 38 | parse q as q(u, v) in { 39 | assert(length(u) == |pke_pk|); 40 | assert(length(v) == |nonce|); 41 | () 42 | } otherwise () 43 | | RR => () 44 | otherwise => () 45 | } 46 | } otherwise () -------------------------------------------------------------------------------- /tests/success/parse_refinement.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name n : nonce @ alice 4 | name m : nonce @ alice 5 | 6 | struct T { 7 | x : Data | |nonce| |, 8 | y : Data | |nonce| | 9 | } 10 | 11 | def main(i : T) @ alice : Unit = 12 | assume (x(i) == get(n)); 13 | parse i as T(x, y) in 14 | assert (x == x(i)); 15 | assert (x == get(n)); 16 | () 17 | -------------------------------------------------------------------------------- /tests/success/pke.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob 3 | 4 | name d : nonce @ bob 5 | name skA : pkekey Name(d) @ alice 6 | 7 | def bob_main () @ bob : Unit = 8 | let pkA : encpk(skA) = get_encpk(skA) in 9 | let c = pkenc(pkA, get(d)) in 10 | output c to endpoint(alice); 11 | () 12 | 13 | def alice_main () @ alice : Unit = 14 | input i in 15 | corr_case skA in 16 | let c = pkdec(get(skA), i) in 17 | debug printTyOf(c); 18 | // Here, if sec(sk), x can have type Name(d) or Data; if sk is corrupt, 19 | // x has type Data 20 | () 21 | -------------------------------------------------------------------------------- /tests/success/predicates.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | name n : nonce @ alice 4 | name m : nonce @ alice 5 | 6 | predicate p(x) = (x == get(n)) 7 | predicate q(x) = (x == get(m)) 8 | 9 | def main(x : (a:Data{p[a]})) @ alice : Unit = 10 | assert(x == get(n)) 11 | 12 | def main2(x : Data) @ alice : Unit = 13 | assume(q[x]); 14 | assert(x == get(m)) 15 | -------------------------------------------------------------------------------- /tests/success/running_example.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob : 1 3 | 4 | name msg<@j> : nonce @ bob 5 | name k_data<@j> : enckey (Name(msg<@j>)) @ alice 6 | name psk<@j> : enckey (Name(k_data<@j>)) @ alice, bob 7 | 8 | enum Result { 9 | | Ok Name(msg<@j>) 10 | | Err 11 | } 12 | 13 | def alice<@j>() @ alice : if sec(msg<@j>) then Result else Data = 14 | let c = aenc(get(psk<@j>), get(k_data<@j>)) in 15 | output c; 16 | input i in 17 | corr_case k_data<@j> in 18 | corr_case msg<@j> in 19 | case adec(get(k_data<@j>), i) { 20 | | Some o => Ok(o) 21 | | None => Err() 22 | } 23 | 24 | def bob<@j>() @ bob : Unit = 25 | input i in 26 | corr_case psk<@j> in 27 | case adec(get(psk<@j>), i) { 28 | | Some k => 29 | let c = aenc(k, get(msg<@j>)) in 30 | output c 31 | | None => () 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/success/singleton-type.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob 3 | 4 | name n: nonce @ alice 5 | corr adv ==> [n] 6 | 7 | struct s { 8 | _tag : Const(0x00000001), 9 | _message : Data | |nonce| | 10 | } 11 | 12 | def alice_main() @ alice : Unit = 13 | let n = get(n) in 14 | let t = 0x00000001 in 15 | let sv = s(t, n) in 16 | output sv to endpoint(bob) 17 | 18 | def bob_main() @ bob : Unit = 19 | input i in 20 | parse i as s(t, n) in { 21 | assert(t == 0x00000001); 22 | () 23 | } otherwise () 24 | 25 | -------------------------------------------------------------------------------- /tests/success/struct.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | name X : nonce @ alice 3 | 4 | func some_length 5 | arity 0 6 | 7 | struct t { 8 | _x : Name(X), 9 | _y : Data |some_length()| 10 | } 11 | 12 | 13 | def a () @ alice : Unit = 14 | input i in 15 | debug "======="; 16 | debug "Good case for foo"; 17 | debug "======="; 18 | let b = eq(length(i), some_length()) in 19 | if b then 20 | // TODO: currently the type system requires you to unfold out your major 21 | // subtyping queries into different let statements. So putting "i" 22 | // instead of "j" won't work below. 23 | let j : Data |some_length()| = i in 24 | let foo : t = t(get(X), j) in 25 | parse foo as t(x', y') in 26 | // When we print, we see that foo has type t 27 | debug printTyContext; 28 | () 29 | else 30 | () 31 | 32 | def b () @ alice : Unit = 33 | debug "======="; 34 | debug "Bad case for foo"; 35 | debug "======="; 36 | input i in 37 | let foo = t(get(X), i) in 38 | parse foo as t(x', y') in 39 | // When we print, we see that foo only has type Data<[X] /\ adv> 40 | debug printTyContext; 41 | () 42 | otherwise () 43 | -------------------------------------------------------------------------------- /tests/success/struct_eta.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | struct t { 4 | _x : Data | |nonce| |, 5 | _y : Data | |nonce| |, 6 | _z : Data | |nonce| | 7 | } 8 | 9 | name n : nonce @ alice 10 | struct t2 { 11 | _a : Name(n), 12 | _b : Data 13 | } 14 | 15 | def amain (a : t) @ alice : Unit = 16 | assert (length(a) == 3 * |nonce|); 17 | () 18 | 19 | def tst2(x : Data | |nonce| |, 20 | y : Data | |nonce| |, 21 | z : Data | |nonce| | 22 | ) @ alice : Unit = 23 | let s = t(x, y, z) in 24 | assert (x == _x(s)); 25 | assert (y == _y(s)); 26 | assert (z == _z(s)); 27 | () 28 | 29 | def tst3() @ alice :Unit = 30 | input inp in 31 | let x = get(n) in 32 | let s = t2(x, inp) in 33 | assert (_a(s) == x); 34 | assert (_b(s) == inp); 35 | () 36 | 37 | -------------------------------------------------------------------------------- /tests/success/struct_ext.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | 3 | 4 | set_option ":rlimit" "500000" 5 | 6 | struct t1 { 7 | _t1_a : Data | |nonce| |, 8 | _t1_b : Data | |vk| |, 9 | _t1_c : (x:Data {x == _t1_a ++ _t1_b}) 10 | } 11 | 12 | struct t { 13 | // Length annotations below are arbitrary 14 | _t_x : t1, 15 | _t_y : Data | |vk| | 16 | } 17 | 18 | def tst_ex (x : t) @ alice : Unit = 19 | // let c = _t1_c(x) in 20 | // assert (_t1_c(x) == _t1_a(x) ++ _t1_b(x)); 21 | assert (length(x) == (3 * |vk|) + (2 * |nonce|)); 22 | () 23 | 24 | def alice_main () @ alice : Unit = () 25 | -------------------------------------------------------------------------------- /tests/wip/hpke/full.owl: -------------------------------------------------------------------------------- 1 | include "defs.owl" 2 | include "sender.owl" 3 | include "receiver.owl" 4 | -------------------------------------------------------------------------------- /tests/wip/unauth_hash.owl: -------------------------------------------------------------------------------- 1 | locality alice 2 | locality bob 3 | name K : nonce @ alice, bob 4 | name N : nonce @ alice 5 | corr adv ==> [N] // secrecy of N doesn't matter 6 | 7 | name roKN : RO get(K) || get(N) -> enckey (x:Data{x == 0x00}) 8 | 9 | def alice_main() @ alice : Unit = 10 | let K2 = hash(get(K), get(N)) in 11 | let c = aenc(K2, 0x00) in 12 | let _ = output get(N) in 13 | output c 14 | 15 | def bob_main() @ bob 16 | requires sec(K) 17 | : Option(Name(roKN)) = 18 | input N' in 19 | input c in 20 | pcase (N' == get(N)) in 21 | corr_case roKN when N' == get(N) in 22 | let K2 = hash(get(K), N') in 23 | case adec(K2, c) 24 | | None => None() 25 | | Some p => 26 | guard (eq(p, 0x00)) in 27 | Some(K2) 28 | 29 | /* 30 | N' : Data 31 | c : Data 32 | K2 : x:(Data){ro(concat(get(K), N', 0)) /\ length(x) == |enckey|} 33 | 34 | p : Data 35 | _ : eq(p, 0x00) 36 | 37 | The issue is K2 : Data. This says that K2 is safe to disclose to the 38 | adv, but in this case, we want to maintain its underivability. 39 | */ 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /tests/wip/wg/full.owl: -------------------------------------------------------------------------------- 1 | include "init.owl" 2 | include "resp.owl" 3 | include "transp.owl" 4 | -------------------------------------------------------------------------------- /vim/ftdetect/owl.vim: -------------------------------------------------------------------------------- 1 | autocmd BufNewFile,BufRead *.owl setf owl 2 | autocmd BufNewFile,BufRead *.owli setf owl 3 | -------------------------------------------------------------------------------- /vim/syntax/owl.vim: -------------------------------------------------------------------------------- 1 | " OWL highlight 2 | if version < 600 3 | syntax clear 4 | elseif exists("b:current_syntax") 5 | finish 6 | endif 7 | 8 | syn keyword owlConditional case if guard then else pack unpack 9 | syn keyword owlCommand input output requires ensures 10 | syn keyword owlDecl name func def locality enum struct table module type corr counter 11 | syn keyword owlKeyword let in return get_counter inc_counter aenc adec aenc_with_nonce adec_with_nonce sign vrfy mac mac_vrfy adv ghost 12 | 13 | syn keyword owlTypeName Data Name Option Ghost 14 | syn region owlCommentLine start="//" end="$" 15 | syn region owlCommentBlock matchgroup=owlCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" 16 | 17 | hi def link owlDecl Include 18 | hi def link owlTypeName Type 19 | hi def link owlCommentLine Comment 20 | hi def link owlCommentBlock Comment 21 | hi def link owlCommand Typedef 22 | hi def link owlKeyword Keyword 23 | 24 | let b:current_syntax = 'owl' 25 | 26 | 27 | -------------------------------------------------------------------------------- /vscode/owl-support-for-vscode/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /vscode/owl-support-for-vscode/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .gitignore 4 | vsc-extension-quickstart.md 5 | -------------------------------------------------------------------------------- /vscode/owl-support-for-vscode/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "owl-support-for-vscode" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /vscode/owl-support-for-vscode/README.md: -------------------------------------------------------------------------------- 1 | # Owl Support for VSCode 2 | 3 | Basic syntax highlighting for Owl. 4 | 5 | Rules can be added/removed/modified in the `syntaxes/owl.tmLanguage.json`. Rule names should ideally follow the [naming convention](https://macromates.com/manual/en/language_grammars#naming-conventions) so that standard themes can correctly apply the formatting. 6 | 7 | ## Installation 8 | 9 | Copy this directory to `~/.vscode-server/extensions` and reload VSCode. 10 | 11 | ## TODOs 12 | 13 | * Switch to [Semantic Tokenization](https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide) at some point? 14 | * Improve rule names -------------------------------------------------------------------------------- /vscode/owl-support-for-vscode/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "//", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ "/*", "*/" ] 7 | }, 8 | // symbols used as brackets 9 | "brackets": [ 10 | ["{", "}"], 11 | ["[", "]"], 12 | ["(", ")"], 13 | ["<", ">"] 14 | ], 15 | // symbols that are auto closed when typing 16 | "autoClosingPairs": [ 17 | ["{", "}"], 18 | ["[", "]"], 19 | ["(", ")"], 20 | // ["\"", "\""], 21 | ["<", ">"] 22 | ], 23 | // symbols that can be used to surround a selection 24 | "surroundingPairs": [ 25 | ["{", "}"], 26 | ["[", "]"], 27 | ["(", ")"], 28 | // ["\"", "\""], 29 | ["<", ">"] 30 | ] 31 | } -------------------------------------------------------------------------------- /vscode/owl-support-for-vscode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "owl-support-for-vscode", 3 | "displayName": "Owl Support for VSCode", 4 | "description": "", 5 | "version": "0.0.1", 6 | "engines": { 7 | "vscode": "^1.71.0" 8 | }, 9 | "categories": [ 10 | "Programming Languages" 11 | ], 12 | "contributes": { 13 | "languages": [{ 14 | "id": "owl", 15 | "aliases": ["Owl", "owl"], 16 | "extensions": [".owl"], 17 | "configuration": "./language-configuration.json" 18 | }], 19 | "grammars": [{ 20 | "language": "owl", 21 | "scopeName": "text.owl", 22 | "path": "./syntaxes/owl.tmLanguage.json" 23 | }] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /vscode/owl-support-for-vscode/syntaxes/owl.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", 3 | "name": "Owl", 4 | "patterns": [ 5 | { 6 | "include": "#keywords" 7 | }, 8 | { 9 | "include": "#strings" 10 | }, 11 | { 12 | "include": "#comments" 13 | }, 14 | { 15 | "include": "#storage" 16 | } 17 | ], 18 | "repository": { 19 | "comments": { 20 | "patterns": [{ 21 | "name": "comment.line.double-slash.owl", 22 | "begin": "(\\/\\/)", 23 | "end": "(?=\\n)" 24 | }, { 25 | "name": "comment.block.owl", 26 | "begin": "\\s*+(\\/\\*)", 27 | "end": "\\*\\/" 28 | }] 29 | }, 30 | "keywords": { 31 | "patterns": [{ 32 | "name": "keyword.other.owl", 33 | "match": "\\b(input|output|requires|ensures)\\b" 34 | }, 35 | { 36 | "name": "keyword.control.owl", 37 | "match": "\\b(case|if|guard|then|else|pack|unpack)\\b" 38 | }, 39 | { 40 | "name": "keyword.other.owl", 41 | "match": "\\b(name|func|def|locality|enum|flow|type|struct|table|random_oracle)\\b" 42 | }, 43 | { 44 | "name": "keyword.other.owl", 45 | "match": "\\b(let|in|return|ghost)\\b" 46 | }, 47 | { 48 | "name": "support.class.owl", 49 | "match": "\\b(enckey|sigkey|nonce|mackey|dhpk|shared_secret|RO)\\b" 50 | }, 51 | { 52 | "name": "support.function.owl", 53 | "match": "\\b(enc|dec|get|parse|sign|get_vk|H)\\b" 54 | }, 55 | { 56 | "name": "constant.language.owl", 57 | "match": "\\b(Some|None)\\b" 58 | }] 59 | }, 60 | "storage": { 61 | "patterns": [{ 62 | "name": "storage.type.owl", 63 | "match": "\\b(Data|Name|Option|Ghost)\\b" 64 | }, 65 | { 66 | "name": "storage.modifier.owl", 67 | "match": "\\b(Some|None)\\b" 68 | }] 69 | }, 70 | "strings": { 71 | "name": "string.quoted.double.owl", 72 | "begin": "\"", 73 | "end": "\"", 74 | "patterns": [ 75 | { 76 | "name": "constant.character.escape.owl", 77 | "match": "\\\\." 78 | } 79 | ] 80 | } 81 | }, 82 | "scopeName": "text.owl" 83 | } 84 | -------------------------------------------------------------------------------- /vscode/owl-support-for-vscode/vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension. 7 | * `syntaxes/owl.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization. 8 | * `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets. 9 | 10 | ## Get up and running straight away 11 | 12 | * Make sure the language configuration settings in `language-configuration.json` are accurate. 13 | * Press `F5` to open a new window with your extension loaded. 14 | * Create a new file with a file name suffix matching your language. 15 | * Verify that syntax highlighting works and that the language configuration settings are working. 16 | 17 | ## Make changes 18 | 19 | * You can relaunch the extension from the debug toolbar after making changes to the files listed above. 20 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 21 | 22 | ## Add more language features 23 | 24 | * To add features such as IntelliSense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs 25 | 26 | ## Install your extension 27 | 28 | * To start using your extension with Visual Studio Code copy it into the `/.vscode/extensions` folder and restart Code. 29 | * To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension. 30 | -------------------------------------------------------------------------------- /wg/.gitignore: -------------------------------------------------------------------------------- 1 | iperf-tests/ 2 | iperf-linedelay-tests/ 3 | *.iperf-log -------------------------------------------------------------------------------- /wg/cleanup-netconfig.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script deletes the network configuration set up by setup-netconfig.sh 4 | 5 | set -uo pipefail 6 | 7 | # Delete wg1 interface 8 | ip link del wg1 9 | ip netns exec net1 ip link del wg1n 10 | 11 | # Delete veth1 interface 12 | ip link del veth1 13 | 14 | # Delete net1 namespace. This deletes veth1n interface too 15 | ip netns del net1 16 | 17 | 18 | -------------------------------------------------------------------------------- /wg/jq_dump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | function usage() { 6 | echo "Usage: ${0} [-l|-m] " 7 | exit 2 8 | } 9 | 10 | json_dir="" 11 | linedelay="false" 12 | mss="false" 13 | 14 | # Parse command line options 15 | while getopts "lm" opt; do 16 | case "${opt}" in 17 | l) linedelay="true" ;; 18 | m) mss="true" ;; 19 | \? ) usage ;; 20 | : ) usage ;; 21 | esac 22 | done 23 | shift $((OPTIND -1)) 24 | 25 | # Check if there's a required argument provided 26 | if [[ -n $1 ]]; then 27 | json_dir=$(realpath "$1") 28 | else 29 | echo "Path to json dir is missing" 1>&2 30 | exit 1 31 | fi 32 | 33 | if [ $linedelay = "true" ]; then 34 | for f in 0ms 0.5ms 1ms 1.5ms 2ms 3ms 4ms 5ms 6ms 7ms 8ms 9ms 10ms 35 | do 36 | fname="iperf_$f.json" 37 | jq '.end.sum_received.bits_per_second' --arg f $f $json_dir/$fname 38 | done 39 | fi 40 | 41 | if [ $mss = "true" ]; then 42 | for f in 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1440 43 | do 44 | fname="iperf_$f.json" 45 | jq '.end.sum_received.bits_per_second' --arg f $f $json_dir/$fname 46 | done 47 | fi 48 | 49 | -------------------------------------------------------------------------------- /wg/wg1.conf: -------------------------------------------------------------------------------- 1 | [Interface] 2 | PrivateKey = AINt6JsQ2YYr6MSEtL00ocinBcuarnbZbvXf+f8Wnlg= 3 | ListenPort = 9101 4 | 5 | [Peer] 6 | PublicKey = 4CWIB5n4pYykwVbN0v8vnFToPl09JQyqxED43O6yLiY= 7 | Endpoint = 10.100.1.2:9102 8 | AllowedIPs = 10.100.2.2/32 -------------------------------------------------------------------------------- /wg/wg1n.conf: -------------------------------------------------------------------------------- 1 | [Interface] 2 | PrivateKey = yIM6P89SwECA9pHCSafMT4nG4kix6aCq1OcphCVwNlY= 3 | ListenPort = 9102 4 | 5 | [Peer] 6 | PublicKey = q28ZmzfeS5VUaxqkkuss6vrgJRHsVArfUZfAYAou+yg= 7 | Endpoint = 10.100.1.1:9101 8 | AllowedIPs = 10.100.2.1/32 -------------------------------------------------------------------------------- /wg/wireguard-go/.gitignore: -------------------------------------------------------------------------------- 1 | wireguard-go 2 | -------------------------------------------------------------------------------- /wg/wireguard-go/LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy of 2 | this software and associated documentation files (the "Software"), to deal in 3 | the Software without restriction, including without limitation the rights to 4 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 5 | of the Software, and to permit persons to whom the Software is furnished to do 6 | so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. 18 | -------------------------------------------------------------------------------- /wg/wireguard-go/Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr 2 | DESTDIR ?= 3 | BINDIR ?= $(PREFIX)/bin 4 | RUSTLIB_ARGS ?= 5 | export GO111MODULE := on 6 | 7 | all: generate-version-and-build 8 | 9 | MAKEFLAGS += --no-print-directory 10 | 11 | rustlib: 12 | @cd lib/owl_wireguard && cargo +nightly build $(RUSTLIB_ARGS) --release 13 | @cp lib/owl_wireguard/target/release/libowl_wireguard.a lib/ 14 | 15 | generate-version-and-build: 16 | @export GIT_CEILING_DIRECTORIES="$(realpath $(CURDIR)/..)" && \ 17 | tag="$$(git describe --dirty 2>/dev/null)" && \ 18 | ver="$$(printf 'package main\n\nconst Version = "%s"\n' "$$tag")" && \ 19 | [ "$$(cat version.go 2>/dev/null)" != "$$ver" ] && \ 20 | echo "$$ver" > version.go && \ 21 | git update-index --assume-unchanged version.go || true 22 | @$(MAKE) wireguard-go 23 | 24 | wireguard-go: $(wildcard *.go) $(wildcard */*.go) rustlib 25 | go build -v -o "$@" 26 | 27 | install: wireguard-go 28 | @install -v -d "$(DESTDIR)$(BINDIR)" && install -v -m 0755 "$<" "$(DESTDIR)$(BINDIR)/wireguard-go" 29 | 30 | test: 31 | go test ./... 32 | 33 | clean: 34 | rm -f wireguard-go 35 | @cd lib/owl_wireguard && cargo clean && rm -f ../libowl_wireguard.a 36 | 37 | .PHONY: all clean test install generate-version-and-build rustlib 38 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/boundif_android.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package conn 7 | 8 | func (s *StdNetBind) PeekLookAtSocketFd4() (fd int, err error) { 9 | sysconn, err := s.ipv4.SyscallConn() 10 | if err != nil { 11 | return -1, err 12 | } 13 | err = sysconn.Control(func(f uintptr) { 14 | fd = int(f) 15 | }) 16 | if err != nil { 17 | return -1, err 18 | } 19 | return 20 | } 21 | 22 | func (s *StdNetBind) PeekLookAtSocketFd6() (fd int, err error) { 23 | sysconn, err := s.ipv6.SyscallConn() 24 | if err != nil { 25 | return -1, err 26 | } 27 | err = sysconn.Control(func(f uintptr) { 28 | fd = int(f) 29 | }) 30 | if err != nil { 31 | return -1, err 32 | } 33 | return 34 | } 35 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/conn_test.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package conn 7 | 8 | import ( 9 | "testing" 10 | ) 11 | 12 | func TestPrettyName(t *testing.T) { 13 | var ( 14 | recvFunc ReceiveFunc = func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) { return } 15 | ) 16 | 17 | const want = "TestPrettyName" 18 | 19 | t.Run("ReceiveFunc.PrettyName", func(t *testing.T) { 20 | if got := recvFunc.PrettyName(); got != want { 21 | t.Errorf("PrettyName() = %v, want %v", got, want) 22 | } 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/controlfns.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package conn 7 | 8 | import ( 9 | "net" 10 | "syscall" 11 | ) 12 | 13 | // UDP socket read/write buffer size (7MB). The value of 7MB is chosen as it is 14 | // the max supported by a default configuration of macOS. Some platforms will 15 | // silently clamp the value to other maximums, such as linux clamping to 16 | // net.core.{r,w}mem_max (see _linux.go for additional implementation that works 17 | // around this limitation) 18 | const socketBufferSize = 7 << 20 19 | 20 | // controlFn is the callback function signature from net.ListenConfig.Control. 21 | // It is used to apply platform specific configuration to the socket prior to 22 | // bind. 23 | type controlFn func(network, address string, c syscall.RawConn) error 24 | 25 | // controlFns is a list of functions that are called from the listen config 26 | // that can apply socket options. 27 | var controlFns = []controlFn{} 28 | 29 | // listenConfig returns a net.ListenConfig that applies the controlFns to the 30 | // socket prior to bind. This is used to apply socket buffer sizing and packet 31 | // information OOB configuration for sticky sockets. 32 | func listenConfig() *net.ListenConfig { 33 | return &net.ListenConfig{ 34 | Control: func(network, address string, c syscall.RawConn) error { 35 | for _, fn := range controlFns { 36 | if err := fn(network, address, c); err != nil { 37 | return err 38 | } 39 | } 40 | return nil 41 | }, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/controlfns_linux.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package conn 7 | 8 | import ( 9 | "fmt" 10 | "runtime" 11 | "syscall" 12 | 13 | "golang.org/x/sys/unix" 14 | ) 15 | 16 | func init() { 17 | controlFns = append(controlFns, 18 | 19 | // Attempt to set the socket buffer size beyond net.core.{r,w}mem_max by 20 | // using SO_*BUFFORCE. This requires CAP_NET_ADMIN, and is allowed here to 21 | // fail silently - the result of failure is lower performance on very fast 22 | // links or high latency links. 23 | func(network, address string, c syscall.RawConn) error { 24 | return c.Control(func(fd uintptr) { 25 | // Set up to *mem_max 26 | _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, socketBufferSize) 27 | _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, socketBufferSize) 28 | // Set beyond *mem_max if CAP_NET_ADMIN 29 | _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, socketBufferSize) 30 | _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, socketBufferSize) 31 | }) 32 | }, 33 | 34 | // Enable receiving of the packet information (IP_PKTINFO for IPv4, 35 | // IPV6_PKTINFO for IPv6) that is used to implement sticky socket support. 36 | func(network, address string, c syscall.RawConn) error { 37 | var err error 38 | switch network { 39 | case "udp4": 40 | if runtime.GOOS != "android" { 41 | c.Control(func(fd uintptr) { 42 | err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_PKTINFO, 1) 43 | }) 44 | } 45 | case "udp6": 46 | c.Control(func(fd uintptr) { 47 | if runtime.GOOS != "android" { 48 | err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVPKTINFO, 1) 49 | if err != nil { 50 | return 51 | } 52 | } 53 | err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_V6ONLY, 1) 54 | }) 55 | default: 56 | err = fmt.Errorf("unhandled network: %s: %w", network, unix.EINVAL) 57 | } 58 | return err 59 | }, 60 | 61 | // Attempt to enable UDP_GRO 62 | func(network, address string, c syscall.RawConn) error { 63 | c.Control(func(fd uintptr) { 64 | _ = unix.SetsockoptInt(int(fd), unix.IPPROTO_UDP, unix.UDP_GRO, 1) 65 | }) 66 | return nil 67 | }, 68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/controlfns_unix.go: -------------------------------------------------------------------------------- 1 | //go:build !windows && !linux && !wasm 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package conn 9 | 10 | import ( 11 | "syscall" 12 | 13 | "golang.org/x/sys/unix" 14 | ) 15 | 16 | func init() { 17 | controlFns = append(controlFns, 18 | func(network, address string, c syscall.RawConn) error { 19 | return c.Control(func(fd uintptr) { 20 | _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, socketBufferSize) 21 | _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, socketBufferSize) 22 | }) 23 | }, 24 | 25 | func(network, address string, c syscall.RawConn) error { 26 | var err error 27 | if network == "udp6" { 28 | c.Control(func(fd uintptr) { 29 | err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_V6ONLY, 1) 30 | }) 31 | } 32 | return err 33 | }, 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/controlfns_windows.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package conn 7 | 8 | import ( 9 | "syscall" 10 | 11 | "golang.org/x/sys/windows" 12 | ) 13 | 14 | func init() { 15 | controlFns = append(controlFns, 16 | func(network, address string, c syscall.RawConn) error { 17 | return c.Control(func(fd uintptr) { 18 | _ = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_RCVBUF, socketBufferSize) 19 | _ = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_SNDBUF, socketBufferSize) 20 | }) 21 | }, 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/default.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package conn 9 | 10 | func NewDefaultBind() Bind { return NewStdNetBind() } 11 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/errors_default.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package conn 9 | 10 | func errShouldDisableUDPGSO(err error) bool { 11 | return false 12 | } 13 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/errors_linux.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package conn 7 | 8 | import ( 9 | "errors" 10 | "os" 11 | 12 | "golang.org/x/sys/unix" 13 | ) 14 | 15 | func errShouldDisableUDPGSO(err error) bool { 16 | var serr *os.SyscallError 17 | if errors.As(err, &serr) { 18 | // EIO is returned by udp_send_skb() if the device driver does not have 19 | // tx checksumming enabled, which is a hard requirement of UDP_SEGMENT. 20 | // See: 21 | // https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man7/udp.7?id=806eabd74910447f21005160e90957bde4db0183#n228 22 | // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv4/udp.c?h=v6.2&id=c9c3395d5e3dcc6daee66c6908354d47bf98cb0c#n942 23 | return serr.Err == unix.EIO 24 | } 25 | return false 26 | } 27 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/features_default.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | // +build !linux 3 | 4 | /* SPDX-License-Identifier: MIT 5 | * 6 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 7 | */ 8 | 9 | package conn 10 | 11 | import "net" 12 | 13 | func supportsUDPOffload(conn *net.UDPConn) (txOffload, rxOffload bool) { 14 | return 15 | } 16 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/features_linux.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package conn 7 | 8 | import ( 9 | "net" 10 | 11 | "golang.org/x/sys/unix" 12 | ) 13 | 14 | func supportsUDPOffload(conn *net.UDPConn) (txOffload, rxOffload bool) { 15 | rc, err := conn.SyscallConn() 16 | if err != nil { 17 | return 18 | } 19 | err = rc.Control(func(fd uintptr) { 20 | _, errSyscall := unix.GetsockoptInt(int(fd), unix.IPPROTO_UDP, unix.UDP_SEGMENT) 21 | txOffload = errSyscall == nil 22 | opt, errSyscall := unix.GetsockoptInt(int(fd), unix.IPPROTO_UDP, unix.UDP_GRO) 23 | rxOffload = errSyscall == nil && opt == 1 24 | }) 25 | if err != nil { 26 | return false, false 27 | } 28 | return txOffload, rxOffload 29 | } 30 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/gso_default.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package conn 9 | 10 | // getGSOSize parses control for UDP_GRO and if found returns its GSO size data. 11 | func getGSOSize(control []byte) (int, error) { 12 | return 0, nil 13 | } 14 | 15 | // setGSOSize sets a UDP_SEGMENT in control based on gsoSize. 16 | func setGSOSize(control *[]byte, gsoSize uint16) { 17 | } 18 | 19 | // gsoControlSize returns the recommended buffer size for pooling sticky and UDP 20 | // offloading control data. 21 | const gsoControlSize = 0 22 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/gso_linux.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package conn 9 | 10 | import ( 11 | "fmt" 12 | "unsafe" 13 | 14 | "golang.org/x/sys/unix" 15 | ) 16 | 17 | const ( 18 | sizeOfGSOData = 2 19 | ) 20 | 21 | // getGSOSize parses control for UDP_GRO and if found returns its GSO size data. 22 | func getGSOSize(control []byte) (int, error) { 23 | var ( 24 | hdr unix.Cmsghdr 25 | data []byte 26 | rem = control 27 | err error 28 | ) 29 | 30 | for len(rem) > unix.SizeofCmsghdr { 31 | hdr, data, rem, err = unix.ParseOneSocketControlMessage(rem) 32 | if err != nil { 33 | return 0, fmt.Errorf("error parsing socket control message: %w", err) 34 | } 35 | if hdr.Level == unix.SOL_UDP && hdr.Type == unix.UDP_GRO && len(data) >= sizeOfGSOData { 36 | var gso uint16 37 | copy(unsafe.Slice((*byte)(unsafe.Pointer(&gso)), sizeOfGSOData), data[:sizeOfGSOData]) 38 | return int(gso), nil 39 | } 40 | } 41 | return 0, nil 42 | } 43 | 44 | // setGSOSize sets a UDP_SEGMENT in control based on gsoSize. It leaves existing 45 | // data in control untouched. 46 | func setGSOSize(control *[]byte, gsoSize uint16) { 47 | existingLen := len(*control) 48 | avail := cap(*control) - existingLen 49 | space := unix.CmsgSpace(sizeOfGSOData) 50 | if avail < space { 51 | return 52 | } 53 | *control = (*control)[:cap(*control)] 54 | gsoControl := (*control)[existingLen:] 55 | hdr := (*unix.Cmsghdr)(unsafe.Pointer(&(gsoControl)[0])) 56 | hdr.Level = unix.SOL_UDP 57 | hdr.Type = unix.UDP_SEGMENT 58 | hdr.SetLen(unix.CmsgLen(sizeOfGSOData)) 59 | copy((gsoControl)[unix.CmsgLen(0):], unsafe.Slice((*byte)(unsafe.Pointer(&gsoSize)), sizeOfGSOData)) 60 | *control = (*control)[:existingLen+space] 61 | } 62 | 63 | // gsoControlSize returns the recommended buffer size for pooling UDP 64 | // offloading control data. 65 | var gsoControlSize = unix.CmsgSpace(sizeOfGSOData) 66 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/mark_default.go: -------------------------------------------------------------------------------- 1 | //go:build !linux && !openbsd && !freebsd 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package conn 9 | 10 | func (s *StdNetBind) SetMark(mark uint32) error { 11 | return nil 12 | } 13 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/mark_unix.go: -------------------------------------------------------------------------------- 1 | //go:build linux || openbsd || freebsd 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package conn 9 | 10 | import ( 11 | "runtime" 12 | 13 | "golang.org/x/sys/unix" 14 | ) 15 | 16 | var fwmarkIoctl int 17 | 18 | func init() { 19 | switch runtime.GOOS { 20 | case "linux", "android": 21 | fwmarkIoctl = 36 /* unix.SO_MARK */ 22 | case "freebsd": 23 | fwmarkIoctl = 0x1015 /* unix.SO_USER_COOKIE */ 24 | case "openbsd": 25 | fwmarkIoctl = 0x1021 /* unix.SO_RTABLE */ 26 | } 27 | } 28 | 29 | func (s *StdNetBind) SetMark(mark uint32) error { 30 | var operr error 31 | if fwmarkIoctl == 0 { 32 | return nil 33 | } 34 | if s.ipv4 != nil { 35 | fd, err := s.ipv4.SyscallConn() 36 | if err != nil { 37 | return err 38 | } 39 | err = fd.Control(func(fd uintptr) { 40 | operr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark)) 41 | }) 42 | if err == nil { 43 | err = operr 44 | } 45 | if err != nil { 46 | return err 47 | } 48 | } 49 | if s.ipv6 != nil { 50 | fd, err := s.ipv6.SyscallConn() 51 | if err != nil { 52 | return err 53 | } 54 | err = fd.Control(func(fd uintptr) { 55 | operr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark)) 56 | }) 57 | if err == nil { 58 | err = operr 59 | } 60 | if err != nil { 61 | return err 62 | } 63 | } 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /wg/wireguard-go/conn/sticky_default.go: -------------------------------------------------------------------------------- 1 | //go:build !linux || android 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package conn 9 | 10 | import "net/netip" 11 | 12 | func (e *StdNetEndpoint) SrcIP() netip.Addr { 13 | return netip.Addr{} 14 | } 15 | 16 | func (e *StdNetEndpoint) SrcIfidx() int32 { 17 | return 0 18 | } 19 | 20 | func (e *StdNetEndpoint) SrcToString() string { 21 | return "" 22 | } 23 | 24 | // TODO: macOS, FreeBSD and other BSDs likely do support the sticky sockets 25 | // {get,set}srcControl feature set, but use alternatively named flags and need 26 | // ports and require testing. 27 | 28 | // getSrcFromControl parses the control for PKTINFO and if found updates ep with 29 | // the source information found. 30 | func getSrcFromControl(control []byte, ep *StdNetEndpoint) { 31 | } 32 | 33 | // setSrcControl parses the control for PKTINFO and if found updates ep with 34 | // the source information found. 35 | func setSrcControl(control *[]byte, ep *StdNetEndpoint) { 36 | } 37 | 38 | // stickyControlSize returns the recommended buffer size for pooling sticky 39 | // offloading control data. 40 | const stickyControlSize = 0 41 | 42 | const StdNetSupportsStickySockets = false 43 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/bind_test.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import ( 9 | "errors" 10 | 11 | "golang.zx2c4.com/wireguard/conn" 12 | ) 13 | 14 | type DummyDatagram struct { 15 | msg []byte 16 | endpoint conn.Endpoint 17 | } 18 | 19 | type DummyBind struct { 20 | in6 chan DummyDatagram 21 | in4 chan DummyDatagram 22 | closed bool 23 | } 24 | 25 | func (b *DummyBind) SetMark(v uint32) error { 26 | return nil 27 | } 28 | 29 | func (b *DummyBind) ReceiveIPv6(buf []byte) (int, conn.Endpoint, error) { 30 | datagram, ok := <-b.in6 31 | if !ok { 32 | return 0, nil, errors.New("closed") 33 | } 34 | copy(buf, datagram.msg) 35 | return len(datagram.msg), datagram.endpoint, nil 36 | } 37 | 38 | func (b *DummyBind) ReceiveIPv4(buf []byte) (int, conn.Endpoint, error) { 39 | datagram, ok := <-b.in4 40 | if !ok { 41 | return 0, nil, errors.New("closed") 42 | } 43 | copy(buf, datagram.msg) 44 | return len(datagram.msg), datagram.endpoint, nil 45 | } 46 | 47 | func (b *DummyBind) Close() error { 48 | close(b.in6) 49 | close(b.in4) 50 | b.closed = true 51 | return nil 52 | } 53 | 54 | func (b *DummyBind) Send(buf []byte, end conn.Endpoint) error { 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/constants.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import ( 9 | "time" 10 | ) 11 | 12 | /* Specification constants */ 13 | 14 | const ( 15 | RekeyAfterMessages = (1 << 60) 16 | RejectAfterMessages = (1 << 64) - (1 << 13) - 1 17 | RekeyAfterTime = time.Second * 120 18 | RekeyAttemptTime = time.Second * 90 19 | RekeyTimeout = time.Second * 5 20 | MaxTimerHandshakes = 90 / 5 /* RekeyAttemptTime / RekeyTimeout */ 21 | RekeyTimeoutJitterMaxMs = 334 22 | RejectAfterTime = time.Second * 180 23 | KeepaliveTimeout = time.Second * 10 24 | CookieRefreshTime = time.Second * 120 25 | HandshakeInitationRate = time.Second / 50 26 | PaddingMultiple = 16 27 | ) 28 | 29 | const ( 30 | MinMessageSize = MessageKeepaliveSize // minimum size of transport message (keepalive) 31 | MaxMessageSize = MaxSegmentSize // maximum size of transport message 32 | MaxContentSize = MaxSegmentSize - MessageTransportSize // maximum size of transport message content 33 | ) 34 | 35 | /* Implementation constants */ 36 | 37 | const ( 38 | UnderLoadAfterTime = time.Second // how long does the device remain under load after detected 39 | MaxPeers = 1 << 16 // maximum number of configured peers 40 | ) 41 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/devicestate_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type deviceState -trimprefix=deviceState"; DO NOT EDIT. 2 | 3 | package device 4 | 5 | import "strconv" 6 | 7 | const _deviceState_name = "DownUpClosed" 8 | 9 | var _deviceState_index = [...]uint8{0, 4, 6, 12} 10 | 11 | func (i deviceState) String() string { 12 | if i >= deviceState(len(_deviceState_index)-1) { 13 | return "deviceState(" + strconv.FormatInt(int64(i), 10) + ")" 14 | } 15 | return _deviceState_name[_deviceState_index[i]:_deviceState_index[i+1]] 16 | } 17 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/endpoint_test.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import ( 9 | "math/rand" 10 | "net/netip" 11 | ) 12 | 13 | type DummyEndpoint struct { 14 | src, dst netip.Addr 15 | } 16 | 17 | func CreateDummyEndpoint() (*DummyEndpoint, error) { 18 | var src, dst [16]byte 19 | if _, err := rand.Read(src[:]); err != nil { 20 | return nil, err 21 | } 22 | _, err := rand.Read(dst[:]) 23 | return &DummyEndpoint{netip.AddrFrom16(src), netip.AddrFrom16(dst)}, err 24 | } 25 | 26 | func (e *DummyEndpoint) ClearSrc() {} 27 | 28 | func (e *DummyEndpoint) SrcToString() string { 29 | return netip.AddrPortFrom(e.SrcIP(), 1000).String() 30 | } 31 | 32 | func (e *DummyEndpoint) DstToString() string { 33 | return netip.AddrPortFrom(e.DstIP(), 1000).String() 34 | } 35 | 36 | func (e *DummyEndpoint) DstToBytes() []byte { 37 | out := e.DstIP().AsSlice() 38 | out = append(out, byte(1000&0xff)) 39 | out = append(out, byte((1000>>8)&0xff)) 40 | return out 41 | } 42 | 43 | func (e *DummyEndpoint) DstIP() netip.Addr { 44 | return e.dst 45 | } 46 | 47 | func (e *DummyEndpoint) SrcIP() netip.Addr { 48 | return e.src 49 | } 50 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/indextable.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import ( 9 | "crypto/rand" 10 | "encoding/binary" 11 | "sync" 12 | ) 13 | 14 | type IndexTableEntry struct { 15 | peer *Peer 16 | handshake *Handshake 17 | keypair *Keypair 18 | } 19 | 20 | type IndexTable struct { 21 | sync.RWMutex 22 | table map[uint32]IndexTableEntry 23 | } 24 | 25 | func randUint32() (uint32, error) { 26 | var integer [4]byte 27 | _, err := rand.Read(integer[:]) 28 | // Arbitrary endianness; both are intrinsified by the Go compiler. 29 | return binary.LittleEndian.Uint32(integer[:]), err 30 | } 31 | 32 | func (table *IndexTable) Init() { 33 | table.Lock() 34 | defer table.Unlock() 35 | table.table = make(map[uint32]IndexTableEntry) 36 | } 37 | 38 | func (table *IndexTable) Delete(index uint32) { 39 | table.Lock() 40 | defer table.Unlock() 41 | delete(table.table, index) 42 | } 43 | 44 | func (table *IndexTable) SwapIndexForKeypair(index uint32, keypair *Keypair) { 45 | table.Lock() 46 | defer table.Unlock() 47 | entry, ok := table.table[index] 48 | if !ok { 49 | return 50 | } 51 | table.table[index] = IndexTableEntry{ 52 | peer: entry.peer, 53 | keypair: keypair, 54 | handshake: nil, 55 | } 56 | } 57 | 58 | func (table *IndexTable) NewIndexForHandshake(peer *Peer, handshake *Handshake) (uint32, error) { 59 | for { 60 | // generate random index 61 | 62 | index, err := randUint32() 63 | if err != nil { 64 | return index, err 65 | } 66 | 67 | // check if index used 68 | 69 | table.RLock() 70 | _, ok := table.table[index] 71 | table.RUnlock() 72 | if ok { 73 | continue 74 | } 75 | 76 | // check again while locked 77 | 78 | table.Lock() 79 | _, found := table.table[index] 80 | if found { 81 | table.Unlock() 82 | continue 83 | } 84 | table.table[index] = IndexTableEntry{ 85 | peer: peer, 86 | handshake: handshake, 87 | keypair: nil, 88 | } 89 | table.Unlock() 90 | return index, nil 91 | } 92 | } 93 | 94 | func (table *IndexTable) Lookup(id uint32) IndexTableEntry { 95 | table.RLock() 96 | defer table.RUnlock() 97 | return table.table[id] 98 | } 99 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/ip.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import ( 9 | "net" 10 | ) 11 | 12 | const ( 13 | IPv4offsetTotalLength = 2 14 | IPv4offsetSrc = 12 15 | IPv4offsetDst = IPv4offsetSrc + net.IPv4len 16 | ) 17 | 18 | const ( 19 | IPv6offsetPayloadLength = 4 20 | IPv6offsetSrc = 8 21 | IPv6offsetDst = IPv6offsetSrc + net.IPv6len 22 | ) 23 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/keypair.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import ( 9 | "crypto/cipher" 10 | "sync" 11 | "sync/atomic" 12 | "time" 13 | 14 | "golang.org/x/crypto/chacha20poly1305" 15 | "golang.zx2c4.com/wireguard/replay" 16 | ) 17 | 18 | /* Due to limitations in Go and /x/crypto there is currently 19 | * no way to ensure that key material is securely ereased in memory. 20 | * 21 | * Since this may harm the forward secrecy property, 22 | * we plan to resolve this issue; whenever Go allows us to do so. 23 | */ 24 | 25 | type Keypair struct { 26 | sendNonce atomic.Uint64 27 | send cipher.AEAD 28 | receive cipher.AEAD 29 | replayFilter replay.Filter 30 | isInitiator bool 31 | created time.Time 32 | localIndex uint32 33 | remoteIndex uint32 34 | // just for testing 35 | sendKey [chacha20poly1305.KeySize]byte 36 | recvKey [chacha20poly1305.KeySize]byte 37 | } 38 | 39 | type Keypairs struct { 40 | sync.RWMutex 41 | current *Keypair 42 | previous *Keypair 43 | next atomic.Pointer[Keypair] 44 | } 45 | 46 | func (kp *Keypairs) Current() *Keypair { 47 | kp.RLock() 48 | defer kp.RUnlock() 49 | return kp.current 50 | } 51 | 52 | func (device *Device) DeleteKeypair(key *Keypair) { 53 | if key != nil { 54 | device.indexTable.Delete(key.localIndex) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/logger.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import ( 9 | "log" 10 | "os" 11 | ) 12 | 13 | // A Logger provides logging for a Device. 14 | // The functions are Printf-style functions. 15 | // They must be safe for concurrent use. 16 | // They do not require a trailing newline in the format. 17 | // If nil, that level of logging will be silent. 18 | type Logger struct { 19 | Verbosef func(format string, args ...any) 20 | Errorf func(format string, args ...any) 21 | } 22 | 23 | // Log levels for use with NewLogger. 24 | const ( 25 | LogLevelSilent = iota 26 | LogLevelError 27 | LogLevelVerbose 28 | ) 29 | 30 | // Function for use in Logger for discarding logged lines. 31 | func DiscardLogf(format string, args ...any) {} 32 | 33 | // NewLogger constructs a Logger that writes to stdout. 34 | // It logs at the specified log level and above. 35 | // It decorates log lines with the log level, date, time, and prepend. 36 | func NewLogger(level int, prepend string) *Logger { 37 | logger := &Logger{DiscardLogf, DiscardLogf} 38 | logf := func(prefix string) func(string, ...any) { 39 | return log.New(os.Stdout, prefix+": "+prepend, log.Ldate|log.Ltime).Printf 40 | } 41 | if level >= LogLevelVerbose { 42 | logger.Verbosef = logf("DEBUG") 43 | } 44 | if level >= LogLevelError { 45 | logger.Errorf = logf("ERROR") 46 | } 47 | return logger 48 | } 49 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/mobilequirks.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | // DisableSomeRoamingForBrokenMobileSemantics should ideally be called before peers are created, 9 | // though it will try to deal with it, and race maybe, if called after. 10 | func (device *Device) DisableSomeRoamingForBrokenMobileSemantics() { 11 | device.net.brokenRoaming = true 12 | device.peers.RLock() 13 | for _, peer := range device.peers.keyMap { 14 | peer.endpoint.Lock() 15 | peer.endpoint.disableRoaming = peer.endpoint.val != nil 16 | peer.endpoint.Unlock() 17 | } 18 | device.peers.RUnlock() 19 | } 20 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/noise-types.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import ( 9 | "crypto/subtle" 10 | "encoding/hex" 11 | "errors" 12 | ) 13 | 14 | const ( 15 | NoisePublicKeySize = 32 16 | NoisePrivateKeySize = 32 17 | NoisePresharedKeySize = 32 18 | ) 19 | 20 | type ( 21 | NoisePublicKey [NoisePublicKeySize]byte 22 | NoisePrivateKey [NoisePrivateKeySize]byte 23 | NoisePresharedKey [NoisePresharedKeySize]byte 24 | NoiseNonce uint64 // padded to 12-bytes 25 | ) 26 | 27 | func loadExactHex(dst []byte, src string) error { 28 | slice, err := hex.DecodeString(src) 29 | if err != nil { 30 | return err 31 | } 32 | if len(slice) != len(dst) { 33 | return errors.New("hex string does not fit the slice") 34 | } 35 | copy(dst, slice) 36 | return nil 37 | } 38 | 39 | func (key NoisePrivateKey) IsZero() bool { 40 | var zero NoisePrivateKey 41 | return key.Equals(zero) 42 | } 43 | 44 | func (key NoisePrivateKey) Equals(tar NoisePrivateKey) bool { 45 | return subtle.ConstantTimeCompare(key[:], tar[:]) == 1 46 | } 47 | 48 | func (key *NoisePrivateKey) FromHex(src string) (err error) { 49 | err = loadExactHex(key[:], src) 50 | key.clamp() 51 | return 52 | } 53 | 54 | func (key *NoisePrivateKey) FromMaybeZeroHex(src string) (err error) { 55 | err = loadExactHex(key[:], src) 56 | if key.IsZero() { 57 | return 58 | } 59 | key.clamp() 60 | return 61 | } 62 | 63 | func (key *NoisePublicKey) FromHex(src string) error { 64 | return loadExactHex(key[:], src) 65 | } 66 | 67 | func (key NoisePublicKey) IsZero() bool { 68 | var zero NoisePublicKey 69 | return key.Equals(zero) 70 | } 71 | 72 | func (key NoisePublicKey) Equals(tar NoisePublicKey) bool { 73 | return subtle.ConstantTimeCompare(key[:], tar[:]) == 1 74 | } 75 | 76 | func (key *NoisePresharedKey) FromHex(src string) error { 77 | return loadExactHex(key[:], src) 78 | } 79 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/queueconstants_android.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import "golang.zx2c4.com/wireguard/conn" 9 | 10 | /* Reduce memory consumption for Android */ 11 | 12 | const ( 13 | QueueStagedSize = conn.IdealBatchSize 14 | QueueOutboundSize = 1024 15 | QueueInboundSize = 1024 16 | QueueHandshakeSize = 1024 17 | MaxSegmentSize = (1 << 16) - 1 // largest possible UDP datagram 18 | PreallocatedBuffersPerPool = 4096 19 | ) 20 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/queueconstants_default.go: -------------------------------------------------------------------------------- 1 | //go:build !android && !ios && !windows 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package device 9 | 10 | import "golang.zx2c4.com/wireguard/conn" 11 | 12 | const ( 13 | QueueStagedSize = conn.IdealBatchSize 14 | QueueOutboundSize = 1024 15 | QueueInboundSize = 1024 16 | QueueHandshakeSize = 1024 17 | MaxSegmentSize = (1 << 16) - 1 // largest possible UDP datagram 18 | PreallocatedBuffersPerPool = 0 // Disable and allow for infinite memory growth 19 | ) 20 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/queueconstants_ios.go: -------------------------------------------------------------------------------- 1 | //go:build ios 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package device 9 | 10 | // Fit within memory limits for iOS's Network Extension API, which has stricter requirements. 11 | // These are vars instead of consts, because heavier network extensions might want to reduce 12 | // them further. 13 | var ( 14 | QueueStagedSize = 128 15 | QueueOutboundSize = 1024 16 | QueueInboundSize = 1024 17 | QueueHandshakeSize = 1024 18 | PreallocatedBuffersPerPool uint32 = 1024 19 | ) 20 | 21 | const MaxSegmentSize = 1700 22 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/queueconstants_windows.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | const ( 9 | QueueStagedSize = 128 10 | QueueOutboundSize = 1024 11 | QueueInboundSize = 1024 12 | QueueHandshakeSize = 1024 13 | MaxSegmentSize = 2048 - 32 // largest possible UDP datagram 14 | PreallocatedBuffersPerPool = 0 // Disable and allow for infinite memory growth 15 | ) 16 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/race_disabled_test.go: -------------------------------------------------------------------------------- 1 | //go:build !race 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package device 9 | 10 | const raceEnabled = false 11 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/race_enabled_test.go: -------------------------------------------------------------------------------- 1 | //go:build race 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package device 9 | 10 | const raceEnabled = true 11 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/sticky_default.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | 3 | package device 4 | 5 | import ( 6 | "golang.zx2c4.com/wireguard/conn" 7 | "golang.zx2c4.com/wireguard/rwcancel" 8 | ) 9 | 10 | func (device *Device) startRouteListener(bind conn.Bind) (*rwcancel.RWCancel, error) { 11 | return nil, nil 12 | } 13 | -------------------------------------------------------------------------------- /wg/wireguard-go/device/tun.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package device 7 | 8 | import ( 9 | "fmt" 10 | 11 | "golang.zx2c4.com/wireguard/tun" 12 | ) 13 | 14 | const DefaultMTU = 1420 15 | 16 | func (device *Device) RoutineTUNEventReader() { 17 | device.log.Verbosef("Routine: event worker - started") 18 | 19 | for event := range device.tun.device.Events() { 20 | if event&tun.EventMTUUpdate != 0 { 21 | mtu, err := device.tun.device.MTU() 22 | if err != nil { 23 | device.log.Errorf("Failed to load updated MTU of device: %v", err) 24 | continue 25 | } 26 | if mtu < 0 { 27 | device.log.Errorf("MTU not updated to negative value: %v", mtu) 28 | continue 29 | } 30 | var tooLarge string 31 | if mtu > MaxContentSize { 32 | tooLarge = fmt.Sprintf(" (too large, capped at %v)", MaxContentSize) 33 | mtu = MaxContentSize 34 | } 35 | old := device.tun.mtu.Swap(int32(mtu)) 36 | if int(old) != mtu { 37 | device.log.Verbosef("MTU updated: %v%s", mtu, tooLarge) 38 | } 39 | } 40 | 41 | if event&tun.EventUp != 0 { 42 | device.log.Verbosef("Interface up requested") 43 | device.Up() 44 | } 45 | 46 | if event&tun.EventDown != 0 { 47 | device.log.Verbosef("Interface down requested") 48 | device.Down() 49 | } 50 | } 51 | 52 | device.log.Verbosef("Routine: event worker - stopped") 53 | } 54 | -------------------------------------------------------------------------------- /wg/wireguard-go/format_test.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | package main 6 | 7 | // func TestFormatting(t *testing.T) { 8 | // var wg sync.WaitGroup 9 | // filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error { 10 | // if err != nil { 11 | // t.Errorf("unable to walk %s: %v", path, err) 12 | // return nil 13 | // } 14 | // if d.IsDir() || filepath.Ext(path) != ".go" { 15 | // return nil 16 | // } 17 | // wg.Add(1) 18 | // go func(path string) { 19 | // defer wg.Done() 20 | // src, err := os.ReadFile(path) 21 | // if err != nil { 22 | // t.Errorf("unable to read %s: %v", path, err) 23 | // return 24 | // } 25 | // if runtime.GOOS == "windows" { 26 | // src = bytes.ReplaceAll(src, []byte{'\r', '\n'}, []byte{'\n'}) 27 | // } 28 | // formatted, err := format.Source(src) 29 | // if err != nil { 30 | // t.Errorf("unable to format %s: %v", path, err) 31 | // return 32 | // } 33 | // if !bytes.Equal(src, formatted) { 34 | // t.Errorf("unformatted code: %s", path) 35 | // } 36 | // }(path) 37 | // return nil 38 | // }) 39 | // wg.Wait() 40 | // } 41 | -------------------------------------------------------------------------------- /wg/wireguard-go/go.mod: -------------------------------------------------------------------------------- 1 | module golang.zx2c4.com/wireguard 2 | 3 | go 1.20 4 | 5 | require ( 6 | golang.org/x/crypto v0.13.0 7 | golang.org/x/net v0.15.0 8 | golang.org/x/sys v0.12.0 9 | golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 10 | gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 11 | ) 12 | 13 | require ( 14 | github.com/google/btree v1.0.1 // indirect 15 | golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /wg/wireguard-go/go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= 2 | github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= 3 | golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= 4 | golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= 5 | golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= 6 | golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 7 | golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= 8 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 9 | golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= 10 | golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 11 | golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= 12 | golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= 13 | gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ= 14 | gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY= 15 | -------------------------------------------------------------------------------- /wg/wireguard-go/ipc/uapi_unix.go: -------------------------------------------------------------------------------- 1 | //go:build linux || darwin || freebsd || openbsd 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package ipc 9 | 10 | import ( 11 | "errors" 12 | "fmt" 13 | "net" 14 | "os" 15 | 16 | "golang.org/x/sys/unix" 17 | ) 18 | 19 | const ( 20 | IpcErrorIO = -int64(unix.EIO) 21 | IpcErrorProtocol = -int64(unix.EPROTO) 22 | IpcErrorInvalid = -int64(unix.EINVAL) 23 | IpcErrorPortInUse = -int64(unix.EADDRINUSE) 24 | IpcErrorUnknown = -55 // ENOANO 25 | ) 26 | 27 | // socketDirectory is variable because it is modified by a linker 28 | // flag in wireguard-android. 29 | var socketDirectory = "/var/run/wireguard" 30 | 31 | func sockPath(iface string) string { 32 | return fmt.Sprintf("%s/%s.sock", socketDirectory, iface) 33 | } 34 | 35 | func UAPIOpen(name string) (*os.File, error) { 36 | if err := os.MkdirAll(socketDirectory, 0o755); err != nil { 37 | return nil, err 38 | } 39 | 40 | socketPath := sockPath(name) 41 | addr, err := net.ResolveUnixAddr("unix", socketPath) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | oldUmask := unix.Umask(0o077) 47 | defer unix.Umask(oldUmask) 48 | 49 | listener, err := net.ListenUnix("unix", addr) 50 | if err == nil { 51 | return listener.File() 52 | } 53 | 54 | // Test socket, if not in use cleanup and try again. 55 | if _, err := net.Dial("unix", socketPath); err == nil { 56 | return nil, errors.New("unix socket in use") 57 | } 58 | if err := os.Remove(socketPath); err != nil { 59 | return nil, err 60 | } 61 | listener, err = net.ListenUnix("unix", addr) 62 | if err != nil { 63 | return nil, err 64 | } 65 | return listener.File() 66 | } 67 | -------------------------------------------------------------------------------- /wg/wireguard-go/ipc/uapi_wasm.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package ipc 7 | 8 | // Made up sentinel error codes for {js,wasip1}/wasm. 9 | const ( 10 | IpcErrorIO = 1 11 | IpcErrorInvalid = 2 12 | IpcErrorPortInUse = 3 13 | IpcErrorUnknown = 4 14 | IpcErrorProtocol = 5 15 | ) 16 | -------------------------------------------------------------------------------- /wg/wireguard-go/ipc/uapi_windows.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package ipc 7 | 8 | import ( 9 | "net" 10 | 11 | "golang.org/x/sys/windows" 12 | "golang.zx2c4.com/wireguard/ipc/namedpipe" 13 | ) 14 | 15 | // TODO: replace these with actual standard windows error numbers from the win package 16 | const ( 17 | IpcErrorIO = -int64(5) 18 | IpcErrorProtocol = -int64(71) 19 | IpcErrorInvalid = -int64(22) 20 | IpcErrorPortInUse = -int64(98) 21 | IpcErrorUnknown = -int64(55) 22 | ) 23 | 24 | type UAPIListener struct { 25 | listener net.Listener // unix socket listener 26 | connNew chan net.Conn 27 | connErr chan error 28 | kqueueFd int 29 | keventFd int 30 | } 31 | 32 | func (l *UAPIListener) Accept() (net.Conn, error) { 33 | for { 34 | select { 35 | case conn := <-l.connNew: 36 | return conn, nil 37 | 38 | case err := <-l.connErr: 39 | return nil, err 40 | } 41 | } 42 | } 43 | 44 | func (l *UAPIListener) Close() error { 45 | return l.listener.Close() 46 | } 47 | 48 | func (l *UAPIListener) Addr() net.Addr { 49 | return l.listener.Addr() 50 | } 51 | 52 | var UAPISecurityDescriptor *windows.SECURITY_DESCRIPTOR 53 | 54 | func init() { 55 | var err error 56 | UAPISecurityDescriptor, err = windows.SecurityDescriptorFromString("O:SYD:P(A;;GA;;;SY)(A;;GA;;;BA)S:(ML;;NWNRNX;;;HI)") 57 | if err != nil { 58 | panic(err) 59 | } 60 | } 61 | 62 | func UAPIListen(name string) (net.Listener, error) { 63 | listener, err := (&namedpipe.ListenConfig{ 64 | SecurityDescriptor: UAPISecurityDescriptor, 65 | }).Listen(`\\.\pipe\ProtectedPrefix\Administrators\WireGuard\` + name) 66 | if err != nil { 67 | return nil, err 68 | } 69 | 70 | uapi := &UAPIListener{ 71 | listener: listener, 72 | connNew: make(chan net.Conn, 1), 73 | connErr: make(chan error, 1), 74 | } 75 | 76 | go func(l *UAPIListener) { 77 | for { 78 | conn, err := l.listener.Accept() 79 | if err != nil { 80 | l.connErr <- err 81 | break 82 | } 83 | l.connNew <- conn 84 | } 85 | }(uapi) 86 | 87 | return uapi, nil 88 | } 89 | -------------------------------------------------------------------------------- /wg/wireguard-go/lib/.gitignore: -------------------------------------------------------------------------------- 1 | libowl_wireguard.a -------------------------------------------------------------------------------- /wg/wireguard-go/lib/owl_wireguard.h: -------------------------------------------------------------------------------- 1 | // void test(char *arg); 2 | #include 3 | #include 4 | 5 | void wg_send(void* plaintext, size_t plaintext_len, uint32_t peer, void* send_key, size_t send_key_len, size_t nonce, void* obuf, size_t obuf_len); 6 | 7 | void wg_recv(uint32_t peer, void* recv_key, size_t recv_key_len, size_t nonce, void* buf, size_t buf_len); -------------------------------------------------------------------------------- /wg/wireguard-go/lib/owl_wireguard/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /wg/wireguard-go/lib/owl_wireguard/rust_toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" -------------------------------------------------------------------------------- /wg/wireguard-go/lib/owl_wireguard/src/owl_dhke.rs: -------------------------------------------------------------------------------- 1 | use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; 2 | use vstd::prelude::*; 3 | use libcrux::ecdh::*; 4 | use libcrux::drbg::*; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_ecdh_key_pair() -> (Vec, Vec) { 10 | #[cfg(feature = "nonverif-crypto")] 11 | { 12 | let mut rng = rand::thread_rng(); 13 | let secret = StaticSecret::new(&mut rng); 14 | let public = PublicKey::from(&secret); 15 | let sk_bytes = secret.to_bytes().to_vec(); 16 | let pk_bytes = public.to_bytes().to_vec(); 17 | (sk_bytes, pk_bytes) 18 | } 19 | #[cfg(not(feature = "nonverif-crypto"))] 20 | { 21 | let mut rng = Drbg::new(libcrux::digest::Algorithm::Sha256).unwrap(); 22 | let (pk, sk) = x25519_key_gen(&mut rng).unwrap(); 23 | let pk_bytes = pk.0.to_vec(); 24 | let sk_bytes = sk.0.to_vec(); 25 | (sk_bytes, pk_bytes) 26 | } 27 | } 28 | 29 | pub fn ecdh_dhpk(sk: &[u8]) -> Vec { 30 | #[cfg(feature = "nonverif-crypto")] 31 | { 32 | use std::convert::TryInto; 33 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 34 | let sk_decoded = StaticSecret::from(sk_length_checked); 35 | let pk = PublicKey::from(&sk_decoded); 36 | pk.to_bytes().to_vec() 37 | } 38 | #[cfg(not(feature = "nonverif-crypto"))] 39 | { 40 | secret_to_public(Algorithm::X25519, sk).unwrap() 41 | } 42 | } 43 | 44 | #[verifier(external_body)] 45 | pub fn ecdh_combine(sk: &[u8], others_pk: &[u8]) -> Vec { 46 | #[cfg(feature = "nonverif-crypto")] 47 | { 48 | use std::convert::TryInto; 49 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 50 | let pk_length_checked: [u8; 32] = others_pk.try_into().unwrap(); 51 | let sk_decoded = StaticSecret::from(sk_length_checked); 52 | let pk_decoded = PublicKey::from(pk_length_checked); 53 | let shared_secret = sk_decoded.diffie_hellman(&pk_decoded); 54 | shared_secret.as_bytes().to_vec() 55 | } 56 | #[cfg(not(feature = "nonverif-crypto"))] 57 | { 58 | derive(Algorithm::X25519, others_pk, sk).unwrap() 59 | } 60 | } 61 | 62 | } // verus! 63 | -------------------------------------------------------------------------------- /wg/wireguard-go/lib/owl_wireguard/src/owl_hkdf.rs: -------------------------------------------------------------------------------- 1 | use hkdf::Hkdf; 2 | use blake2::Blake2s; 3 | use vstd::prelude::*; 4 | 5 | verus! { 6 | 7 | pub open spec fn spec_kdfkey_size() -> usize { 32 } 8 | pub const fn kdfkey_size() -> (r:usize) ensures r == spec_kdfkey_size() { 32 } 9 | 10 | #[verifier(external_body)] 11 | pub fn gen_rand_kdf_key() -> Vec { 12 | crate::owl_util::gen_rand_bytes(kdfkey_size()) 13 | } 14 | 15 | #[verifier(external_body)] 16 | pub fn extract_expand_to_len(ikm: &[u8], salt: &[u8], info: &[u8], len: usize) -> Vec { 17 | let h = Hkdf::::new(Some(salt), ikm); 18 | let mut okm = vec![0u8; len]; 19 | h.expand(info, &mut okm).expect("failed to expand"); 20 | okm 21 | } 22 | 23 | } // verus! 24 | -------------------------------------------------------------------------------- /wg/wireguard-go/lib/owl_wireguard/src/owl_util.rs: -------------------------------------------------------------------------------- 1 | use rand::{distributions::Uniform, Rng}; 2 | use vstd::prelude::*; 3 | use libcrux::drbg::*; 4 | use libcrux::digest::Algorithm; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_rand_bytes(len: usize) -> Vec { 10 | let mut rng = Drbg::new(Algorithm::Sha256).unwrap(); 11 | rng.generate_vec(len).unwrap() 12 | } 13 | 14 | } // verus! 15 | -------------------------------------------------------------------------------- /wg/wireguard-go/replay/replay.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | // Package replay implements an efficient anti-replay algorithm as specified in RFC 6479. 7 | package replay 8 | 9 | type block uint64 10 | 11 | const ( 12 | blockBitLog = 6 // 1<<6 == 64 bits 13 | blockBits = 1 << blockBitLog // must be power of 2 14 | ringBlocks = 1 << 7 // must be power of 2 15 | windowSize = (ringBlocks - 1) * blockBits 16 | blockMask = ringBlocks - 1 17 | bitMask = blockBits - 1 18 | ) 19 | 20 | // A Filter rejects replayed messages by checking if message counter value is 21 | // within a sliding window of previously received messages. 22 | // The zero value for Filter is an empty filter ready to use. 23 | // Filters are unsafe for concurrent use. 24 | type Filter struct { 25 | last uint64 26 | ring [ringBlocks]block 27 | } 28 | 29 | // Reset resets the filter to empty state. 30 | func (f *Filter) Reset() { 31 | f.last = 0 32 | f.ring[0] = 0 33 | } 34 | 35 | // ValidateCounter checks if the counter should be accepted. 36 | // Overlimit counters (>= limit) are always rejected. 37 | func (f *Filter) ValidateCounter(counter, limit uint64) bool { 38 | if counter >= limit { 39 | return false 40 | } 41 | indexBlock := counter >> blockBitLog 42 | if counter > f.last { // move window forward 43 | current := f.last >> blockBitLog 44 | diff := indexBlock - current 45 | if diff > ringBlocks { 46 | diff = ringBlocks // cap diff to clear the whole ring 47 | } 48 | for i := current + 1; i <= current+diff; i++ { 49 | f.ring[i&blockMask] = 0 50 | } 51 | f.last = counter 52 | } else if f.last-counter > windowSize { // behind current window 53 | return false 54 | } 55 | // check and set bit 56 | indexBlock &= blockMask 57 | indexBit := counter & bitMask 58 | old := f.ring[indexBlock] 59 | new := old | 1< 0 37 | } 38 | 39 | func (t Timestamp) String() string { 40 | return time.Unix(int64(binary.BigEndian.Uint64(t[:8])-base), int64(binary.BigEndian.Uint32(t[8:12]))).String() 41 | } 42 | -------------------------------------------------------------------------------- /wg/wireguard-go/tai64n/tai64n_test.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package tai64n 7 | 8 | import ( 9 | "testing" 10 | "time" 11 | ) 12 | 13 | // Test that timestamps are monotonic as required by Wireguard and that 14 | // nanosecond-level information is whitened to prevent side channel attacks. 15 | func TestMonotonic(t *testing.T) { 16 | startTime := time.Unix(0, 123456789) // a nontrivial bit pattern 17 | // Whitening should reduce timestamp granularity 18 | // to more than 10 but fewer than 20 milliseconds. 19 | tests := []struct { 20 | name string 21 | t1, t2 time.Time 22 | wantAfter bool 23 | }{ 24 | {"after_10_ns", startTime, startTime.Add(10 * time.Nanosecond), false}, 25 | {"after_10_us", startTime, startTime.Add(10 * time.Microsecond), false}, 26 | {"after_1_ms", startTime, startTime.Add(time.Millisecond), false}, 27 | {"after_10_ms", startTime, startTime.Add(10 * time.Millisecond), false}, 28 | {"after_20_ms", startTime, startTime.Add(20 * time.Millisecond), true}, 29 | } 30 | 31 | for _, tt := range tests { 32 | t.Run(tt.name, func(t *testing.T) { 33 | ts1, ts2 := stamp(tt.t1), stamp(tt.t2) 34 | got := ts2.After(ts1) 35 | if got != tt.wantAfter { 36 | t.Errorf("after = %v; want %v", got, tt.wantAfter) 37 | } 38 | }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /wg/wireguard-go/tun/alignment_windows_test.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package tun 7 | 8 | import ( 9 | "reflect" 10 | "testing" 11 | "unsafe" 12 | ) 13 | 14 | func checkAlignment(t *testing.T, name string, offset uintptr) { 15 | t.Helper() 16 | if offset%8 != 0 { 17 | t.Errorf("offset of %q within struct is %d bytes, which does not align to 64-bit word boundaries (missing %d bytes). Atomic operations will crash on 32-bit systems.", name, offset, 8-(offset%8)) 18 | } 19 | } 20 | 21 | // TestRateJugglerAlignment checks that atomically-accessed fields are 22 | // aligned to 64-bit boundaries, as required by the atomic package. 23 | // 24 | // Unfortunately, violating this rule on 32-bit platforms results in a 25 | // hard segfault at runtime. 26 | func TestRateJugglerAlignment(t *testing.T) { 27 | var r rateJuggler 28 | 29 | typ := reflect.TypeOf(&r).Elem() 30 | t.Logf("Peer type size: %d, with fields:", typ.Size()) 31 | for i := 0; i < typ.NumField(); i++ { 32 | field := typ.Field(i) 33 | t.Logf("\t%30s\toffset=%3v\t(type size=%3d, align=%d)", 34 | field.Name, 35 | field.Offset, 36 | field.Type.Size(), 37 | field.Type.Align(), 38 | ) 39 | } 40 | 41 | checkAlignment(t, "rateJuggler.current", unsafe.Offsetof(r.current)) 42 | checkAlignment(t, "rateJuggler.nextByteCount", unsafe.Offsetof(r.nextByteCount)) 43 | checkAlignment(t, "rateJuggler.nextStartTime", unsafe.Offsetof(r.nextStartTime)) 44 | } 45 | 46 | // TestNativeTunAlignment checks that atomically-accessed fields are 47 | // aligned to 64-bit boundaries, as required by the atomic package. 48 | // 49 | // Unfortunately, violating this rule on 32-bit platforms results in a 50 | // hard segfault at runtime. 51 | func TestNativeTunAlignment(t *testing.T) { 52 | var tun NativeTun 53 | 54 | typ := reflect.TypeOf(&tun).Elem() 55 | t.Logf("Peer type size: %d, with fields:", typ.Size()) 56 | for i := 0; i < typ.NumField(); i++ { 57 | field := typ.Field(i) 58 | t.Logf("\t%30s\toffset=%3v\t(type size=%3d, align=%d)", 59 | field.Name, 60 | field.Offset, 61 | field.Type.Size(), 62 | field.Type.Align(), 63 | ) 64 | } 65 | 66 | checkAlignment(t, "NativeTun.rate", unsafe.Offsetof(tun.rate)) 67 | } 68 | -------------------------------------------------------------------------------- /wg/wireguard-go/tun/checksum_test.go: -------------------------------------------------------------------------------- 1 | package tun 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | func BenchmarkChecksum(b *testing.B) { 10 | lengths := []int{ 11 | 64, 12 | 128, 13 | 256, 14 | 512, 15 | 1024, 16 | 1500, 17 | 2048, 18 | 4096, 19 | 8192, 20 | 9000, 21 | 9001, 22 | } 23 | 24 | for _, length := range lengths { 25 | b.Run(fmt.Sprintf("%d", length), func(b *testing.B) { 26 | buf := make([]byte, length) 27 | rng := rand.New(rand.NewSource(1)) 28 | rng.Read(buf) 29 | b.ResetTimer() 30 | for i := 0; i < b.N; i++ { 31 | checksum(buf, 0) 32 | } 33 | }) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /wg/wireguard-go/tun/errors.go: -------------------------------------------------------------------------------- 1 | package tun 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ( 8 | // ErrTooManySegments is returned by Device.Read() when segmentation 9 | // overflows the length of supplied buffers. This error should not cause 10 | // reads to cease. 11 | ErrTooManySegments = errors.New("too many segments") 12 | ) 13 | -------------------------------------------------------------------------------- /wg/wireguard-go/tun/netstack/examples/http_client.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "io" 12 | "log" 13 | "net/http" 14 | "net/netip" 15 | 16 | "golang.zx2c4.com/wireguard/conn" 17 | "golang.zx2c4.com/wireguard/device" 18 | "golang.zx2c4.com/wireguard/tun/netstack" 19 | ) 20 | 21 | func main() { 22 | tun, tnet, err := netstack.CreateNetTUN( 23 | []netip.Addr{netip.MustParseAddr("192.168.4.28")}, 24 | []netip.Addr{netip.MustParseAddr("8.8.8.8")}, 25 | 1420) 26 | if err != nil { 27 | log.Panic(err) 28 | } 29 | dev := device.NewDevice(tun, conn.NewDefaultBind(), device.NewLogger(device.LogLevelVerbose, "")) 30 | err = dev.IpcSet(`private_key=087ec6e14bbed210e7215cdc73468dfa23f080a1bfb8665b2fd809bd99d28379 31 | public_key=c4c8e984c5322c8184c72265b92b250fdb63688705f504ba003c88f03393cf28 32 | allowed_ip=0.0.0.0/0 33 | endpoint=127.0.0.1:58120 34 | `) 35 | err = dev.Up() 36 | if err != nil { 37 | log.Panic(err) 38 | } 39 | 40 | client := http.Client{ 41 | Transport: &http.Transport{ 42 | DialContext: tnet.DialContext, 43 | }, 44 | } 45 | resp, err := client.Get("http://192.168.4.29/") 46 | if err != nil { 47 | log.Panic(err) 48 | } 49 | body, err := io.ReadAll(resp.Body) 50 | if err != nil { 51 | log.Panic(err) 52 | } 53 | log.Println(string(body)) 54 | } 55 | -------------------------------------------------------------------------------- /wg/wireguard-go/tun/netstack/examples/http_server.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "io" 12 | "log" 13 | "net" 14 | "net/http" 15 | "net/netip" 16 | 17 | "golang.zx2c4.com/wireguard/conn" 18 | "golang.zx2c4.com/wireguard/device" 19 | "golang.zx2c4.com/wireguard/tun/netstack" 20 | ) 21 | 22 | func main() { 23 | tun, tnet, err := netstack.CreateNetTUN( 24 | []netip.Addr{netip.MustParseAddr("192.168.4.29")}, 25 | []netip.Addr{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("8.8.4.4")}, 26 | 1420, 27 | ) 28 | if err != nil { 29 | log.Panic(err) 30 | } 31 | dev := device.NewDevice(tun, conn.NewDefaultBind(), device.NewLogger(device.LogLevelVerbose, "")) 32 | dev.IpcSet(`private_key=003ed5d73b55806c30de3f8a7bdab38af13539220533055e635690b8b87ad641 33 | listen_port=58120 34 | public_key=f928d4f6c1b86c12f2562c10b07c555c5c57fd00f59e90c8d8d88767271cbf7c 35 | allowed_ip=192.168.4.28/32 36 | persistent_keepalive_interval=25 37 | `) 38 | dev.Up() 39 | listener, err := tnet.ListenTCP(&net.TCPAddr{Port: 80}) 40 | if err != nil { 41 | log.Panicln(err) 42 | } 43 | http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 44 | log.Printf("> %s - %s - %s", request.RemoteAddr, request.URL.String(), request.UserAgent()) 45 | io.WriteString(writer, "Hello from userspace TCP!") 46 | }) 47 | err = http.Serve(listener, nil) 48 | if err != nil { 49 | log.Panicln(err) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /wg/wireguard-go/tun/netstack/examples/ping_client.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "bytes" 12 | "log" 13 | "math/rand" 14 | "net/netip" 15 | "time" 16 | 17 | "golang.org/x/net/icmp" 18 | "golang.org/x/net/ipv4" 19 | 20 | "golang.zx2c4.com/wireguard/conn" 21 | "golang.zx2c4.com/wireguard/device" 22 | "golang.zx2c4.com/wireguard/tun/netstack" 23 | ) 24 | 25 | func main() { 26 | tun, tnet, err := netstack.CreateNetTUN( 27 | []netip.Addr{netip.MustParseAddr("192.168.4.29")}, 28 | []netip.Addr{netip.MustParseAddr("8.8.8.8")}, 29 | 1420) 30 | if err != nil { 31 | log.Panic(err) 32 | } 33 | dev := device.NewDevice(tun, conn.NewDefaultBind(), device.NewLogger(device.LogLevelVerbose, "")) 34 | dev.IpcSet(`private_key=a8dac1d8a70a751f0f699fb14ba1cff7b79cf4fbd8f09f44c6e6a90d0369604f 35 | public_key=25123c5dcd3328ff645e4f2a3fce0d754400d3887a0cb7c56f0267e20fbf3c5b 36 | endpoint=163.172.161.0:12912 37 | allowed_ip=0.0.0.0/0 38 | `) 39 | err = dev.Up() 40 | if err != nil { 41 | log.Panic(err) 42 | } 43 | 44 | socket, err := tnet.Dial("ping4", "zx2c4.com") 45 | if err != nil { 46 | log.Panic(err) 47 | } 48 | requestPing := icmp.Echo{ 49 | Seq: rand.Intn(1 << 16), 50 | Data: []byte("gopher burrow"), 51 | } 52 | icmpBytes, _ := (&icmp.Message{Type: ipv4.ICMPTypeEcho, Code: 0, Body: &requestPing}).Marshal(nil) 53 | socket.SetReadDeadline(time.Now().Add(time.Second * 10)) 54 | start := time.Now() 55 | _, err = socket.Write(icmpBytes) 56 | if err != nil { 57 | log.Panic(err) 58 | } 59 | n, err := socket.Read(icmpBytes[:]) 60 | if err != nil { 61 | log.Panic(err) 62 | } 63 | replyPacket, err := icmp.ParseMessage(1, icmpBytes[:n]) 64 | if err != nil { 65 | log.Panic(err) 66 | } 67 | replyPing, ok := replyPacket.Body.(*icmp.Echo) 68 | if !ok { 69 | log.Panicf("invalid reply type: %v", replyPacket) 70 | } 71 | if !bytes.Equal(replyPing.Data, requestPing.Data) || replyPing.Seq != requestPing.Seq { 72 | log.Panicf("invalid ping reply: %v", replyPing) 73 | } 74 | log.Printf("Ping latency: %v", time.Since(start)) 75 | } 76 | -------------------------------------------------------------------------------- /wg/wireguard-go/tun/operateonfd.go: -------------------------------------------------------------------------------- 1 | //go:build darwin || freebsd 2 | 3 | /* SPDX-License-Identifier: MIT 4 | * 5 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 | */ 7 | 8 | package tun 9 | 10 | import ( 11 | "fmt" 12 | ) 13 | 14 | func (tun *NativeTun) operateOnFd(fn func(fd uintptr)) { 15 | sysconn, err := tun.tunFile.SyscallConn() 16 | if err != nil { 17 | tun.errors <- fmt.Errorf("unable to find sysconn for tunfile: %s", err.Error()) 18 | return 19 | } 20 | err = sysconn.Control(fn) 21 | if err != nil { 22 | tun.errors <- fmt.Errorf("unable to control sysconn for tunfile: %s", err.Error()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /wg/wireguard-go/tun/tun.go: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: MIT 2 | * 3 | * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 | */ 5 | 6 | package tun 7 | 8 | import ( 9 | "os" 10 | ) 11 | 12 | type Event int 13 | 14 | const ( 15 | EventUp = 1 << iota 16 | EventDown 17 | EventMTUUpdate 18 | ) 19 | 20 | type Device interface { 21 | // File returns the file descriptor of the device. 22 | File() *os.File 23 | 24 | // Read one or more packets from the Device (without any additional headers). 25 | // On a successful read it returns the number of packets read, and sets 26 | // packet lengths within the sizes slice. len(sizes) must be >= len(bufs). 27 | // A nonzero offset can be used to instruct the Device on where to begin 28 | // reading into each element of the bufs slice. 29 | Read(bufs [][]byte, sizes []int, offset int) (n int, err error) 30 | 31 | // Write one or more packets to the device (without any additional headers). 32 | // On a successful write it returns the number of packets written. A nonzero 33 | // offset can be used to instruct the Device on where to begin writing from 34 | // each packet contained within the bufs slice. 35 | Write(bufs [][]byte, offset int) (int, error) 36 | 37 | // MTU returns the MTU of the Device. 38 | MTU() (int, error) 39 | 40 | // Name returns the current name of the Device. 41 | Name() (string, error) 42 | 43 | // Events returns a channel of type Event, which is fed Device events. 44 | Events() <-chan Event 45 | 46 | // Close stops the Device and closes the Event channel. 47 | Close() error 48 | 49 | // BatchSize returns the preferred/max number of packets that can be read or 50 | // written in a single read/write call. BatchSize must not change over the 51 | // lifetime of a Device. 52 | BatchSize() int 53 | } 54 | -------------------------------------------------------------------------------- /wg/wireguard-go/version.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | const Version = "0.0.20230223" 4 | -------------------------------------------------------------------------------- /wg/wireguard-rs/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | proptest-regressions/ 4 | .idea/ 5 | iperf-tests/ 6 | iperf-linedelay-tests/ -------------------------------------------------------------------------------- /wg/wireguard-rs/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mathias Hall-Andersen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /wg/wireguard-rs/README.md: -------------------------------------------------------------------------------- 1 | # Rust Implementation of WireGuard 2 | 3 | ## Usage 4 | 5 | Most Linux kernel WireGuard users are used to adding an interface with `ip link add wg0 type wireguard`. 6 | With wireguard-rs, instead simply run: 7 | 8 | $ wireguard-rs wg0 9 | 10 | This will create an interface and fork into the background. To remove the interface, use the usual `ip link del wg0`, 11 | or if your system does not support removing interfaces directly, you may instead remove the control socket via 12 | `rm -f /var/run/wireguard/wg0.sock`, which will result in wireguard-rs shutting down. 13 | 14 | When an interface is running, you may use `wg(8)` to configure it, as well as the usual `ip(8)` and `ifconfig(8)` commands. 15 | 16 | ## Platforms 17 | 18 | ### Linux 19 | 20 | This will run on Linux; 21 | however YOU SHOULD NOT RUN THIS ON LINUX. Instead use the kernel module; see the installation page for instructions. 22 | 23 | ### Windows 24 | 25 | Coming soon. 26 | 27 | ### FreeBSD 28 | 29 | Coming soon. 30 | 31 | ### OpenBSD 32 | 33 | Coming soon. 34 | 35 | ## Building 36 | 37 | The wireguard-rs project is targeting the current nightly (although it should also build with stable Rust). 38 | 39 | To build wireguard-rs (on supported platforms): 40 | 41 | 1. Obtain nightly `cargo` and `rustc` through [rustup](https://rustup.rs/) 42 | 2. Clone the repository: `git clone https://git.zx2c4.com/wireguard-rs`. 43 | 3. Run `cargo build --release` from inside the `wireguard-rs` directory. 44 | 45 | ## Architecture 46 | 47 | This section is intended for those wishing to read/contribute to the code. 48 | 49 | WireGuard Rust has a similar separation of concerns as many other implementations of various cryptographic transports: 50 | separating the handshake code from the packet protector. 51 | The handshake module implements an authenticated key-exchange (NoiseIK), 52 | which provides key-material, which is then consumed by the router module (packet protector) 53 | responsible for the actual encapsulation of transport messages (IP packets). 54 | This is illustrated below: 55 | 56 | ![Structure](architecture.svg) 57 | -------------------------------------------------------------------------------- /wg/wireguard-rs/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" -------------------------------------------------------------------------------- /wg/wireguard-rs/src/configuration/error.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt; 3 | 4 | #[cfg(unix)] 5 | use libc::*; 6 | 7 | #[derive(Debug)] 8 | pub enum ConfigError { 9 | FailedToBind, 10 | InvalidHexValue, 11 | InvalidPortNumber, 12 | InvalidFwmark, 13 | InvalidKey, 14 | InvalidSocketAddr, 15 | InvalidKeepaliveInterval, 16 | InvalidAllowedIp, 17 | InvalidOperation, 18 | LineTooLong, 19 | IOError, 20 | UnsupportedValue, 21 | UnsupportedProtocolVersion, 22 | } 23 | 24 | impl fmt::Display for ConfigError { 25 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 26 | write!(f, "ConfigError(errno = {})", self.errno()) 27 | } 28 | } 29 | 30 | impl Error for ConfigError { 31 | fn description(&self) -> &str { 32 | "" 33 | } 34 | 35 | fn source(&self) -> Option<&(dyn Error + 'static)> { 36 | None 37 | } 38 | } 39 | 40 | #[cfg(unix)] 41 | impl ConfigError { 42 | pub fn errno(&self) -> i32 { 43 | // TODO: obtain the correct errorno values 44 | match self { 45 | // insufficient perms 46 | ConfigError::FailedToBind => EPERM, 47 | 48 | // parsing of value failed 49 | ConfigError::InvalidHexValue => EINVAL, 50 | ConfigError::InvalidPortNumber => EINVAL, 51 | ConfigError::InvalidFwmark => EINVAL, 52 | ConfigError::InvalidSocketAddr => EINVAL, 53 | ConfigError::InvalidKeepaliveInterval => EINVAL, 54 | ConfigError::InvalidAllowedIp => EINVAL, 55 | ConfigError::InvalidOperation => EINVAL, 56 | ConfigError::UnsupportedValue => EINVAL, 57 | 58 | // other protocol errors 59 | ConfigError::LineTooLong => EPROTO, 60 | ConfigError::InvalidKey => EPROTO, 61 | ConfigError::UnsupportedProtocolVersion => EPROTO, 62 | 63 | // IO 64 | ConfigError::IOError => EIO, 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/configuration/mod.rs: -------------------------------------------------------------------------------- 1 | mod config; 2 | mod error; 3 | pub mod uapi; 4 | 5 | use super::platform::Endpoint; 6 | use super::platform::{tun, udp}; 7 | use super::wireguard::WireGuard; 8 | 9 | pub use error::ConfigError; 10 | 11 | pub use config::Configuration; 12 | pub use config::WireGuardConfig; 13 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/configuration/uapi/get.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | use super::Configuration; 4 | 5 | pub fn serialize(writer: &mut W, config: &C) -> io::Result<()> { 6 | let mut write = |key: &'static str, value: String| { 7 | debug_assert!(value.is_ascii()); 8 | debug_assert!(key.is_ascii()); 9 | log::trace!("UAPI: return : {}={}", key, value); 10 | writer.write_all(key.as_ref())?; 11 | writer.write_all(b"=")?; 12 | writer.write_all(value.as_ref())?; 13 | writer.write_all(b"\n") 14 | }; 15 | 16 | // serialize interface 17 | config 18 | .get_private_key() 19 | .map(|sk| write("private_key", hex::encode(sk.to_bytes()))); 20 | 21 | config 22 | .get_listen_port() 23 | .map(|port| write("listen_port", port.to_string())); 24 | 25 | config 26 | .get_fwmark() 27 | .map(|fwmark| write("fwmark", fwmark.to_string())); 28 | 29 | // serialize all peers 30 | let mut peers = config.get_peers(); 31 | while let Some(p) = peers.pop() { 32 | write("public_key", hex::encode(p.public_key.as_bytes()))?; 33 | write("preshared_key", hex::encode(p.preshared_key))?; 34 | write("rx_bytes", p.rx_bytes.to_string())?; 35 | write("tx_bytes", p.tx_bytes.to_string())?; 36 | write( 37 | "persistent_keepalive_interval", 38 | p.persistent_keepalive_interval.to_string(), 39 | )?; 40 | 41 | if let Some((secs, nsecs)) = p.last_handshake_time { 42 | write("last_handshake_time_sec", secs.to_string())?; 43 | write("last_handshake_time_nsec", nsecs.to_string())?; 44 | } 45 | 46 | if let Some(endpoint) = p.endpoint { 47 | write("endpoint", endpoint.to_string())?; 48 | } 49 | 50 | for (ip, cidr) in p.allowed_ips { 51 | write("allowed_ip", ip.to_string() + "/" + &cidr.to_string())?; 52 | } 53 | } 54 | 55 | Ok(()) 56 | } 57 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/dummy/endpoint.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use super::super::Endpoint; 4 | 5 | #[derive(Clone, Copy)] 6 | pub struct UnitEndpoint {} 7 | 8 | impl Endpoint for UnitEndpoint { 9 | fn from_address(_: SocketAddr) -> UnitEndpoint { 10 | UnitEndpoint {} 11 | } 12 | 13 | fn into_address(&self) -> SocketAddr { 14 | "127.0.0.1:8080".parse().unwrap() 15 | } 16 | 17 | fn clear_src(&mut self) {} 18 | } 19 | 20 | impl UnitEndpoint { 21 | pub fn new() -> UnitEndpoint { 22 | UnitEndpoint {} 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/dummy/mod.rs: -------------------------------------------------------------------------------- 1 | mod endpoint; 2 | mod tun; 3 | mod udp; 4 | 5 | /* A pure dummy platform available during "test-time" 6 | * 7 | * The use of the dummy platform is to enable unit testing of full WireGuard, 8 | * the configuration interface and the UAPI parser. 9 | */ 10 | 11 | pub use endpoint::*; 12 | pub use tun::*; 13 | pub use udp::*; 14 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/dummy/tun/mod.rs: -------------------------------------------------------------------------------- 1 | use super::super::tun::*; 2 | 3 | mod dummy; 4 | mod void; 5 | 6 | #[derive(Debug)] 7 | pub enum TunError { 8 | Disconnected, 9 | } 10 | 11 | pub use dummy::*; 12 | pub use void::*; 13 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/dummy/tun/void.rs: -------------------------------------------------------------------------------- 1 | /* 2 | // This code provides a "void" implementation of the tunnel interface: 3 | // The implementation never reads and immediately discards any write without error 4 | // 5 | // This is used during benchmarking and profiling of the inbound path. 6 | 7 | use super::*; 8 | 9 | pub struct VoidTun {} 10 | 11 | pub struct VoidReader {} 12 | 13 | pub struct VoidWriter {} 14 | 15 | impl Tun for VoidTun { 16 | type Writer = VoidWriter; 17 | type Reader = VoidReader; 18 | type Error = TunError; 19 | } 20 | 21 | 22 | impl Reader for VodReader { 23 | type Error = TunError; 24 | 25 | fn write(&self, src: &[u8]) -> Result<(), Self::Error> { 26 | debug!( 27 | "dummy::TUN({}) : write ({}, {})", 28 | self.id, 29 | src.len(), 30 | hex::encode(src) 31 | ); 32 | if self.store { 33 | let m = src.to_owned(); 34 | match self.tx.lock().unwrap().send(m) { 35 | Ok(_) => Ok(()), 36 | Err(_) => Err(TunError::Disconnected), 37 | } 38 | } else { 39 | Ok(()) 40 | } 41 | } 42 | } 43 | */ 44 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/endpoint.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | pub trait Endpoint: Send + 'static { 4 | fn from_address(addr: SocketAddr) -> Self; 5 | fn into_address(&self) -> SocketAddr; 6 | fn clear_src(&mut self); 7 | } 8 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/linux/mod.rs: -------------------------------------------------------------------------------- 1 | mod tun; 2 | mod uapi; 3 | mod udp; 4 | 5 | pub use tun::LinuxTun as Tun; 6 | pub use uapi::LinuxUAPI as UAPI; 7 | pub use udp::LinuxUDP as UDP; 8 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/linux/uapi.rs: -------------------------------------------------------------------------------- 1 | use super::super::uapi::*; 2 | 3 | use std::fs; 4 | use std::io; 5 | use std::os::unix::net::{UnixListener, UnixStream}; 6 | 7 | const SOCK_DIR: &str = "/var/run/wireguard/"; 8 | 9 | pub struct LinuxUAPI {} 10 | 11 | impl PlatformUAPI for LinuxUAPI { 12 | type Error = io::Error; 13 | type Bind = UnixListener; 14 | 15 | fn bind(name: &str) -> Result { 16 | let socket_path = format!("{}{}.sock", SOCK_DIR, name); 17 | let _ = fs::create_dir_all(SOCK_DIR); 18 | let _ = fs::remove_file(&socket_path); 19 | UnixListener::bind(socket_path) 20 | } 21 | } 22 | 23 | impl BindUAPI for UnixListener { 24 | type Stream = UnixStream; 25 | type Error = io::Error; 26 | 27 | fn connect(&self) -> Result { 28 | let (stream, _) = self.accept()?; 29 | Ok(stream) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/mod.rs: -------------------------------------------------------------------------------- 1 | mod endpoint; 2 | 3 | pub mod tun; 4 | pub mod uapi; 5 | pub mod udp; 6 | 7 | pub use endpoint::Endpoint; 8 | 9 | #[cfg(target_os = "linux")] 10 | pub mod linux; 11 | 12 | #[cfg(test)] 13 | pub mod dummy; 14 | 15 | #[cfg(target_os = "linux")] 16 | pub use linux as plt; 17 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/tun.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | pub enum TunEvent { 4 | Up(usize), // interface is up (supply MTU) 5 | Down, // interface is down 6 | } 7 | 8 | pub trait Status: Send + 'static { 9 | type Error: Error; 10 | 11 | /// Returns status updates for the interface 12 | /// When the status is unchanged the method blocks 13 | fn event(&mut self) -> Result; 14 | } 15 | 16 | pub trait Writer: Send + Sync + 'static { 17 | type Error: Error; 18 | 19 | /// Receive a cryptkey routed IP packet 20 | /// 21 | /// # Arguments 22 | /// 23 | /// - src: Buffer containing the IP packet to be written 24 | /// 25 | /// # Returns 26 | /// 27 | /// Unit type or an error 28 | fn write(&self, src: &[u8]) -> Result<(), Self::Error>; 29 | } 30 | 31 | pub trait Reader: Send + 'static { 32 | type Error: Error; 33 | 34 | /// Reads an IP packet into dst[offset:] from the tunnel device 35 | /// 36 | /// The reason for providing space for a prefix 37 | /// is to efficiently accommodate platforms on which the packet is prefaced by a header. 38 | /// This space is later used to construct the transport message inplace. 39 | /// 40 | /// # Arguments 41 | /// 42 | /// - buf: Destination buffer (enough space for MTU bytes + header) 43 | /// - offset: Offset for the beginning of the IP packet 44 | /// 45 | /// # Returns 46 | /// 47 | /// The size of the IP packet (ignoring the header) or an std::error::Error instance: 48 | fn read(&self, buf: &mut [u8], offset: usize) -> Result; 49 | } 50 | 51 | pub trait Tun: Send + Sync + 'static { 52 | type Writer: Writer; 53 | type Reader: Reader; 54 | type Error: Error; 55 | } 56 | 57 | /// On some platforms the application can create the TUN device itself. 58 | pub trait PlatformTun: Tun { 59 | type Status: Status; 60 | 61 | #[allow(clippy::type_complexity)] 62 | fn create(name: &str) -> Result<(Vec, Self::Writer, Self::Status), Self::Error>; 63 | } 64 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/uapi.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::io::{Read, Write}; 3 | 4 | pub trait BindUAPI { 5 | type Stream: Read + Write; 6 | type Error: Error; 7 | 8 | fn connect(&self) -> Result; 9 | } 10 | 11 | pub trait PlatformUAPI { 12 | type Error: Error; 13 | type Bind: BindUAPI; 14 | 15 | fn bind(name: &str) -> Result; 16 | } 17 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/platform/udp.rs: -------------------------------------------------------------------------------- 1 | use super::Endpoint; 2 | use std::error::Error; 3 | 4 | pub trait Reader: Send + Sync { 5 | type Error: Error; 6 | 7 | fn read(&self, buf: &mut [u8]) -> Result<(usize, E), Self::Error>; 8 | } 9 | 10 | pub trait Writer: Send + Sync + 'static { 11 | type Error: Error; 12 | 13 | fn write(&self, buf: &[u8], dst: &mut E) -> Result<(), Self::Error>; 14 | } 15 | 16 | pub trait UDP: Send + Sync + 'static { 17 | type Error: Error; 18 | type Endpoint: Endpoint; 19 | 20 | /* Until Rust gets type equality constraints these have to be generic */ 21 | type Writer: Writer; 22 | type Reader: Reader; 23 | } 24 | 25 | /// On platforms where fwmark can be set and the 26 | /// implementation can bind to a new port during later configuration (UAPI support), 27 | /// this type provides the ability to set the fwmark and close the socket (by dropping the instance) 28 | pub trait Owner: Send { 29 | type Error: Error; 30 | 31 | fn get_port(&self) -> u16; 32 | 33 | fn set_fwmark(&mut self, value: Option) -> Result<(), Self::Error>; 34 | } 35 | 36 | /// On some platforms the application can itself bind to a socket. 37 | /// This enables configuration using the UAPI interface. 38 | pub trait PlatformUDP: UDP { 39 | type Owner: Owner; 40 | 41 | /// Bind to a new port, returning the reader/writer and 42 | /// an associated instance of the owner type, which closes the UDP socket upon "drop" 43 | /// and enables configuration of the fwmark value. 44 | #[allow(clippy::type_complexity)] 45 | fn bind(port: u16) -> Result<(Vec, Self::Writer, Self::Owner), Self::Error>; 46 | } 47 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/constants.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | use std::u64; 3 | 4 | pub const REKEY_AFTER_MESSAGES: u64 = 1 << 60; 5 | pub const REJECT_AFTER_MESSAGES: u64 = u64::MAX - (1 << 4); 6 | 7 | pub const REKEY_AFTER_TIME: Duration = Duration::from_secs(120); 8 | pub const REJECT_AFTER_TIME: Duration = Duration::from_secs(180); 9 | pub const REKEY_ATTEMPT_TIME: Duration = Duration::from_secs(90); 10 | pub const REKEY_TIMEOUT: Duration = Duration::from_secs(5); 11 | pub const KEEPALIVE_TIMEOUT: Duration = Duration::from_secs(10); 12 | 13 | pub const MAX_TIMER_HANDSHAKES: usize = 14 | (REKEY_ATTEMPT_TIME.as_secs() / REKEY_TIMEOUT.as_secs()) as usize; 15 | 16 | // Semantics: 17 | // Maximum number of buffered handshake requests 18 | // (either from outside message or handshake requests triggered locally) 19 | pub const MAX_QUEUED_INCOMING_HANDSHAKES: usize = 4096; 20 | 21 | // Semantics: 22 | // When the number of queued handshake requests exceeds this number 23 | // the device is considered under load and DoS mitigation is triggered. 24 | pub const THRESHOLD_UNDER_LOAD: usize = MAX_QUEUED_INCOMING_HANDSHAKES / 8; 25 | 26 | // Semantics: 27 | // When a device is detected to go under load, 28 | // it will remain under load for at least the following duration. 29 | pub const DURATION_UNDER_LOAD: Duration = Duration::from_secs(1); 30 | 31 | // Semantics: 32 | // The payload of transport messages are padded to this multiple 33 | pub const MESSAGE_PADDING_MULTIPLE: usize = 16; 34 | 35 | // Semantics: 36 | // Longest possible duration of any WireGuard timer 37 | pub const TIMER_MAX_DURATION: Duration = Duration::from_secs(200); 38 | 39 | // Semantics: 40 | // Resolution of the timer-wheel 41 | pub const TIMERS_TICK: Duration = Duration::from_millis(100); 42 | 43 | // Semantics: 44 | // Resulting number of slots in the wheel 45 | pub const TIMERS_SLOTS: usize = (TIMER_MAX_DURATION.as_micros() / TIMERS_TICK.as_micros()) as usize; 46 | 47 | // Performance: 48 | // Initial capacity of timer-wheel (grows to accommodate more timers). 49 | pub const TIMERS_CAPACITY: usize = 16; 50 | 51 | /* A long duration (compared to the WireGuard time constants), 52 | * used in places to avoid Option by instead using a long "expired" Instant: 53 | * (Instant::now() - TIME_HORIZON) 54 | * 55 | * Note, this duration need not fit inside the timer wheel. 56 | */ 57 | pub const TIME_HORIZON: Duration = Duration::from_secs(TIMER_MAX_DURATION.as_secs() * 2); 58 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/handshake/mod.rs: -------------------------------------------------------------------------------- 1 | /* Implementation of the: 2 | * 3 | * Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s 4 | * 5 | * Protocol pattern, see: http://www.noiseprotocol.org/noise.html. 6 | * For documentation. 7 | */ 8 | 9 | pub mod device; 10 | mod macs; 11 | mod messages; 12 | mod noise; 13 | mod peer; 14 | mod ratelimiter; 15 | pub mod timestamp; 16 | mod types; 17 | 18 | #[cfg(test)] 19 | mod tests; 20 | 21 | // publicly exposed interface 22 | 23 | pub use device::Device; 24 | pub use messages::{MAX_HANDSHAKE_MSG_SIZE, TYPE_COOKIE_REPLY, TYPE_INITIATION, TYPE_RESPONSE}; 25 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/handshake/timestamp.rs: -------------------------------------------------------------------------------- 1 | use std::time::{SystemTime, UNIX_EPOCH}; 2 | 3 | pub type TAI64N = [u8; 12]; 4 | 5 | const TAI64_EPOCH: u64 = 0x400000000000000a; 6 | 7 | pub const ZERO: TAI64N = [0u8; 12]; 8 | 9 | pub fn now() -> TAI64N { 10 | // get system time as duration 11 | let sysnow = SystemTime::now(); 12 | let delta = sysnow.duration_since(UNIX_EPOCH).unwrap(); 13 | 14 | // convert to tai64n 15 | let tai64_secs = delta.as_secs() + TAI64_EPOCH; 16 | let tai64_nano = delta.subsec_nanos(); 17 | 18 | // serialize 19 | let mut res = [0u8; 12]; 20 | res[..8].copy_from_slice(&tai64_secs.to_be_bytes()[..]); 21 | res[8..].copy_from_slice(&tai64_nano.to_be_bytes()[..]); 22 | res 23 | } 24 | 25 | pub fn compare(old: &TAI64N, new: &TAI64N) -> bool { 26 | for i in 0..12 { 27 | if new[i] > old[i] { 28 | return true; 29 | } 30 | } 31 | false 32 | } 33 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/mod.rs: -------------------------------------------------------------------------------- 1 | /// The wireguard sub-module represents a full, pure, WireGuard implementation: 2 | /// 3 | /// The WireGuard device described here does not depend on particular IO implementations 4 | /// or UAPI, and can be instantiated in unit-tests with the dummy IO implementation. 5 | /// 6 | /// The code at this level serves to "glue" the handshake state-machine 7 | /// and the crypto-key router code together, 8 | /// e.g. every WireGuard peer consists of one handshake peer and one router peer. 9 | mod constants; 10 | mod handshake; 11 | mod peer; 12 | mod queue; 13 | mod router; 14 | mod timers; 15 | mod types; 16 | mod workers; 17 | 18 | mod owl_wg; 19 | 20 | #[cfg(test)] 21 | mod tests; 22 | 23 | #[allow(clippy::module_inception)] 24 | mod wireguard; 25 | 26 | // represents a WireGuard interface 27 | pub use wireguard::WireGuard; 28 | 29 | #[cfg(test)] 30 | use super::platform::dummy; 31 | 32 | use super::platform::{tun, udp, Endpoint}; 33 | use types::KeyPair; 34 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/owl_wg/owl_dhke.rs: -------------------------------------------------------------------------------- 1 | use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; 2 | use vstd::prelude::*; 3 | use libcrux::ecdh::*; 4 | use libcrux::drbg::*; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_ecdh_key_pair() -> (Vec, Vec) { 10 | #[cfg(feature = "nonverif-crypto")] 11 | { 12 | let mut rng = rand::thread_rng(); 13 | let secret = StaticSecret::new(&mut rng); 14 | let public = PublicKey::from(&secret); 15 | let sk_bytes = secret.to_bytes().to_vec(); 16 | let pk_bytes = public.to_bytes().to_vec(); 17 | (sk_bytes, pk_bytes) 18 | } 19 | #[cfg(not(feature = "nonverif-crypto"))] 20 | { 21 | let mut rng = Drbg::new(libcrux::digest::Algorithm::Sha256).unwrap(); 22 | let (pk, sk) = x25519_key_gen(&mut rng).unwrap(); 23 | let pk_bytes = pk.0.to_vec(); 24 | let sk_bytes = sk.0.to_vec(); 25 | (sk_bytes, pk_bytes) 26 | } 27 | } 28 | 29 | pub fn ecdh_dhpk(sk: &[u8]) -> Vec { 30 | #[cfg(feature = "nonverif-crypto")] 31 | { 32 | use std::convert::TryInto; 33 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 34 | let sk_decoded = StaticSecret::from(sk_length_checked); 35 | let pk = PublicKey::from(&sk_decoded); 36 | pk.to_bytes().to_vec() 37 | } 38 | #[cfg(not(feature = "nonverif-crypto"))] 39 | { 40 | secret_to_public(Algorithm::X25519, sk).unwrap() 41 | } 42 | } 43 | 44 | #[verifier(external_body)] 45 | pub fn ecdh_combine(sk: &[u8], others_pk: &[u8]) -> Vec { 46 | #[cfg(feature = "nonverif-crypto")] 47 | { 48 | use std::convert::TryInto; 49 | let sk_length_checked: [u8; 32] = sk.try_into().unwrap(); 50 | let pk_length_checked: [u8; 32] = others_pk.try_into().unwrap(); 51 | let sk_decoded = StaticSecret::from(sk_length_checked); 52 | let pk_decoded = PublicKey::from(pk_length_checked); 53 | let shared_secret = sk_decoded.diffie_hellman(&pk_decoded); 54 | shared_secret.as_bytes().to_vec() 55 | } 56 | #[cfg(not(feature = "nonverif-crypto"))] 57 | { 58 | derive(Algorithm::X25519, others_pk, sk).unwrap() 59 | } 60 | } 61 | 62 | } // verus! 63 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/owl_wg/owl_hkdf.rs: -------------------------------------------------------------------------------- 1 | use hkdf::Hkdf; 2 | use blake2::Blake2s; 3 | use vstd::prelude::*; 4 | 5 | verus! { 6 | 7 | pub open spec fn spec_kdfkey_size() -> usize { 32 } 8 | pub const fn kdfkey_size() -> (r:usize) ensures r == spec_kdfkey_size() { 32 } 9 | 10 | #[verifier(external_body)] 11 | pub fn gen_rand_kdf_key() -> Vec { 12 | crate::wireguard::owl_wg::owl_util::gen_rand_bytes(kdfkey_size()) 13 | } 14 | 15 | #[verifier(external_body)] 16 | pub fn extract_expand_to_len(ikm: &[u8], salt: &[u8], info: &[u8], len: usize) -> Vec { 17 | let h = Hkdf::::new(Some(salt), ikm); 18 | let mut okm = vec![0u8; len]; 19 | h.expand(info, &mut okm).expect("failed to expand"); 20 | okm 21 | } 22 | 23 | } // verus! 24 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/owl_wg/owl_util.rs: -------------------------------------------------------------------------------- 1 | use rand::{distributions::Uniform, Rng}; 2 | use vstd::prelude::*; 3 | use libcrux::drbg::*; 4 | use libcrux::digest::Algorithm; 5 | 6 | verus! { 7 | 8 | #[verifier(external_body)] 9 | pub fn gen_rand_bytes(len: usize) -> Vec { 10 | let mut rng = Drbg::new(Algorithm::Sha256).unwrap(); 11 | rng.generate_vec(len).unwrap() 12 | } 13 | 14 | } // verus! 15 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/queue.rs: -------------------------------------------------------------------------------- 1 | use crossbeam_channel::{bounded, Receiver, Sender}; 2 | use std::sync::Mutex; 3 | 4 | pub struct ParallelQueue { 5 | queue: Mutex>>, 6 | } 7 | 8 | impl ParallelQueue { 9 | /// Create a new ParallelQueue instance 10 | /// 11 | /// # Arguments 12 | /// 13 | /// - `queues`: number of readers 14 | /// - `capacity`: capacity of each internal queue 15 | pub fn new(queues: usize, capacity: usize) -> (Self, Vec>) { 16 | let mut receivers = Vec::with_capacity(queues); 17 | let (tx, rx) = bounded(capacity); 18 | for _ in 0..queues { 19 | receivers.push(rx.clone()); 20 | } 21 | ( 22 | ParallelQueue { 23 | queue: Mutex::new(Some(tx)), 24 | }, 25 | receivers, 26 | ) 27 | } 28 | 29 | pub fn send(&self, v: T) { 30 | if let Some(s) = self.queue.lock().unwrap().as_ref() { 31 | let _ = s.send(v); 32 | } 33 | } 34 | 35 | pub fn close(&self) { 36 | *self.queue.lock().unwrap() = None; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/router/constants.rs: -------------------------------------------------------------------------------- 1 | // WireGuard semantics constants 2 | 3 | pub const MAX_QUEUED_PACKETS: usize = 1024; 4 | 5 | // performance constants 6 | 7 | pub const PARALLEL_QUEUE_SIZE: usize = 4 * MAX_QUEUED_PACKETS; 8 | 9 | pub const INORDER_QUEUE_SIZE: usize = MAX_QUEUED_PACKETS; 10 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/router/ip.rs: -------------------------------------------------------------------------------- 1 | use core::mem; 2 | 3 | use byteorder::BigEndian; 4 | use zerocopy::byteorder::U16; 5 | use zerocopy::LayoutVerified; 6 | use zerocopy::{AsBytes, FromBytes}; 7 | 8 | pub const VERSION_IP4: u8 = 4; 9 | pub const VERSION_IP6: u8 = 6; 10 | 11 | #[repr(packed)] 12 | #[derive(Copy, Clone, FromBytes, AsBytes)] 13 | pub struct IPv4Header { 14 | _f_space1: [u8; 2], 15 | pub f_total_len: U16, 16 | _f_space2: [u8; 8], 17 | pub f_source: [u8; 4], 18 | pub f_destination: [u8; 4], 19 | } 20 | 21 | #[repr(packed)] 22 | #[derive(Copy, Clone, FromBytes, AsBytes)] 23 | pub struct IPv6Header { 24 | _f_space1: [u8; 4], 25 | pub f_len: U16, 26 | _f_space2: [u8; 2], 27 | pub f_source: [u8; 16], 28 | pub f_destination: [u8; 16], 29 | } 30 | 31 | #[inline(always)] 32 | pub fn inner_length(packet: &[u8]) -> Option { 33 | match packet.get(0)? >> 4 { 34 | VERSION_IP4 => { 35 | let (header, _): (LayoutVerified<&[u8], IPv4Header>, _) = 36 | LayoutVerified::new_from_prefix(packet)?; 37 | 38 | Some(header.f_total_len.get() as usize) 39 | } 40 | VERSION_IP6 => { 41 | // check length and cast to IPv6 header 42 | let (header, _): (LayoutVerified<&[u8], IPv6Header>, _) = 43 | LayoutVerified::new_from_prefix(packet)?; 44 | 45 | Some(header.f_len.get() as usize + mem::size_of::()) 46 | } 47 | _ => None, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/router/messages.rs: -------------------------------------------------------------------------------- 1 | use byteorder::LittleEndian; 2 | use zerocopy::byteorder::{U32, U64}; 3 | use zerocopy::{AsBytes, FromBytes}; 4 | 5 | pub const TYPE_TRANSPORT: u32 = 4; 6 | 7 | #[repr(packed)] 8 | #[derive(Copy, Clone, FromBytes, AsBytes)] 9 | pub struct TransportHeader { 10 | pub f_type: U32, 11 | pub f_receiver: U32, 12 | pub f_counter: U64, 13 | } 14 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/router/mod.rs: -------------------------------------------------------------------------------- 1 | mod anti_replay; 2 | mod constants; 3 | mod device; 4 | mod ip; 5 | mod messages; 6 | mod peer; 7 | mod route; 8 | mod types; 9 | 10 | mod queue; 11 | mod receive; 12 | mod send; 13 | mod worker; 14 | 15 | #[cfg(test)] 16 | mod tests; 17 | 18 | use messages::TransportHeader; 19 | 20 | use super::constants::REJECT_AFTER_MESSAGES; 21 | use super::queue::ParallelQueue; 22 | use super::types::*; 23 | 24 | use core::mem; 25 | 26 | pub const SIZE_TAG: usize = 16; 27 | pub const SIZE_MESSAGE_PREFIX: usize = mem::size_of::(); 28 | pub const CAPACITY_MESSAGE_POSTFIX: usize = SIZE_TAG; 29 | 30 | pub const fn message_data_len(payload: usize) -> usize { 31 | payload + mem::size_of::() + SIZE_TAG 32 | } 33 | 34 | pub use device::DeviceHandle as Device; 35 | pub use messages::TYPE_TRANSPORT; 36 | pub use peer::PeerHandle; 37 | pub use types::Callbacks; 38 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/router/tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod bench; 2 | mod tests; 3 | 4 | use super::message_data_len; 5 | use super::SIZE_MESSAGE_PREFIX; 6 | use super::{Callbacks, Device}; 7 | use super::{Key, KeyPair}; 8 | 9 | use super::super::dummy; 10 | use super::super::tests::make_packet; 11 | 12 | use std::time::Instant; 13 | 14 | fn init() { 15 | let _ = env_logger::builder().is_test(true).try_init(); 16 | } 17 | 18 | fn pad(msg: &[u8]) -> Vec { 19 | let mut o = vec![0; msg.len() + SIZE_MESSAGE_PREFIX]; 20 | o[SIZE_MESSAGE_PREFIX..SIZE_MESSAGE_PREFIX + msg.len()].copy_from_slice(msg); 21 | o 22 | } 23 | 24 | pub fn dummy_keypair(initiator: bool) -> KeyPair { 25 | let k1 = Key { 26 | key: [0x53u8; 32], 27 | id: 0x646e6573, 28 | }; 29 | let k2 = Key { 30 | key: [0x52u8; 32], 31 | id: 0x76636572, 32 | }; 33 | if initiator { 34 | KeyPair { 35 | birth: Instant::now(), 36 | initiator: true, 37 | send: k1, 38 | recv: k2, 39 | } 40 | } else { 41 | KeyPair { 42 | birth: Instant::now(), 43 | initiator: false, 44 | send: k2, 45 | recv: k1, 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/router/worker.rs: -------------------------------------------------------------------------------- 1 | use super::queue::ParallelJob; 2 | use super::receive::ReceiveJob; 3 | use super::send::SendJob; 4 | 5 | use super::super::{tun, udp, Endpoint}; 6 | use super::types::Callbacks; 7 | 8 | use crossbeam_channel::Receiver; 9 | 10 | pub enum JobUnion> { 11 | Outbound(SendJob), 12 | Inbound(ReceiveJob), 13 | } 14 | 15 | pub fn worker>( 16 | receiver: Receiver>, 17 | ) { 18 | loop { 19 | log::trace!("pool worker awaiting job"); 20 | match receiver.recv() { 21 | Err(e) => { 22 | log::debug!("worker stopped with {}", e); 23 | break; 24 | } 25 | Ok(JobUnion::Inbound(job)) => { 26 | job.parallel_work(); 27 | job.queue().consume(); 28 | } 29 | Ok(JobUnion::Outbound(job)) => { 30 | job.parallel_work(); 31 | job.queue().consume(); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /wg/wireguard-rs/src/wireguard/types.rs: -------------------------------------------------------------------------------- 1 | use clear_on_drop::clear::Clear; 2 | use std::fmt; 3 | use std::time::Instant; 4 | 5 | #[derive(Clone)] 6 | pub struct Key { 7 | pub key: [u8; 32], 8 | pub id: u32, 9 | } 10 | 11 | // zero key on drop 12 | impl Drop for Key { 13 | fn drop(&mut self) { 14 | self.key.clear() 15 | } 16 | } 17 | 18 | #[cfg(test)] 19 | impl PartialEq for Key { 20 | fn eq(&self, other: &Self) -> bool { 21 | self.id == other.id && self.key[..] == other.key[..] 22 | } 23 | } 24 | 25 | impl fmt::Debug for Key { 26 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 27 | write!(f, "Key {{ id = {} }}", self.id) 28 | } 29 | } 30 | 31 | #[derive(Clone)] 32 | pub struct KeyPair { 33 | pub birth: Instant, // when was the key-pair created 34 | pub initiator: bool, // has the key-pair been confirmed? 35 | pub send: Key, // key for outbound messages 36 | pub recv: Key, // key for inbound messages 37 | } 38 | 39 | impl fmt::Debug for KeyPair { 40 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 41 | write!( 42 | f, 43 | "KeyPair {{ initator = {}, age = {} secs, send = {:?}, recv = {:?}}}", 44 | self.initiator, 45 | self.birth.elapsed().as_secs(), 46 | self.send, 47 | self.recv 48 | ) 49 | } 50 | } 51 | 52 | impl KeyPair { 53 | pub fn local_id(&self) -> u32 { 54 | self.recv.id 55 | } 56 | } 57 | 58 | #[derive(Clone, Copy, Debug)] 59 | pub enum RouterDeviceType { 60 | NoOwl, 61 | OwlInitiator, 62 | OwlResponder, 63 | } 64 | --------------------------------------------------------------------------------