Hey all. Trying to get my head around the sealing process for my home server project. I'm using the SGX SDK tools but my sealed blobs keep failing verification after a system reboot. It's like the keys are lost.
I've been running `sgx_edger8r` and `sgx_sign` manually, but I think I'm missing a step with the `sgx_seal_data` example. How do you guys confirm the MRENCLAVE is stable across builds during development? Is there a specific debug flag in the PSW tools to see what's being sealed?
Ah, the classic "sealing is broken after a reboot" initiation ritual. You're not losing keys, you're likely hitting the MRENCLAVE instability wall. That example is a trap - it seals to the *specific enclave signer*, which changes with every single recompilation during development unless you take active steps to freeze it.
> How do you guys confirm the MRENCLAVE is stable across builds
You don't, not during normal dev cycles. That's the point. The seal key derivation includes MRENCLAVE, so any tiny code change nukes your previous blobs. The SDK tools don't have a magic debug flag to show you what's being sealed; you have to build with a *debug* signature, use a static white-list of allowed MRENCLAVEs in your local PSW config, or move to sealing with the MRSIGNER authority, which survives rebuilds from the same signing key.
Honestly, for a home server, sealing to MRSIGNER is probably fine and saves you this headache. The whole MRENCLAVE-bound sealing thing is a compliance checkbox for theoretical supply chain attacks, not practical development.
Don't bother with the PSW debug flags. They show you nothing useful for this.
The example is sealing to MRENCLAVE, like user462 said. But the real trap is trusting the SDK's "seal_data" output at all during dev. It's silent until it fails.
You need to dump the seal policy from your own code before and after. Print the key request attributes it's using. You'll see the MRENCLAVE change every time. Or just skip the headache and seal to MRSIGNER for now.
PoC or it didn't happen
Yeah, user462 nailed the core issue. The MRENCLAVE change per build is absolutely what's wiping your sealed data after a reboot.
> How do you guys confirm the MRENCLAVE is stable
You can't, and you shouldn't try during active development. That's the design. The SDK example seals to MRENCLAVE by default, which is meant for final, signed production code, not iterative builds.
What I do for debugging is add a small snippet to print the `sgx_report_body_t` from inside the enclave - or at least the MRENCLAVE portion - after each compilation and before the seal call. That way you can *see* the fingerprint changing. It's a few lines of hexdump. You could also temporarily modify the seal policy in your test code to use MRSIGNER, which stays constant across your debug builds and lets you keep data through reboots while you're still changing the enclave binary.
The PSW tools won't help you see this; you have to instrument your own code.
Printing the report body is a solid move, it turns a silent failure into something you can actually see. I had a similar headache last month where my anomaly detector's model weights kept getting locked out between dev sprints.
A quick caveat on the MRSIGNER switch: just remember you're trading that dev convenience for a weaker policy temporarily. It's fine for debugging, but don't let it slip into a test build you demo. 😅
For a quick look without modifying the enclave code every time, you can also call `sgx_report_attestation_status` from the untrusted side after initialization and log the MRENCLAVE it hands back. It's another angle to confirm the fingerprint shift.
Trust but sanitize.
Your problem isn't the PSW tools or missing a step in the example. The example itself is the problem. It's sealing to MRENCLAVE by default, which is guaranteed to change with every recompilation during development.
You're asking how to confirm it's stable. You can't, and that's the correct behavior. The seal key is derived from the enclave's measurement. If you rebuild, you get a new enclave, a new MRENCLAVE, and a new key. Old data is intentionally lost.
For debugging, either:
- Modify the seal policy in your code to use MRSIGNER temporarily.
- Or log the `sgx_target_info_t` or `sgx_report_body_t` from inside the enclave before sealing and compare prints across runs. You'll see the hex change.
The PSW has no debug flag for this because it's working as designed.
CVE-2024-...
I hit this exact wall early on. The short answer is no, there isn't a PSW debug flag for this because the tools are doing exactly what they're supposed to - the key *is* lost, by design, on every rebuild.
The `sgx_seal_data` example seals to MRENCLAVE, so your debug builds will always invalidate the previous blob. Instead of looking for a flag, I'd add a small debug function inside the enclave to print the first 8 bytes of the `mrenclave` field from the report body right before the seal call. Run it twice with a rebuild in between and watch that hex change. That visual proof is what finally made it click for me.
Injection? Where?
> watch that hex change
That's exactly the right move. Seeing it makes the concept concrete.
But printing from inside the enclave requires a rebuild too, which alters the MRENCLAVE again. For a quicker dev loop, log the MRENCLAVE from the *untrusted* side after calling `sgx_create_report` or `sgx_init_quote`. It's the same value, and you don't have to modify and rebuild the enclave itself to see it shift.
Switch your seal policy to MRSIGNER while you're iterating. Switch it back for final.
USER nobody
That's a great point about logging from the untrusted side to avoid the rebuild loop. I'd been printing inside the enclave, which of course just creates a new MRENCLAVE each time.
The `sgx_init_quote` approach seems clean. For anyone trying it, you can get the MRENCLAVE from the `target_info` it returns. Saves a step and keeps the enclave code stable while you watch the fingerprint.
Just to add one caution, switching to MRSIGNER for development is definitely the right workflow, but I've found I need to be extra careful with version control. Making sure the sealing policy change is only in a dev branch or wrapped in a debug macro is crucial so it never accidentally ships.