~sircmpwn/himitsu-devel

all: add some light hardening v1 APPLIED

Drew DeVault: 2
 all: add some light hardening
 docs/security.txt: document security model

 6 files changed, 152 insertions(+), 1 deletions(-)
This is exactly what I had in mind. Great writeup!

I was thinking that the easiest attack would be to replace the daemon
binary. Maybe it would be helpful to add something like "any process
could request a secret value or even replace the daemon itself". But
then again there are probably far too many possible attacks to enumerate
them all.
Was "store retain" intentional here? English is not my first language,
but I felt like there should be only one verb.
Thanks for writing this!
Next
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~sircmpwn/himitsu-devel/patches/50772/mbox | git am -3
Learn more about email & git

[PATCH 1/2] all: add some light hardening Export this patch

- Wipes more data from memory when the key store is unlocked.
- Prevents core dumps and debugging on Linux

Signed-off-by: Drew DeVault <sir@cmpwn.com>
---
 cmd/himitsud/harden+linux.ha | 6 ++++++
 cmd/himitsud/harden.ha       | 3 +++
 cmd/himitsud/main.ha         | 2 ++
 secstore/secstore.ha         | 3 ++-
 secstore/types.ha            | 3 +++
 5 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 cmd/himitsud/harden+linux.ha
 create mode 100644 cmd/himitsud/harden.ha

diff --git a/cmd/himitsud/harden+linux.ha b/cmd/himitsud/harden+linux.ha
new file mode 100644
index 0000000..b384158
--- /dev/null
+++ b/cmd/himitsud/harden+linux.ha
@@ -0,0 +1,6 @@
use rt;

fn harden() void = {
	// Prevent core dumps from being made and debuggers from attaching
	rt::prctl(rt::PR_SET_DUMPABLE, 0, 0, 0, 0)!;
};
diff --git a/cmd/himitsud/harden.ha b/cmd/himitsud/harden.ha
new file mode 100644
index 0000000..6ae5f8c
--- /dev/null
+++ b/cmd/himitsud/harden.ha
@@ -0,0 +1,3 @@
fn harden() void = {
	return;
};
diff --git a/cmd/himitsud/main.ha b/cmd/himitsud/main.ha
index 607a724..653ca52 100644
--- a/cmd/himitsud/main.ha
+++ b/cmd/himitsud/main.ha
@@ -40,6 +40,8 @@ export fn main() void = {
	};
	defer secstore::close(&store);

	harden();

	let pipe = unix::pipe()!;
	sigwrite = pipe.1;
	signal::handle(signal::sig::INT, &handle);
diff --git a/secstore/secstore.ha b/secstore/secstore.ha
index 1612611..67b6b57 100644
--- a/secstore/secstore.ha
+++ b/secstore/secstore.ha
@@ -317,12 +317,13 @@ export fn lock(store: *secstore) void = {
		yield;
	};
	store.state = state::SOFT_LOCKED;
	free_keys(store);
	free(store.entries);
};

// Closes the secstore, freeing any associated resources.
export fn close(store: *secstore) void = {
	lock(store);
	free_keys(store);
	io::close(store.index)!;
	free(store.dir);
};
diff --git a/secstore/types.ha b/secstore/types.ha
index eae73ed..81eb46b 100644
--- a/secstore/types.ha
+++ b/secstore/types.ha
@@ -1,7 +1,9 @@
use bytes;
use crypto::keystore;
use errors;
use fs;
use io;
use strings;
use uuid;

