Protected Update
Module 4 · Secure boot and Protected Update · Module overview · Course home
A device’s certificate must be changeable over its lifetime, but if anyone can write the certificate slot, an attacker can write it too. The OPTIGA™ Trust M’s Protected Update solves this by having the chip itself check the signature before it agrees to write — so a compromised host cannot forge an update.
Let’s be clear from the start: Protected Update in this lesson means updating an object inside the chip (a certificate, a key, metadata), not updating the MCU’s firmware. We compare the two at the end of the lesson, using the OTA example on the Developer Hub.
Objectives
Section titled “Objectives”By the end of this lesson you will:
- Explain Protected Update’s steps, from the request to manifest verification
- Explain the anti-rollback counter’s job, and the effect of a manifest lock
- Identify the chip change that no reflash can undo, as the SDK’s example warns
Before you start
Section titled “Before you start”- Already covered: Lesson 4.1: Secure boot and the chain of trust, and the metadata table in lesson 2.1 (tags
C0,C1,D0) - Board: the SDK’s template, already building. The main lab does not send a real request; the optional lab that sends a real request needs a device already registered and able to reach the platform, and needs the instructor’s permission.
See it work first
Section titled “See it work first”Chapter D2 of the SDK docs gives the sequence of UART lines when a successful Protected Update is triggered from the screen.
[Subscriber] Protected Update bundle (%d bytes)[PU-Ingest] Fragment count: %u[PU-Ingest] OPTIGA acquired: OK[PU-Ingest] STEP 3: Processing fragments...[PU-Ingest] STEP 4: Executing OPTIGA Trust M Protected Update[PU-Ingest] [4.1] Manifest verification OK (Trust Anchor signature valid)[PU-Ingest] PROTECTED UPDATE COMPLETED SUCCESSFULLY![PU-Ingest] [ACK] Certificate ACK published successfullyGuess first: if the host were compromised, which of these lines could an attacker forge, and what is the one piece of evidence they cannot forge?
Concepts
Section titled “Concepts”1. From request to manifest verification inside the chip
Section titled “1. From request to manifest verification inside the chip”The SDK’s PROTECTED_UPDATE_CONTRACT.md explains that
the OPTIGA™ Trust M refuses a certificate written as plain bytes into a protected slot. It requires a manifest, signed by a key the chip already trusts (a trust anchor),
plus one or more fragments carrying the real data. The chip checks the manifest against the trust anchor before writing anything at all.
The manifest is a COSE_Sign1 structure that names the anchor’s OID in its kid header (CSR contract section 4.5).
Infineon’s data-set builder tool (protected_update_data_set, MIT)
lists what a manifest carries: payload_version, trust_anchor_oid, target_oid, the signature algorithm (default ES_256), and the payload type (data, key or metadata),
and, if confidentiality is needed, fragments can be encrypted with a shared key kept inside the chip.
The whole path on our board, summarised from chapter D2 and the SDK’s contract:
Device Platform 1. Reads and keeps 0xE0E1's metadata (C0, D0) 2. SUBSCRIBE device/<id>/commands/# ── always before asking 3. tesaiot_publish_protected_update("E0E1","E0E8",ver,with_csr) Checks locally first: if the slot is already locked to a different anchor, refuses on its own PUBLISH device/<id>/commands/request ─────────▶ builds a manifest + fragment version = max(ours, last used) + 1 signs it with the platform's key ◀───── commands/protected_update (manifest, fragment_0..n, the signer's certificate) 4. Checks the correlation id: no request outstanding = discard (prevents replay) 5. Writes the signer's certificate to 0xE0E8, sets its type to trust anchor 6. optiga_util_protected_update_start(manifest) ▶ the chip verifies the manifest's signature against 0xE0E8 ◀ the point the host cannot forge 7. Sends the fragment(s) with _continue / _final — the chip writes the target slot 8. Sends an ACK, then trustm_reset_state() clears the correlation id 9. Reads metadata again: D0 has changed to 21 E0 E8, C0 is still 01The answer to the guess: every line in the log is just a printf — a compromised host can print anything at all. Chapter D2 points out that the one event that cannot be forged is the chip successfully verifying the platform’s signature against its own trust anchor,
which the firmware reports right after the [4.1] line. But if you want real proof, ask the chip itself by reading metadata back (step 9) — do not just trust the log.
tesaiot_publish_protected_update() returning 0 means requested, not done. Per example 06’s comment, the chip has not changed at all until the manifest arrives and is applied.
The OID is a hexadecimal string, "E0E1", not the number 0xE0E1.
2. The anti-rollback counter, and the manifest lock
Section titled “2. The anti-rollback counter, and the manifest lock”The version counter (tag C1). The chip remembers each object’s version and refuses a manifest whose version is not greater than the one it already has; the counter only ever goes up.
Its job is to stop a valid, correctly signed but old manifest from being replayed to bring back an older certificate.
The SDK’s contract says the platform computes the version as max(ours, last used) + 1, so a device can send 1 every time.
But example 06 warns that if the version you actually use is lower than the chip’s counter, the chip’s refusal looks exactly like a bad signature.
The manifest lock (tag D0). A successful apply sets the target slot’s Change condition to Int(anchor), or 21 E0 E8.
From then on, that slot accepts only writes that arrive with a manifest signed by that anchor; a plain write is refused. This is the whole point of the feature.
What you see on the board: if you press Enrol against a slot that is already locked, the screen shows “This slot takes signed manifests only. Use Protect, or clear the requirement first. Nothing was changed.” before generating any key at all.
This lock can be reversed, as long as LcsO is still below op. Chapter D2 measured on a real board that 0xE0E1’s D0 read 21 e0 e8 before and e1 fc 07 after writing it back.
On a board still at creation, the HSM Security → Unlock menu does this step, but example 06 states that the function to clear the lock is not among the 18 functions libbento_hsm.a exports.
So the SDK’s advice is “plan not to need it,” and choose the target slot deliberately: running a Protected Update against the certificate slot you actually use, in effect, locks the certificate you actually use.
One error code, several meanings. Example 06 states that the chip answers 0x800F both when the slot is locked to a different anchor, and when the version is stale.
The SDK’s PU contract adds the most common case of all: the trust-anchor slot being empty (the signer’s certificate was never written to 0xE0E8) also produces 0x800F.
So when you see this code, read the target slot’s metadata and read back 0xE0E8’s data first — do not conclude the signature is wrong yet.
Preventing replay with a correlation id. Every request carries a correlation id. If a bundle arrives while no request is outstanding (trustm_current_correlation_id() is NULL), the firmware must discard it.
Chapter D2 records an incident where an old bundle was applied again without anyone asking, and the result was the slot getting locked a second time and the counter being consumed by one more step.
Two SDK documents describe the broker’s behaviour differently here (D2 says the latest bundle is retransmitted on every connection; the PU contract says the platform clears the retained message on every connection).
The lesson from this contradiction is that the firmware must not rely on any one broker behaviour — checking the correlation id is what protects you regardless.
3. What a reflash cannot undo
Section titled “3. What a reflash cannot undo”The 06_protected_update.c example opens with the heading “READ THIS BEFORE YOU SET EITHER SWITCH” and separates what changes into three levels.
| What changes | Reversible? | Who causes it |
|---|---|---|
LcsO (tag C0) 01 → 03 → 07 → 0F |
Not at all. No reflash, erase or power cut brings it back. Once it reaches op, writing metadata stops permanently |
Writing metadata containing tag C0; no example in the SDK does this, and this lesson’s Protected Update never touches it |
The target slot’s version counter (tag C1) |
No — only ever goes up | Every successfully applied Protected Update |
The target slot’s manifest lock (tag D0) |
Yes, only while LcsO is still below op; treated as permanent on a shipped device | Every successfully applied Protected Update |
The one that a reflash literally cannot undo is LcsO. Example 06 says advancing the lifecycle should live in a separate, clearly named tool, run only by someone who has already decided to ship that board — not in an example that anyone can click “run” on just to “see what happens.”
Another function to be careful with is tesaiot_run_protected_update_isolated_test(). Example 06 notes that it is an interactive menu waiting on scanf() from the console, and it does not return until the user chooses to exit.
Never call it from an unattended task, from the boot path, or anywhere a watchdog is active. It writes the metadata of a slot meant for testing, and reads LcsO to display it, but does not write LcsO.
Compared to a firmware update. ETSI EN 303 645 provision 5.3-10 (M) requires verifying the authenticity and integrity of any update that arrives over the network. The c_ota_client example
reads a job document that carries file_hash and signature fields, but the function that checks them is not yet actually implemented (see the worked example), and if no CA file is configured, it also disables verifying the server’s certificate.
This example is a good starting point for an OTA skeleton, but must never be used on a real device without adding real verification.
Another path in the SDK is updating over BLE, per the Firmware update (BLE NUS) page.
Every flash triggered from a desktop must pass a Y/N confirmation screen on the board that shows the first 8 characters of the target’s SHA-256; there is no way to skip it, and a timeout does not count as answering Y.
ETSI provision 5.3-10 counts user confirmation as one valid form of trust relationship, but you should know this path is compiled in only when ENABLE_PAGE_BENTO_BUDDY=1,
and the CM33-side example’s README states that in the shipped template, this library is not yet linked into the firmware image.
Worked example
Section titled “Worked example”The Protected Update request, taken from 06_protected_update.c, lines 110–122 and 167–173 (TESAIoT PSE84 Dev Kit SDK, © Thai Embedded Systems Association, Apache-2.0)
/* Hex strings, as the API takes them. "E0E1" is the TESAIoT device certificate * slot and "E0E8" the trust anchor this project pairs with it. Change the * target to the isolated test slot if you are only rehearsing. */#define EXAMPLE_PU_TARGET "E0E1"#define EXAMPLE_PU_ANCHOR "E0E8"
/* The platform takes max(chip counter, its own record, this) + 1, so a value * that is merely plausible is fine; a value LOWER than the chip's counter is * not, and the chip's refusal will look like a signature failure. */#define EXAMPLE_PU_VERSION (1U)
/* false: update the object, do not enrol a new key at the same time. */#define EXAMPLE_PU_WITH_CSR false /* The request. Returns 0 when it was published, -1 when it was not — and * -1 also covers the local refusals it makes on your behalf, such as a * target already locked to a different anchor. Its own printf says which. */ int rc = tesaiot_publish_protected_update(EXAMPLE_PU_TARGET, EXAMPLE_PU_ANCHOR, (uint32_t)EXAMPLE_PU_VERSION, EXAMPLE_PU_WITH_CSR);This example is disabled by default. You must build it with DEFINES+=EXAMPLE_HSM_REQUEST_PU=1 for it to send a real request. If not enabled, it prints the plan (which slot, which anchor, what version) and says it is skipping.
Printing the plan before doing anything is deliberate: this is the one command in the SDK whose target OID deserves to be read twice before you press go.
The firmware-verification function inside the OTA client, taken from ota_client.c, lines 375–386 (© 2026 TESAIoT Platform (TESA), Apache-2.0)
ota_error_t ota_verify_firmware(ota_client_t *ctx){ if (!ctx) return OTA_ERR_PARSE;
ctx->state = OTA_STATE_VERIFYING; OTA_LOG("Verifying firmware integrity...");
/* TODO: Calculate SHA256 hash and compare with ctx->job.file_hash */
ctx->state = OTA_STATE_IDLE; return OTA_OK;}ota_run_update_cycle() in the same file calls, in order: download → ota_verify_firmware() → apply_firmware. Since the verification function always returns OTA_OK, every downloaded file gets applied.
Compare this to lesson 1.2: it is the same case as the AI-model verification hook — a function named “verify” must never return pass before it has actually verified anything.
Practice
Section titled “Practice”Predict the outcome of each scenario. Choose from (a) requested successfully and the chip applies it, (b) refused locally before the request is even sent, (c) the chip refuses during manifest verification, (d) the firmware discards the bundle because no request is outstanding.
- Slot
0xE0E1is already locked to0xE0E9, but the request names anchor"E0E8"____ - A valid bundle arrives after a reboot, while
trustm_current_correlation_id()isNULL____ - The signer’s certificate was never written to
0xE0E8, but every other step was done correctly ____ - The device subscribes to
commands/#and requests; the signer’s certificate is written to0xE0E8, and the version the platform uses is greater than the chip’s counter ____ - Someone sends a previously-applied manifest from an earlier version, paired with a correlation id that matches an outstanding request ____
Solution
- (b).
tesaiot_publish_protected_update()reads the chip first and refuses on its own when the slot is bound to a different anchor, returning-1. Example 06 points out this is useful, because if it reached the chip instead, error0x800Fwould be indistinguishable from a stale version. - (d). This is exactly the replay protection at work — a bundle nobody asked for must never be applied.
- (c). The chip has nothing to verify the signature against, so it returns
0x800Feven though the signature itself is correct. The PU contract calls this the most common cause. - (a).
- (c). The old manifest’s version is not greater than the chip’s counter — the anti-rollback counter does its job, even though the signature is valid.
Check your understanding
Section titled “Check your understanding”The questions below are part of the full set in quiz.yaml, which the automated grader uses.
-
In the Protected Update path, which step can a compromised host not forge? (objective 1)
- a) Printing the line
PROTECTED UPDATE COMPLETED SUCCESSFULLY! - b) The chip successfully verifying the manifest’s signature against its own trust anchor, and then writing the target slot
- c) Sending an ACK to the platform
- d) Subscribing to
commands/#
Solution
b. Anything the host does or prints, whoever controls the host can forge. But the chip refuses to write if the signature does not verify, so the evidence lies in reading state back from the chip itself.
- a) Printing the line
-
What does the version counter (tag
C1) protect against? (objective 2)- a) A correctly signed but older manifest being replayed
- b) Reading a certificate
- c) Reconnecting to WiFi
- d) Writing tag
C0
Solution
a. A signature says who issued the manifest, but not whether it is new or old — that is the counter’s job.
-
A development board with
0xE0E1’sC0reading01has just been through a Protected Update. Which statement is correct? (objective 2)- a) This slot is now permanently locked
- b) This slot accepts only a manifest signed by the anchor, but the lock can still be cleared because LcsO is still below op; the version counter, however, cannot be reversed
- c) Both the lock and the counter can be reversed with a reflash
- d) LcsO has already changed to op
Solution
b. These two must be kept apart: the lock is a condition in metadata, while the counter only ever goes up.
-
Per example 06, which chip change has no reflash, erase or power cut that can bring it back? (objective 3)
- a) Writing a certificate to
0xE0E1 - b) Advancing LcsO (metadata tag
C0) - c) Connecting to MQTT
- d) Reading metadata
Solution
b. And once it reaches
op, writing metadata stops permanently, which is also what makes a Protected Update’s lock permanent. - a) Writing a certificate to
Main lab: read the request’s plan without sending it for real
- Build example 06 with no switch enabled.
Record the lines
Terminal window make build ENABLE_PAGE_EXAMPLES=1 SDK_EXAMPLE_CM33=cm33/security/06_protected_updatemake program BENTO_WORKSPACE="$(cd .. && pwd)"target OID,anchor OID,version,with_csr,life cycle, and theSKIPPED both pathsmessage, then explain in your own words what each line tells you. - Draw a sequence diagram of Protected Update, from the request to reading metadata back. Mark three points: where the host can forge something, where the chip verifies the signature, and where the counter changes.
- Write a three-item checklist you would run before concluding that a
0x800Fcode means “the signature is wrong.” - OTA. Read ota_client.c, then write a step-by-step plan for filling in
ota_verify_firmware()(compute SHA-256, compare againstfile_hash, then verifysignaturewith a public key the device trusts). State where that public key should come from, and whyfile_hashalone is not enough (lesson 1.2).
Optional lab: a real Protected Update — only with the instructor’s permission
What permanently changes on your chip is slot 0xE0E1’s version counter advancing by one. What changes but can still be reversed on a board at creation state is that slot’s lock.
The Protected Update button on the screen calls tesaiot_publish_protected_update() with with_csr = true, so per chapter D2 it also creates a new key pair inside the chip; LcsO is not touched.
- Your device must be able to reach the platform (lesson 3.2). On the mtb-mpy variant, read
optiga.read_metadata(0xE0E1)and record tagsC0andD0. IfC0is not01, stop and tell your instructor. - HSM Security → Protected Update on the screen. Record the on-screen message and the
[PU-Ingest]lines on UART, and compare them against “See it work first.” - Read metadata again.
D0must have changed to the value naming the anchor, andC0must be unchanged. IfC0has changed, stop and report immediately. - Power the board off and on, then reconnect. Check whether the line
Ignoring a Protected Update bundle nobody asked forappears. If instead you see STEP 3 and STEP 4 running without you pressing anything, the replay protection is broken — report it. - Try pressing Enrol against the now-locked slot. Record the on-screen message, then let your instructor decide whether to use the Unlock menu to restore it.
Going further
Section titled “Going further”Protected Update needs a device certificate already in place, or a CSR sent along with the request. The final module looks at enrolling with a CSR, from generating a key inside the chip to getting a certificate back, and brings everything together into one secure device.
Next lesson: Lesson 5.1: Enrolling with a CSR
Reflect
Section titled “Reflect”- In your own system, which log line does the team trust as evidence, when it is really just a message the program printed?
- If you had to ship a device with LcsO advanced, how would you design the approval step so no one does it by accident?
- A function named “verify” in your own code — what does it actually check?
References
Section titled “References”- SDK: cm33/security/06_protected_update.c
- SDK: PROTECTED_UPDATE_CONTRACT.md
- D2 — Enrolment and Protected Update end to end (SDK docs built from commit ef72c1b)
- SDK: cm33/security/02_model_signature_hook.c
- Firmware update (BLE NUS) (SDK docs built from commit ef72c1b)
- Infineon: protected_update_data_set tool README @ release-v5.3.0 (MIT)
- ETSI EN 303 645 V3.1.3 (2024-09), provision 5.3
- Examples on the Developer Hub: TESAIoT OTA HTTPS Client (C Version) (Apache-2.0) · PSoC Edge E84 + OPTIGA Trust M: TESAIoT MQTT Client (Cypress EULA, link only)
Review questions
Answer on your own first, then open the answer.
-
In the Protected Update path, which step can a compromised host not fake? (Objective 1)
- การพิมพ์บรรทัด PROTECTED UPDATE COMPLETED SUCCESSFULLY!
- การที่ชิปตรวจลายเซ็นของ manifest กับ trust anchor ของตัวเองสำเร็จ แล้วเขียนช่องเป้าหมาย
- การส่ง ACK ขึ้นแพลตฟอร์ม
- การ subscribe commands/#
Show answer
Answer: B. การที่ชิปตรวจลายเซ็นของ manifest กับ trust anchor ของตัวเองสำเร็จ แล้วเขียนช่องเป้าหมาย
ทุกอย่างที่ host ทำหรือพิมพ์ ผู้ที่คุม host ปลอมได้ แต่ชิปไม่ยอมเขียนถ้าลายเซ็นไม่ผ่าน หลักฐานจึงอยู่ที่การอ่านสถานะจากชิปเอง
-
What does a 0 return from tesaiot_publish_protected_update() mean? (Objective 1)
- ชิปเขียนใบรับรองใหม่เสร็จแล้ว
- คำขอถูก publish แล้ว ชิปยังไม่เปลี่ยนจนกว่า manifest จะมาถึงและถูก apply
- LcsO เปลี่ยนแล้ว
- แพลตฟอร์มปฏิเสธคำขอ
Show answer
Answer: B. คำขอถูก publish แล้ว ชิปยังไม่เปลี่ยนจนกว่า manifest จะมาถึงและถูก apply
คอมเมนต์ของตัวอย่าง 06 บอกว่า 0 แปลว่าขอแล้ว ไม่ใช่เสร็จแล้ว ต้องติดตามด้วย correlation id จนคำตอบมาถึง
-
What does the version counter (metadata tag C1) protect against? (Objective 2)
- ป้องกันไม่ให้ manifest ที่ลงนามถูกต้องแต่เป็นรุ่นเก่า ถูกนำมาใช้ซ้ำ
- ป้องกันการอ่านใบรับรอง
- ป้องกันการเชื่อมต่อ WiFi ซ้ำ
- ป้องกันการเขียน tag C0
Show answer
Answer: A. ป้องกันไม่ให้ manifest ที่ลงนามถูกต้องแต่เป็นรุ่นเก่า ถูกนำมาใช้ซ้ำ
ลายเซ็นบอกว่าใครออก manifest แต่ไม่บอกว่ามันใหม่หรือเก่า ตัวนับที่ขึ้นอย่างเดียวทำหน้าที่ส่วนนั้น
-
A development board whose 0xE0E1 has C0 = 01 has just completed a Protected Update. Which is right? (Objective 2)
- ช่องนี้ถูกล็อกถาวร
- ช่องนี้รับเฉพาะ manifest ที่ลงนามโดย anchor แต่ล็อกยังเคลียร์ได้เพราะ LcsO ยังต่ำกว่า op ส่วนตัวนับ version ย้อนไม่ได้
- ทั้งล็อกและตัวนับย้อนได้ด้วยการ reflash
- LcsO เปลี่ยนเป็น op แล้ว
Show answer
Answer: B. ช่องนี้รับเฉพาะ manifest ที่ลงนามโดย anchor แต่ล็อกยังเคลียร์ได้เพราะ LcsO ยังต่ำกว่า op ส่วนตัวนับ version ย้อนไม่ได้
ล็อกเป็นเงื่อนไข Change ใน metadata ที่เขียนกลับได้ตราบที่ LcsO ต่ำกว่า op ส่วนตัวนับขึ้นอย่างเดียว
-
According to example 06, which chip change can no reflash, erase or power cycle undo? (Objective 3)
- การเขียนใบรับรองลง 0xE0E1
- การเลื่อน LcsO (metadata tag C0)
- การเชื่อมต่อ MQTT
- การอ่าน metadata
Show answer
Answer: B. การเลื่อน LcsO (metadata tag C0)
LcsO เดินทางเดียว cr ไป in ไป op ไป te และเมื่อถึง op การเขียน metadata หยุดถาวร ไม่มีตัวอย่างใดใน SDK เขียน tag นี้
Cite this lesson
If you teach from this lesson or reuse it in slides or documents, credit it with the text below. If you changed it, add (adapted) after the title.
"Protected Update" from TESA Open Knowledge by the Thai Embedded Systems Association (TESA), https://github.com/tesaiot/tesa-qualification-program, licensed under CC BY-NC 4.0
Thai attribution: "Protected Update" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0
This lesson adapts the source below; keep its credit too.
https://github.com/tesaiot/tesaiot-pse84-devkit-sdk/tree/ef72c1b658178eee8c38b1e47d28b006f80a59b5 · SDK security examples and docs are linked at this commit; lesson pages quote short excerpts with attribution and copy no files.
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0
Content is licensed CC BY-NC 4.0. Reuse it non-commercially and credit the Thai Embedded Systems Association (TESA) every time. · How to cite TESA