hirsch-securefido 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hirsch_securefido-1.0.0/.gitignore +24 -0
- hirsch_securefido-1.0.0/Formula/hirsch-securefido.rb +82 -0
- hirsch_securefido-1.0.0/HOMEBREW.md +207 -0
- hirsch_securefido-1.0.0/LICENSE +27 -0
- hirsch_securefido-1.0.0/PKG-INFO +233 -0
- hirsch_securefido-1.0.0/PUBLISHING.md +118 -0
- hirsch_securefido-1.0.0/README.md +172 -0
- hirsch_securefido-1.0.0/pyproject.toml +83 -0
- hirsch_securefido-1.0.0/scripts/brew_release.sh +104 -0
- hirsch_securefido-1.0.0/scripts/mutation_check.py +105 -0
- hirsch_securefido-1.0.0/src/hirsch_securefido/__init__.py +74 -0
- hirsch_securefido-1.0.0/src/hirsch_securefido/__main__.py +8 -0
- hirsch_securefido-1.0.0/src/hirsch_securefido/cli.py +462 -0
- hirsch_securefido-1.0.0/src/hirsch_securefido/device.py +509 -0
- hirsch_securefido-1.0.0/src/hirsch_securefido/menu.py +133 -0
- hirsch_securefido-1.0.0/tests/conftest.py +128 -0
- hirsch_securefido-1.0.0/tests/test_cli.py +229 -0
- hirsch_securefido-1.0.0/tests/test_device.py +233 -0
- hirsch_securefido-1.0.0/tests/test_encoding.py +133 -0
- hirsch_securefido-1.0.0/tests/test_formula.py +167 -0
- hirsch_securefido-1.0.0/tests/test_integration.py +176 -0
- hirsch_securefido-1.0.0/tests/test_menu.py +183 -0
- hirsch_securefido-1.0.0/tests/test_packaging.py +135 -0
- hirsch_securefido-1.0.0/tests/virtual_authenticator.py +211 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
.venv-*/
|
|
10
|
+
venv/
|
|
11
|
+
|
|
12
|
+
# Testing
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
htmlcov/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
|
|
18
|
+
# macOS
|
|
19
|
+
.DS_Store
|
|
20
|
+
|
|
21
|
+
# Editors
|
|
22
|
+
.idea/
|
|
23
|
+
.vscode/
|
|
24
|
+
*.swp
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# typed: false
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Homebrew formula for the Hirsch SecureFIDO device-configuration CLI.
|
|
5
|
+
#
|
|
6
|
+
# Regenerate the `resource` blocks after a dependency bump with:
|
|
7
|
+
# ./scripts/brew_release.sh <version>
|
|
8
|
+
#
|
|
9
|
+
# The top-level `sha256` is a placeholder until the sdist is published to
|
|
10
|
+
# PyPI; `scripts/brew_release.sh` fills in the real digest. See HOMEBREW.md.
|
|
11
|
+
class HirschSecurefido < Formula
|
|
12
|
+
include Language::Python::Virtualenv
|
|
13
|
+
|
|
14
|
+
desc "Device configuration CLI for Hirsch SecureKey FIDO2 authenticators"
|
|
15
|
+
homepage "https://github.com/hirschsecure/hirsch-securefido"
|
|
16
|
+
url "https://files.pythonhosted.org/packages/source/h/hirsch-securefido/hirsch_securefido-1.0.0.tar.gz"
|
|
17
|
+
sha256 "REPLACE_WITH_SDIST_SHA256"
|
|
18
|
+
license "BSD-3-Clause"
|
|
19
|
+
|
|
20
|
+
depends_on "python@3.12"
|
|
21
|
+
|
|
22
|
+
# cryptography ships prebuilt wheels, but Homebrew builds from source, so the
|
|
23
|
+
# Rust toolchain is required to compile its extension modules.
|
|
24
|
+
depends_on "rust" => :build
|
|
25
|
+
|
|
26
|
+
resource "cffi" do
|
|
27
|
+
url "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz"
|
|
28
|
+
sha256 "dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
resource "pycparser" do
|
|
32
|
+
url "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz"
|
|
33
|
+
sha256 "600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
resource "cryptography" do
|
|
37
|
+
url "https://files.pythonhosted.org/packages/bb/ad/5d6702db60b1e40b41ef513b6967ff5848f307d50f8449baf1634f5908f1/cryptography-50.0.1.tar.gz"
|
|
38
|
+
sha256 "5dd9bda1c12b4162f6ff568eeb5e0ff956c28d14406e875cfe8a63a2d414ff20"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
resource "fido2" do
|
|
42
|
+
url "https://files.pythonhosted.org/packages/ba/ea/6f08c354b7aeb8019249d46a86c2153f8218499cced4d21bf16b6d49fc16/fido2-2.2.1.tar.gz"
|
|
43
|
+
sha256 "85787428a94c3f8eaf72f0ff30afba983b559a1b1b795c93318c81b4ad4062c4"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def install
|
|
47
|
+
virtualenv_install_with_resources
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def caveats
|
|
51
|
+
<<~EOS
|
|
52
|
+
hirsch-securefido talks to FIDO2 authenticators over USB HID.
|
|
53
|
+
No sudo is required on macOS: HID access is granted to the console user.
|
|
54
|
+
|
|
55
|
+
Verify your setup with:
|
|
56
|
+
hirsch-securefido list
|
|
57
|
+
hirsch-securefido info
|
|
58
|
+
|
|
59
|
+
NFC / smart-card readers need the optional pyscard extra:
|
|
60
|
+
$(brew --prefix)/opt/hirsch-securefido/libexec/bin/pip install pyscard
|
|
61
|
+
EOS
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
test do
|
|
65
|
+
# Version reporting must work with no hardware attached.
|
|
66
|
+
assert_match version.to_s, shell_output("#{bin}/hirsch-securefido --version")
|
|
67
|
+
|
|
68
|
+
# Help must advertise exactly the four device-configuration commands.
|
|
69
|
+
help = shell_output("#{bin}/hirsch-securefido --help")
|
|
70
|
+
["info", "set-pin", "change-pin", "reset"].each do |cmd|
|
|
71
|
+
assert_match cmd, help
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# With no authenticator present the tool must exit 2 (EXIT_NO_DEVICE)
|
|
75
|
+
# rather than crash with a traceback.
|
|
76
|
+
output = shell_output("#{bin}/hirsch-securefido info 2>&1", 2)
|
|
77
|
+
assert_match "No Hirsch FIDO2 token found", output
|
|
78
|
+
|
|
79
|
+
# The library must import cleanly inside the virtualenv.
|
|
80
|
+
system libexec/"bin/python", "-c", "import hirsch_securefido"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Publishing to Homebrew
|
|
2
|
+
|
|
3
|
+
How to get `brew install hirsch-securefido` working on macOS.
|
|
4
|
+
|
|
5
|
+
## The ordering constraint
|
|
6
|
+
|
|
7
|
+
Homebrew does not host code. The formula points at a **PyPI sdist** and builds
|
|
8
|
+
from it, so the order is fixed:
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
1. publish to PyPI -> 2. get the sdist sha256 -> 3. update the formula -> 4. push the tap
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Step 3 cannot happen first. Until the version exists on PyPI there is nothing
|
|
15
|
+
to checksum, which is why `Formula/hirsch-securefido.rb` currently carries
|
|
16
|
+
`REPLACE_WITH_SDIST_SHA256`.
|
|
17
|
+
|
|
18
|
+
## Which distribution channel?
|
|
19
|
+
|
|
20
|
+
| | Formula (`brew install`) | Cask (`brew install --cask`) |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| For | CLI tools built from source | prebuilt `.app` bundles, binaries |
|
|
23
|
+
| Ours | **yes** | no |
|
|
24
|
+
|
|
25
|
+
This is a command-line tool, so it is a **formula**. A cask would only apply if
|
|
26
|
+
you later ship a `.app`, which would additionally need codesigning and
|
|
27
|
+
notarization.
|
|
28
|
+
|
|
29
|
+
## Which tap?
|
|
30
|
+
|
|
31
|
+
**Your own tap** (`hirschsecure/homebrew-tap`) is the right choice here:
|
|
32
|
+
|
|
33
|
+
- You control releases; no third-party review queue.
|
|
34
|
+
- homebrew-core requires notability (roughly 30+ GitHub stars, 30+ forks, or
|
|
35
|
+
equivalent usage) and rejects vendor-specific hardware tools that only work
|
|
36
|
+
with one company's device. This tool is gated to Hirsch VID `04E6`, so it
|
|
37
|
+
would very likely be declined.
|
|
38
|
+
|
|
39
|
+
Users then run:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
brew tap hirschsecure/tap
|
|
43
|
+
brew install hirsch-securefido
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`brew tap hirschsecure/tap` resolves to `github.com/hirschsecure/homebrew-tap`.
|
|
47
|
+
The `homebrew-` prefix on the repo name is required; the tap name drops it.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Step 1 - Publish to PyPI
|
|
52
|
+
|
|
53
|
+
One-time: register the project name and configure Trusted Publishing at
|
|
54
|
+
<https://pypi.org/manage/account/publishing/>
|
|
55
|
+
|
|
56
|
+
| Field | Value |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| PyPI project | `hirsch-securefido` |
|
|
59
|
+
| Owner | `hirschsecure` |
|
|
60
|
+
| Repository | `hirsch-securefido` |
|
|
61
|
+
| Workflow | `publish.yml` |
|
|
62
|
+
| Environment | `pypi` |
|
|
63
|
+
|
|
64
|
+
Then release:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git tag v1.0.0
|
|
68
|
+
git push origin v1.0.0
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The `Publish` workflow verifies the tag matches `pyproject.toml`, builds, and
|
|
72
|
+
uploads with no stored API token. Confirm it worked:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip download --no-deps --no-binary :all: hirsch-securefido==1.0.0
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Manual alternative
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
python -m build
|
|
82
|
+
twine upload --repository testpypi dist/* # rehearse
|
|
83
|
+
twine upload dist/*
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Step 2 - Create the tap repository
|
|
87
|
+
|
|
88
|
+
Once, on GitHub: create a **public** repo named `homebrew-tap` under the
|
|
89
|
+
`hirschsecure` org.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git clone https://github.com/hirschsecure/homebrew-tap
|
|
93
|
+
cd homebrew-tap
|
|
94
|
+
mkdir -p Formula
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The `Formula/` subdirectory name matters; Homebrew looks there.
|
|
98
|
+
|
|
99
|
+
## Step 3 - Update the formula for the release
|
|
100
|
+
|
|
101
|
+
On macOS, from this repository:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
./scripts/brew_release.sh 1.0.0
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
That script:
|
|
108
|
+
|
|
109
|
+
1. confirms `1.0.0` is actually on PyPI, and stops if not
|
|
110
|
+
2. rewrites the formula's `url` and `sha256` from the real sdist
|
|
111
|
+
3. regenerates the Python `resource` blocks via `brew update-python-resources`
|
|
112
|
+
4. runs `ruby -c` and `brew style`
|
|
113
|
+
|
|
114
|
+
It edits **only** the formula's own url/sha256; the four vendored resource
|
|
115
|
+
digests are left untouched.
|
|
116
|
+
|
|
117
|
+
## Step 4 - Validate locally before publishing
|
|
118
|
+
|
|
119
|
+
Do not skip this. It is the first time the formula is genuinely exercised.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
brew install --build-from-source Formula/hirsch-securefido.rb
|
|
123
|
+
brew test hirsch-securefido
|
|
124
|
+
brew audit --strict --new hirsch-securefido
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- `install` proves the virtualenv builds and every resource resolves. Expect a
|
|
128
|
+
few minutes: `cryptography` compiles Rust extensions from source.
|
|
129
|
+
- `test` runs the formula's test block: `--version`, the four commands in
|
|
130
|
+
`--help`, and the exit-2 no-device contract.
|
|
131
|
+
- `audit --strict --new` applies the rules a new formula must satisfy.
|
|
132
|
+
|
|
133
|
+
Then confirm it behaves with hardware attached:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
hirsch-securefido # interactive menu
|
|
137
|
+
hirsch-securefido info # must work WITHOUT sudo
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Step 5 - Push the tap
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
cp Formula/hirsch-securefido.rb ../homebrew-tap/Formula/
|
|
144
|
+
cd ../homebrew-tap
|
|
145
|
+
git add Formula/hirsch-securefido.rb
|
|
146
|
+
git commit -m "hirsch-securefido 1.0.0"
|
|
147
|
+
git push
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Verify as a user would, from a clean state:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
brew untap hirschsecure/tap 2>/dev/null || true
|
|
154
|
+
brew tap hirschsecure/tap
|
|
155
|
+
brew install hirsch-securefido
|
|
156
|
+
hirsch-securefido --version
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Subsequent releases
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# 1. bump the version in pyproject.toml AND src/hirsch_securefido/__init__.py
|
|
163
|
+
# (tests/test_packaging.py fails if they disagree)
|
|
164
|
+
git tag v1.1.0 && git push origin v1.1.0 # publishes to PyPI
|
|
165
|
+
|
|
166
|
+
# 2. refresh and validate the formula
|
|
167
|
+
./scripts/brew_release.sh 1.1.0
|
|
168
|
+
brew install --build-from-source Formula/hirsch-securefido.rb
|
|
169
|
+
brew test hirsch-securefido
|
|
170
|
+
|
|
171
|
+
# 3. ship it
|
|
172
|
+
cp Formula/hirsch-securefido.rb ../homebrew-tap/Formula/
|
|
173
|
+
cd ../homebrew-tap && git commit -am "hirsch-securefido 1.1.0" && git push
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Users upgrade with `brew update && brew upgrade hirsch-securefido`.
|
|
177
|
+
|
|
178
|
+
## Troubleshooting
|
|
179
|
+
|
|
180
|
+
**`SHA256 mismatch`** - the formula's checksum does not match what PyPI served.
|
|
181
|
+
Re-run `./scripts/brew_release.sh <version>`. Never edit a digest by hand.
|
|
182
|
+
|
|
183
|
+
**`Could not find a version that satisfies the requirement`** - a transitive
|
|
184
|
+
dependency lacks a `resource` block. Re-run `brew update-python-resources`.
|
|
185
|
+
|
|
186
|
+
**`cryptography` fails to build** - the Rust toolchain is missing. The formula
|
|
187
|
+
declares `depends_on "rust" => :build`; confirm `brew install rust` succeeds.
|
|
188
|
+
|
|
189
|
+
**`Error: Formula is not in the tap`** - the file must be at
|
|
190
|
+
`Formula/hirsch-securefido.rb`, and the class name `HirschSecurefido` must match
|
|
191
|
+
the filename. `tests/test_formula.py` checks that pairing.
|
|
192
|
+
|
|
193
|
+
**`No such keg`** on `brew test` - install before testing.
|
|
194
|
+
|
|
195
|
+
## What is verified, and what is not
|
|
196
|
+
|
|
197
|
+
Automated in CI (`.github/workflows/ci.yml`, `formula` job on macOS):
|
|
198
|
+
`ruby -c` parses the formula, and `brew style` audits it.
|
|
199
|
+
|
|
200
|
+
Also checked offline by `tests/test_formula.py`: block balance, required
|
|
201
|
+
fields, audit-sensitive `desc` style, version agreement, full-length resource
|
|
202
|
+
digests, and that the test block asserts real behavior. Resource URLs are
|
|
203
|
+
confirmed reachable on PyPI over the network.
|
|
204
|
+
|
|
205
|
+
**Not verified here**, because this repo has no macOS host, no Ruby, and no
|
|
206
|
+
Hirsch key: `brew install`, `brew test`, `brew audit`, and every USB HID path.
|
|
207
|
+
Step 4 is the first time those run. Treat it as required, not optional.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright (c) 2026, Hirsch Secure, Inc.
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
15
|
+
contributors may be used to endorse or promote products derived from
|
|
16
|
+
this software without specific prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: hirsch-securefido
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Device configuration for Hirsch SecureKey FIDO2 authenticators: device info, set PIN, change PIN, factory reset.
|
|
5
|
+
Project-URL: Homepage, https://github.com/hirschsecure/hirsch-securefido
|
|
6
|
+
Project-URL: Repository, https://github.com/hirschsecure/hirsch-securefido
|
|
7
|
+
Project-URL: Issues, https://github.com/hirschsecure/hirsch-securefido/issues
|
|
8
|
+
Author: Hirsch Secure, Inc.
|
|
9
|
+
License: Copyright (c) 2026, Hirsch Secure, Inc.
|
|
10
|
+
All rights reserved.
|
|
11
|
+
|
|
12
|
+
Redistribution and use in source and binary forms, with or without
|
|
13
|
+
modification, are permitted provided that the following conditions are met:
|
|
14
|
+
|
|
15
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
16
|
+
list of conditions and the following disclaimer.
|
|
17
|
+
|
|
18
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
19
|
+
this list of conditions and the following disclaimer in the documentation
|
|
20
|
+
and/or other materials provided with the distribution.
|
|
21
|
+
|
|
22
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
23
|
+
contributors may be used to endorse or promote products derived from
|
|
24
|
+
this software without specific prior written permission.
|
|
25
|
+
|
|
26
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
27
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
28
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
29
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
30
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
31
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
32
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
33
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
34
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
35
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
36
|
+
License-File: LICENSE
|
|
37
|
+
Keywords: ctap,fido2,hirsch,macos,passkey,security-key,webauthn
|
|
38
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
39
|
+
Classifier: Environment :: Console
|
|
40
|
+
Classifier: Intended Audience :: System Administrators
|
|
41
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
42
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
43
|
+
Classifier: Programming Language :: Python :: 3
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
46
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
47
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
48
|
+
Classifier: Topic :: Security
|
|
49
|
+
Classifier: Topic :: System :: Hardware
|
|
50
|
+
Requires-Python: >=3.10
|
|
51
|
+
Requires-Dist: fido2>=1.1.0
|
|
52
|
+
Provides-Extra: dev
|
|
53
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
54
|
+
Requires-Dist: pytest-cov>=4.1; extra == 'dev'
|
|
55
|
+
Requires-Dist: pytest>=7.4; extra == 'dev'
|
|
56
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
57
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
58
|
+
Provides-Extra: pcsc
|
|
59
|
+
Requires-Dist: pyscard>=2.0.0; extra == 'pcsc'
|
|
60
|
+
Description-Content-Type: text/markdown
|
|
61
|
+
|
|
62
|
+
# Hirsch SecureFIDO Device Config
|
|
63
|
+
|
|
64
|
+
Command-line device configuration for Hirsch SecureKey / SecureKey GOV FIDO2
|
|
65
|
+
authenticators on macOS.
|
|
66
|
+
|
|
67
|
+
This is the **device configuration subset** of the Windows
|
|
68
|
+
*Hirsch SecureFIDO Cred Manager*. It provides exactly four operations:
|
|
69
|
+
|
|
70
|
+
| Command | Description | Origin |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| `info` | Read authenticator info: AAGUID, versions, options, limits, PIN retries | ported from the Windows app |
|
|
73
|
+
| `set-pin` | Set the initial PIN on a factory-fresh token | new |
|
|
74
|
+
| `change-pin` | Change an existing PIN | new |
|
|
75
|
+
| `reset` | Factory reset: erase all credentials and clear the PIN | new |
|
|
76
|
+
|
|
77
|
+
Only the device-info view existed in the Windows original. It read
|
|
78
|
+
authenticator info and rendered the AAGUID, versions, options, and limits;
|
|
79
|
+
that logic, including the option labels and COSE algorithm names, is carried
|
|
80
|
+
over here. The Windows app could *report* on the PIN (retry count, whether one
|
|
81
|
+
was set) and could surface PIN errors, but it had no way to set, change, or
|
|
82
|
+
clear one: it only ever called `getPinToken` to authenticate credential
|
|
83
|
+
management. Set PIN, Change PIN, and Factory Reset are therefore newly
|
|
84
|
+
implemented against CTAP `authenticatorClientPIN` and `authenticatorReset`.
|
|
85
|
+
|
|
86
|
+
Credential enumeration and deletion, which were the Windows app's main
|
|
87
|
+
purpose, are intentionally **not** included.
|
|
88
|
+
|
|
89
|
+
## Install
|
|
90
|
+
|
|
91
|
+
### Homebrew
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
brew tap hirschsecure/tap
|
|
95
|
+
brew install hirsch-securefido
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### PyPI
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install hirsch-securefido
|
|
102
|
+
|
|
103
|
+
# with NFC / CCID reader support
|
|
104
|
+
pip install "hirsch-securefido[pcsc]"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Usage
|
|
108
|
+
|
|
109
|
+
Run it with no arguments for an interactive menu:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
$ hirsch-securefido
|
|
113
|
+
|
|
114
|
+
Hirsch SecureFIDO Device Config v1.0.0
|
|
115
|
+
--------------------------------------------------------
|
|
116
|
+
Hirsch SecureKey USB HID (VID 04E6) PIN set, 8 attempt(s) left
|
|
117
|
+
--------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
1 Device information
|
|
120
|
+
2 Set PIN
|
|
121
|
+
3 Change PIN
|
|
122
|
+
4 Factory reset
|
|
123
|
+
r Refresh device status
|
|
124
|
+
q Quit
|
|
125
|
+
|
|
126
|
+
Select an option:
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The header shows live device status and refreshes after every action. The
|
|
130
|
+
menu appears **only** on an interactive terminal: with a piped stdin or
|
|
131
|
+
redirected stdout the tool prints help and exits, so scripts never block on a
|
|
132
|
+
prompt.
|
|
133
|
+
|
|
134
|
+
Every operation is also available directly:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
hirsch-securefido info # human-readable device report
|
|
138
|
+
hirsch-securefido info --json # machine-readable, for MDM tooling
|
|
139
|
+
hirsch-securefido list # enumerate connected authenticators
|
|
140
|
+
|
|
141
|
+
hirsch-securefido set-pin # prompts for a new PIN, twice
|
|
142
|
+
hirsch-securefido change-pin # prompts for current then new PIN
|
|
143
|
+
hirsch-securefido reset # requires typing RESET, then a touch
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
By default only Hirsch authenticators (USB Vendor ID `04E6`) are accepted.
|
|
147
|
+
Pass `--any-vendor` to work with other FIDO2 keys.
|
|
148
|
+
|
|
149
|
+
### Unattended use
|
|
150
|
+
|
|
151
|
+
PINs may be supplied by environment variable for provisioning scripts:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
HIRSCH_PIN=oldpin HIRSCH_NEW_PIN=newpin hirsch-securefido change-pin
|
|
155
|
+
hirsch-securefido reset --yes
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
PINs are also read from stdin when it is not a TTY:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
echo "123456" | hirsch-securefido set-pin
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Exit codes
|
|
165
|
+
|
|
166
|
+
| Code | Meaning |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `0` | Success |
|
|
169
|
+
| `1` | General device error |
|
|
170
|
+
| `2` | No authenticator found |
|
|
171
|
+
| `3` | PIN rejected or blocked |
|
|
172
|
+
| `4` | Operation unsupported by the token |
|
|
173
|
+
| `130` | Cancelled by the user |
|
|
174
|
+
|
|
175
|
+
## Factory reset
|
|
176
|
+
|
|
177
|
+
CTAP requires a factory reset to arrive within a few seconds of the token
|
|
178
|
+
powering up, confirmed by a physical touch. The `reset` command therefore
|
|
179
|
+
prompts you to unplug and re-insert the token first. If you see
|
|
180
|
+
"a factory reset must be started within a few seconds", re-insert the key and
|
|
181
|
+
run the command again promptly.
|
|
182
|
+
|
|
183
|
+
A reset destroys every passkey on the device and clears the PIN. You will lose
|
|
184
|
+
access to any account that relies on this key as its only factor.
|
|
185
|
+
|
|
186
|
+
## macOS notes
|
|
187
|
+
|
|
188
|
+
The Windows original auto-elevated to Administrator, because non-elevated
|
|
189
|
+
Windows processes cannot open FIDO HID authenticators. macOS grants HID access
|
|
190
|
+
to the console user, so **no `sudo` is required**. The Windows-only
|
|
191
|
+
`winscard.dll` / `cfgmgr32.dll` hardware gate and disconnect watchdog have been
|
|
192
|
+
replaced by a direct USB Vendor ID check on the CTAP HID descriptor.
|
|
193
|
+
|
|
194
|
+
`pyscard` is optional. Install the `pcsc` extra only if you need NFC or
|
|
195
|
+
smart-card readers; it requires the PCSC-Lite build toolchain.
|
|
196
|
+
|
|
197
|
+
## Development
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
pip install -e ".[dev]"
|
|
201
|
+
pytest
|
|
202
|
+
ruff check src tests
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
The test suite runs entirely against software authenticators, so no hardware is
|
|
206
|
+
needed. It has two layers:
|
|
207
|
+
|
|
208
|
+
- `tests/test_device.py`, `tests/test_cli.py` stub out `fido2` to test error
|
|
209
|
+
handling and CLI behavior in isolation.
|
|
210
|
+
- `tests/test_integration.py` runs the **real** python-fido2 stack (CBOR, ECDH
|
|
211
|
+
key agreement, AES-CBC PIN encryption, HMAC `pinUvAuthParam`) against the
|
|
212
|
+
virtual authenticator in `tests/virtual_authenticator.py`, then asserts on
|
|
213
|
+
the resulting device state.
|
|
214
|
+
|
|
215
|
+
To confirm the suite actually detects bugs rather than passing vacuously:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
python scripts/mutation_check.py
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
This injects plausible defects (swapped PIN arguments, a skipped guard, a reset
|
|
222
|
+
that never fires) and requires the suite to fail on each one.
|
|
223
|
+
|
|
224
|
+
### What software cannot verify
|
|
225
|
+
|
|
226
|
+
USB HID transport, the CTAP reset power-up window, and the physical touch
|
|
227
|
+
confirmation have no software equivalent. `brew install` likewise needs macOS.
|
|
228
|
+
These are covered by the manual hardware checklist in
|
|
229
|
+
[PUBLISHING.md](PUBLISHING.md).
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
BSD 3-Clause. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Publishing
|
|
2
|
+
|
|
3
|
+
Release checklist for `hirsch-securefido`.
|
|
4
|
+
|
|
5
|
+
## 1. Pre-flight
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install -e ".[dev]"
|
|
9
|
+
ruff check src tests
|
|
10
|
+
pytest -q
|
|
11
|
+
python scripts/mutation_check.py # suite must detect all injected bugs
|
|
12
|
+
python -m build
|
|
13
|
+
twine check dist/*
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Confirm the version in `pyproject.toml` and `src/hirsch_securefido/__init__.py`
|
|
17
|
+
match, and that `CHANGELOG` / README reflect the release. `tests/test_packaging.py`
|
|
18
|
+
and `tests/test_formula.py` enforce that agreement automatically.
|
|
19
|
+
|
|
20
|
+
## 2. PyPI
|
|
21
|
+
|
|
22
|
+
### Automated (recommended)
|
|
23
|
+
|
|
24
|
+
The `Publish` workflow uses PyPI **Trusted Publishing** (OIDC), so no API token
|
|
25
|
+
is stored in the repository.
|
|
26
|
+
|
|
27
|
+
One-time setup at
|
|
28
|
+
<https://pypi.org/manage/project/hirsch-securefido/settings/publishing/>:
|
|
29
|
+
|
|
30
|
+
| Field | Value |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| Owner | `hirschsecure` |
|
|
33
|
+
| Repository | `hirsch-securefido` |
|
|
34
|
+
| Workflow | `publish.yml` |
|
|
35
|
+
| Environment | `pypi` |
|
|
36
|
+
|
|
37
|
+
Then release by tagging:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git tag v1.0.0
|
|
41
|
+
git push origin v1.0.0
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The workflow refuses to publish if the tag does not match the packaged version.
|
|
45
|
+
|
|
46
|
+
### Manual
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
python -m build
|
|
50
|
+
twine upload --repository testpypi dist/* # rehearse first
|
|
51
|
+
twine upload dist/*
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Verify the published artifact installs cleanly:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python -m venv /tmp/verify && /tmp/verify/bin/pip install hirsch-securefido
|
|
58
|
+
/tmp/verify/bin/hirsch-securefido --version
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 3. Homebrew
|
|
62
|
+
|
|
63
|
+
See **[HOMEBREW.md](HOMEBREW.md)** for the full walkthrough: tap setup,
|
|
64
|
+
formula-vs-cask, local validation, and troubleshooting.
|
|
65
|
+
|
|
66
|
+
Short version, after the PyPI release is live:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
./scripts/brew_release.sh 1.0.0 # rewrites url + sha256, refreshes resources
|
|
70
|
+
brew install --build-from-source Formula/hirsch-securefido.rb
|
|
71
|
+
brew test hirsch-securefido
|
|
72
|
+
brew audit --strict --new hirsch-securefido
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Then publish to the tap:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
cp Formula/hirsch-securefido.rb ../homebrew-tap/Formula/
|
|
79
|
+
cd ../homebrew-tap && git commit -am "hirsch-securefido 1.0.0" && git push
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Users install with:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
brew tap hirschsecure/tap
|
|
86
|
+
brew install hirsch-securefido
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 4. Post-release
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
brew uninstall hirsch-securefido && brew install hirschsecure/tap/hirsch-securefido
|
|
93
|
+
hirsch-securefido info # with a real Hirsch key attached
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Manual hardware verification
|
|
97
|
+
|
|
98
|
+
Everything below is **outside** what the automated suite can reach. The tests
|
|
99
|
+
use a virtual authenticator that speaks real CTAP2 CBOR, so protocol logic is
|
|
100
|
+
covered, but USB HID transport, the reset power-up window, and the physical
|
|
101
|
+
touch have no software equivalent.
|
|
102
|
+
|
|
103
|
+
Run this once per release on macOS with a real Hirsch SecureKey:
|
|
104
|
+
|
|
105
|
+
- [ ] `hirsch-securefido list` shows the key over USB HID
|
|
106
|
+
- [ ] `hirsch-securefido info` reports the true AAGUID and firmware version
|
|
107
|
+
- [ ] `info` runs **without `sudo`** (the core macOS port claim)
|
|
108
|
+
- [ ] `set-pin` on a factory-fresh token
|
|
109
|
+
- [ ] `change-pin` with the correct current PIN
|
|
110
|
+
- [ ] `change-pin` with a wrong PIN decrements the retry counter shown by `info`
|
|
111
|
+
- [ ] `reset` refused when run outside the power-up window
|
|
112
|
+
- [ ] `reset` succeeds when the token is re-inserted, and the touch prompt appears
|
|
113
|
+
- [ ] `reset` cancelled by declining the touch, leaving credentials intact
|
|
114
|
+
- [ ] After a successful `reset`, `info` reports `PIN Set: No`
|
|
115
|
+
- [ ] NFC path with `pip install pyscard` and a card on a reader, if in scope
|
|
116
|
+
|
|
117
|
+
Record the macOS version, the key's firmware version, and the fido2 version
|
|
118
|
+
used, so a regression can be attributed later.
|