fix: EA-1 refuse authorize of an already-recorded key (v0.1.3)
authorize never checked the target fingerprint against existing docs before save()'s upsert-by-_id, so authorizing the local machine's own public key under a new friendly name silently replaced the local authorizer record (can_authorize demoted to False) while printing a success banner. With a sole authorizer this bricks the CLI: authorize refuses (not permitted), init refuses (already initialized), and revoke of the local key refuses (refusing to revoke the local key) -- no in-CLI recovery. Mirror revoke's local-key guard and extend it to any existing _id, so a duplicate target is refused with a clear message instead of silently replacing the record. Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
@@ -1 +1 @@
|
||||
__version__ = "0.1.2"
|
||||
__version__ = "0.1.3"
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
boots the local DEK, verifies the local key is itself an authorizer, then wraps
|
||||
the same DEK to the target public key and stores a new key doc. `--can-authorize`
|
||||
decides whether the new key may authorize others (omit it for servers).
|
||||
decides whether the new key may authorize others (omit it for servers). Refuses
|
||||
a target key that fingerprints to an existing `_id` — `save` upserts by `_id`, so
|
||||
authorizing a key that is already on record (most dangerously the local key
|
||||
itself) would silently replace that doc's capability flag and friendly name
|
||||
under a success banner instead of adding a new key.
|
||||
"""
|
||||
|
||||
from . import (
|
||||
@@ -10,6 +14,7 @@ from . import (
|
||||
boot_local,
|
||||
build_doc,
|
||||
find_by_friendly,
|
||||
local_fingerprint,
|
||||
make_flag,
|
||||
read_flag,
|
||||
)
|
||||
@@ -25,9 +30,23 @@ def run(config, storage, args) -> None:
|
||||
if not read_flag(crypto, local_doc["meta"]["authorizer"]):
|
||||
raise CommandError("this key is not permitted to authorize others")
|
||||
|
||||
new_fp, new_wrapped = crypto.encrypt_aes_key_with_rsa(
|
||||
crypto.master_key, args.key
|
||||
)
|
||||
new_fp = crypto.get_rsa_key_fingerprint(args.key)
|
||||
if new_fp == local_fingerprint(crypto, config):
|
||||
raise CommandError(
|
||||
"target key is the local key; authorize would silently replace the "
|
||||
"local authorizer record — use a different keypair, or `authorizer "
|
||||
"list` if you meant to check its status"
|
||||
)
|
||||
existing = storage.get(new_fp)
|
||||
if existing:
|
||||
existing_friendly = existing.get("meta", {}).get("friendly", "?")
|
||||
raise CommandError(
|
||||
f"target key is already authorized as '{existing_friendly}'; "
|
||||
f"authorize would silently replace that record — revoke it first "
|
||||
f"if you intend to re-authorize it"
|
||||
)
|
||||
|
||||
_, new_wrapped = crypto.encrypt_aes_key_with_rsa(crypto.master_key, args.key)
|
||||
flag = make_flag(crypto, args.can_authorize)
|
||||
doc = build_doc(new_fp, new_wrapped, flag, config.identity, args.friendly)
|
||||
storage.save(doc)
|
||||
|
||||
Reference in New Issue
Block a user