Verify the master key against the database at startup (B-89, SEC-49, SEC-50, SEC-09)
The lifespan decrypts the key and compares a fixed sample (reserve/round pool addresses, the 10 lowest and highest user addresses, unrevealed round secrets) with the database, and refuses to serve on any mismatch without printing key material. The key scripts refuse a new or imported key that would not reproduce the stored addresses, and write 0600. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
32df50cb75
commit
55d852fe08
14 files changed
+281
-46
No files matched your search
@@ -25,7 +25,8 @@ import os
|
||||
from embit.bip32 import HDKey
|
||||
|
||||
from app.config import settings
|
||||
from app.wallet.keystore import encrypt_xprv
|
||||
from app.wallet.keystore import encrypt_xprv, write_secret_file
|
||||
from app.wallet.verify import account_key, load_sample, sample_problems
|
||||
|
||||
_DOCKER_COMPOSE_DIR = "./data/keys"
|
||||
|
||||
@@ -69,8 +70,13 @@ if __name__ == "__main__":
|
||||
if not parsed.is_private:
|
||||
raise SystemExit("This is a public key (xpub), not a private key (xprv) — refusing to encrypt it as one.")
|
||||
|
||||
# SEC-05/SEC-50: the version bytes cannot tell a PLM key from a Bitcoin one, the stored
|
||||
# addresses can. A mismatch is refused even with --overwrite.
|
||||
problems = sample_problems(account_key(xprv), load_sample())
|
||||
if problems:
|
||||
raise SystemExit("this xprv does not match the database — refusing to write it: " + "; ".join(problems))
|
||||
|
||||
os.makedirs(os.path.dirname(key_path) or ".", exist_ok=True)
|
||||
with open(key_path, "wb") as f:
|
||||
f.write(encrypt_xprv(xprv))
|
||||
write_secret_file(key_path, encrypt_xprv(xprv))
|
||||
|
||||
print(f"Master key written (encrypted) to {key_path}")
|
||||
@@ -8,9 +8,14 @@ Usage:
|
||||
|
||||
from app.config import settings
|
||||
from app.wallet.hd import generate_master_key
|
||||
from app.wallet.verify import load_sample
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not settings.xprv_encryption_key:
|
||||
raise SystemExit("XPRV_ENCRYPTION_KEY is not set")
|
||||
sample = load_sample()
|
||||
if sample.users or sample.rounds or sample.seeds:
|
||||
# SEC-50: a new key cannot reproduce the addresses the database already holds.
|
||||
raise SystemExit("the database already has users or rounds: a new key would not reproduce their addresses")
|
||||
generate_master_key()
|
||||
print(f"Master key written (encrypted) to {settings.master_key_path}")
|
||||
Reference in new issue
Block a user