Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ version: 2
build:
os: "ubuntu-22.04"
tools:
python: "3"
python: "3.10"

python:
install:
- requirements: docs/requirements.txt

sphinx:
configuration: docs/conf.py
configuration: docs/conf.py
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ sudo yum -y install python3-devel libusbx-devel systemd-devel
For macOS:
```
brew install libusb

```

For Windows:
```
# Install Visual Studio Build Tools with Windows 10 SDK and C++ CMake tools
# Install OpenSSL development libraries
```

## Install
Expand Down Expand Up @@ -77,6 +84,26 @@ All output will be in JSON form and sent to `stdout`.
Additional information or prompts will be sent to `stderr` and will not necessarily be in JSON.
This additional information is for debugging purposes.

### PKCS11 Token Support

HWI supports PKCS11 tokens (HSMs) with secp256k1 curve support. To use a PKCS11 token:

1. Set the required environment variables:
```bash
# Windows
$env:PKCS11_LIB_PATH = "C:\path\to\your\pkcs11\library.dll"
$env:PKCS11_TOKEN_LABEL = "YourTokenLabel"

# Unix-like
export PKCS11_LIB_PATH=/path/to/your/pkcs11/library.so
export PKCS11_TOKEN_LABEL=YourTokenLabel
```

2. Use the token with HWI:
```bash
hwi --device-type pkcs11 --path /path/to/library.so getmasterxpub
```

To see a complete list of available commands and global parameters, run
`./hwi.py --help`. To see options specific to a particular command,
pass the `--help` parameter after the command name; for example:
Expand Down
17 changes: 15 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,18 @@
# Show both class and init docstring
autoclass_content = "both"

# Mock these imports
autodoc_mock_imports = ["hid", "ecdsa", "pyaes", "mnemonic", "typing_extensions", "usb1", "PySide2"]
autodoc_mock_imports = [
"hid",
"hidapi",
"libusb1",
"usb",
"usb.core",
"usb.util",
"usb1",
"btchip",
"trezorlib",
"ledgerblue",
"jadepy",
"PySide2",
"hwilib.udevinstaller",
]
101 changes: 101 additions & 0 deletions docs/devices/pkcs11.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
PKCS#11 Token
=============

The PKCS#11 Token device implementation allows HWI to interact with PKCS#11-compliant Hardware Security Modules (HSMs) that support the secp256k1 curve.

Requirements
------------

- A PKCS#11-compliant HSM with secp256k1 curve support.
- The PKCS#11 library for your HSM.
- The ``python-pkcs11`` Python package.

Windows-specific Requirements
-----------------------------

On Windows, you'll need:

1. **Visual Studio Build Tools with C++ support**
- Download from: https://visualstudio.microsoft.com/visual-cpp-build-tools/
- Select "Desktop development with C++".
- Make sure to include the Windows 10 SDK.

2. **OpenSSL development headers**
- Download from: https://slproweb.com/products/Win32OpenSSL.html
- Choose the "Win64 OpenSSL" version.
- Ensure the OpenSSL bin directory is on PATH.

3. **The PKCS#11 library for your HSM** (usually a ``.dll`` file)
- Prefer specifying its absolute path via ``PKCS11_LIB_PATH`` or placing it alongside the application.
- Avoid copying into ``C:\Windows\System32`` to reduce DLL hijacking risks.

Installation Steps for Windows:

1. Install the prerequisites in the order listed above.
2. Install ``python-pkcs11``:

.. code-block:: shell

pip install python-pkcs11

If you get a "Failed building wheel" error, ensure prerequisites are installed correctly and try running the command in a new terminal.

Configuration
-------------

The device can be configured using environment variables. Command-line flags will override these variables if provided.

- ``PKCS11_LIB_PATH``: **(Required)** Path to the PKCS#11 library.
- ``PKCS11_TOKEN_LABEL``: Label of the token to use (default: "Bitcoin").
- ``PKCS11_PIN``: User PIN for token login. For security, it is better to rely on the interactive prompt than to set this variable.

Example environment variable setup:

.. code-block:: powershell

# On Windows (PowerShell)
$env:PKCS11_LIB_PATH = "C:\path\to\your\pkcs11\library.dll"
$env:PKCS11_TOKEN_LABEL = "YourTokenLabel"

.. code-block:: shell

# On Linux/macOS
export PKCS11_LIB_PATH=/path/to/your/pkcs11/library.so
export PKCS11_TOKEN_LABEL=YourTokenLabel

Usage
-----

