Commit a770adf
committed
refactor(ota): use bundled public key for offline signature verification
The offline update path previously fell back to a "warn and bypass"
prompt when the device could not reach GPG keyservers to fetch the
signing key. This defeated the purpose of offline updates, which
exist precisely for air-gapped devices without internet access.
The archive format now includes a .pub file (armored GPG public key)
alongside the binary, .sha256, and .sig. On upload, the bundled key
is validated against the pinned root fingerprint in gpg.go:21 via
parseAndValidateKeyring — the same trust anchor used by the online
update path. If the fingerprint matches, the key is used to verify
the signature locally. No keyserver call is made.
Verification is now binary: it passes or it fails. There is no
third "key fetch failed" state and no bypass option.
Backend (internal/ota/offline.go, ota_offline.go):
- OfflineBundle gains PublicKeyData []byte field
- ExtractOfflineArchive requires .pub (4 files, up from 3)
- VerifyOfflineBundle calls new VerifySignatureFromFileWithKey
method on GPGVerifier instead of VerifySignatureFromFile
- Removed isKeyFetchError(), KeyFetchFailed from OfflineVerifyResult,
BypassSignature from offlineUpdateApplyRequest, offlineUploadTimeout
- VerifyOfflineBundle no longer takes a context parameter
New GPG method (internal/ota/gpg.go):
- VerifySignatureFromFileWithKey accepts raw armored key bytes,
validates the fingerprint via parseAndValidateKeyring, then
calls CheckDetachedSignature with the resulting single-entity
keyring. No keyserver interaction, no cache mutation.
Frontend (ui/src/components/OfflineUpdateCard.tsx):
- Removed bypass confirmation dialog, showBypassPrompt state,
keyFetchFailed from UploadResult, bypassSignature from apply
request, ExclamationTriangleIcon import
- Signature OK indicator now always shows on verified state
Localisation (ui/localization/messages/en.json):
- Removed offline_update_signature_bypass_title,
offline_update_signature_bypass_description,
offline_update_signature_bypass_confirm
Tests (internal/ota/offline_test.go):
- All archives now include .pub files
- newOfflineSigningFixture replaces newSigningTestFixture for
offline tests — no mock HTTP client needed
- Added TestExtractOfflineArchive_MissingPub,
TestVerifyOfflineBundle_EmptyPublicKey,
TestVerifyOfflineBundle_WrongKey (bundled key fingerprint
mismatch)
- Removed TestIsKeyFetchError,
TestVerifyOfflineBundle_KeyFetchFailure
- End-to-end tests updated for 4-file archive format
Makefile:
- offline_archive_app target includes jetkvm_app.pub
Key rotation is not addressed here. rootKeyFP is a single string;
expanding to []string for the v1→v2→v3→v4 key rollover model is
a separate change.
Signed-off-by: Alex Howells <alex@howells.me>1 parent 9cfcfc7 commit a770adf
7 files changed
Lines changed: 208 additions & 229 deletions
File tree
- internal/ota
- ui
- localization/messages
- src/components
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
314 | 314 | | |
315 | 315 | | |
316 | 316 | | |
317 | | - | |
318 | | - | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
319 | 320 | | |
320 | 321 | | |
321 | | - | |
| 322 | + | |
322 | 323 | | |
323 | 324 | | |
324 | 325 | | |
325 | 326 | | |
326 | 327 | | |
327 | | - | |
| 328 | + | |
328 | 329 | | |
329 | 330 | | |
330 | 331 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
256 | 256 | | |
257 | 257 | | |
258 | 258 | | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
259 | 284 | | |
260 | 285 | | |
261 | 286 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
7 | 6 | | |
8 | 7 | | |
9 | 8 | | |
| |||
18 | 17 | | |
19 | 18 | | |
20 | 19 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
| 29 | + | |
| 30 | + | |
33 | 31 | | |
34 | 32 | | |
35 | 33 | | |
| |||
59 | 57 | | |
60 | 58 | | |
61 | 59 | | |
62 | | - | |
| 60 | + | |
63 | 61 | | |
64 | 62 | | |
65 | 63 | | |
| |||
120 | 118 | | |
121 | 119 | | |
122 | 120 | | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
123 | 129 | | |
124 | 130 | | |
125 | 131 | | |
| |||
134 | 140 | | |
135 | 141 | | |
136 | 142 | | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
137 | 146 | | |
138 | 147 | | |
139 | 148 | | |
| |||
153 | 162 | | |
154 | 163 | | |
155 | 164 | | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
161 | 169 | | |
162 | 170 | | |
163 | 171 | | |
| |||
172 | 180 | | |
173 | 181 | | |
174 | 182 | | |
175 | | - | |
| 183 | + | |
176 | 184 | | |
177 | 185 | | |
178 | 186 | | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
179 | 190 | | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | | - | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
| 191 | + | |
191 | 192 | | |
192 | 193 | | |
193 | 194 | | |
| |||
196 | 197 | | |
197 | 198 | | |
198 | 199 | | |
199 | | - | |
200 | | - | |
201 | | - | |
202 | | - | |
203 | | - | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
209 | 200 | | |
210 | 201 | | |
211 | 202 | | |
| |||
0 commit comments