export type state = enum {
@@ -40,6 +42,7 @@ fn entry_finish(ent: *entry) void = {
		free(pair.key);
		match (pair.value) {
		case let val: str =>
			bytes::zero(strings::toutf8(val));
			free(val);
		case uuid::uuid =>
			yield;
-- 
2.44.0
Thanks!

To https://git.sr.ht/~sircmpwn/himitsu
   c657d70..6becc84  master -> master

[PATCH 2/2] docs/security.txt: document security model Export this patch

Signed-off-by: Drew DeVault <sir@cmpwn.com>
---
 docs/security.txt | 136 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 136 insertions(+)
 create mode 100644 docs/security.txt

diff --git a/docs/security.txt b/docs/security.txt
new file mode 100644
index 0000000..8f41546
--- /dev/null
+++ b/docs/security.txt
@@ -0,0 +1,136 @@
# Himitsu security model

This document discusses Himitsu's approach to and design regarding security and
privacy, what guarantees it attempts to make, and what it does not attempt to
protect against.

Note that Himitsu's implementation has not been independently audited, and in
practice the security may be undermined by bugs and/or unforeseen issues with
the design and implementation.

## Glossary

* **key store**: the set of keys stored in Himitsu
* **key**: a single "key", which may have many key/value "pairs".
  `foo=bar bar!=baz` is a key.
* **secret pair**: a key/value pair of a key which has the secret flag set, such
  as `bar!=baz`. "baz" is the **secret value** of this pair.
* **secstore**: "Secure store", the encrypted-at-rest storage for the key store
* **master key**: an cryptographic key used to encrypt and authenticate your key
  store
* **master passphrase**: the passphrase from which Himitsu derives your master
  key

## Offline security

*"Offline security" in this document refers to the security measures taken to
protect your key store when the Himitsu daemon is not running. Threats covered
here include attackers running programs on the same system as yourself or
another user, a copy of your key store being in the posession of an attacker,
and so on.*

Himitsu's secret store is used to store your private data offline. The secstore
contains the following information:

* Your master key, obfuscated
* An index, encrypted with your master key
* Secret keys, encrypted with your master key

Your master key is used as the input to a key derivation algorithm (argon2id at
the time of writing) which both derives the symmetric encryption key and
obfuscates the master password stored on disk. The key derivation algorithm is
designed to be resistant to an offline attack, and at the time of writing there
are no known practical attacks against argon2id.

However, the master key is ultimately only as secure as your passphrase. If you
use very short or common passphrases, an attacker may be able to guess it in a
practical amount of time. Moreover, no amount of software security will prevent
someone from reading the master passphrase off of a sticky note on your desk. An
ideal passphrase is long, so it's secure, and memorable, so you don't have to
write it down: 5 or 6 randomly-selected dictionary words are a safe bet.

The master key is used to separately encrypt each key in the secstore "index".
The index is encrypted and authenticated. An attacker can determine the number
of keys in your key store, and can estimate the length of each key in bytes, but
cannot read the pairs, secret or not. An attacker cannot tamper with your
key-store, either: they may change the order of the pairs but they cannot read,
modify, or forge your keys.

The index stores the "key" portion of a secret pair (i.e. **key**!=value) and
stores a UUID uniquely associated with the secret value. The secret value is
stored in a separate file named for this UUID. The secret value itself is
encrypted and authenticated in a tamper-resistant manner. An attacker can
determine the total number of secret values among all keys in your key store,
and estimate each of their lengths in bytes, but cannot read, modify, or forge
secret values.

Authenticated encryption is performed at the time of with an algorithm based on
RFC 8439, but using XChaCha20 instead of ChaCha20.

### Additional offline security measures

Your secstore is stored with the Unix permissions configured such that it is
only readable and writable by your user account.

### Securely handling your secstore

Himitsu is designed such that your secstore can fall into an adversary's hands
and remain secure. Assuming you have chosen a strong enough password, you are
able to safely store it with a cloud provider, copy it between machines, put it
on a flash drive and lose it, and so on.


## Online security

The Himitsu daemon has several security features to implement a defense-in-depth
design. The Himitsu daemon has two online security models: locked and unlocked.

When you start Himitsu, it runs in locked mode. In this mode, Himitsu waits for
the user to initiate an key store operation and stores no sensitive information
in memory whatsoever. When you attempt any operation for the first time, Himitsu
will prompt you for your master passphrase and enter unlocked mode to complete
your request.

Once unlocked, the daemon will decrypt and authenticate the index, then store
retain the master key and a copy of the index in memory. It will *not* decrypt
secret values or store them in memory while unlocked.

Clients access the key store via a Unix socket. The Unix socket is located in
the user's runtime directory and its file permissions are only read/writable by
the user's Unix user. When the daemon is unlocked, any client may read the key
store pairs *without* their secret values, without user approval. When a client
requests to read a secret value, the user is prompted to consent to disclosure
of the secret value.

If the user agrees, the daemon will look up the appropriate secret value by UUID
in the secstore, decrypt and authenticate it, and provide it to the client
application in plain text over the Unix socket connection.

No attempt is made to authenticate the client request. It will have come from a
process running on the user's Unix account, but if the user runs untrusted code,
or their system is otherwise compromised, any process could request a secret
value and cause the consent dialog to appear. It is up to the user to approve
secret requests with appropriate scrutiny and discretion. Furthermore, nothing
prevents the client from retaining the secret value once disclosed, or otherwise
handling the secret value incautiously.

### Hardening features

The following extra steps are taken to harden the daemon:

* All sensitive data is securely erased from memory after use, such as the
  master passphrase, secret values, and so on.

**Linux-specific**

* In the unlocked state, the master key is retained in kernel memory via keyctl.
  It is only present in daemon memory during cryptographic operations, and is
  securely erased when the operations are completed. This prevents bugs which
  could be exploited to read the daemon's memory from accessing the master key
  when it is not in use.
* Note that no attempt is made to lock memory (Himitsu requires more memory than
  it is practical to lock on Linux). It is recommended to use encrypted swap to
  reduce the risk of your key store contents being stored in plain text on swap.
  The risk of disclosure is relatively low, as Himitsu does not use enough
  memory to generally be a priority for Linux to swap to reclaim space, and a
  limited amount of sensitive information is stored on idle pages.
-- 
2.44.0
This is exactly what I had in mind. Great writeup!

I was thinking that the easiest attack would be to replace the daemon
binary. Maybe it would be helpful to add something like "any process
could request a secret value or even replace the daemon itself". But
then again there are probably far too many possible attacks to enumerate
them all.
Was "store retain" intentional here? English is not my first language,
but I felt like there should be only one verb.
Thanks for writing this!