1. **Initialize your HSM** with a master key labeled ``MASTER_KEY`` using the secp256k1 curve.
2. **Use HWI** with your PKCS#11 token:

.. code-block:: shell

# List available devices
hwi enumerate

# Get the master public key
hwi --device-type pkcs11 --path /path/to/library.so getmasterxpub

Security Considerations
-----------------------

- The PKCS#11 token must be properly configured with appropriate access controls.
- The master key should be protected with a strong PIN/password.
- The PKCS#11 library should be from a trusted source.
- The token should be physically secured.

Limitations
-----------

- Only supports the secp256k1 curve.
- Requires the token to be pre-initialized with a master key.
- May not support all HWI features depending on the token's capabilities.

Troubleshooting
---------------

- Verify your PKCS#11 library is properly installed and the path is correct.
- Check that your token supports the secp256k1 curve.
- Ensure the ``MASTER_KEY`` exists and is accessible.
- Check the token's logs for any error messages.
10 changes: 10 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
sphinxcontrib-autoprogram>=0.1.5
sphinx>=3.2.1
sphinx_rtd_theme>=1.0.0
python-pkcs11>=0.7.0
cbor2>=5.4.6,<6.0.0
pyserial>=3.5
ecdsa>=0
mnemonic>=0
noiseprotocol>=0.3.1,<0.4.0
protobuf>=4.23.3,<5.0.0
pyaes>=1.6
semver>=2.13.0,<3.0.0
typing-extensions>=4.4
66 changes: 66 additions & 0 deletions hwilib/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
Union,
)

import pkcs11
from pkcs11 import Mechanism, ObjectClass, KeyType

py_enumerate = enumerate

Expand Down Expand Up @@ -590,3 +592,67 @@ def install_udev_rules(source: str, location: str) -> Dict[str, bool]:
from .udevinstaller import UDevInstaller
return {"success": UDevInstaller.install(source, location)}
raise NotImplementedError("udev rules are not needed on your platform")

from .key import ExtendedKey
from .errors import HWWError

class PKCS11Client(HardwareWalletClient):
def __init__(
self,
path: str,
password: Optional[str] = None,
expert: bool = False,
chain: Chain = Chain.MAIN,
token_label: str = "Bitcoin",
master_key_label: str = "MASTER_KEY"
) -> None:
super(PKCS11Client, self).__init__(path, password, expert, chain)

try:
# Initialize PKCS11 library and token
self.lib = pkcs11.lib(path)
self.token = self.lib.get_token(token_label=token_label)
self.session = self.token.open(user_pin=password)

# Find the master key
self.master_key = self.session.get_key(
object_class=ObjectClass.PRIVATE_KEY,
key_type=KeyType.EC,
label=master_key_label
)
except Exception as e:
if hasattr(self, 'session'):
self.session.close()
raise HWWError(f"Failed to initialize PKCS11 client: {e}")
def get_pubkey_at_path(self, bip32_path: str) -> ExtendedKey:
# Implement BIP32 path derivation and get public key
# You'll need to implement BIP32 path derivation logic
# and use the PKCS11 token to get the public key
pass

def sign_tx(self, psbt: PSBT) -> PSBT:
# Implement PSBT signing using the PKCS11 token
# You'll need to:
# 1. Parse the PSBT
# 2. For each input that needs signing:
# - Get the appropriate key from the token
# - Sign the transaction
# 3. Return the signed PSBT
pass

def sign_message(self, message: Union[str, bytes], keypath: str) -> str:
# Implement message signing using the PKCS11 token
# You'll need to:
# 1. Get the key at the specified path
# 2. Sign the message
# 3. Return the signature
pass

def get_master_fingerprint(self) -> bytes:
# Get the master key's fingerprint
# This is typically the first 4 bytes of the hash160 of the master public key
pass

def close(self) -> None:
# Close the PKCS11 session
self.session.close()
18 changes: 17 additions & 1 deletion hwilib/devices/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
"""
Devices
*******
This module contains all of the device implementations.
Each device implementation is a subclass of :class:`~hwilib.hwwclient.HardwareWalletClient`.
"""

from .trezor import TrezorClient
from .ledger import LedgerClient
from .keepkey import KeepkeyClient
from .jade import JadeClient
from .coldcard import ColdcardClient
from .digitalbitbox import DigitalbitboxClient
from .bitbox02 import Bitbox02Client
from .pkcs11 import PKCS11Client
__all__ = [
'trezor',
'ledger',
'keepkey',
'digitalbitbox',
'coldcard',
'bitbox02',
'jade'
'jade',
'pkcs11'
]
Loading