Repository navigation
Expand file tree
/
Copy pathllms-full.txt
More file actions
2326 lines (1790 loc) · 105 KB
/
Copy pathllms-full.txt
File metadata and controls
2326 lines (1790 loc) · 105 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
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
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# eBoot — full documentation (llms-full.txt)
This file is a checked-in concatenation of eBoot's documentation,
in the order listed below, so agents and tools can read the whole
corpus as one document. It is generated by hand from the sources —
when a source doc changes, update this file in the same commit.
Sources, in order:
- `docs/architecture.md`
- `docs/secure_boot_chain.md`
- `docs/security.md`
- `docs/threat_model.md`
- `docs/update-flow.md`
- `docs/key_lifecycle.md`
- `docs/memory-map.md`
- `docs/installation_usage.md`
- `docs/quickstart.md`
- `docs/eflash.md`
- `docs/mcuboot_comparison.md`
# === docs/architecture.md ===
# eBootloader Architecture
## Staged Boot Architecture
```
ROM / Reset Vector
↓
eBootloader (stage-0 / minimal core)
↓
E-Boot (stage-1 boot manager)
↓
Application Firmware
↕
EoS Firmware Services
```
## Module Map
| Module | Layer | Role |
|---------------|---------|-------------------------------------------|
| `stage0/` | Stage-0 | Reset entry, minimal HW init, recovery check, jump to stage-1 |
| `stage1/` | Stage-1 | Image scan, boot policy, boot log, jump to application |
| `core/` | Shared | Boot control, image verify, slot management, recovery state machine, firmware services |
| `hal/` | HAL | Board-agnostic flash/watchdog/UART/jump wrappers |
| `boards/` | BSP | Board-specific register-level implementations |
| `include/` | API | All public headers and type definitions |
| `tools/` | Host | Image packer, signing tool, UART recovery client |
| `tests/` | Test | Host-side unit tests with simulated flash |
## Flash Memory Map (STM32F407 Reference)
```
Address Range Size Region
─────────────────────────────────────────────────────
0x08000000 - 0x08003FFF 16K Stage-0 (eBootloader)
0x08004000 - 0x0800FFFF 48K Stage-1 (E-Boot)
0x08010000 - 0x0807FFFF 448K Slot A (active firmware)
0x08080000 - 0x080EFFFF 448K Slot B (candidate firmware)
0x080F0000 - 0x080F3FFF 16K Recovery image
0x080F4000 - 0x080F5FFF 8K Boot control (primary)
0x080F6000 - 0x080F7FFF 8K Boot control (backup)
0x080F8000 - 0x080F9FFF 8K Boot log
0x080FA000 - 0x080FFFFF 24K Device config / reserved
```
## Boot Flow
```
Reset_Handler()
├── Copy .data, zero .bss
├── ebldr_hw_init_minimal()
│ ├── board_get_ops() → register HAL
│ └── board_early_init() → clocks, flash latency
└── ebldr_stage0_main()
├── ebldr_watchdog_init()
├── eos_bootctl_load() → load boot state
├── ebldr_recovery_triggered()?
│ └── YES → eos_recovery_enter() → UART command loop
└── jump to stage-1 → eboot_main()
├── eos_bootctl_load()
├── eos_boot_log_init()
├── eboot_should_recover()?
│ └── YES → eos_recovery_enter()
├── eboot_scan_images() → verify both slots
├── eboot_select_slot() → boot policy
│ ├── Check max attempts → rollback
│ ├── Check pending upgrade → test boot
│ ├── Try active slot
│ └── Fallback to alternate slot
└── eboot_jump_to_app()
├── Increment boot attempts
├── Disable interrupts
├── Deinit peripherals
└── Jump to application vector table
```
## Rollback Sequence
```
1. Application writes new image → Slot B
2. eos_fw_request_upgrade(SLOT_B, EOS_UPGRADE_TEST)
3. system_reboot()
4. E-Boot sees pending_slot = B, flags = TEST_BOOT
5. Verifies Slot B image → boots Slot B
6. boot_attempts++
7. New firmware runs self-test
8. eos_fw_confirm_running_image() → marks CONFIRMED
OR
Firmware crashes / fails self-test
→ Watchdog resets → boot_attempts++
→ After max_attempts reached → E-Boot rolls back to Slot A
```
## Recovery Protocol (UART)
| Command | Code | Description |
|-----------|------|---------------------------------|
| PING | 0x01 | Identity check — returns "EOS" |
| INFO | 0x02 | Flash layout, slot addresses and capabilities. Unauthenticated (ADR-021). Response: 22 bytes packed -- `ack`, `flash_size`, `slot_a_addr`, `slot_a_size`, `slot_b_addr`, `slot_b_size` (LE `uint32`), `caps` (bit 0 RNG, bit 1 OTP) |
| ERASE | 0x03 | Erase target slot |
| WRITE | 0x04 | Write chunk to slot |
| VERIFY | 0x05 | Verify slot image integrity |
| BOOT | 0x06 | Set active slot and reboot |
| LOG | 0x07 | Dump boot log |
| RESET | 0x08 | System reset |
| FACTORY | 0x09 | Erase all + reset defaults |
Packet format: `[cmd:1][slot:1][len:2][offset:4]`
# === docs/secure_boot_chain.md ===
# Secure Boot Chain — eBootloader
> **Last updated:** 2026-04-03
>
> **Scope:** Complete chain of trust from ROM through application firmware in the eBootloader system.
---
## 1. Chain of Trust Overview
The eBootloader implements a staged chain of trust where each boot stage verifies the next before transferring execution. Every link in the chain must pass verification — a single failure triggers recovery or halt.
```
┌─────────────────────────────────────────────────────────────────────┐
│ SILICON ROM │
│ (immutable root of trust) │
│ │
│ • Loads from fixed flash address (0x08000000) │
│ • Platform-dependent: may verify stage-0 hash via eFuse/OTP │
│ • Sets initial stack pointer and jumps to Reset_Handler │
└────────────────────────┬────────────────────────────────────────────┘
│ TB-1: ROM → Stage-0
│ Verified by: ROM hash (SoC-dependent)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ STAGE-0 (eBootloader) │
│ 16 KB flash region │
│ │
│ • Copy .data, zero .bss │
│ • ebldr_hw_init_minimal() — clocks, flash latency │
│ • board_get_ops() — register HAL vtable │
│ • ebldr_watchdog_init() │
│ • eos_bootctl_load() — load boot state from flash │
│ • Check recovery trigger (pin or flag) │
│ • ★ VERIFY stage-1 image (hash + signature) │
│ • Jump to stage-1 entry point │
└────────────────────────┬────────────────────────────────────────────┘
│ TB-2: Stage-0 → Stage-1
│ Verified by: SHA-256 + Ed25519 signature
▼
┌─────────────────────────────────────────────────────────────────────┐
│ STAGE-1 (E-Boot) │
│ 48 KB flash region │
│ │
│ • eos_bootctl_load() — reload boot state │
│ • eos_boot_log_init() — initialize boot log │
│ • Check recovery trigger (pin, flag, max attempts) │
│ • eboot_scan_images() — parse and verify both slots │
│ • ★ VERIFY application image (hash + signature + version) │
│ • eboot_select_slot() — boot policy decision │
│ • Anti-rollback check (security counter) │
│ • eboot_jump_to_app() — transfer to application │
└────────────────────────┬────────────────────────────────────────────┘
│ TB-3: Stage-1 → Application
│ Verified by: SHA-256 + Ed25519 + anti-rollback
▼
┌─────────────────────────────────────────────────────────────────────┐
│ APPLICATION FIRMWARE │
│ 448 KB × 2 slots (A/B) │
│ │
│ • Application entry point (vector table) │
│ • Self-test → eos_fw_confirm_running_image() │
│ • Runtime firmware services via eos_fwsvc API │
│ • OTA update: write to inactive slot + eos_fw_request_upgrade() │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 2. Verification Steps at Each Stage
### 2.1 ROM → Stage-0 (TB-1)
| Step | Operation | API / Mechanism |
|---|---|---|
| 1 | ROM reads stage-0 vector table from `0x08000000` | SoC boot ROM (vendor) |
| 2 | ROM verifies stage-0 hash against OTP/eFuse value | SoC-specific (e.g., STM32 Secure Boot, nRF Secure Boot) |
| 3 | ROM sets MSP from vector table entry 0 | Hardware |
| 4 | ROM jumps to Reset_Handler (vector table entry 1) | Hardware |
**What is verified:**
- Stage-0 binary integrity (hash match)
- Stage-0 authenticity (if ROM supports signature verification)
**What is NOT verified by ROM:**
- Stage-1 or application images (responsibility of stage-0 and stage-1)
- Boot control block integrity (loaded later by stage-0)
### 2.2 Stage-0 → Stage-1 (TB-2)
| Step | Operation | API |
|---|---|---|
| 1 | Initialize minimal hardware | `ebldr_hw_init_minimal()` |
| 2 | Register board HAL | `board_get_ops()` → `eos_hal_init()` |
| 3 | Start watchdog | `ebldr_watchdog_init()` |
| 4 | Load boot control block | `eos_bootctl_load()` |
| 5 | Check recovery trigger | `ebldr_recovery_triggered()` |
| 6 | Parse stage-1 image header at `0x08004000` | `eos_image_parse_header()` |
| 7 | Verify stage-1 CRC32 (Phase 1) or SHA-256 hash (Phase 2) | `eos_image_verify_integrity()` |
| 8 | Verify stage-1 Ed25519 signature (Phase 2) | `eos_image_verify_signature()` |
| 9 | Check stage-1 version against minimum (Phase 2) | `eos_image_check_version()` |
| 10 | Disable interrupts, deinit peripherals | `eos_hal_disable_interrupts()` |
| 11 | Set MSP and jump to stage-1 | `eos_hal_set_msp()` → `eos_hal_jump()` |
**Verification flow (Phase 2):**
```c
int stage0_verify_stage1(void) {
eos_image_header_t hdr;
int rc;
rc = eos_image_parse_header(STAGE1_ADDR, &hdr);
if (rc != EOS_OK) return rc;
rc = eos_image_verify_integrity(&hdr, STAGE1_ADDR + hdr.hdr_size);
if (rc != EOS_OK) return rc;
rc = eos_image_verify_signature(&hdr);
if (rc != EOS_OK) return rc;
rc = eos_image_check_version(hdr.image_version, min_stage1_version);
if (rc != EOS_OK) return rc;
return EOS_OK;
}
```
### 2.3 Stage-1 → Application (TB-3)
| Step | Operation | API |
|---|---|---|
| 1 | Reload boot control block | `eos_bootctl_load()` |
| 2 | Initialize boot log | `eos_boot_log_init()` |
| 3 | Check recovery conditions | `eboot_should_recover()` |
| 4 | Scan both image slots (A and B) | `eboot_scan_images()` |
| 5 | Parse image header for candidate slot | `eos_image_parse_header()` |
| 6 | Verify image integrity (CRC32 / SHA-256) | `eos_image_verify_integrity()` |
| 7 | Verify image signature (Ed25519) | `eos_image_verify_signature()` |
| 8 | Check image version against security counter | `eos_image_check_version()` |
| 9 | Apply boot policy (test boot, rollback, fallback) | `eboot_select_slot()` |
| 10 | Increment boot attempts | `eos_bootctl_increment_attempts()` |
| 11 | Disable interrupts, deinit peripherals | `eos_hal_disable_interrupts()`, `eos_hal_deinit_peripherals()` |
| 12 | Jump to application vector table | `eboot_jump_to_app()` |
---
## 3. Failure Modes and Recovery Paths
### 3.1 Failure Mode Summary
| Stage | Failure | Detection | Recovery |
|---|---|---|---|
| ROM → Stage-0 | Stage-0 hash mismatch | ROM verification | Device-specific (JTAG/SWD reflash, ROM recovery mode) |
| ROM → Stage-0 | Stage-0 corrupted | ROM verification or crash | JTAG/SWD reflash |
| Stage-0 → Stage-1 | Stage-1 header invalid | `eos_image_parse_header()` returns error | Enter UART recovery mode |
| Stage-0 → Stage-1 | Stage-1 integrity check fails | `eos_image_verify_integrity()` returns `EOS_ERR_CRC` | Enter UART recovery mode |
| Stage-0 → Stage-1 | Stage-1 payload unreadable | `eos_image_verify_integrity()` returns `EOS_ERR_FLASH` | Enter UART recovery mode |
| Stage-0 → Stage-1 | Stage-1 signature invalid | `eos_image_verify_signature()` returns `EOS_ERR_SIGNATURE` | Enter UART recovery mode |
| Stage-0 → Stage-1 | Stage-1 header edited after signing | `eos_image_verify_signature()` returns `EOS_ERR_SIGNATURE` (the signature covers the header prefix) | Enter UART recovery mode |
| Stage-0 → Stage-1 | Stage-1 version too old | `eos_image_check_version()` returns `EOS_ERR_VERSION` | Enter UART recovery mode |
| Stage-1 → App | Active slot image invalid | Integrity/signature check fails | Try alternate slot (B→A or A→B) |
| Stage-1 → App | Both slots invalid | Both fail verification | Enter UART recovery mode |
| Stage-1 → App | Boot attempts exceeded | `boot_attempts >= max_attempts` | Rollback to `confirmed_slot` |
| Stage-1 → App | Application crashes on test boot | Watchdog reset; `boot_attempts` incremented | After `max_attempts`: rollback |
| Stage-1 → App | Application fails self-test | App calls `eos_fw_request_recovery()` | Recovery mode on next boot |
| Any stage | Boot control block corrupt | `eos_bootctl_validate()` returns false | Use backup copy; if both corrupt, init defaults |
### 3.2 Recovery Decision Tree
```
Stage-0 verification of stage-1:
├── PASS → jump to stage-1
└── FAIL
├── Recovery pin asserted? → YES → UART recovery
└── NO → attempt recovery anyway (no valid stage-1)
Stage-1 verification of application:
├── Active slot PASS
│ ├── Test boot?
│ │ ├── YES → boot with attempt tracking
│ │ └── NO → boot normally
│ └── Boot
├── Active slot FAIL
│ ├── Alternate slot PASS → boot alternate
│ └── Alternate slot FAIL → UART recovery
└── max_attempts exceeded → rollback to confirmed_slot
```
### 3.3 Unrecoverable Conditions
| Condition | Cause | Resolution |
|---|---|---|
| ROM verification fails (if enabled) | Corrupted stage-0 in flash | JTAG/SWD reflash required |
| All OTP key slots revoked | Incorrect key revocation sequence | Device is permanently bricked — hardware replacement |
| Flash hardware failure | Physical damage, wear-out | Hardware replacement |
| Debug interface locked + no valid firmware | Debug lock prevents reflash | Contact manufacturer for unlock (if supported) |
---
## 4. Anti-Rollback Mechanism
### 4.1 Monotonic Security Counter
Each firmware image carries a `security_counter` field in its header. The device maintains a monotonic counter in persistent storage that can only increase.
```
┌─────────────┐ ┌─────────────────┐
│ Image Header│ │ Device Storage │
│ │ │ │
│ security_ │───────>│ security_version │
│ counter: N │ compare│ (monotonic): M │
│ │ │ │
└─────────────┘ └─────────────────┘
If N >= M → ACCEPT (M is *not* raised yet — see below)
If N < M → REJECT (rollback attempt)
```
Acceptance and raising the floor are deliberately separate steps.
Raising `M` at verification time — the moment a new image is accepted — would
make every older image unbootable while the new one is still unproven. If it
then failed to run, the device would have no bootable fallback: an
unrecoverable brick caused by the security control itself.
`M` is therefore raised only once the booted image has been **confirmed**:
| Step | Function | Effect on `M` |
|---|---|---|
| Image verified during boot | `eos_rollback_verify()` then `eos_rollback_stage()` | unchanged; `N` remembered |
| Image runs and proves itself | `eos_bootctl_confirm()` → `eos_rollback_commit()` | raised to `N` |
| Image fails its trial boot | slot rolled back by boot policy | unchanged |
The device is protected throughout: between verification and confirmation the
previous image can still boot, but nothing below the *existing* floor can.
Because the counter is backed by one-time-programmable storage,
`eos_rollback_commit()` also:
- **never lowers `M`** — confirming an older-but-acceptable image burns nothing;
- **is idempotent** — re-confirming the same image consumes no further fuses;
- **refuses advances larger than `EOS_ROLLBACK_MAX_STEP` (16)** — a build
mistake or hostile image requesting a huge jump would exhaust the fuse bank
and permanently end the device's ability to accept future counter bumps;
- **reads the counter back** after incrementing, because a fuse burn can fail
without reporting an error, and a counter that silently did not move would
leave the device believing it is protected when it is not.
Boards whose `eos_board_ops_t` provides no `monotonic_read`/`monotonic_increment`
report `EOS_ERR_NOT_SUPPORTED`; verification is permissive on those boards, since
failing closed would make every device without OTP unbootable. Detect this at
provisioning time with `eos_rollback_get_device_counter()` rather than relying on
boot-time enforcement.
### 4.2 Counter Storage Options
| Method | Storage | Properties |
|---|---|---|
| OTP/eFuse bits | One-time programmable fuses | Irreversible; limited counter range (depends on fuse count) |
| Flash sector | Dedicated flash sector with anti-tearing | Reversible with physical access; unlimited range |
| Secure element | SE-managed counter | Irreversible; high counter range; tamper-resistant |
### 4.3 Version vs. Security Counter
| Field | Purpose | Comparison |
|---|---|---|
| `image_version` | Human-readable version (major.minor.patch) | Informational; logged in boot log |
| `security_counter` | Anti-rollback enforcement | Compared against device monotonic counter |
The `security_counter` is incremented independently of `image_version`. A minor patch may not increment the security counter, while a critical security fix always does.
---
## 5. Comparison with mcuboot's Approach
| Aspect | eBootloader | mcuboot |
|---|---|---|
| Boot stages | 3-stage (ROM → stage-0 → stage-1 → app) | 2-stage (ROM → mcuboot → app) |
| Upgrade strategy | Direct-write A/B slots | Swap-based (default), overwrite, or direct-XIP |
| Image verification | Hash-then-verify-signature (same as mcuboot) | Hash-then-verify-signature |
| Anti-rollback | Monotonic counter (OTP/flash/SE) | Security counter in image TLV |
| HAL abstraction | `eos_board_ops_t` vtable (function pointers) | `flash_area` API |
| Multi-arch | 24+ platform targets | Primarily ARM Cortex-M |
| Recovery | Dedicated UART recovery protocol | No built-in recovery; depends on external tools |
| Metadata format | Fixed-layout image header + optional TLV | TLV-based metadata after image |
See [mcuboot Comparison](mcuboot_comparison.md) for a detailed analysis.
---
## 6. Debug Interface State at Each Boot Stage
The debug interface (JTAG/SWD) state transitions through the boot chain to balance development needs with production security.
### 6.1 Debug State Matrix
| Boot Stage | Development Build | Production Build |
|---|---|---|
| ROM | Enabled (default) | Enabled (ROM cannot change) |
| Stage-0 entry | Enabled | Enabled (not yet configured) |
| Stage-0 after init | Enabled | **Locked** — debug lock applied via `board_early_init()` |
| Stage-1 | Enabled | Locked (inherited from stage-0) |
| Application | Enabled | Locked (inherited) |
### 6.2 Debug Lock Implementation
```c
void board_early_init(void) {
/* ... clock and flash init ... */
#if defined(EOS_BUILD_PRODUCTION)
/* Lock debug interface — platform-specific */
#if defined(STM32F4)
/* Set RDP Level 1 (or Level 2 for permanent lock) */
HAL_FLASH_OB_Unlock();
FLASH_OBProgramInitTypeDef ob = { .RDPLevel = OB_RDP_LEVEL_1 };
HAL_FLASHEx_OBProgram(&ob);
HAL_FLASH_OB_Lock();
#elif defined(NRF52)
NRF_APPROTECT->FORCEPROTECT = 1;
#endif
#endif
}
```
### 6.3 Debug Lock Policy
| Policy | Description |
|---|---|
| **Development** | Debug always enabled. Well-known development signing key used. |
| **Staging** | Debug enabled via flag. Staging signing key used. |
| **Production** | Debug locked at stage-0. Production signing key. Unlock requires authenticated procedure (platform-dependent). |
---
## References
- [Architecture](architecture.md)
- [Key Lifecycle](key_lifecycle.md)
- [Threat Model](threat_model.md)
- [Security Model](security.md)
- [mcuboot Comparison](mcuboot_comparison.md)
- [Update Flow](update-flow.md)
# === docs/security.md ===
# eBootloader Security Model
## Phased Security Approach
eBootloader uses an incremental security model. The idea is to start
with a correct, simple system and layer complexity only when needed.
## Phase 1: Minimum Viable Protection
Available now in the initial codebase.
### CRC32 Integrity Checks
- Every firmware image has a CRC32 in its header hash field
- The boot manager verifies CRC32 before jumping to any image
- Boot control blocks carry CRC32 to detect corruption
### Version Comparison
- Image headers include a version field (major.minor.patch)
- The `eos_image_check_version()` API enables anti-rollback policies
- Firmware services expose version info to the application
### Redundant Metadata
- Boot control block is stored in two independent flash sectors
- If the primary copy is corrupt, the backup is used
- Both copies are written on every metadata update
### Anti-Tearing Writes
- Write sequence: compute CRC → erase primary → write primary → erase backup → write backup
- Power loss at any point leaves at least one valid copy
## Phase 2: Production-Grade Protection
Planned for future releases.
### SHA-256 Image Hash
- Replace CRC32 with a full SHA-256 hash in the header
- `sign_image.py --method sha256` already generates SHA-256 hashes
- Firmware verification reads the hash and recomputes over the payload
### Ed25519 / ECDSA Signature Verification
- The image header has a 64-byte signature field
- `sig_type` field indicates the signature algorithm
- Public key is embedded in the stage-1 boot code (cannot be modified)
- Signature verification happens in `eos_image_verify_signature()`
### Anti-Rollback Counters
- A monotonic counter stored in a dedicated flash region
- Each firmware release increments the counter
- Older firmware versions cannot be installed
## Phase 3: Advanced Security
### Payload Encryption
- Images can be encrypted (AES-256-CBC or AES-256-GCM)
- Decryption key stored in hardware secure storage (OTP / eFuse)
- `EOS_IMG_FLAG_ENCRYPTED` flag in the image header
### Recovery Authorization
- Recovery mode requires authentication (shared secret or challenge-response)
- Prevents unauthorized firmware replacement via physical access
### Secure Boot Chain
- Stage-0 verifies stage-1 before jumping
- Stage-1 verifies application before jumping
- Full chain of trust from ROM to application
## Design Rules
1. **Do not start with maximum complexity.** A correct CRC-based boot
path is better than a broken signature implementation.
2. **Security features should be additive.** Phase 1 code should work
unchanged when Phase 2 features are added.
3. **Never store secrets in flash alongside firmware.** Use hardware
secure storage (OTP, eFuse, secure enclave) for keys.
4. **Recovery mode is a security boundary.** Physical access to UART
should require authentication in production builds.
---
## Implementation Status
### Phase 2 Feature Status
| Feature | Module | API | Status | Acceptance Criteria |
|---|---|---|---|---|
| SHA-256 image hash | `core/crypto_boot.c` | `eos_crypto_hash()`, `eos_crypto_verify_image()` | ✅ Implemented (FIPS 180-4) | Hash matches NIST CAVP test vectors; image verification rejects single-bit payload corruption |
| Ed25519 signature verification | `core/ed25519_verify.c` | `eos_ed25519_verify()`, via `eos_crypto_verify_signature()` | ✅ Implemented (RFC 8032) | RFC 8032 §7.1 vectors 1–3 accepted; every single-bit flip of a valid signature (512 cases) rejected; wrong key, tampered message, all-zero key/signature and non-canonical S (S+L) rejected — all asserted in `tests/unit/test_ed25519.c`. Scalar multiplication is branch-free; **timing has not been measured**, and verification handles only public inputs. |
| Image signature check | `core/image_verify.c` | `eos_image_verify_signature()` | ✅ Implemented | Valid signatures accepted; invalid rejected with `EOS_ERR_SIGNATURE`; all return codes checked |
| Key hash in TLV | `include/eos_image.h` | TLV extension (planned) | 🔲 Not started | Key hash selects correct verification key slot; unknown key hash returns error |
| Anti-rollback counter | `include/eos_bootctl.h` | `eos_image_check_version()` | 🔶 API defined | Counter stored in OTP/flash; images with lower counter rejected; counter survives factory reset |
| Security counter in header | `include/eos_image.h` | Header `reserved` field allocation | 🔲 Not started | Counter field parsed from header; compared against device counter before boot |
| Dual key slots | `include/eos_signing_key.h` | Compiled-in key array | 🔲 Not started | Two key slots available; revoked slots skipped; rotation without bricking |
### Phase 3 Feature Status
| Feature | Module | API | Status | Acceptance Criteria |
|---|---|---|---|---|
| AES-256-GCM payload encryption | `core/crypto_boot.c` | Planned | 🔲 Not started | Encrypted images decrypted before verification; GCM tag validated; plaintext never stored in flash |
| Recovery authentication | `core/recovery.c` | Planned | 🔲 Not started | Unauthenticated UART commands rejected; challenge-response completes in < 5 seconds; brute-force rate limited |
| Debug lock at boot | `boards/*/board_init.c` | Platform-specific | 🔲 Not started | JTAG/SWD locked in production builds; debug lock applied before any secret processing; verified by probe test |
| MPU isolation between stages | `core/mpu_boot.c` | `eos_mpu_boot.h` | 🔲 Not started | Stage-1 cannot write stage-0 region; application cannot write bootloader regions; MPU fault handler logs violation |
| Flash write protection | HAL | Platform-specific | 🔲 Not started | Bootloader flash sectors marked read-only after stage-0 init; write attempts generate fault |
| Recovery audit logging | `core/recovery.c` | Planned | 🔲 Not started | All recovery commands logged with timestamp; log survives reset; log readable via LOG command |
### Status Legend
| Symbol | Meaning |
|---|---|
| ✅ | Implemented and tested |
| 🔶 | API defined, partial or stub implementation |
| 🔲 | Not started |
---
## Cross-References
| Document | Description |
|---|---|
| [Threat Model](threat_model.md) | STRIDE-based threat analysis with risk ratings for each trust boundary |
| [Key Lifecycle](key_lifecycle.md) | Ed25519 key generation, dual-slot support, rotation, revocation, and emergency response |
| [Secure Boot Chain](secure_boot_chain.md) | Complete chain of trust from ROM → stage-0 → stage-1 → application with verification steps |
| [mcuboot Comparison](mcuboot_comparison.md) | Design decisions relative to mcuboot — adopted patterns, intentional divergences |
| [Security Review Checklist](security_review_checklist.md) | PR review checklist for security-critical code changes |
| [Architecture](architecture.md) | Staged boot architecture, module map, flash memory map, boot flow |
| [Update Flow](update-flow.md) | OTA update sequence, rollback triggers, anti-tearing protection |
| [Risk Register](compliance/risk_register.md) | Project-wide risk register with likelihood, impact, and mitigation status |
# === docs/threat_model.md ===
# Threat Model — eBootloader
> **Methodology:** STRIDE (Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege)
>
> **Last updated:** 2026-04-03
>
> **Scope:** eBootloader staged boot system (stage-0, stage-1, recovery, flash storage, firmware update pipeline)
---
## 1. Assumptions
### 1.1 Physical Access Model
| Assumption | Description |
|---|---|
| **Field deployment** | Devices are deployed in physically accessible locations (edge gateways, industrial controllers, IoT endpoints). An attacker may gain physical access to the device enclosure. |
| **Debug ports** | JTAG/SWD debug headers may be populated on development boards but should be disabled or locked in production builds. |
| **UART access** | The recovery UART is accessible with enclosure removal. Production builds must authenticate recovery sessions. |
| **Chip decapping** | Invasive silicon attacks (decapping, FIB probing) are out of scope for the base threat model. Devices requiring this level of protection should use a discrete secure element. |
### 1.2 Deployment Context
| Parameter | Value |
|---|---|
| Target platforms | Cortex-M0/M3/M4/M7/M33, Cortex-A53/A72, Cortex-R5F, RISC-V RV32/RV64 |
| Connectivity | Devices may be network-connected (OTA updates via application firmware) |
| Lifetime | 5–15 year field deployment |
| Update frequency | Quarterly security patches, ad-hoc critical fixes |
| Regulatory context | ISO/IEC 20243 (supply chain), ISO/IEC/IEEE 15288:2023 (secure lifecycle) |
---
## 2. Trust Boundaries
```
┌──────────────────────────────────────────────────┐
│ Silicon ROM │
│ (immutable, vendor-provided) │
├─ ─ ─ ─ ─ ─ TB-1: ROM → Stage-0 ─ ─ ─ ─ ─ ─ ─ ─┤
│ Stage-0 (eBootloader) │
│ 16 KB — minimal HW init, recovery check │
├─ ─ ─ ─ ─ ─ TB-2: Stage-0 → Stage-1 ─ ─ ─ ─ ─ ─┤
│ Stage-1 (E-Boot) │
│ 48 KB — image scan, boot policy, boot log │
├─ ─ ─ ─ ─ ─ TB-3: Stage-1 → Application ─ ─ ─ ─ ┤
│ Application Firmware │
│ 448 KB × 2 slots (A/B) │
└──────────────────────────────────────────────────┘
External boundaries:
TB-4: UART Recovery Interface (physical)
TB-5: Flash Storage (internal/external NOR/NAND)
TB-6: Debug Interface (JTAG/SWD)
TB-7: Firmware Update Pipeline (OTA → application → slot write)
```
### Boundary Descriptions
| Boundary | From | To | Data Crossing | Protection |
|---|---|---|---|---|
| TB-1 | Silicon ROM | Stage-0 | Execution handoff, vector table | ROM validates stage-0 hash (SoC-dependent) |
| TB-2 | Stage-0 | Stage-1 | Execution handoff, HAL vtable | Stage-0 verifies stage-1 image header + hash/signature |
| TB-3 | Stage-1 | Application | Execution handoff, boot state | Stage-1 verifies application image header + hash/signature |
| TB-4 | External host | Stage-0/Stage-1 | UART packets (PING, ERASE, WRITE, BOOT, etc.) | Packet format validation; authentication planned (Phase 3) |
| TB-5 | Flash IC | CPU | Image payloads, boot control block, boot log | CRC32 (Phase 1), SHA-256 + signatures (Phase 2), encryption (Phase 3) |
| TB-6 | Debug probe | CPU | Memory read/write, halt, step | Debug lock bits (platform-dependent) |
| TB-7 | Cloud/server | Application → Flash | Firmware image bytes | Application-layer TLS; bootloader verifies image before activation |
---
## 3. Attack Surfaces
### 3.1 UART Recovery Protocol
- **Interface:** `eos_hal_uart_send()` / `eos_hal_uart_recv()` via `eos_board_ops_t` function pointers
- **Packet format:** `[cmd:1][slot:1][len:2][offset:4]` — 8-byte header
- **Commands exposed:** PING, INFO, ERASE, WRITE, VERIFY, BOOT, LOG, RESET, FACTORY
- **Attack vector:** Malformed packets, unauthorized firmware replacement, command injection
### 3.2 Flash Contents
- **Regions:** Slot A (448 KB), Slot B (448 KB), Recovery (16 KB), Boot control primary (8 KB), Boot control backup (8 KB), Boot log (8 KB), Device config (24 KB)
- **Attack vector:** Direct flash modification (physical), corrupted OTA writes, bit-flip attacks
### 3.3 JTAG/SWD Debug Interface
- **Attack vector:** Memory extraction, firmware dumping, runtime state manipulation, bypassing boot verification
- **Notes:** Debug lock mechanism is platform-dependent (e.g., STM32 RDP level, nRF APPROTECT)
### 3.4 Firmware Update Pipeline
- **Flow:** Cloud → Application (TLS download) → `eos_hal_flash_write()` to inactive slot → `eos_fw_request_upgrade()` → reboot → Stage-1 verification
- **Attack vector:** Man-in-the-middle on OTA channel, supply chain compromise, malicious update server
### 3.5 Boot Control Block
- **Structure:** `eos_bootctl_t` — 96 bytes with CRC32 protection
- **Fields at risk:** `active_slot`, `pending_slot`, `boot_attempts`, `max_attempts`, `flags`
- **Attack vector:** Corrupt control block to force boot to attacker-controlled slot, reset boot attempts to prevent rollback, set factory reset flag
---
## 4. Threat Matrix
### TB-1: ROM → Stage-0
| ID | STRIDE | Threat | Likelihood | Impact | Risk | Mitigation | Status |
|---|---|---|---|---|---|---|---|
| T-101 | Tampering | Attacker modifies stage-0 binary in flash | Low | Critical | High | ROM hash verification (SoC-dependent); debug lock | Planned |
| T-102 | Elevation of Privilege | Stage-0 contains vulnerability allowing arbitrary code execution | Low | Critical | High | Minimal code surface (16 KB); no dynamic memory; stack bounds | Mitigated |
| T-103 | Information Disclosure | Stage-0 leaks key material or secrets via UART during early init | Low | High | Medium | No secrets processed in stage-0; UART output limited to recovery mode | Mitigated |
### TB-2: Stage-0 → Stage-1
| ID | STRIDE | Threat | Likelihood | Impact | Risk | Mitigation | Status |
|---|---|---|---|---|---|---|---|
| T-201 | Tampering | Attacker replaces stage-1 binary with malicious code | Medium | Critical | High | SHA-256 hash verification of stage-1 image (Phase 2); Ed25519 signature verification (Phase 2) | Planned |
| T-202 | Spoofing | Attacker presents old stage-1 version to exploit known vulnerability | Medium | High | High | Anti-rollback security counter enforced against the device monotonic counter (`eos_rollback_verify()`), raised on slot confirmation (`eos_rollback_commit()`); `eos_image_check_version()` | Mitigated (boards with a monotonic counter) |
| T-203 | Denial of Service | Corrupt stage-1 image prevents boot | Low | High | Medium | Recovery mode fallback; redundant boot control block | Mitigated |
| T-204 | Elevation of Privilege | Stage-1 runs with same privilege as stage-0 (no isolation) | Medium | High | Medium | MPU configuration at stage boundary (Phase 3); `eos_mpu_boot.h` | Planned |
### TB-3: Stage-1 → Application
| ID | STRIDE | Threat | Likelihood | Impact | Risk | Mitigation | Status |
|---|---|---|---|---|---|---|---|
| T-301 | Tampering | Attacker modifies application firmware in flash | Medium | Critical | High | CRC32 integrity check (Phase 1); SHA-256 + Ed25519 signature over the full header prefix (Phase 2) | Partial |
| T-303 | Tampering | Attacker edits image header metadata (entry point, load address, integrity flags) while keeping a valid signature | Medium | Critical | High | Signature covers `EOS_IMG_SIGNED_LEN` bytes of the header, not `hash[]` alone (image header v2) | Mitigated |
| T-302 | Spoofing | Rollback to older firmware version with known vulnerabilities | Medium | High | High | Version comparison via `eos_image_check_version()`; monotonic counter (Phase 2) | Planned |
| T-303 | Information Disclosure | Unencrypted firmware reveals intellectual property | Medium | Medium | Medium | AES-256-GCM payload encryption (Phase 3); `EOS_IMG_FLAG_ENCRYPTED` | Planned |
| T-304 | Denial of Service | Both slots contain invalid images, device is bricked | Low | Critical | Medium | Recovery image in dedicated partition (16 KB); UART recovery protocol | Mitigated |
| T-305 | Repudiation | No audit trail of which firmware version was booted | Low | Medium | Low | Boot log records slot, version, verification result, reset reason | Mitigated |
| T-306 | Elevation of Privilege | Application gains ability to overwrite bootloader regions | Low | Critical | Medium | Flash write protection for bootloader regions (platform MPU/flash lock) | Planned |
### TB-4: UART Recovery Interface
| ID | STRIDE | Threat | Likelihood | Impact | Risk | Mitigation | Status |
|---|---|---|---|---|---|---|---|
| T-401 | Spoofing | Unauthorized party connects to UART and replaces firmware | Medium | Critical | High | Recovery authentication — challenge-response or shared secret (Phase 3) | Planned |
| T-402 | Tampering | Malformed UART packets corrupt flash or boot state | Medium | High | High | Packet validation; length bounds checking; CRC on write data | Partial |
| T-403 | Denial of Service | Flood UART with garbage to prevent legitimate recovery | Low | Medium | Low | Command timeout; watchdog feed during recovery; rate limiting | Partial |
| T-404 | Information Disclosure | INFO discloses flash geometry and, since #139, a capability byte (`caps`: has RNG, has OTP); LOG discloses boot history | Low | Medium | Low | LOG restricted to authenticated sessions (Phase 3). INFO is deliberately unauthenticated per ADR-021: everything it discloses an attacker learns by trying, and the integrator needs it before AUTH to diagnose a board with no entropy source | Partial (INFO decided; LOG planned) |
| T-405 | Repudiation | Recovery operations not logged | Medium | Medium | Medium | Boot log records recovery entry, commands executed, exit reason | Planned |
| T-406 | Elevation of Privilege | FACTORY command erases all data without authorization | Medium | Critical | High | Require authentication before FACTORY; confirmation sequence | Planned |
### TB-5: Flash Storage
| ID | STRIDE | Threat | Likelihood | Impact | Risk | Mitigation | Status |
|---|---|---|---|---|---|---|---|
| T-501 | Tampering | Direct flash modification via physical access or glitch attack | Low | Critical | Medium | SHA-256 + signature verification at boot; flash write protection | Planned |
| T-502 | Tampering | Power loss during boot control block write corrupts metadata | Medium | High | High | Anti-tearing dual-write (primary + backup); CRC32 validation on load | Mitigated |
| T-503 | Information Disclosure | Flash contents readable via chip-off or debug interface | Low | High | Medium | Payload encryption with AES-256-GCM (Phase 3); debug lock | Planned |
| T-504 | Denial of Service | Flash wear-out from excessive erase/write cycles | Low | High | Low | Wear-leveling for boot control region; write coalescing | Monitored |
### TB-6: Debug Interface (JTAG/SWD)
| ID | STRIDE | Threat | Likelihood | Impact | Risk | Mitigation | Status |
|---|---|---|---|---|---|---|---|
| T-601 | Information Disclosure | Firmware and secrets extracted via debug probe | Medium | Critical | High | Platform debug lock (STM32 RDP Level 2, nRF APPROTECT); disabled in production | Planned |
| T-602 | Tampering | Runtime memory modified to bypass signature checks | Medium | Critical | High | Debug lock; glitch detection (platform-dependent) | Planned |
| T-603 | Elevation of Privilege | Debug interface used to execute arbitrary code | Medium | Critical | High | Debug lock in production; conditional compilation removes debug hooks | Planned |
### TB-7: Firmware Update Pipeline
| ID | STRIDE | Threat | Likelihood | Impact | Risk | Mitigation | Status |
|---|---|---|---|---|---|---|---|
| T-701 | Tampering | Man-in-the-middle modifies firmware image during OTA download | Medium | Critical | High | Application-layer TLS; Stage-1 verifies image signature before boot | Partial |
| T-702 | Spoofing | Attacker impersonates update server | Medium | High | High | Certificate pinning in application; image signed with Ed25519 key | Planned |
| T-703 | Repudiation | No record of who authorized a firmware update | Low | Medium | Low | Boot log records update source, version, timestamp | Planned |
| T-704 | Denial of Service | Repeated invalid update attempts exhaust flash erase cycles | Low | Medium | Low | Rate limiting on update requests; validate header before erase | Monitored |
**External evidence — CVE-2026-86326 (Moxa, Oct 2026).** Moxa MGate
MB3000/EIP3000/5000 gateways do not verify firmware authenticity
(CVSSv4 8.6, MPSA-269540) — and **no firmware fix shipped at disclosure**;
customers were given a compensating-controls playbook only. This is the
exact flaw class the #162 Ed25519 envelope answers, and the "no fix
shipped" detail is why eBoot's verify-before-boot must be fail-closed
(boot refuses unsigned firmware) rather than advisory: when the vendor
never patches, the device's only protection is the one baked into the
boot chain.
**External evidence — CVE-2026-84411 (MikroTik RouterOS, Oct 2026).**
Unauthenticated RCE via integer underflow in the RouterOS HTTP login
(CVSS 9.8, CISA advisory) — a single crafted request, all RouterOS <7.24.
Patched in 7.24, but field adoption is ~zero as of Oct 5: the patch exists
and the fleet is still vulnerable. The "patch-available-but-not-deployed"
class — the device's own boot chain cannot rely on the vendor's update
cadence reaching it in time.
**External evidence — CVE-2026-105484 (TOTOLINK X6000R, Oct 2026).**
Unauthenticated RCE (CVSS 10.0) with **no patched firmware confirmed at
disclosure** — a second "no firmware fix at disclosure" case alongside the
Moxa row above. When neither a patch nor a timeline exists, fail-closed
verify-before-boot is the only control the device actually has.
---
## 5. Risk Summary
| Risk Level | Count | Examples |
|---|---|---|
| **Critical** | 0 | — |
| **High** | 12 | T-201, T-301, T-401, T-601, T-602, T-603, T-701 |
| **Medium** | 10 | T-204, T-303, T-304, T-306, T-402, T-405, T-501, T-503 |
| **Low** | 6 | T-103, T-305, T-403, T-404, T-504, T-704 |
> **Note:** No risks are rated Critical overall because the phased mitigation strategy addresses the highest-impact threats. Residual risk is High for threats dependent on Phase 2/3 implementation.
---
## 6. Mitigation Roadmap
### Phase 1 — Implemented
| Control | Threats Addressed |
|---|---|
| CRC32 integrity check on images | T-301 (partial) |
| Dual boot control block with CRC | T-502 |
| Version comparison API | T-302 (partial) |
| Boot log with reset reason | T-305 |
| Recovery mode with packet validation | T-402 (partial) |
| Redundant metadata (primary + backup) | T-203, T-304 |
### Phase 2 — Planned
| Control | Threats Addressed | Target |
|---|---|---|
| SHA-256 image hash | T-201, T-301, T-501 | v0.2.0 |
| Ed25519 signature verification | T-201, T-301, T-701 | v0.2.0 |
| Anti-rollback monotonic counter | T-202, T-302 | v0.2.0 |
| Key hash in image TLV | T-701, T-702 | v0.2.0 |
| Security counter in image header | T-202, T-302 | v0.2.0 |
### Phase 3 — Planned
| Control | Threats Addressed | Target |
|---|---|---|
| AES-256-GCM payload encryption | T-303, T-503 | v0.3.0 |
| Recovery authentication (challenge-response) | T-401, T-404, T-405, T-406 | v0.3.0 |
| Debug lock enforcement at boot | T-601, T-602, T-603 | v0.3.0 |
| MPU isolation between stages | T-204, T-306 | v0.3.0 |
| Flash write protection for bootloader | T-101, T-306 | v0.3.0 |
### Watch items — external dependencies
| Item | Detail | eBoot impact | Status |
|---|---|---|---|
| ESP-IDF v6.1 disables ECDSA Secure Boot V2 on ESP32-H2/C5/P4 | Disabled "due to a security vulnerability found in the ECDSA based Secure Boot flow"; details promised in chip errata. 192-bit curve removed. | If eBoot's ESP32 trust path assumes the ECDSA-SBv2 flow, it inherits the vulnerability. Verify the assumption and plan the migration to the v6.1-supported flow. | Monitored |
| ESP-IDF v6.1: ESP32-P4 default silicon rev v3.0 | Images must target the revision they ship for. | eBoot ESP32-P4 bring-up docs must name the rev. | Monitored |
| ESP-IDF v6.1 fixes LP-SPI MISO bug (v6.0-6.0.3) | | Relevant to SPI flash attach on affected parts. | Monitored |
---
## 7. Risk Assessment Method
Consistent with [risk_register.md](compliance/risk_register.md):
- **Likelihood:** Low / Medium / High
- **Impact:** Low / Medium / High / Critical
- **Overall Risk:** Derived from likelihood × impact matrix:
| | Low Impact | Medium Impact | High Impact | Critical Impact |
|---|---|---|---|---|
| **High Likelihood** | Medium | High | High | Critical |
| **Medium Likelihood** | Low | Medium | High | High |
| **Low Likelihood** | Low | Low | Medium | Medium |
- **Status:** Open / Monitored / Partial / Planned / Mitigated / Closed
---
## 8. Review Schedule
| Activity | Frequency | Owner |
|---|---|---|
| Threat model review | Every major release | Security lead |
| Risk rating update | Quarterly | Project lead |
| New attack surface assessment | On architecture change | Development team |
| Penetration test (UART, flash) | Annually | External assessor |
---
## References
- [Security Model](security.md)
- [Risk Register](compliance/risk_register.md)
- [Architecture](architecture.md)
- [Key Lifecycle](key_lifecycle.md)
- [Secure Boot Chain](secure_boot_chain.md)
# === docs/update-flow.md ===
# eBootloader Update Flow
## Overview
eBootloader supports three firmware update strategies. This document
describes the recommended OTA workflow (firmware-owned download,
bootloader-owned activation).
## OTA Update Sequence
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Cloud / │ │ Application │ │ E-Boot │
│ Server │ │ Firmware │ │ (Stage-1) │
└──────┬───────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ 1. New version │ │
│ available │ │
│ ──────────────────>│ │
│ │ │
│ 2. Download │ │
│ image chunks │ │
│ ──────────────────>│ │
│ │ │
│ │ 3. Write to │
│ │ inactive slot │
│ │ (Slot B) │
│ │ │
│ │ 4. Request │
│ │ test boot │
│ │ eos_fw_request_ │
│ │ upgrade(B, TEST) │
│ │ │
│ │ 5. Reboot │
│ │ ──────────────────>│
│ │ │
│ │ │ 6. Verify Slot B
│ │ │ image
│ │ │
│ │ │ 7. Boot Slot B
│ │ │ (test mode)
│ │ │
│ │ 8. Self-test │
│ │<───────────────────│
│ │ │
│ │ 9. eos_fw_confirm_ │
│ │ running_image() │
│ │ │
│ │ ── OR ── │
│ │ │
│ │ 9b. Crash / │
│ │ watchdog │
│ │ → rollback │
│ │ │
```
## Application Code Example
### Requesting an Update
```c
int do_ota_update(const uint8_t *image_data, size_t image_len)
{
eos_slot_t target = EOS_SLOT_B;
uint32_t addr = eos_hal_slot_addr(target);
/* Erase target slot */
eos_hal_flash_erase(addr, eos_hal_slot_size(target));
/* Write image (header + payload) */
eos_hal_flash_write(addr, image_data, image_len);
/* Request test boot */
int rc = eos_fw_request_upgrade(target, EOS_UPGRADE_TEST);
if (rc != EOS_OK) return rc;
/* Reboot to apply */
eos_hal_system_reset();
return EOS_OK; /* unreachable */
}
```
### Confirming After Self-Test
```c
int app_startup(void)
{
if (eos_fw_is_test_boot()) {
if (self_test_passed()) {
eos_fw_confirm_running_image();
} else {
/* Don't confirm — let watchdog trigger rollback */
eos_fw_request_recovery();
eos_hal_system_reset();
}
}