Compare commits

..

64 Commits

Author SHA1 Message Date
wucke13
44264a7bb6 chore: Release rosenpass version 0.2.1-rc.3 2023-11-18 22:58:57 +01:00
wucke13
b095bdaa7c refine ab085998bb
This commit refines the above by making cargo release emit no prefix for release tags even if only a single package is released.
2023-11-18 22:57:53 +01:00
wucke13
9597e485bf chore: Release rosenpass version 0.2.1-rc.2 2023-11-18 22:48:35 +01:00
wucke13
ab085998bb add new trigger for release workflow
The change to a multi crate cargo workspace makes `cargo release` behave differently. Now it prefixes the release tags (e.g. `v0.2.0`) with the package name, so for example `rosenpass-v0.2.0`. This change adds the
2023-11-18 22:43:47 +01:00
wucke13
3901e668cb chore: Release rosenpass version 0.2.1-rc.1 2023-11-18 22:30:46 +01:00
wucke13
b7444bf9b4 add readme link to rosenpass package 2023-11-18 22:25:05 +01:00
Benjamin Lipp
0051cbd48e doc: Add unit test for xor_into 2023-11-15 14:32:19 +01:00
Karolin Varner
27746781c0 fix: Doctest should pass buffers of correct length to handle_msg 2023-11-12 14:42:23 +01:00
Karolin Varner
93439858d1 fix crash on undersized buffers going through the lenses
Co-authored-by: wucke13 <wucke13@gmail.com>
2023-11-12 14:42:23 +01:00
wucke13
1223048b48 Merge pull request #148 from rosenpass/dev/wucke13-update-lock-files
update lock files
2023-11-12 13:44:10 +01:00
wucke13
932bde39cc flake.lock: Update
Flake lock file updates:

• Updated input 'fenix':
    'github:nix-community/fenix/add522038f2a32aa1263c8d3c81e1ea2265cc4e1' (2023-08-23)
  → 'github:nix-community/fenix/81ab0b4f7ae9ebb57daa0edf119c4891806e4d3a' (2023-11-12)
• Updated input 'fenix/rust-analyzer-src':
    'github:rust-lang/rust-analyzer/9e3bf69ad3c736893b285f47f4d014ae1aed1cb0' (2023-08-22)
  → 'github:rust-lang/rust-analyzer/5fcf5289e726785d20d3aa4d13d90a43ed248e83' (2023-11-11)
• Updated input 'flake-utils':
    'github:numtide/flake-utils/919d646de7be200f3bf08cb76ae1f09402b6f9b4' (2023-07-11)
  → 'github:numtide/flake-utils/ff7b65b44d01cf9ba6a71320833626af21126384' (2023-09-12)
• Updated input 'naersk':
    'github:nix-community/naersk/78789c30d64dea2396c9da516bbcc8db3a475207' (2023-08-18)
  → 'github:nix-community/naersk/aeb58d5e8faead8980a807c840232697982d47b9' (2023-10-27)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/78287547942dd8e8afff0ae47fb8e2553db79d7e' (2023-08-08)
  → 'github:NixOS/nixpkgs/34bdaaf1f0b7fb6d9091472edc968ff10a8c2857' (2023-11-01)
2023-11-12 13:29:22 +01:00
wucke13
1d9e62e56b update Cargo.lock 2023-11-12 13:29:06 +01:00
wucke13
3af722a066 Merge pull request #143 from rosenpass/dev/refactor-rp-to-workspace
refactor rp to workspace
2023-11-12 13:27:31 +01:00
wucke13
df60b0bfc3 refine source filter
In particular, replace the error prone sourceByRegex filter for the rosenpass derivation with a simple file suffix filter.
2023-11-12 13:16:34 +01:00
wucke13
6274c6fcdd add workspace Cargo.toml 2023-11-12 13:16:34 +01:00
wucke13
cd00f023fb move the current rosenpass codebase into a subdir
This is preparation to make the rosenpass repo a workspace, which can contain multiple crates.
2023-11-12 13:16:34 +01:00
Karolin Varner
13563237cb chore: rustfmt 2023-11-08 22:05:30 +01:00
Karolin Varner
447a4f7a44 fix: Restore benchmarks to working order 2023-11-08 22:05:30 +01:00
wucke13
6bac6a59ff Merge pull request #141 from rosenpass/dev/engler/app_server
app_server: Replace `is_ok()` by `if let`
2023-10-19 23:09:05 +02:00
Emil Engler
e5e04c6d95 app_server: Replace is_ok() by if let
This commit replaces an `is_ok()` call with a call to `if let`, thereby
fixing a clippy warning.
2023-10-19 13:54:13 +02:00
Emil Engler
15ce25ccd2 Merge pull request #140 from rosenpass/AliceOrunitia-patch-1
Update rosenpass.1
2023-10-19 13:51:28 +02:00
Alice Michaela Bowman
1b383d494c Update rosenpass.1
Small grammatical changes.
2023-10-19 12:44:56 +02:00
Emil Engler
605b6463ff Merge pull request #134 from rosenpass/dev/engler/stack
Follow-ups to the stack increasements
2023-10-06 10:55:14 +02:00
Ashish SHUKLA
04eb86af87 cli: move wg exit status check to thread 2023-10-06 08:27:43 +02:00
Ashish SHUKLA
bf850e3072 cli: handle the exit status of wg process 2023-10-06 08:27:43 +02:00
Ashish SHUKLA
dd39936220 cli: reap spawned wireguard child
Fixes #132
2023-10-06 08:27:43 +02:00
wucke13
b15f17133f Merge pull request #135 from lorenzleutgeb/patch-1
config: Default `WireGuard::extra_params` to empty `Vec`
2023-09-28 19:59:15 +02:00
Lorenz Leutgeb
b50820ecc0 config: Default WireGuard::extra_params to empty Vec
Otherwise, omitting `extra_params` in the configuration file will result in a `WireGuard` configuration object of `None`, even though not specifying `extra_params` is sane.
2023-09-28 11:16:38 +02:00
Emil Engler
f323839967 test: Fix wrong comment
This commit fixes a wrong comment, claiming that the unit tests uses a
stack size of 16MB, where in fact it only uses 8MiB.
2023-09-28 07:58:17 +02:00
Emil Engler
6e15c38254 flake: Remove redundant stack increase
This commit removes the setting of `RUST_MIN_STACK` by the Nix
development shell, because the tests now set the stack size on their
own.

See #128
2023-10-06 10:43:41 +02:00
Emil Engler
b7a76849b7 test: Ensure 8MiB of stack size for key generation
This commit ensures that the call to `StaticKEM::keygen` has a stack of
8MiB.

Especially on Darwin system, this commit is necessary in order to
prevent a stack overflow, as this system only provides stack sizes of
roughly 500KB which is way to small for a Classic McEliece key.

Fixes #118
2023-09-22 16:30:00 +02:00
Emil Engler
d2d72143b5 Merge pull request #126 from rosenpass/dev/engler/unsafe
Remove some `unsafe`s
2023-09-18 07:20:04 -10:00
Emil Engler
1135cd7bbb util: Remove unsafe from store_secret 2023-09-14 10:36:53 +02:00
Emil Engler
51f04f749f cli: Remove unsafe from store_secret
This commit removes the `unsafe` block from the `store_secret` function,
as I see no reason why we should have one here.
2023-09-14 10:34:07 +02:00
Emil Engler
37d1326481 Merge pull request #123 from rosenpass/dev/engler/unsafe
cli: Move `StaticKEM::keygen` out of `unsafe`
2023-09-13 18:09:28 +02:00
Emil Engler
d0a84294aa cli: Move StaticKEM::keygen out of unsafe
This commit moves the `StaticKEM::keygen` call out of an `unsafe` call,
because the function is not unsafe.
2023-09-13 16:36:35 +02:00
wucke13
a98f64c17d Merge pull request #119 from rosenpass/dev/engler/clippy
Fix all clippy warnings
2023-09-07 12:25:47 +02:00
Emil Engler
d6a7ebe88f clippy: Allow false positive with redundancies
This commit allows a redundant closure call in the regard of clippy
warnings, as it is a false positive in our case.
2023-09-06 17:40:34 +02:00
Emil Engler
212336728c build: Fix clippy warnings in build.rs
This commit fixes the clippy warnings in `build.rs`, by making use of
the `if let` language feature.
2023-09-06 17:32:26 +02:00
Emil Engler
f48a923dbf refactor: Remove redundant references
This commit removes redundant references, noted by clippy.
2023-09-06 17:31:56 +02:00
Emil Engler
7b5d0f7d66 Merge pull request #117 from rosenpass/dev/engler/rp-ip
doc: Clarify the assumptions about the server
2023-09-06 17:20:27 +02:00
Emil Engler
1e37f89e83 doc: Clarify the assumptions about the server
This commit clarifies the assumptions about the server/responder in the
`rp.1` manual page, by specifying an IP and open UDP ports that the rest
of this tutorial is going to assume.

Reported-by: Robert Clausecker <fuzxxl@gmail.com>

Fixes #116
2023-09-06 14:25:48 +02:00
wucke13
b997238f42 chore: Release rosenpass version 0.2.0 2023-09-05 19:33:50 +02:00
wucke13
d915e63445 bump versions 2023-08-29 23:48:48 +02:00
wucke13
53d7996dd3 Merge pull request #111 from rosenpass/dev/bsd-port-for-rp-script
add freebsd support, prepare for other BSDs
2023-08-29 23:39:10 +02:00
wucke13
47b4d394ef small fixups for rp script 2023-08-29 23:32:14 +02:00
Emil Engler
578d9e2eb5 Merge pull request #114 from rosenpass/dev/update-deps
cargo: Update outdated dependencies
2023-08-25 11:50:33 +02:00
wucke13
d6b83a4a0b add freebsd support, prepare for other BSDs 2023-08-23 18:20:17 +02:00
Emil Engler
959cd50ef6 Merge pull request #113 from rosenpass/dev/ci/shellcheck 2023-08-23 16:09:05 +02:00
Emil Engler
6025623aad cargo: Update outdated dependencies 2023-08-23 14:44:11 +02:00
Emil Engler
5a67b4708a ci: Perform a shellcheck 2023-08-23 14:39:38 +02:00
wucke13
45145cdd9b Merge pull request #110 from rosenpass/dev/update-oqs-and-flake
Dev/update oqs and flake
2023-08-23 12:59:44 +02:00
wucke13
66e696fea3 flake.lock: Update
Flake lock file updates:

• Updated input 'fenix':
    'github:nix-community/fenix/6e6a94c4d0cac4821b6452fbae46609b89a8ddcf' (2023-06-09)
  → 'github:nix-community/fenix/add522038f2a32aa1263c8d3c81e1ea2265cc4e1' (2023-08-23)
• Updated input 'fenix/rust-analyzer-src':
    'github:rust-lang/rust-analyzer/9c03aa1ac2e67051db83a85baf3cfee902e4dd84' (2023-06-08)
  → 'github:rust-lang/rust-analyzer/9e3bf69ad3c736893b285f47f4d014ae1aed1cb0' (2023-08-22)
• Updated input 'flake-utils':
    'github:numtide/flake-utils/a1720a10a6cfe8234c0e93907ffe81be440f4cef' (2023-05-31)
  → 'github:numtide/flake-utils/919d646de7be200f3bf08cb76ae1f09402b6f9b4' (2023-07-11)
• Updated input 'naersk':
    'github:nix-community/naersk/88cd22380154a2c36799fe8098888f0f59861a15' (2023-03-23)
  → 'github:nix-community/naersk/78789c30d64dea2396c9da516bbcc8db3a475207' (2023-08-18)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/81ed90058a851eb73be835c770e062c6938c8a9e' (2023-06-08)
  → 'github:NixOS/nixpkgs/78287547942dd8e8afff0ae47fb8e2553db79d7e' (2023-08-08)
2023-08-23 11:33:20 +02:00
wucke13
91d0592ad6 update oqs-sys from 0.7.2 to 0.8.0 2023-08-23 11:32:51 +02:00
Emil Engler
8ff9b53365 cli: include a static compiled manual page
This commit re-introduces a static and pre-compiled version of the
manual page back into the source code, in case that an installed version
cannot be found on the host system.
2023-08-21 14:05:34 +02:00
Marek Küthe
067a839d4b rp: Defaults to dual-stack
If currently no IP address, only on IPv6 is listen by default. This commit would make it listen dual-stack - i.e. IPv4 and IPv6 - by default.

Signed-off-by: Marek Küthe <m.k@mk16.de>
2023-08-21 14:04:46 +02:00
Marek Küthe
38835fb0f8 Readme: Add mirrors
Signed-off-by: Marek Küthe <m.k@mk16.de>
2023-08-21 13:59:34 +02:00
wucke13
a2b177470c Merge pull request #101 from rosenpass/dev/fix-ci
add .gitlab-ci.yml
2023-07-01 00:03:52 +02:00
wucke13
1c1e38e2f7 add .gitlab-ci.yml
This gitlab-ci.yml solely is there to enable mirroring to
https://gitlab.com/rosenpass/rosenpass
2023-06-30 23:54:40 +02:00
wucke13
46383bdc4d Merge pull request #99 from rosenpass/dev/fix-ci
add smoke test for devshell and test without nix
2023-06-30 22:31:10 +02:00
wucke13
2805d686e6 default pinpointed macos-13, update nix action
This resolves an error with the darwin based builds, where the install
fails. Pinpointing the macos version will prevent random failrue in
the future --- now we have to opt-in to potential breaking changes when
a new macos release is added to the GitHub Actions runners.

relevant error message:

```console
...
---- Reminders -----------------------------------------------------------------
[ 1 ]
Nix won't work in active shell sessions until you restart them.

Could not set environment: 150: Operation not permitted while System Integrity Protection is engaged
Error: Process completed with exit code 150.
```

fixes #100
2023-06-30 22:17:35 +02:00
wucke13
b274519bad add smoke test for devshell and test without nix
This commit adds two new jobs. One checks that `cargo test` runs
through, and second one checking that `cargo test` inside the nix
devshell runs through as well.

fixes #98
2023-06-30 21:23:04 +02:00
wucke13
3086c7fb93 Merge pull request #97 from rosenpass/engler/cargo-build-hotfix
fix devshell bug introduced in #90
2023-06-30 21:08:40 +02:00
wucke13
d21e3af1bb fix broken devShell
The use of a fakecmake in the main step of the Rosenpass build removed real CMake from the devShell, essentially breaking cargo build from within it. This commit fixes that, by explicitly placing the real CMake in the devShell's nativeBuildInputs.
2023-06-30 21:03:32 +02:00
33 changed files with 1159 additions and 986 deletions

View File

