Skip to content

tuf: Support importing root keys from a fioctl tarball#199

Merged
doanac merged 2 commits into
mainfrom
tuf-import
Jul 13, 2026
Merged

tuf: Support importing root keys from a fioctl tarball#199
doanac merged 2 commits into
mainfrom
tuf-import

Conversation

@doanac

@doanac doanac commented Jul 8, 2026

Copy link
Copy Markdown
Member

Add an optional --import-keys flag to the tuf-init command that reads a fioctl/ota-tuf tarball containing the offline root key(s) and root.json. The imported root.json files are stored verbatim, fresh online keys are generated for every role, and a new root.json is created and signed by both the imported (old) root key(s) and the new root key so clients can verify the chain of trust.

Chatting with Copilot on this, it was decided to be more efficient to use our own code for talking with the FIO backend for getting the root.json files rather than trying to integrate with the fioctl client library code.

Fixes bug #189

@doanac doanac requested a review from vkhoroz July 8, 2026 18:53
Comment thread storage/file_tuf_import.go Fixed
Comment thread cmd/server/tuf_init.go Outdated
Comment thread cmd/server/tuf_config.go Outdated
@doanac doanac force-pushed the tuf-import branch 2 times, most recently from 51b9d44 to 4606e14 Compare July 8, 2026 21:52
Comment thread cmd/server/tuf_init.go Fixed
@doanac

doanac commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

This has been tested e2e migrating a foundries factory device to my update server instance with the help of fioctl pr foundriesio/fioctl#541

@vkhoroz vkhoroz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me.

I'm only a bit surprised by a sheer amount of code needed to do this.
But that's irrelevant. You did a great job.

Comment thread cmd/server/tuf_init.go
Comment thread cmd/server/tuf_init.go Outdated
Comment thread storage/file_tuf_import.go Outdated
Comment thread storage/file_tuf_import.go Outdated
Comment thread storage/file_tuf_import.go Outdated
Comment thread storage/file_tuf_import.go Outdated
Comment thread storage/file_tuf_import.go
Comment thread storage/file_tuf_import.go Outdated
Comment thread storage/file_tuf_import.go Outdated
Add an optional --import-keys flag to the tuf-init command that reads a
fioctl/ota-tuf tarball containing the offline root key(s) and root.json.
The imported root.json files are stored verbatim, fresh online keys are
generated for every role, and a new root.json is created and signed by
both the imported (old) root key(s) and the new root key so clients can
verify the chain of trust.

Fixes bug #189

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Co-authored-by: GitHub Copilot <bot@github.com>

@vkhoroz vkhoroz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

I'd still recommend to sort out that feeling of adding multiple old key signatures.
(That what the code seems to do, but we only ever have one matching old key in the tarball).

Feel free to merge when you like it.

Comment thread cmd/server/tuf_init.go
Comment on lines +72 to +85
fmt.Println()
fmt.Println("TUF initialization completed successfully.")
fmt.Println()
fmt.Println("IMPORTANT: A new root key was created at:")
fmt.Printf(" %s\n", rootKeyPath)
fmt.Println()
fmt.Println("This key is encrypted at rest using the HMAC secret at:")
fmt.Printf(" %s\n", hmacPath)
fmt.Println()
fmt.Println("Make a backup copy of BOTH files and store them somewhere safe NOW.")
fmt.Println("The root key is useless without the HMAC secret needed to decrypt it.")
fmt.Println("If either file is lost it CANNOT be recovered, and you will permanently")
fmt.Println("lose the ability to rotate or manage your TUF root of trust.")
fmt.Println()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, use a multi-line format, like this:

Suggested change
fmt.Println()
fmt.Println("TUF initialization completed successfully.")
fmt.Println()
fmt.Println("IMPORTANT: A new root key was created at:")
fmt.Printf(" %s\n", rootKeyPath)
fmt.Println()
fmt.Println("This key is encrypted at rest using the HMAC secret at:")
fmt.Printf(" %s\n", hmacPath)
fmt.Println()
fmt.Println("Make a backup copy of BOTH files and store them somewhere safe NOW.")
fmt.Println("The root key is useless without the HMAC secret needed to decrypt it.")
fmt.Println("If either file is lost it CANNOT be recovered, and you will permanently")
fmt.Println("lose the ability to rotate or manage your TUF root of trust.")
fmt.Println()
fmt.Printf(`
TUF initialization completed successfully.
IMPORTANT: A new root key was created at:
%s
This key is encrypted at rest using the HMAC secret at:
%s
Make a backup copy of BOTH files and store them somewhere safe NOW.
The root key is useless without the HMAC secret needed to decrypt it.
If either file is lost it CANNOT be recovered, and you will permanently
lose the ability to rotate or manage your TUF root of trust.
`,
rootKeyPath, hmacPath)

On successful tuf-init (both fresh init and root import), print a notice
that a new root key was created and must be backed up along with the
hmac.secret used to encrypt it at rest. The root key is unrecoverable if
lost. Document the same guidance in the quick-start guide.

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
@doanac doanac merged commit c8e6a87 into main Jul 13, 2026
14 checks passed
@doanac doanac deleted the tuf-import branch July 13, 2026 19:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants