diff --git a/conn.py b/conn.py index 71423e1..f000e0c 100644 --- a/conn.py +++ b/conn.py @@ -13,9 +13,10 @@ from hmac import HMAC from hashlib import sha256 from concurrent.futures import ThreadPoolExecutor -from ckcc.protocol import CCProtocolPacker, CCProtocolUnpacker, CCFramingError -from ckcc.protocol import CCProtoError, CCUserRefused, CCBusyError -from ckcc.client import ColdcardDevice, COINKITE_VID, CKCC_PID +from ckcc.protocol import CCProtocolPacker, CCFramingError +from ckcc.protocol import CCProtoError, CCUserRefused +from ckcc.constants import USB_NCRY_V2 +from ckcc.client import ColdcardDevice from ckcc.constants import (USER_AUTH_TOTP, USER_AUTH_HMAC, USER_AUTH_SHOW_QR, MAX_USERNAME_LEN) from ckcc.utils import calc_local_pincode @@ -52,8 +53,9 @@ class Connection(metaclass=Singleton): else: sn = self.serial - d = ColdcardDevice(sn=sn) - logging.info(f"Found Coldcard {d.serial}.") + ncry_ver = settings.USB_NCRY_VERSION + d = ColdcardDevice(sn=sn, ncry_ver=ncry_ver) + logging.info(f"Found Coldcard {d.serial}. USB encryption version: {ncry_ver}") await asyncio.get_running_loop().run_in_executor(executor, d.check_mitm) diff --git a/docs/setup.md b/docs/setup.md index cbbff93..5122ef4 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -128,6 +128,10 @@ there. policy are captured and saved into the encrypted settings. This includes details like the HSM text summary, user names, and other details that are know only when the policy is created. +- USB Encryption should be set to version 2 if firmware supports this . + For now default version is still 1. To enable version 2: + `echo "USB_NCRY_VERSION: 2" > /tmp/ckbunker_ncryV2.yaml; ckbunker setup -c /tmp/ckbunker_ncryV2.yaml`. With version 2 + enabled, in case of any ckbunker or communication failure, one needs to re-login to Coldcard # Next Steps diff --git a/persist.py b/persist.py index 21402c1..6b85f83 100644 --- a/persist.py +++ b/persist.py @@ -56,6 +56,20 @@ class Settings(metaclass=Singleton): # delay between retries connecting to missing/awol Coldcard RECONNECT_DELAY = 10 # seconds between retries PING_RATE = 15 # seconds between pings (CC status checks) + USB_NCRY_VERSION = 0x01 # default ncry version is 1 + + # USB encryption versions (default 1) + # + # V2 introduces a new ncry version to close a potential attack vector: + # + # A malicious program may re-initialize the connection encryption by sending the ncry command a second time during USB operation. + # This may prove particularly harmful in HSM mode. + # + # Sending version 0x02 changes the behavior in two ways: + # * All future commands must be encrypted + # * Returns an error if the ncry command is sent again for the duration of the power cycle + # + # If using 0x02 and ckbunker is killed - you also need to re-login to Coldcard def read(self, fobj): t = yaml.safe_load(fobj) diff --git a/requirements.txt b/requirements.txt index 0f8e4fd..7aac040 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ # stem==1.8.0 aiohttp>=3.7.4 -aiohttp-jinja2==1.2.0 +aiohttp-jinja2>=1.2 ckcc-protocol>=1.0.1 pynacl==1.3.0 aiohttp_session diff --git a/setup.py b/setup.py index 3d3b374..7aa7222 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup( 'stem', 'aiohttp', 'aiohttp-jinja2', - 'ckcc-protocol>=1.0.0', + 'ckcc-protocol>=1.3.2', ], entry_points=''' [console_scripts] diff --git a/webapp.py b/webapp.py index 238e684..31846ef 100755 --- a/webapp.py +++ b/webapp.py @@ -20,7 +20,10 @@ from persist import settings, BP from hashlib import sha256 from chain import broadcast_txn from version import VERSION -from jinja2 import Markup +try: + from jinja2 import Markup +except ImportError: + from markupsafe import Markup import policy from ckcc.constants import USER_AUTH_TOTP, USER_AUTH_HMAC, USER_AUTH_SHOW_QR, MAX_USERNAME_LEN