@@ -33,7 +33,7 @@ let systems_map = {
# aarch64-linux
i686-linux: ubuntu-latest,
x86_64-darwin: macos-latest,
x86_64-darwin: macos-13,
x86_64-linux: ubuntu-latest
}
@@ -64,7 +64,7 @@ let runner_setup = [
uses: "actions/checkout@v3"
}
{
uses: "cachix/install-nix-action@v21",
uses: "cachix/install-nix-action@v22",
with: { nix_path: "nixpkgs=channel:nixos-unstable" }
}
{

View File

@@ -15,7 +15,7 @@ jobs:
- i686-linux---rosenpass
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -31,7 +31,7 @@ jobs:
needs: []
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -48,7 +48,7 @@ jobs:
- i686-linux---rosenpass
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -63,7 +63,7 @@ jobs:
- ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -75,12 +75,12 @@ jobs:
x86_64-darwin---default:
name: Build x86_64-darwin.default
runs-on:
- macos-latest
- macos-13
needs:
- x86_64-darwin---rosenpass
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -92,13 +92,13 @@ jobs:
x86_64-darwin---release-package:
name: Build x86_64-darwin.release-package
runs-on:
- macos-latest
- macos-13
needs:
- x86_64-darwin---rosenpass
- x86_64-darwin---rosenpass-oci-image
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -110,11 +110,11 @@ jobs:
x86_64-darwin---rosenpass:
name: Build x86_64-darwin.rosenpass
runs-on:
- macos-latest
- macos-13
needs: []
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -126,12 +126,12 @@ jobs:
x86_64-darwin---rosenpass-oci-image:
name: Build x86_64-darwin.rosenpass-oci-image
runs-on:
- macos-latest
- macos-13
needs:
- x86_64-darwin---rosenpass
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -143,10 +143,10 @@ jobs:
x86_64-darwin---check:
name: Run Nix checks on x86_64-darwin
runs-on:
- macos-latest
- macos-13
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -163,7 +163,7 @@ jobs:
- x86_64-linux---rosenpass
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -180,7 +180,7 @@ jobs:
- x86_64-linux---proverif-patched
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -196,7 +196,7 @@ jobs:
needs: []
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -210,11 +210,11 @@ jobs:
runs-on:
- ubuntu-latest
needs:
- x86_64-linux---rosenpass-static
- x86_64-linux---rosenpass-static-oci-image
- x86_64-linux---rosenpass-static
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -230,7 +230,7 @@ jobs:
needs: []
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -247,7 +247,7 @@ jobs:
- x86_64-linux---rosenpass
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -263,7 +263,7 @@ jobs:
needs: []
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -280,7 +280,7 @@ jobs:
- x86_64-linux---rosenpass-static
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -296,7 +296,7 @@ jobs:
needs: []
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -311,7 +311,7 @@ jobs:
- ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -326,7 +326,7 @@ jobs:
if: ${{ github.ref == 'refs/heads/main' }}
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12

View File

@@ -17,6 +17,14 @@ jobs:
with:
args: --check .
shellcheck:
name: Shellcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
cargo-audit:
runs-on: ubuntu-latest
steps:
@@ -66,3 +74,46 @@ jobs:
# - https://github.com/rosenpass/rosenpass/issues/62
# - https://github.com/rust-lang/rust/issues/108378
- run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items
cargo-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install libsodium
run: sudo apt-get install -y libsodium-dev
# liboqs requires quite a lot of stack memory, thus we adjust
# the default stack size picked for new threads (which is used
# by `cargo test`) to be _big enough_. Setting it to 8 MiB
- run: RUST_MIN_STACK=8388608 cargo test
cargo-test-nix-devshell-x86_64-linux:
runs-on:
- ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- uses: cachix/install-nix-action@v21
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- run: nix develop --command cargo test

View File

@@ -12,7 +12,7 @@ jobs:
- ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -30,10 +30,10 @@ jobs:
x86_64-darwin---release:
name: Build release artifacts for x86_64-darwin
runs-on:
- macos-latest
- macos-13
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12
@@ -54,7 +54,7 @@ jobs:
- ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v21
- uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v12

17
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,17 @@
# TODO use CI_JOB_TOKEN once https://gitlab.com/groups/gitlab-org/-/epics/6310 is fixed
pull-from-gh:
only: ["schedules"]
variables:
REMOTE: "https://github.com/rosenpass/rosenpass.git"
LOCAL: " git@gitlab.com:rosenpass/rosenpass.git"
GIT_STRATEGY: none
before_script:
- mkdir ~/.ssh/
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- echo "$REPO_SSH_KEY" > ~/.ssh/id_ed25519
- chmod 600 --recursive ~/.ssh/
- git config --global user.email "ci@gitlab.com"
- git config --global user.name "CI"
script:
- git clone --mirror $REMOTE rosenpass
- cd rosenpass && git push --mirror $LOCAL

825
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +1,10 @@
[package]
name = "rosenpass"
version = "0.1.2-rc.4"
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Build post-quantum-secure VPNs with WireGuard!"
homepage = "https://rosenpass.eu/"
repository = "https://github.com/rosenpass/rosenpass"
readme = "readme.md"
[workspace]
resolver = "2"
[[bench]]
name = "handshake"
harness = false
members = [
"rosenpass",
]
[dependencies]
base64 = "0.21.1"
static_assertions = "1.1.0"
memoffset = "0.9.0"
libsodium-sys-stable = { version = "1.19.28", features = ["use-pkg-config"] }
oqs-sys = { version = "0.7.2", default-features = false, features = ['classic_mceliece', 'kyber'] }
lazy_static = "1.4.0"
thiserror = "1.0.40"
paste = "1.0.12"
log = { version = "0.4.17", optional = true }
env_logger = { version = "0.10.0", optional = true }
serde = { version = "1.0.163", features = ["derive"] }
toml = "0.7.4"
clap = { version = "4.3.0", features = ["derive"] }
mio = { version = "0.8.6", features = ["net", "os-poll"] }
[build-dependencies]
anyhow = "1.0.71"
[dev-dependencies]
criterion = "0.4.0"
test_bin = "0.4.0"
[features]
default = ["log", "env_logger"]
[workspace.metadata.release]
# ensure that adding `--package` as argument to `cargo release` still creates version tags in the form of `vx.y.z`
tag-prefix = ""

View File

@@ -12,13 +12,13 @@
.Sh DESCRIPTION
.Nm
performs cryptographic key exchanges that are secure against quantum-computers
and outputs the keys.
These keys can then be passed to various services such as wireguard or other
vpn services as pre-shared-keys to achieve security against attackers with
and then outputs the keys.
These keys can then be passed to various services, such as wireguard or other
vpn services, as pre-shared-keys to achieve security against attackers with
quantum computers.
.Pp
This is a research project and quantum computers are not thought to become
practical in less than ten years.
practical in fewer than ten years.
If you are not specifically tasked with developing post-quantum secure systems,
you probably do not need this tool.
.Ss COMMANDS
@@ -31,7 +31,7 @@ file secret!
Start a process to exchange keys with the specified peers.
You should specify at least one peer.
.Pp
It's
Its
.Ar OPTIONS
are as follows:
.Bl -tag -width Ds
@@ -39,7 +39,7 @@ are as follows:
Instructs
.Nm
to listen on the specified interface and port.
By default
By default,
.Nm
will listen on all interfaces and select a random port.
.It Ar verbose

View File

@@ -59,6 +59,10 @@ listening on the provided IP and port combination, allowing connections from
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
In this example, we will assume that the server has an interface bound to
192.168.0.1, that accepts incoming connections on port 9999/UDP for Rosenpass
and port 10000/UDP for WireGuard.
.Pp
To create a VPN connection, start by generating secret keys on both hosts.
.Bd -literal -offset indent
rp genkey server.rosenpass-secret

30
flake.lock generated
View File

@@ -8,11 +8,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1686291735,
"narHash": "sha256-mpq2m6TN3ImqqUqA4u93NvkZu5vH//3spqjmPRbRlvA=",
"lastModified": 1699770036,
"narHash": "sha256-bZmI7ytPAYLpyFNgj5xirDkKuAniOkj1xHdv5aIJ5GM=",
"owner": "nix-community",
"repo": "fenix",
"rev": "6e6a94c4d0cac4821b6452fbae46609b89a8ddcf",
"rev": "81ab0b4f7ae9ebb57daa0edf119c4891806e4d3a",
"type": "github"
},
"original": {
@@ -26,11 +26,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1685518550,
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
@@ -46,11 +46,11 @@
]
},
"locked": {
"lastModified": 1679567394,
"narHash": "sha256-ZvLuzPeARDLiQUt6zSZFGOs+HZmE+3g4QURc8mkBsfM=",
"lastModified": 1698420672,
"narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=",
"owner": "nix-community",
"repo": "naersk",
"rev": "88cd22380154a2c36799fe8098888f0f59861a15",
"rev": "aeb58d5e8faead8980a807c840232697982d47b9",
"type": "github"
},
"original": {
@@ -61,11 +61,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1686237827,
"narHash": "sha256-fAZB+Zkcmc+qlauiFnIH9+2qgwM0NO/ru5pWEw3tDow=",
"lastModified": 1698846319,
"narHash": "sha256-4jyW/dqFBVpWFnhl0nvP6EN4lP7/ZqPxYRjl6var0Oc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "81ed90058a851eb73be835c770e062c6938c8a9e",
"rev": "34bdaaf1f0b7fb6d9091472edc968ff10a8c2857",
"type": "github"
},
"original": {
@@ -84,11 +84,11 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1686239338,
"narHash": "sha256-c6Mm7UnDf3j3akY3YB3rELFA76QRbB8ttSBsh00LWi0=",
"lastModified": 1699715108,
"narHash": "sha256-yPozsobJU55gj+szgo4Lpcg1lHvGQYAT6Y4MrC80mWE=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "9c03aa1ac2e67051db83a85baf3cfee902e4dd84",
"rev": "5fcf5289e726785d20d3aa4d13d90a43ed248e83",
"type": "github"
},
"original": {

View File

@@ -55,14 +55,13 @@
};
# parsed Cargo.toml
cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
cargoToml = builtins.fromTOML (builtins.readFile ./rosenpass/Cargo.toml);
# source files relevant for rust
src = pkgs.lib.sourceByRegex ./. [
"Cargo\\.(toml|lock)"
"build.rs"
"(src|benches)(/.*\\.(rs|md))?"
"rp"
src = pkgs.lib.sources.sourceFilesBySuffices ./. [
".lock"
".rs"
".toml"
];
# builds a bin path for all dependencies for the `rp` shellscript
@@ -112,6 +111,9 @@
version = cargoToml.package.version;
inherit src;
cargoBuildOptions = x: x ++ [ "-p" "rosenpass" ];
cargoTestOptions = x: x ++ [ "-p" "rosenpass" ];
doCheck = true;
nativeBuildInputs = with pkgs; [
@@ -157,11 +159,6 @@
'';
};
# liboqs requires quite a lot of stack memory, thus we adjust
# the default stack size picked for new threads (which is used
# by `cargo test`) to be _big enough_
RUST_MIN_STACK = 8 * 1024 * 1024; # 8 MiB
# We want to build for a specific target...
CARGO_BUILD_TARGET = target;
@@ -290,7 +287,7 @@
packages.proof-proverif = pkgs.stdenv.mkDerivation {
name = "rosenpass-proverif-proof";
version = "unstable";
src = pkgs.lib.sourceByRegex ./. [
src = pkgs.lib.sources.sourceByRegex ./. [
"analyze.sh"
"marzipan(/marzipan.awk)?"
"analysis(/.*)?"
@@ -309,7 +306,6 @@
#
devShells.default = pkgs.mkShell {
inherit (packages.proof-proverif) CRYPTOVERIF_LIB;
inherit (packages.rosenpass) RUST_MIN_STACK;
inputsFrom = [ packages.default ];
nativeBuildInputs = with pkgs; [
cmake # override the fakecmake from the main step above
@@ -322,7 +318,6 @@
};
devShells.coverage = pkgs.mkShell {
inputsFrom = [ packages.default ];
inherit (packages.rosenpass) RUST_MIN_STACK;
nativeBuildInputs = with pkgs; [ inputs.fenix.packages.${system}.complete.toolchain cargo-llvm-cov ];
};

View File

@@ -71,6 +71,13 @@ Rosenpass is packaged for more and more distributions, maybe also for the distri
[![Packaging status](https://repology.org/badge/vertical-allrepos/rosenpass.svg)](https://repology.org/project/rosenpass/versions)
# Mirrors
Don't want to use GitHub or only have an IPv6 connection? Rosenpass has set up two mirrors for this:
- [NotABug](https://notabug.org/rosenpass/rosenpass)
- [GitLab](https://gitlab.com/rosenpass/rosenpass/)
# Supported by
Funded through <a href="https://nlnet.nl/">NLNet</a> with financial support for the European Commission's <a href="https://nlnet.nl/assure">NGI Assure</a> program.

42
rosenpass/Cargo.toml Normal file
View File

@@ -0,0 +1,42 @@
[package]
name = "rosenpass"
version = "0.2.1-rc.3"
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Build post-quantum-secure VPNs with WireGuard!"
homepage = "https://rosenpass.eu/"
repository = "https://github.com/rosenpass/rosenpass"
readme = "readme.md"
[[bench]]
name = "handshake"
harness = false
[dependencies]
anyhow = { version = "1.0.71", features = ["backtrace"] }
base64 = "0.21.1"
static_assertions = "1.1.0"
memoffset = "0.9.0"
libsodium-sys-stable = { version = "1.19.28", features = ["use-pkg-config"] }
oqs-sys = { version = "0.8", default-features = false, features = ['classic_mceliece', 'kyber'] }
lazy_static = "1.4.0"
thiserror = "1.0.40"
paste = "1.0.12"
log = { version = "0.4.17", optional = true }
env_logger = { version = "0.10.0", optional = true }
serde = { version = "1.0.163", features = ["derive"] }
toml = "0.7.4"
clap = { version = "4.3.0", features = ["derive"] }
mio = { version = "0.8.6", features = ["net", "os-poll"] }
[build-dependencies]
anyhow = "1.0.71"
[dev-dependencies]
criterion = "0.4.0"
test_bin = "0.4.0"
stacker = "0.1.15"
[features]
default = ["log", "env_logger"]

View File

@@ -1,7 +1,8 @@
use anyhow::Result;
use rosenpass::pqkem::KEM;
use rosenpass::{
pqkem::{EphemeralKEM, CCAKEM},
protocol::{CcaPk, CcaSk, CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, SymKey},
pqkem::StaticKEM,
protocol::{CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, SPk, SSk, SymKey},
sodium::sodium_init,
};
@@ -38,9 +39,9 @@ fn hs(ini: &mut CryptoServer, res: &mut CryptoServer) -> Result<()> {
Ok(())
}
fn keygen() -> Result<(CcaSk, CcaPk)> {
let (mut sk, mut pk) = (CcaSk::zero(), CcaPk::zero());
CCAKEM::keygen(sk.secret_mut(), pk.secret_mut())?;
fn keygen() -> Result<(SSk, SPk)> {
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
StaticKEM::keygen(sk.secret_mut(), pk.secret_mut())?;
Ok((sk, pk))
}
@@ -61,12 +62,12 @@ fn criterion_benchmark(c: &mut Criterion) {
let (mut a, mut b) = make_server_pair().unwrap();
c.bench_function("cca_secret_alloc", |bench| {
bench.iter(|| {
CcaSk::zero();
SSk::zero();
})
});
c.bench_function("cca_public_alloc", |bench| {
bench.iter(|| {
CcaPk::zero();
SPk::zero();
})
});
c.bench_function("keygen", |bench| {

View File

@@ -21,13 +21,13 @@ fn generate_man() -> String {
// This function is purposely stupid and redundant
let man = render_man("mandoc", "./doc/rosenpass.1");
if man.is_ok() {
return man.unwrap();
if let Ok(man) = man {
return man;
}
let man = render_man("groff", "./doc/rosenpass.1");
if man.is_ok() {
return man.unwrap();
if let Ok(man) = man {
return man;
}
// TODO: Link to online manual here

1
rosenpass/readme.md Symbolic link
View File

@@ -0,0 +1 @@
../readme.md

View File

@@ -1,4 +1,7 @@
use log::{error, info, warn};
use anyhow::bail;
use anyhow::Result;
use log::{debug, error, info, warn};
use mio::Interest;
use mio::Token;
@@ -16,15 +19,14 @@ use std::path::PathBuf;
use std::process::Command;
use std::process::Stdio;
use std::slice;
use std::thread;
use std::time::Duration;
use crate::util::fopen_w;
use crate::RosenpassError;
use crate::{
config::Verbosity,
protocol::{CryptoServer, MsgBuf, PeerPtr, SPk, SSk, SymKey, Timing},
util::{b64_writer, fmt_b64},
Result,
};
const IPV4_ANY_ADDR: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
@@ -97,8 +99,8 @@ impl SocketPtr {
&mut srv.sockets[self.0]
}
pub fn send_to(&self, srv: &AppServer, buf: &[u8], addr: SocketAddr) -> Result<()> {
self.get(srv).send_to(&buf, addr)?;
pub fn send_to(&self, srv: &AppServer, buf: &[u8], addr: SocketAddr) -> anyhow::Result<()> {
self.get(srv).send_to(buf, addr)?;
Ok(())
}
}
@@ -180,7 +182,7 @@ impl Endpoint {
}
/// Start endpoint discovery from a hostname
pub fn discovery_from_hostname(hostname: String) -> Result<Self> {
pub fn discovery_from_hostname(hostname: String) -> anyhow::Result<Self> {
let host = HostPathDiscoveryEndpoint::lookup(hostname)?;
Ok(Endpoint::Discovery(host))
}
@@ -210,7 +212,7 @@ impl Endpoint {
Some(Self::discovery_from_addresses(addrs))
}
pub fn send(&self, srv: &AppServer, buf: &[u8]) -> Result<()> {
pub fn send(&self, srv: &AppServer, buf: &[u8]) -> anyhow::Result<()> {
use Endpoint::*;
match self {
SocketBoundAddress { socket, addr } => socket.send_to(srv, buf, *addr),
@@ -269,7 +271,7 @@ impl HostPathDiscoveryEndpoint {
}
/// Lookup a hostname
pub fn lookup(hostname: String) -> Result<Self> {
pub fn lookup(hostname: String) -> anyhow::Result<Self> {
Ok(Self {
addresses: ToSocketAddrs::to_socket_addrs(&hostname)?.collect(),
scouting_state: Cell::new((0, 0)),
@@ -290,16 +292,16 @@ impl HostPathDiscoveryEndpoint {
/// Attempt to reach the host
///
/// Will round-robin-try different socket-ip-combinations on each call.
pub fn send_scouting(&self, srv: &AppServer, buf: &[u8]) -> Result<()> {
pub fn send_scouting(&self, srv: &AppServer, buf: &[u8]) -> anyhow::Result<()> {
let (addr_off, sock_off) = self.scouting_state.get();
let mut addrs = (&self.addresses)
let mut addrs = (self.addresses)
.iter()
.enumerate()
.cycle()
.skip(addr_off)
.take(self.addresses.len());
let mut sockets = (&srv.sockets)
let mut sockets = (srv.sockets)
.iter()
.enumerate()
.cycle()
@@ -329,19 +331,23 @@ impl HostPathDiscoveryEndpoint {
}
}
error!("Unable to send message: All sockets returned errors.");
return Err(RosenpassError::RuntimeError);
bail!("Unable to send message: All sockets returned errors.")
}
}
impl AppServer {
pub fn new(sk: SSk, pk: SPk, addrs: Vec<SocketAddr>, verbosity: Verbosity) -> Result<Self> {
pub fn new(
sk: SSk,
pk: SPk,
addrs: Vec<SocketAddr>,
verbosity: Verbosity,
) -> anyhow::Result<Self> {
// setup mio
let mio_poll = mio::Poll::new()?;
let events = mio::Events::with_capacity(8);
// bind each SocketAddr to a socket
let maybe_sockets: std::result::Result<Vec<_>, std::io::Error> =
let maybe_sockets: Result<Vec<_>, _> =
addrs.into_iter().map(mio::net::UdpSocket::bind).collect();
let mut sockets = maybe_sockets?;
@@ -408,8 +414,7 @@ impl AppServer {
}
if sockets.is_empty() {
error!("No sockets to listen on!");
return Err(RosenpassError::RuntimeError);
bail!("No sockets to listen on!")
}
// register all sockets to mio
@@ -443,7 +448,7 @@ impl AppServer {
outfile: Option<PathBuf>,
outwg: Option<WireguardOut>,
hostname: Option<String>,
) -> Result<AppPeerPtr> {
) -> anyhow::Result<AppPeerPtr> {
let PeerPtr(pn) = self.crypt.add_peer(psk, pk)?;
assert!(pn == self.peers.len());
let initial_endpoint = hostname
@@ -459,7 +464,7 @@ impl AppServer {
Ok(AppPeerPtr(pn))
}
pub fn listen_loop(&mut self) -> Result<()> {
pub fn listen_loop(&mut self) -> anyhow::Result<()> {
const INIT_SLEEP: f64 = 0.01;
const MAX_FAILURES: i32 = 10;
let mut failure_cnt = 0;
@@ -480,11 +485,10 @@ impl AppServer {
let sleep = INIT_SLEEP * 2.0f64.powf(f64::from(failure_cnt - 1));
let tries_left = MAX_FAILURES - (failure_cnt - 1);
error!(
"unexpected error after processing {} messages: {:?}",
"unexpected error after processing {} messages: {:?} {}",
msgs_processed,
err,
// TODO do we need backtraces?
// err.backtrace()
err.backtrace()
);
if tries_left > 0 {
error!("re-initializing networking in {sleep}! {tries_left} tries left.");
@@ -492,12 +496,11 @@ impl AppServer {
continue;
}
error!("too many network failures");
return Err(RosenpassError::RuntimeError);
bail!("too many network failures");
}
}
pub fn event_loop(&mut self) -> Result<()> {
pub fn event_loop(&mut self) -> anyhow::Result<()> {
let (mut rx, mut tx) = (MsgBuf::zero(), MsgBuf::zero());
/// if socket address for peer is known, call closure
@@ -522,9 +525,11 @@ impl AppServer {
use AppPollResult::*;
use KeyOutputReason::*;
match self.poll(&mut *rx)? {
#[allow(clippy::redundant_closure_call)]
SendInitiation(peer) => tx_maybe_with!(peer, || self
.crypt
.initiate_handshake(peer.lower(), &mut *tx))?,
#[allow(clippy::redundant_closure_call)]
SendRetransmission(peer) => tx_maybe_with!(peer, || self
.crypt
.retransmit_handshake(peer.lower(), &mut *tx))?,
@@ -546,9 +551,11 @@ impl AppServer {
match self.crypt.handle_msg(&rx[..len], &mut *tx) {
Err(ref e) => {
self.verbose().then(|| {
error!(
"error processing incoming message from {:?}: {:?}",
endpoint, e
info!(
"error processing incoming message from {:?}: {:?} {}",
endpoint,
e,
e.backtrace()
);
});
}
@@ -576,7 +583,12 @@ impl AppServer {
}
}
pub fn output_key(&self, peer: AppPeerPtr, why: KeyOutputReason, key: &SymKey) -> Result<()> {
pub fn output_key(
&self,
peer: AppPeerPtr,
why: KeyOutputReason,
key: &SymKey,
) -> anyhow::Result<()> {
let peerid = peer.lower().get(&self.crypt).pidt()?;
let ap = peer.get_app(self);
@@ -611,7 +623,7 @@ impl AppServer {
}
if let Some(owg) = ap.outwg.as_ref() {
let child = Command::new("wg")
let mut child = Command::new("wg")
.arg("set")
.arg(&owg.dev)
.arg("peer")
@@ -621,13 +633,27 @@ impl AppServer {
.stdin(Stdio::piped())
.args(&owg.extra_params)
.spawn()?;
b64_writer(child.stdin.unwrap()).write_all(key.secret())?;
b64_writer(child.stdin.take().unwrap()).write_all(key.secret())?;
thread::spawn(move || {
let status = child.wait();
if let Ok(status) = status {
if status.success() {
debug!("successfully passed psk to wg")
} else {
error!("could not pass psk to wg {:?}", status)
}
} else {
error!("wait failed: {:?}", status)
}
});
}
Ok(())
}
pub fn poll(&mut self, rx_buf: &mut [u8]) -> Result<AppPollResult> {
pub fn poll(&mut self, rx_buf: &mut [u8]) -> anyhow::Result<AppPollResult> {
use crate::protocol::PollResult as C;
use AppPollResult as A;
loop {
@@ -652,7 +678,7 @@ impl AppServer {
&mut self,
buf: &mut [u8],
timeout: Timing,
) -> Result<Option<(usize, Endpoint)>> {
) -> anyhow::Result<Option<(usize, Endpoint)>> {
let timeout = Duration::from_secs_f64(timeout);
// if there is no time to wait on IO, well, then, lets not waste any time!

View File

@@ -1,3 +1,7 @@
use anyhow::{bail, ensure};
use clap::Parser;
use std::path::{Path, PathBuf};
use crate::app_server;
use crate::app_server::AppServer;
use crate::util::{LoadValue, LoadValueB64};
@@ -6,12 +10,7 @@ use crate::{
coloring::Secret,
pqkem::{StaticKEM, KEM},
protocol::{SPk, SSk, SymKey},
Result,
RosenpassError,
};
use clap::Parser;
use log::error;
use std::path::{Path, PathBuf};
use super::config;
@@ -99,21 +98,25 @@ pub enum Cli {
}
impl Cli {
pub fn run() -> Result<()> {
pub fn run() -> anyhow::Result<()> {
let cli = Self::parse();
use Cli::*;
match cli {
Man => {
let _man_cmd = std::process::Command::new("man")
let man_cmd = std::process::Command::new("man")
.args(["1", "rosenpass"])
.status();
if !(man_cmd.is_ok() && man_cmd.unwrap().success()) {
println!(include_str!(env!("ROSENPASS_MAN")));
}
}
GenConfig { config_file, force } => {
if !force && config_file.exists() {
error!("config file {config_file:?} already exists");
return Err(RosenpassError::RuntimeError);
}
ensure!(
force || !config_file.exists(),
"config file {config_file:?} already exists"
);
config::Rosenpass::example_config().store(config_file)?;
}
@@ -127,52 +130,51 @@ impl Cli {
// figure out where the key file is specified, in the config file or directly as flag?
let (pkf, skf) = match (config_file, public_key, secret_key) {
(Some(config_file), _, _) => {
if !config_file.exists() {
error!("config file {config_file:?} does not exist");
return Err(RosenpassError::RuntimeError);
}
ensure!(
config_file.exists(),
"config file {config_file:?} does not exist"
);
let config = config::Rosenpass::load(config_file)?;
(config.public_key, config.secret_key)
}
(_, Some(pkf), Some(skf)) => (pkf, skf),
_ => return Err(RosenpassError::ConfigError(
"either a config-file or both public-key and secret-key file are required"
.into(),
)),
_ => {
bail!("either a config-file or both public-key and secret-key file are required")
}
};
// check that we are not overriding something unintentionally
let mut problems = false;
let mut problems = vec![];
if !force && pkf.is_file() {
problems = true;
error!("public-key file {pkf:?} exist, refusing to overwrite it");
problems.push(format!(
"public-key file {pkf:?} exist, refusing to overwrite it"
));
}
if !force && skf.is_file() {
problems = true;
error!("secret-key file {skf:?} exist, refusing to overwrite it");
problems.push(format!(
"secret-key file {skf:?} exist, refusing to overwrite it"
));
}
if problems {
return Err(RosenpassError::RuntimeError);
if !problems.is_empty() {
bail!(problems.join("\n"));
}
// generate the keys and store them in files
let mut ssk = crate::protocol::SSk::random();
let mut spk = crate::protocol::SPk::random();
StaticKEM::keygen(ssk.secret_mut(), spk.secret_mut())?;
unsafe {
StaticKEM::keygen(ssk.secret_mut(), spk.secret_mut())?;
ssk.store_secret(skf)?;
spk.store_secret(pkf)?;
}
ssk.store_secret(skf)?;
spk.store_secret(pkf)?;
}
ExchangeConfig { config_file } => {
if !config_file.exists() {
error!("config file '{config_file:?}' does not exist");
return Err(RosenpassError::RuntimeError);
}
ensure!(
config_file.exists(),
"config file '{config_file:?}' does not exist"
);
let config = config::Rosenpass::load(config_file)?;
config.validate()?;
@@ -215,7 +217,7 @@ impl Cli {
Ok(())
}
fn event_loop(config: config::Rosenpass) -> Result<()> {
fn event_loop(config: config::Rosenpass) -> anyhow::Result<()> {
// load own keys
let sk = SSk::load(&config.secret_key)?;
let pk = SPk::load(&config.public_key)?;
@@ -248,11 +250,11 @@ impl Cli {
}
trait StoreSecret {
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()>;
fn store_secret<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()>;
}
impl<const N: usize> StoreSecret for Secret<N> {
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()> {
fn store_secret<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
std::fs::write(path, self.secret())?;
Ok(())
}

View File

@@ -6,10 +6,10 @@ use std::{
path::{Path, PathBuf},
};
use log::{error, warn};
use anyhow::{bail, ensure};
use serde::{Deserialize, Serialize};
use crate::{util::fopen_w, Result, RosenpassError};
use crate::util::fopen_w;
#[derive(Debug, Serialize, Deserialize)]
pub struct Rosenpass {
@@ -55,6 +55,8 @@ pub struct RosenpassPeer {
pub struct WireGuard {
pub device: String,
pub peer: String,
#[serde(default)]
pub extra_params: Vec<String>,
}
@@ -62,7 +64,7 @@ impl Rosenpass {
/// Load a config file from a file path
///
/// no validation is conducted
pub fn load<P: AsRef<Path>>(p: P) -> Result<Self> {
pub fn load<P: AsRef<Path>>(p: P) -> anyhow::Result<Self> {
let mut config: Self = toml::from_str(&fs::read_to_string(&p)?)?;
config.config_file_path = p.as_ref().to_owned();
@@ -70,7 +72,7 @@ impl Rosenpass {
}
/// Write a config to a file
pub fn store<P: AsRef<Path>>(&self, p: P) -> Result<()> {
pub fn store<P: AsRef<Path>>(&self, p: P) -> anyhow::Result<()> {
let serialized_config =
toml::to_string_pretty(&self).expect("unable to serialize the default config");
fs::write(p, serialized_config)?;
@@ -78,7 +80,7 @@ impl Rosenpass {
}
/// Commit the configuration to where it came from, overwriting the original file
pub fn commit(&self) -> Result<()> {
pub fn commit(&self) -> anyhow::Result<()> {
let mut f = fopen_w(&self.config_file_path)?;
f.write_all(toml::to_string_pretty(&self)?.as_bytes())?;
@@ -86,40 +88,36 @@ impl Rosenpass {
}
/// Validate a configuration
pub fn validate(&self) -> Result<()> {
pub fn validate(&self) -> anyhow::Result<()> {
// check the public-key file exists
if !(self.public_key.is_file()) {
return Err(RosenpassError::ConfigError(format!(
"public-key file {:?} does not exist",
self.public_key
)));
}
ensure!(
self.public_key.is_file(),
"public-key file {:?} does not exist",
self.public_key
);
// check the secret-key file exists
if !(self.secret_key.is_file()) {
return Err(RosenpassError::ConfigError(format!(
"secret-key file {:?} does not exist",
self.secret_key
)));
}
ensure!(
self.secret_key.is_file(),
"secret-key file {:?} does not exist",
self.secret_key
);
for (i, peer) in self.peers.iter().enumerate() {
// check peer's public-key file exists
if !(peer.public_key.is_file()) {
return Err(RosenpassError::ConfigError(format!(
"peer {i} public-key file {:?} does not exist",
peer.public_key
)));
}
ensure!(
peer.public_key.is_file(),
"peer {i} public-key file {:?} does not exist",
peer.public_key
);
// check endpoint is usable
if let Some(addr) = peer.endpoint.as_ref() {
if !(addr.to_socket_addrs().is_ok()) {
return Err(RosenpassError::ConfigError(format!(
"peer {i} endpoint {} can not be parsed to a socket address",
addr
)));
}
ensure!(
addr.to_socket_addrs().is_ok(),
"peer {i} endpoint {} can not be parsed to a socket address",
addr
);
}
// TODO warn if neither out_key nor exchange_command is defined
@@ -155,7 +153,7 @@ impl Rosenpass {
/// from chaotic args
/// Quest: the grammar is undecideable, what do we do here?
pub fn parse_args(args: Vec<String>) -> Result<Self> {
pub fn parse_args(args: Vec<String>) -> anyhow::Result<Self> {
let mut config = Self::new("", "");
#[derive(Debug, Hash, PartialEq, Eq)]
@@ -178,7 +176,6 @@ impl Rosenpass {
// TODO idea: use config.peers.len() to give index of peer with conflicting argument
use State::*;
let mut problem = false;
let mut state = Own;
let mut current_peer = None;
let p_exists = "a peer should exist by now";
@@ -188,7 +185,9 @@ impl Rosenpass {
(Own, "public-key", None) => OwnPublicKey,
(Own, "secret-key", None) => OwnSecretKey,
(Own, "private-key", None) => {
warn!("the private-key argument is deprecated, please use secret-key instead");
log::warn!(
"the private-key argument is deprecated, please use secret-key instead"
);
OwnSecretKey
}
(Own, "listen", None) => OwnListen,
@@ -197,16 +196,14 @@ impl Rosenpass {
Own
}
(Own, "peer", None) => {
if !(already_set.contains(&OwnPublicKey)) {
return Err(RosenpassError::ConfigError(
"public-key file must be set".into(),
));
}
if !(already_set.contains(&OwnSecretKey)) {
return Err(RosenpassError::ConfigError(
"secret-key file must be set".into(),
));
}
ensure!(
already_set.contains(&OwnPublicKey),
"public-key file must be set"
);
ensure!(
already_set.contains(&OwnSecretKey),
"secret-key file must be set"
);
already_set.clear();
current_peer = Some(RosenpassPeer::default());
@@ -214,20 +211,18 @@ impl Rosenpass {
Peer
}
(OwnPublicKey, pk, None) => {
if !(already_set.insert(OwnPublicKey)) {
return Err(RosenpassError::ConfigError(
"public-key was already set".into(),
));
}
ensure!(
already_set.insert(OwnPublicKey),
"public-key was already set"
);
config.public_key = pk.into();
Own
}
(OwnSecretKey, sk, None) => {
if !(already_set.insert(OwnSecretKey)) {
return Err(RosenpassError::ConfigError(
"secret-key was already set".into(),
));
}
ensure!(
already_set.insert(OwnSecretKey),
"secret-key was already set"
);
config.secret_key = sk.into();
Own
}
@@ -255,45 +250,36 @@ impl Rosenpass {
(Peer, "outfile", Some(_)) => PeerOutfile,
(Peer, "wireguard", Some(_)) => PeerWireguardDev,
(PeerPublicKey, pk, Some(peer)) => {
if !(already_set.insert(PeerPublicKey)) {
return Err(RosenpassError::ConfigError(
"public-key was already set".into(),
));
}
ensure!(
already_set.insert(PeerPublicKey),
"public-key was already set"
);
peer.public_key = pk.into();
Peer
}
(PeerEndpoint, e, Some(peer)) => {
if !already_set.insert(PeerEndpoint) {
error!("endpoint was already set");
problem = true;
}
ensure!(already_set.insert(PeerEndpoint), "endpoint was already set");
peer.endpoint = Some(e.to_owned());
Peer
}
(PeerPsk, psk, Some(peer)) => {
if !already_set.insert(PeerEndpoint) {
error!("peer psk was already set");
problem = true;
}
ensure!(already_set.insert(PeerEndpoint), "peer psk was already set");
peer.pre_shared_key = Some(psk.into());
Peer
}
(PeerOutfile, of, Some(peer)) => {
if !(already_set.insert(PeerOutfile)) {
return Err(RosenpassError::ConfigError(
"peer outfile was already set".into(),
));
}
ensure!(
already_set.insert(PeerOutfile),
"peer outfile was already set"
);
peer.key_out = Some(of.into());
Peer
}
(PeerWireguardDev, dev, Some(peer)) => {
if !(already_set.insert(PeerWireguardDev)) {
return Err(RosenpassError::ConfigError(
"peer wireguard-dev was already set".into(),
));
}
ensure!(
already_set.insert(PeerWireguardDev),
"peer wireguard-dev was already set"
);
assert!(peer.wg.is_none());
peer.wg = Some(WireGuard {
device: dev.to_string(),
@@ -303,11 +289,10 @@ impl Rosenpass {
PeerWireguardPeer
}
(PeerWireguardPeer, p, Some(peer)) => {
if !(already_set.insert(PeerWireguardPeer)) {
return Err(RosenpassError::ConfigError(
"peer wireguard-peer was already set".into(),
));
}
ensure!(
already_set.insert(PeerWireguardPeer),
"peer wireguard-peer was already set"
);
peer.wg.as_mut().expect(wg_exists).peer = p.to_string();
PeerWireguardExtraArgs
}
@@ -322,16 +307,14 @@ impl Rosenpass {
// error cases
(Own, x, None) => {
error!("unrecognised argument {x}");
return Err(RosenpassError::RuntimeError);
bail!("unrecognised argument {x}");
}
(Own | OwnPublicKey | OwnSecretKey | OwnListen, _, Some(_)) => {
panic!("current_peer is not None while in Own* state, this must never happen")
}
(State::Peer, arg, Some(_)) => {
error!("unrecongnised argument {arg}");
return Err(RosenpassError::RuntimeError);
bail!("unrecongnised argument {arg}");
}
(
Peer
@@ -350,10 +333,6 @@ impl Rosenpass {
};
}
if problem {
return Err(RosenpassError::RuntimeError);
}
if let Some(p) = current_peer {
// TODO ensure peer is propagated with sufficient information
config.peers.push(p);

View File

@@ -2,8 +2,8 @@
//! ensures their uniqueness
use {
crate::Result,
crate::{prftree::PrfTree, sodium::KEY_SIZE},
anyhow::Result,
};
pub fn protocol() -> Result<PrfTree> {

60
rosenpass/src/lib.rs Normal file
View File

@@ -0,0 +1,60 @@
#[macro_use]
pub mod util;
#[macro_use]
pub mod sodium;
pub mod coloring;
#[rustfmt::skip]
pub mod labeled_prf;
pub mod app_server;
pub mod cli;
pub mod config;
pub mod msgs;
pub mod pqkem;
pub mod prftree;
pub mod protocol;
#[derive(thiserror::Error, Debug)]
pub enum RosenpassError {
#[error("error in OQS")]
Oqs,
#[error("error from external library while calling OQS")]
OqsExternalLib,
#[error("buffer size mismatch, required {required_size} but found {actual_size}")]
BufferSizeMismatch {
required_size: usize,
actual_size: usize,
},
#[error("invalid message type")]
InvalidMessageType(u8),
}
impl RosenpassError {
/// Helper function to check a buffer size
fn check_buffer_size(required_size: usize, actual_size: usize) -> Result<(), Self> {
if required_size != actual_size {
Err(Self::BufferSizeMismatch {
required_size,
actual_size,
})
} else {
Ok(())
}
}
}
/// Extension trait to attach function calls to foreign types.
trait RosenpassMaybeError {
/// Checks whether something is an error or not
fn to_rg_error(&self) -> Result<(), RosenpassError>;
}
impl RosenpassMaybeError for oqs_sys::common::OQS_STATUS {
fn to_rg_error(&self) -> Result<(), RosenpassError> {
use oqs_sys::common::OQS_STATUS;
match self {
OQS_STATUS::OQS_SUCCESS => Ok(()),
OQS_STATUS::OQS_ERROR => Err(RosenpassError::Oqs),
OQS_STATUS::OQS_EXTERNAL_LIB_ERROR_OPENSSL => Err(RosenpassError::OqsExternalLib),
}
}
}

View File

@@ -6,7 +6,7 @@
//! This is a generalization of a PRF operating
//! on a sequence of inputs instead of a single input.
//!
//! Like a Dec function the Iprf features efficient
//! Like a Dec function the Iprf features efficient
//! incrementability.
//!
//! You can also think of an Iprf as a Dec function with
@@ -27,7 +27,7 @@ pub fn prf_into(out: &mut [u8], key: &[u8], data: &[u8]) {
hmac_into(out, key, data).unwrap()
}
pub fn prf(key: &[u8], data: &[u8]) -> [u8; KEY_SIZE]{
pub fn prf(key: &[u8], data: &[u8]) -> [u8; KEY_SIZE] {
mutating([0u8; KEY_SIZE], |r| prf_into(r, key, data))
}
@@ -40,11 +40,11 @@ impl Iprf {
IprfBranch(self.0)
}
// TODO: Protocol! Use domain separation to ensure that
// TODO: Protocol! Use domain separation to ensure that
fn mix(self, v: &[u8]) -> Self {
Self(prf(&self.0, v))
}
fn mix_secret<const N: usize>(self, v: Secret<N>) -> SecretIprf {
SecretIprf::prf_invoc(&self.0, v.secret())
}
@@ -70,8 +70,9 @@ impl IprfBranch {
impl SecretIprf {
fn prf_invoc(k: &[u8], d: &[u8]) -> SecretIprf {
mutating(SecretIprf(Secret::zero()), |r|
prf_into(k, d, r.secret_mut()))
mutating(SecretIprf(Secret::zero()), |r| {
prf_into(k, d, r.secret_mut())
})
}
fn from_key(k: Secret<N>) -> SecretIprf {

View File

@@ -143,7 +143,7 @@ macro_rules! data_lense(
pub fn check_size(len: usize) -> Result<(), RosenpassError>{
let required_size = $( $len + )+ 0;
let actual_size = len;
if required_size < actual_size {
if required_size != actual_size {
Err(RosenpassError::BufferSizeMismatch {
required_size,
actual_size,
@@ -199,23 +199,53 @@ macro_rules! data_lense(
type __ContainerType;
/// Create a lense to the byte slice
fn [< $type:snake >] $(< $($generic),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError>;
fn [< $type:snake >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError>;
/// Create a lense to the byte slice, automatically truncating oversized buffers
fn [< $type:snake _ truncating >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError>;
}
impl<'a> [< $type Ext >] for &'a [u8] {
type __ContainerType = &'a [u8];
fn [< $type:snake >] $(< $($generic),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
fn [< $type:snake >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
$type::<Self::__ContainerType, $( $($generic),+ )? >::check_size(self.len())?;
Ok($type ( self, $( $( ::core::marker::PhantomData::<$generic> ),+ )? ))
}
fn [< $type:snake _ truncating >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
let required_size = $( $len + )+ 0;
let actual_size = self.len();
if actual_size < required_size {
return Err(RosenpassError::BufferSizeMismatch {
required_size,
actual_size,
});
}
[< $type Ext >]::[< $type:snake >](&self[..required_size])
}
}
impl<'a> [< $type Ext >] for &'a mut [u8] {
type __ContainerType = &'a mut [u8];
fn [< $type:snake >] $(< $($generic),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
fn [< $type:snake >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
$type::<Self::__ContainerType, $( $($generic),+ )? >::check_size(self.len())?;
Ok($type ( self, $( $( ::core::marker::PhantomData::<$generic> ),+ )? ))
}
fn [< $type:snake _ truncating >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
let required_size = $( $len + )+ 0;
let actual_size = self.len();
if actual_size < required_size {
return Err(RosenpassError::BufferSizeMismatch {
required_size,
actual_size,
});
}
[< $type Ext >]::[< $type:snake >](&mut self[..required_size])
}
}
});
);

View File

@@ -1,8 +1,10 @@
//! Implementation of the tree-like structure used for the label derivation in [labeled_prf](crate::labeled_prf)
use crate::{
coloring::Secret,
sodium::{hmac, hmac_into, KEY_SIZE},
Result,
use {
crate::{
coloring::Secret,
sodium::{hmac, hmac_into, KEY_SIZE},
},
anyhow::Result,
};
// TODO Use a proper Dec interface

View File

@@ -23,10 +23,10 @@
//! pqkem::{StaticKEM, KEM},
//! protocol::{SSk, SPk, MsgBuf, PeerPtr, CryptoServer, SymKey},
//! };
//! # fn main() -> Result<(), rosenpass::RosenpassError> {
//! # fn main() -> anyhow::Result<()> {
//!
//! // always init libsodium before anything
//! rosenpass::sodium::sodium_init().unwrap();
//! rosenpass::sodium::sodium_init()?;
//!
//! // initialize secret and public key for peer a ...
//! let (mut peer_a_sk, mut peer_a_pk) = (SSk::zero(), SPk::zero());
@@ -42,32 +42,31 @@
//! let mut b = CryptoServer::new(peer_b_sk, peer_b_pk.clone());
//!
//! // introduce peers to each other
//! a.add_peer(Some(psk.clone()), peer_b_pk).unwrap();
//! b.add_peer(Some(psk), peer_a_pk).unwrap();
//! a.add_peer(Some(psk.clone()), peer_b_pk)?;
//! b.add_peer(Some(psk), peer_a_pk)?;
//!
//! // declare buffers for message exchange
//! let (mut a_buf, mut b_buf) = (MsgBuf::zero(), MsgBuf::zero());
//!
//! // let a initiate a handshake
//! let length = a.initiate_handshake(PeerPtr(0), a_buf.as_mut_slice());
//! let mut maybe_len = Some(a.initiate_handshake(PeerPtr(0), a_buf.as_mut_slice())?);
//!
//! // let b respond to a and a respond to b, in two rounds
//! for _ in 0..2 {
//! b.handle_msg(&a_buf[..], &mut b_buf[..]);
//! a.handle_msg(&b_buf[..], &mut a_buf[..]);
//! // let a and b communicate
//! while let Some(len) = maybe_len {
//! maybe_len = b.handle_msg(&a_buf[..len], &mut b_buf[..])?.resp;
//! std::mem::swap(&mut a, &mut b);
//! std::mem::swap(&mut a_buf, &mut b_buf);
//! }
//!
//! // all done! Extract the shared keys and ensure they are identical
//! let a_key = a.osk(PeerPtr(0));
//! let b_key = b.osk(PeerPtr(0));
//! assert_eq!(a_key.unwrap().secret(), b_key.unwrap().secret(),
//! let a_key = a.osk(PeerPtr(0))?;
//! let b_key = b.osk(PeerPtr(0))?;
//! assert_eq!(a_key.secret(), b_key.secret(),
//! "the key exchanged failed to establish a shared secret");
//! # Ok(())
//! # }
//! ```
use log::{trace, warn};
use crate::{
coloring::*,
labeled_prf as lprf,
@@ -76,8 +75,8 @@ use crate::{
prftree::{SecretPrfTree, SecretPrfTreeBranch},
sodium::*,
util::*,
Result, RosenpassError,
};
use anyhow::{bail, ensure, Context, Result};
use std::collections::hash_map::{
Entry::{Occupied, Vacant},
HashMap,
@@ -487,8 +486,10 @@ impl CryptoServer {
let peerid = peer.pidt()?;
let peerno = self.peers.len();
match self.index.entry(IndexKey::Peer(peerid)) {
// TODO improve type handling, use PeerPtr
Occupied(_) => return Err(RosenpassError::PeerIdAlreadyTaken(peerid)),
Occupied(_) => bail!(
"Cannot insert peer with id {:?}; peer with this id already registered.",
peerid
),
Vacant(e) => e.insert(peerno),
};
self.peers.push(peer);
@@ -500,7 +501,7 @@ impl CryptoServer {
pub fn register_session(&mut self, id: SessionId, peer: PeerPtr) -> Result<()> {
match self.index.entry(IndexKey::Sid(id)) {
Occupied(p) if PeerPtr(*p.get()) == peer => {} // Already registered
Occupied(_) => return Err(RosenpassError::SessionIdAlreadyTaken(id)),
Occupied(_) => bail!("Cannot insert session with id {:?}; id is in use.", id),
Vacant(e) => {
e.insert(peer.0);
}
@@ -522,11 +523,8 @@ impl CryptoServer {
};
}
pub fn find_peer(&self, id: PeerId) -> Result<PeerPtr> {
self.index
.get(&IndexKey::Peer(id))
.map(|no| PeerPtr(*no))
.ok_or_else(|| RosenpassError::NoSuchPeerId(id))
pub fn find_peer(&self, id: PeerId) -> Option<PeerPtr> {
self.index.get(&IndexKey::Peer(id)).map(|no| PeerPtr(*no))
}
// lookup_session in whitepaper
@@ -739,7 +737,7 @@ impl CryptoServer {
// TODO remove unnecessary copying between global tx_buf and per-peer buf
// TODO move retransmission storage to io server
pub fn initiate_handshake(&mut self, peer: PeerPtr, tx_buf: &mut [u8]) -> Result<usize> {
let mut msg = tx_buf.envelope::<InitHello<()>>()?; // Envelope::<InitHello>::default(); // TODO
let mut msg = tx_buf.envelope_truncating::<InitHello<()>>()?; // Envelope::<InitHello>::default(); // TODO
self.handle_initiation(peer, msg.payload_mut().init_hello()?)?;
let len = self.seal_and_commit_msg(peer, MsgType::InitHello, msg)?;
peer.hs()
@@ -784,23 +782,19 @@ impl CryptoServer {
/// | t2 | `InitConf` | -> | |
/// | t3 | | <- | `EmptyData` |
pub fn handle_msg(&mut self, rx_buf: &[u8], tx_buf: &mut [u8]) -> Result<HandleMsgResult> {
let seal_broken = "Message seal broken!";
// length of the response. We assume no response, so None for now
let mut len = 0;
let mut exchanged = false;
if rx_buf.is_empty() {
trace!("received empty message, ignoring it");
return Err(RosenpassError::EmptyMessage);
}
ensure!(!rx_buf.is_empty(), "received empty message, ignoring it");
let peer = match rx_buf[0].try_into() {
Ok(MsgType::InitHello) => {
let msg_in = rx_buf.envelope::<InitHello<&[u8]>>()?;
if msg_in.check_seal(self)? {
return Err(RosenpassError::SealBroken);
}
ensure!(msg_in.check_seal(self)?, seal_broken);
let mut msg_out = tx_buf.envelope::<RespHello<&mut [u8]>>()?;
let mut msg_out = tx_buf.envelope_truncating::<RespHello<&mut [u8]>>()?;
let peer = self.handle_init_hello(
msg_in.payload().init_hello()?,
msg_out.payload_mut().resp_hello()?,
@@ -810,11 +804,9 @@ impl CryptoServer {
}
Ok(MsgType::RespHello) => {
let msg_in = rx_buf.envelope::<RespHello<&[u8]>>()?;
if msg_in.check_seal(self)? {
return Err(RosenpassError::SealBroken);
}
ensure!(msg_in.check_seal(self)?, seal_broken);
let mut msg_out = tx_buf.envelope::<InitConf<&mut [u8]>>()?;
let mut msg_out = tx_buf.envelope_truncating::<InitConf<&mut [u8]>>()?;
let peer = self.handle_resp_hello(
msg_in.payload().resp_hello()?,
msg_out.payload_mut().init_conf()?,
@@ -827,11 +819,9 @@ impl CryptoServer {
}
Ok(MsgType::InitConf) => {
let msg_in = rx_buf.envelope::<InitConf<&[u8]>>()?;
if msg_in.check_seal(self)? {
return Err(RosenpassError::SealBroken);
}
ensure!(msg_in.check_seal(self)?, seal_broken);
let mut msg_out = tx_buf.envelope::<EmptyData<&mut [u8]>>()?;
let mut msg_out = tx_buf.envelope_truncating::<EmptyData<&mut [u8]>>()?;
let peer = self.handle_init_conf(
msg_in.payload().init_conf()?,
msg_out.payload_mut().empty_data()?,
@@ -842,23 +832,15 @@ impl CryptoServer {
}
Ok(MsgType::EmptyData) => {
let msg_in = rx_buf.envelope::<EmptyData<&[u8]>>()?;
if msg_in.check_seal(self)? {
return Err(RosenpassError::SealBroken);
}
ensure!(msg_in.check_seal(self)?, seal_broken);
self.handle_resp_conf(msg_in.payload().empty_data()?)?
}
Ok(MsgType::DataMsg) => {
return Err(RosenpassError::NotImplemented(
"DataMsg handling not implemented!",
))
Ok(MsgType::DataMsg) => bail!("DataMsg handling not implemented!"),
Ok(MsgType::CookieReply) => bail!("CookieReply handling not implemented!"),
Err(_) => {
bail!("CookieReply handling not implemented!")
}
Ok(MsgType::CookieReply) => {
return Err(RosenpassError::NotImplemented(
"CookieReply handling not implemented!",
))
}
Err(e) => return Err(e),
};
Ok(HandleMsgResult {
@@ -1137,10 +1119,10 @@ impl CryptoServer {
impl IniHsPtr {
pub fn store_msg_for_retransmission(&self, srv: &mut CryptoServer, msg: &[u8]) -> Result<()> {
let ih = self.get_mut(srv).as_mut().ok_or_else(|| {
warn!("No current handshake for peer {:?}", self.peer());
RosenpassError::NoCurrentHs(self.peer())
})?;
let ih = self
.get_mut(srv)
.as_mut()
.with_context(|| format!("No current handshake for peer {:?}", self.peer()))?;
cpy_min(msg, &mut *ih.tx_buf);
ih.tx_count = 0;
ih.tx_len = msg.len();
@@ -1149,20 +1131,20 @@ impl IniHsPtr {
}
pub fn apply_retransmission(&self, srv: &mut CryptoServer, tx_buf: &mut [u8]) -> Result<usize> {
let ih = self.get_mut(srv).as_mut().ok_or_else(|| {
warn!("No current handshake for peer {:?}", self.peer());
RosenpassError::NoCurrentHs(self.peer())
})?;
let ih = self
.get_mut(srv)
.as_mut()
.with_context(|| format!("No current handshake for peer {:?}", self.peer()))?;
cpy_min(&ih.tx_buf[..ih.tx_len], tx_buf);
Ok(ih.tx_len)
}
pub fn register_retransmission(&self, srv: &mut CryptoServer) -> Result<()> {
let tb = srv.timebase.clone();
let ih = self.get_mut(srv).as_mut().ok_or_else(|| {
warn!("No current handshake for peer {:?}", self.peer());
RosenpassError::NoCurrentHs(self.peer())
})?;
let ih = self
.get_mut(srv)
.as_mut()
.with_context(|| format!("No current handshake for peer {:?}", self.peer()))?;
// Base delay, exponential increase, ±50% jitter
ih.tx_retry_at = tb.now()
+ RETRANSMIT_DELAY_BEGIN
@@ -1366,16 +1348,18 @@ impl HandshakeState {
hs.mix(biscuit_ct)?;
// Look up the associated peer
let peer = srv.find_peer(pid)?;
let peer = srv
.find_peer(pid) // TODO: FindPeer should return a Result<()>
.with_context(|| format!("Could not decode biscuit for peer {pid:?}: No such peer."))?;
// Defense against replay attacks; implementations may accept
// the most recent biscuit no again (bn = peer.bn_{prev}) which
// indicates retransmission
// TODO: Handle retransmissions without involving the crypto code
if sodium_bigint_cmp(biscuit.biscuit_no(), &*peer.get(srv).biscuit_used) >= 0 {
warn!("Rejecting biscuit: Outdated biscuit number");
return Err(RosenpassError::InvalidBiscuitNo);
}
ensure!(
sodium_bigint_cmp(biscuit.biscuit_no(), &*peer.get(srv).biscuit_used) >= 0,
"Rejecting biscuit: Outdated biscuit number"
);
Ok((peer, no, hs))
}
@@ -1409,10 +1393,11 @@ impl CryptoServer {
///
/// Fail if no session is available with the peer
pub fn osk(&self, peer: PeerPtr) -> Result<SymKey> {
let session = peer.session().get(self).as_ref().ok_or_else(|| {
warn!("No current session for peer {peer:?}");
RosenpassError::NoSuchPeer(peer)
})?;
let session = peer
.session()
.get(self)
.as_ref()
.with_context(|| format!("No current session for peer {:?}", peer))?;
Ok(session.ck.mix(&lprf::osk()?)?.into_secret())
}
}
@@ -1492,7 +1477,8 @@ impl CryptoServer {
let peer = {
let mut peerid = PeerId::zero();
core.decrypt_and_mix(&mut *peerid, ih.pidic())?;
self.find_peer(peerid)?
self.find_peer(peerid)
.with_context(|| format!("No such peer {peerid:?}."))?
};
// IHR7
@@ -1534,12 +1520,13 @@ impl CryptoServer {
mut ic: InitConf<&mut [u8]>,
) -> Result<PeerPtr> {
// RHI2
let sid = SessionId::from_slice(rh.sidi());
let peer = self
.lookup_handshake(sid)
.ok_or_else(|| {
warn!("Got RespHello packet for non-existent session {sid:?}");
RosenpassError::NoSuchSessionId(sid)
.lookup_handshake(SessionId::from_slice(rh.sidi()))
.with_context(|| {
format!(
"Got RespHello packet for non-existent session {:?}",
rh.sidi()
)
})?
.peer();
@@ -1560,14 +1547,13 @@ impl CryptoServer {
let exp = hs!().next;
let got = HandshakeStateMachine::RespHello;
if exp != got {
warn!("Unexpected package in session {sid:?}. Expected {exp:?}, got {got:?}.",);
return Err(RosenpassError::UnexpectedMessage {
session: sid,
expected: Some(exp),
got: Some(got),
});
}
ensure!(
exp == got,
"Unexpected package in session {:?}. Expected {:?}, got {:?}.",
SessionId::from_slice(rh.sidi()),
exp,
got
);
let mut core = hs!().core.clone();
core.sidr.copy_from_slice(rh.sidr());
@@ -1684,10 +1670,11 @@ impl CryptoServer {
// instead of a generic PeerPtr::send(&Server, Option<&[u8]>) -> Either<EmptyData, Data>
// because data transmission is a stub currently. This software is supposed to be used
// as a key exchange service feeding a PSK into some classical (i.e. non post quantum)
let ses = peer.session().get_mut(self).as_mut().ok_or_else(|| {
warn!("Cannot send acknowledgement. No session.");
RosenpassError::NoSession
})?;
let ses = peer
.session()
.get_mut(self)
.as_mut()
.context("Cannot send acknowledgement. No session.")?;
rc.sid_mut().copy_from_slice(&ses.sidt.value);
rc.ctr_mut().copy_from_slice(&ses.txnm.to_le_bytes());
ses.txnm += 1; // Increment nonce before encryption, just in case an error is raised
@@ -1701,39 +1688,30 @@ impl CryptoServer {
pub fn handle_resp_conf(&mut self, rc: EmptyData<&[u8]>) -> Result<PeerPtr> {
let sid = SessionId::from_slice(rc.sid());
let hs = self.lookup_handshake(sid).ok_or_else(|| {
warn!("Got RespConf packet for non-existent session {sid:?}");
RosenpassError::InvalidSessionId(sid)
})?;
let hs = self
.lookup_handshake(sid)
.with_context(|| format!("Got RespConf packet for non-existent session {sid:?}"))?;
let ses = hs.peer().session();
let exp = hs.get(self).as_ref().map(|h| h.next);
let got = Some(HandshakeStateMachine::RespConf);
if exp != got {
warn!("Unexpected package in session {sid:?}. Expected {exp:?}, got {got:?}.",);
return Err(RosenpassError::UnexpectedMessage {
session: sid,
expected: exp,
got,
});
}
ensure!(
exp == got,
"Unexpected package in session {:?}. Expected {:?}, got {:?}.",
sid,
exp,
got
);
// Validate the message
{
// TODO get rid of as_mut necessity
let s = ses.get_mut(self).as_mut().ok_or_else(|| {
warn!("Cannot validate EmptyData message. Missing encryption session for {sid:?}");
RosenpassError::NoSuchSessionId(sid)
let s = ses.get_mut(self).as_mut().with_context(|| {
format!("Cannot validate EmptyData message. Missing encryption session for {sid:?}")
})?;
// the unwrap can not fail, because the slice returned by ctr() is
// guaranteed to have the correct size
let n = u64::from_le_bytes(rc.ctr().try_into().unwrap());
if n < s.txnt {
trace!("Stale nonce");
return Err(RosenpassError::StaleNonce);
}
ensure!(n >= s.txnt, "Stale nonce");
s.txnt = n;
aead_dec_into(
// pt, k, n, ad, ct
@@ -1756,27 +1734,94 @@ impl CryptoServer {
mod test {
use super::*;
fn init_crypto_server() -> CryptoServer {
// always init libsodium before anything
#[test]
/// Ensure that the protocol implementation can deal with truncated
/// messages and with overlong messages.
///
/// This test performs a complete handshake between two randomly generated
/// servers; instead of delivering the message correctly at first messages
/// of length zero through about 1.2 times the correct message size are delivered.
///
/// Producing an error is expected on each of these messages.
///
/// Finally the correct message is delivered and the same process
/// starts again in the other direction.
///
/// Through all this, the handshake should still successfully terminate;
/// i.e. an exchanged key must be produced in both servers.
fn handles_incorrect_size_messages() {
crate::sodium::sodium_init().unwrap();
// initialize secret and public key for the crypto server
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
StaticKEM::keygen(sk.secret_mut(), pk.secret_mut()).expect("unable to generate keys");
stacker::grow(8 * 1024 * 1024, || {
const OVERSIZED_MESSAGE: usize = ((MAX_MESSAGE_LEN as f32) * 1.2) as usize;
type MsgBufPlus = Public<OVERSIZED_MESSAGE>;
CryptoServer::new(sk, pk)
const PEER0: PeerPtr = PeerPtr(0);
let (mut me, mut they) = make_server_pair().unwrap();
let (mut msgbuf, mut resbuf) = (MsgBufPlus::zero(), MsgBufPlus::zero());
// Process the entire handshake
let mut msglen = Some(me.initiate_handshake(PEER0, &mut *resbuf).unwrap());
loop {
if let Some(l) = msglen {
std::mem::swap(&mut me, &mut they);
std::mem::swap(&mut msgbuf, &mut resbuf);
msglen = test_incorrect_sizes_for_msg(&mut me, &*msgbuf, l, &mut *resbuf);
} else {
break;
}
}
assert_eq!(
me.osk(PEER0).unwrap().secret(),
they.osk(PEER0).unwrap().secret()
);
});
}
/// The determination of the message type relies on reading the first byte of the message. Only
/// after that the length of the message is checked against the specified message type. This
/// test ensures that nothing breaks in the case of an empty message.
#[test]
#[should_panic = "called `Result::unwrap()` on an `Err` value: received empty message, ignoring it"]
fn handle_empty_message() {
let mut crypt = init_crypto_server();
let empty_rx_buf = [0u8; 0];
let mut tx_buf = [0u8; 0];
/// Used in handles_incorrect_size_messages() to first deliver many truncated
/// and overlong messages, finally the correct message is delivered and the response
/// returned.
fn test_incorrect_sizes_for_msg(
srv: &mut CryptoServer,
msgbuf: &[u8],
msglen: usize,
resbuf: &mut [u8],
) -> Option<usize> {
resbuf.fill(0);
crypt.handle_msg(&empty_rx_buf, &mut tx_buf).unwrap();
for l in 0..(((msglen as f32) * 1.2) as usize) {
if l == msglen {
continue;
}
let res = srv.handle_msg(&msgbuf[..l], resbuf);
assert!(matches!(res, Err(_))); // handle_msg should raise an error
assert!(!resbuf.iter().find(|x| **x != 0).is_some()); // resbuf should not have been changed
}
// Apply the proper handle_msg operation
srv.handle_msg(&msgbuf[..msglen], resbuf).unwrap().resp
}
fn keygen() -> Result<(SSk, SPk)> {
// TODO: Copied from the benchmark; deduplicate
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
StaticKEM::keygen(sk.secret_mut(), pk.secret_mut())?;
Ok((sk, pk))
}
fn make_server_pair() -> Result<(CryptoServer, CryptoServer)> {
// TODO: Copied from the benchmark; deduplicate
let psk = SymKey::random();
let ((ska, pka), (skb, pkb)) = (keygen()?, keygen()?);
let (mut a, mut b) = (
CryptoServer::new(ska, pka.clone()),
CryptoServer::new(skb, pkb.clone()),
);
a.add_peer(Some(psk.clone()), pkb)?;
b.add_peer(Some(psk), pka)?;
Ok((a, b))
}
}

View File

@@ -1,6 +1,7 @@
//! Bindings and helpers for accessing libsodium functions
use crate::{util::*, Result, RosenpassError};
use crate::util::*;
use anyhow::{ensure, Result};
use libsodium_sys as libsodium;
use log::trace;
use static_assertions::const_assert_eq;
@@ -25,11 +26,9 @@ const_assert_eq!(KEY_SIZE, libsodium::crypto_generichash_BYTES as usize);
macro_rules! sodium_call {
($name:ident, $($args:expr),*) => { attempt!({
if unsafe{libsodium::$name($($args),*)} > -1 {
Ok(())
}else{
Err(RosenpassError::LibsodiumError(concat!("Error in libsodium's {}.", stringify!($name))))
}
ensure!(unsafe{libsodium::$name($($args),*)} > -1,
"Error in libsodium's {}.", stringify!($name));
Ok(())
})};
($name:ident) => { sodium_call!($name, ) };
}
@@ -252,12 +251,7 @@ pub fn mac16(key: &[u8], data: &[u8]) -> Result<[u8; 16]> {
pub fn hmac_into(out: &mut [u8], key: &[u8], data: &[u8]) -> Result<()> {
// Not bothering with padding; the implementation
// uses appropriately sized keys.
if key.len() != KEY_SIZE {
return Err(crate::RosenpassError::BufferSizeMismatch {
required_size: KEY_SIZE,
actual_size: key.len(),
});
}
ensure!(key.len() == KEY_SIZE);
const IPAD: [u8; KEY_SIZE] = [0x36u8; KEY_SIZE];
let mut temp_key = [0u8; KEY_SIZE];

View File

@@ -1,9 +1,9 @@
//! Helper functions and macros
use anyhow::{ensure, Context, Result};
use base64::{
display::Base64Display as B64Display, read::DecoderReader as B64Reader,
write::EncoderWriter as B64Writer,
};
use log::error;
use std::{
borrow::{Borrow, BorrowMut},
cmp::min,
@@ -13,11 +13,19 @@ use std::{
time::{Duration, Instant},
};
use crate::{
coloring::{Public, Secret},
Result,
};
use crate::coloring::{Public, Secret};
/// Xors a and b element-wise and writes the result into a.
///
/// # Examples
///
/// ```
/// use rosenpass::util::xor_into;
/// let mut a = String::from("hello").into_bytes();
/// let b = b"world";
/// xor_into(&mut a, b);
/// assert_eq!(&a, b"\x1f\n\x1e\x00\x0b");
/// ```
#[inline]
pub fn xor_into(a: &mut [u8], b: &[u8]) {
assert!(a.len() == b.len());
@@ -61,7 +69,7 @@ pub fn cpy_min<T: BorrowMut<[u8]> + ?Sized, F: Borrow<[u8]> + ?Sized>(src: &F, d
#[macro_export]
macro_rules! attempt {
($block:expr) => {
(|| -> crate::Result<_> { $block })()
(|| -> ::anyhow::Result<_> { $block })()
};
}
@@ -153,12 +161,8 @@ impl<R: Read> ReadExactToEnd for R {
fn read_exact_to_end(&mut self, buf: &mut [u8]) -> Result<()> {
let mut dummy = [0u8; 8];
self.read_exact(buf)?;
if self.read(&mut dummy)? != 0 {
error!("File too long!");
Err(crate::RosenpassError::RuntimeError)
} else {
Ok(())
}
ensure!(self.read(&mut dummy)? == 0, "File too long!");
Ok(())
}
}
@@ -179,11 +183,11 @@ trait StoreValue {
}
trait StoreSecret {
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()>;
fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()>;
}
impl<T: StoreValue> StoreSecret for T {
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()> {
fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()> {
self.store(path)
}
}
@@ -192,10 +196,9 @@ impl<const N: usize> LoadValue for Secret<N> {
fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
let mut v = Self::random();
let p = path.as_ref();
fopen_r(p)?.read_exact_to_end(v.secret_mut()).map_err(|e| {
error!("Could not load file {p:?}");
e
})?;
fopen_r(p)?
.read_exact_to_end(v.secret_mut())
.with_context(|| format!("Could not load file {p:?}"))?;
Ok(v)
}
}
@@ -213,16 +216,13 @@ impl<const N: usize> LoadValueB64 for Secret<N> {
// not worth it right now.
b64_reader(&mut fopen_r(p)?)
.read_exact(v.secret_mut())
.map_err(|e| {
error!("Could not load base64 file {p:?}");
e
})?;
.with_context(|| format!("Could not load base64 file {p:?}"))?;
Ok(v)
}
}
impl<const N: usize> StoreSecret for Secret<N> {
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()> {
fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()> {
std::fs::write(path, self.secret())?;
Ok(())
}

48
rp
View File

@@ -197,7 +197,7 @@ exchange() {
lip="${listen%:*}";
lport="${listen/*:/}";
if [[ "$lip" = "$lport" ]]; then
lip="[0::0]"
lip="[::]"
fi
shift;;
-h | -help | --help | help) usage; return 0;;
@@ -209,15 +209,41 @@ exchange() {
fatal "Needs at least one peer specified"
fi
frag "
# Create the Wireguard interface
ip link add dev $(enquote "${dev}") type wireguard || true"
# os dependent setup
case "$OSTYPE" in
linux-*) # could be linux-gnu or linux-musl
frag "
# Create the WireGuard interface
ip link add dev $(enquote "${dev}") type wireguard || true"
cleanup "
ip link del dev $(enquote "${dev}") || true"
cleanup "
ip link del dev $(enquote "${dev}") || true"
frag "
ip link set dev $(enquote "${dev}") up"
frag "
ip link set dev $(enquote "${dev}") up"
;;
freebsd*)
frag "
# load the WireGuard kernel module
kldload -n if_wg || fatal 'Cannot load if_wg kernel module'"
frag "
# Create the WireGuard interface
ifconfig wg create name $(enquote "${dev}") || true"
cleanup "
ifconfig $(enquote "${dev}") destroy || true"
frag "
ifconfig $(enquote "${dev}") up"
;;
*)
fatal "Your system $OSTYPE is not yet supported. We are happy to receive patches to address this :)"
;;
esac
frag "
# Deploy the classic wireguard private key
@@ -255,7 +281,7 @@ exchange() {
local arg; arg="$1"; shift
case "${arg}" in
peer) set -- "peer" "$@"; break;; # Next peer
endpoint) ip="${1%:*}"; port="${1/*:/}"; shift;;
endpoint) ip="${1%:*}"; port="${1##*:}"; shift;;
persistent-keepalive) keepalive="${1}"; shift;;
allowed-ips) allowedips="${1}"; shift;;
-h | -help | --help | help) usage; return 0;;
@@ -326,7 +352,9 @@ main() {
verbose=0
scriptdir="$(dirname "${script}")"
gitdir="$(detect_git_dir)" || true
nixdir="$(readlink -f result/bin/rp | grep -Pio '^/nix/store/[^/]+(?=/bin/[^/]+)')" || true
if [[ -d /nix ]]; then
nixdir="$(readlink -f result/bin/rp | grep -Pio '^/nix/store/[^/]+(?=/bin/[^/]+)')" || true
fi
binary="$(find_rosenpass_binary)"
# Parse command

View File

@@ -1,131 +0,0 @@
use protocol::{HandshakeStateMachine, PeerId, PeerPtr, SessionId};
#[macro_use]
pub mod util;
#[macro_use]
pub mod sodium;
pub mod coloring;
#[rustfmt::skip]
pub mod labeled_prf;
pub mod app_server;
pub mod cli;
pub mod config;
pub mod msgs;
pub mod pqkem;
pub mod prftree;
pub mod protocol;
#[derive(thiserror::Error, Debug)]
pub enum RosenpassError {
#[error("error in OQS")]
Oqs,
#[error("error from external library while calling OQS")]
OqsExternalLib,
#[error("error while calling into libsodium")]
LibsodiumError(&'static str),
#[error("buffer size mismatch, required {required_size} but only found {actual_size}")]
BufferSizeMismatch {
required_size: usize,
actual_size: usize,
},
#[error("invalid message type")]
InvalidMessageType(u8),
#[error("peer id {0:?} already taken")]
PeerIdAlreadyTaken(PeerId),
#[error("session id {0:?} already taken")]
SessionIdAlreadyTaken(SessionId),
#[error("{0}")]
NotImplemented(&'static str),
#[error("{0}")]
ConfigError(String),
#[error("see last log messages")]
RuntimeError,
#[error("{0}")]
IoError(#[from] std::io::Error),
#[error("{0}")]
TomlDeserError(#[from] toml::de::Error),
#[error("{0}")]
TomlSerError(#[from] toml::ser::Error),
#[error("invalid session id {0:?} was used")]
InvalidSessionId(SessionId),
#[error("no session available")]
NoSession,
#[error("the peer {0:?} does not exist")]
NoSuchPeer(PeerPtr),
#[error("the peer id {0:?} does not exist")]
NoSuchPeerId(PeerId),
#[error("the session {0:?} does not exist")]
NoSuchSessionId(SessionId),
#[error("no current handshake with peer {0:?}")]
NoCurrentHs(PeerPtr),
// TODO implement Display for Peer/Session ptr?
#[error("message seal broken")]
SealBroken,
#[error("received empty message")]
EmptyMessage,
#[error("biscuit with invalid number")]
InvalidBiscuitNo,
#[error("got unexpected message")]
UnexpectedMessage {
session: SessionId,
expected: Option<HandshakeStateMachine>,
got: Option<HandshakeStateMachine>,
},
#[error("???")]
StaleNonce,
}
/// Rosenpass Result type
pub type Result<T> = core::result::Result<T, RosenpassError>;
impl RosenpassError {
/// Helper function to check a buffer size
fn check_buffer_size(required_size: usize, actual_size: usize) -> Result<()> {
if required_size != actual_size {
Err(Self::BufferSizeMismatch {
required_size,
actual_size,
})
} else {
Ok(())
}
}
}
/// Extension trait to attach function calls to foreign types.
trait RosenpassMaybeError {
/// Checks whether something is an error or not
fn to_rg_error(&self) -> Result<()>;
}
impl RosenpassMaybeError for oqs_sys::common::OQS_STATUS {
fn to_rg_error(&self) -> Result<()> {
use oqs_sys::common::OQS_STATUS;
match self {
OQS_STATUS::OQS_SUCCESS => Ok(()),
OQS_STATUS::OQS_ERROR => Err(RosenpassError::Oqs),
OQS_STATUS::OQS_EXTERNAL_LIB_ERROR_OPENSSL => Err(RosenpassError::OqsExternalLib),
}
}
}