PHPackages                             k2gl/tuf - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. k2gl/tuf

ActiveLibrary[Security](/categories/security)

k2gl/tuf
========

The Update Framework (TUF) client for PHP: a minimal, fail-closed metadata verifier and updater for securely distributed trust roots, such as Sigstore's.

1.0.0(1w ago)059↑2188.1%MITPHPPHP &gt;=8.1CI passing

Since May 31Pushed 1w agoCompare

[ Source](https://github.com/k2gl/tuf)[ Packagist](https://packagist.org/packages/k2gl/tuf)[ Docs](https://github.com/k2gl/tuf)[ RSS](/packages/k2gl-tuf/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (5)Versions (2)Used By (0)

k2gl/tuf
========

[](#k2gltuf)

[![CI](https://camo.githubusercontent.com/fe0c40043e2fd4c9a512540b8ffc1cd581af5147175033b814d85618ad69abe9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6b32676c2f7475662f63692e796d6c3f6272616e63683d6d61696e266c6162656c3d4349266c6f676f3d676974687562)](https://github.com/k2gl/tuf/actions/workflows/ci.yml)[![Latest Stable Version](https://camo.githubusercontent.com/07ab3d0fc60e71f4b662d88440f5d0cea6ad2e9a5d6be6e1d4f3878c2dbb1d9f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b32676c2f7475663f6c6f676f3d7061636b6167697374266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/k2gl/tuf)[![Total Downloads](https://camo.githubusercontent.com/4f35b93c715b6d1b80034520158991a88edaba1e5c0d097f93f0de66cb5af0a3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6b32676c2f7475663f6c6f676f3d7061636b6167697374266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/k2gl/tuf)[![PHPStan Level](https://camo.githubusercontent.com/01c58e66f2fafb70c17613ff2b1da3f549aade3a735b076da5cd9e5c04b945a5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230392d3261356561373f6c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://phpstan.org)[![License](https://camo.githubusercontent.com/d5616e19f554a6853cd0020d34211f16a61d7ee2894bdd04f930f9e1e24ab281/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6b32676c2f7475663f636f6c6f723d79656c6c6f77677265656e)](https://packagist.org/packages/k2gl/tuf)

A minimal, **fail-closed** [TUF](https://theupdateframework.io/) (The Update Framework) client for PHP. Given an embedded trust anchor (the initial `root.json`) and a repository to talk to, it refreshes the signed metadata in the order the specification mandates and lets you resolve and download individual targets — with every byte verified against threshold-signed metadata, or an exception.

The motivating use case is fetching Sigstore's `trusted_root.json` securely, but the client is a faithful, general TUF implementation with no Sigstore specifics baked in.

What it guarantees
------------------

[](#what-it-guarantees)

Refreshing and downloading enforce, in order and fail-closed, the TUF client workflow:

1. **Root** — each new root is signed by the threshold of keys of *both* the currently trusted root and the new one, and its version increases by exactly one (key-compromise and rollback protection).
2. **Timestamp** — signed by the root's timestamp role; neither its version nor the snapshot version it points at may roll back.
3. **Snapshot** — matches the length and hashes the timestamp recorded, is signed by the root's snapshot role, matches the version the timestamp points at, and never rolls back or drops any targets metadata.
4. **Targets** — match the length and hashes the snapshot recorded, signed by the delegating role, version matching the snapshot.
5. **Target files** — verified against the length and hashes in the trusted targets metadata before the bytes are handed back.

Anything missing, expired, mis-versioned, or insufficiently signed throws. There is no "best effort" path.

Install
-------

[](#install)

```
composer require k2gl/tuf
```

Requires PHP 8.1+ and `ext-json`. For signature verification, enable the extension matching the repository's key schemes:

- `ext-sodium` for `ed25519` keys;
- `ext-openssl` for `ecdsa-sha2-nistp256` keys.

`rsassa-pss-sha256` is not verified by this version: such a signature simply does not count toward a threshold (fail-closed).

Usage
-----

[](#usage)

You supply the initial `root.json` (the trust anchor — ship it with your application) and the repository URLs. The updater does the rest.

```
use K2gl\Tuf\Updater;
use K2gl\Tuf\HttpFetcher;
use K2gl\Tuf\Exception\TufException;

$updater = new Updater(
    trustedRoot:     file_get_contents(__DIR__ . '/root.json'),
    metadataBaseUrl: 'https://tuf-repo-cdn.sigstore.dev',
    targetBaseUrl:   'https://tuf-repo-cdn.sigstore.dev/targets',
    fetcher:         new HttpFetcher(),
);

try {
    $updater->refresh();

    $info = $updater->getTargetInfo('trusted_root.json');

    if ($info === null) {
        throw new RuntimeException('Target is not listed in trusted metadata.');
    }
    $trustedRootJson = $updater->downloadTarget($info); // verified bytes
} catch (TufException $e) {
    // Trust could not be established — fail closed.
    throw $e;
}
```

`getTargetInfo()` walks delegations depth-first (honouring terminating delegations), fetching delegated targets metadata as needed, and returns `null`when no trusted role vouches for the path. `downloadTarget()` re-verifies the content's length and hashes before returning it.

Keeping it offline (bring your own fetcher)
-------------------------------------------

[](#keeping-it-offline-bring-your-own-fetcher)

The network is reached only through the `Fetcher` interface, so the trust logic itself is pure. Point the client at a local mirror, an HTTP client you already use, or a fully in-memory source by implementing one method:

```
use K2gl\Tuf\Fetcher;
use K2gl\Tuf\Exception\DownloadException;

final class MirrorFetcher implements Fetcher
{
    public function fetch(string $url, int $maxLength): string
    {
        // Return at most $maxLength bytes, or throw DownloadException
        // (including for "not found", which ends the root version chain).
    }
}
```

The trust anchor
----------------

[](#the-trust-anchor)

The security of the whole chain rests on the initial `root.json` you embed: it is the one piece that is trusted a priori. Ship it with your application and update it deliberately. Its own expiry is intentionally not enforced on load — the refresh immediately walks the root version chain to the latest — but every other piece of metadata must be current.

Lower-level API
---------------

[](#lower-level-api)

For advanced or fully offline use, `TrustedMetadataSet` is the verification core without any I/O: construct it with a trusted root and feed it metadata bytes (`updateRoot()`, `updateTimestamp()`, `updateSnapshot()`, `updateTargets()`, `updateDelegatedTargets()`) in workflow order. It applies exactly the checks listed above and exposes the verified `Root`, `Timestamp`, `Snapshot` and `Targets` value objects from `K2gl\Tuf\Metadata`.

Exceptions
----------

[](#exceptions)

Everything thrown implements `K2gl\Tuf\Exception\TufException`:

- `UnsignedMetadataException` — a role's signature threshold was not met.
- `BadVersionException` — a version rollback or a version that disagrees with its referring metadata.
- `ExpiredMetadataException` — metadata is past its expiry.
- `LengthOrHashMismatchException` — a downloaded file does not match the trusted length or hashes.
- `DownloadException` — a file could not be fetched.
- `RepositoryException` — metadata is malformed or otherwise inconsistent.

License
-------

[](#license)

MIT — see [LICENSE](LICENSE). An independent, clean-room implementation of the TUF specification.

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance98

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

9d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6bc4aa529c7f13ea593297497f6eae20d5c07f476baa0a551960d7e6ff1e5413?d=identicon)[k2gl](/maintainers/k2gl)

---

Top Contributors

[![k2gl](https://avatars.githubusercontent.com/u/2846079?v=4)](https://github.com/k2gl "k2gl (4 commits)")

---

Tags

securitysigningmetadatasupply-chainsigstoretufthe-update-frameworktrust-root

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/k2gl-tuf/health.svg)

```
[![Health](https://phpackages.com/badges/k2gl-tuf/health.svg)](https://phpackages.com/packages/k2gl-tuf)
```

###  Alternatives

[phpseclib/phpseclib

PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.

5.6k455.2M1.4k](/packages/phpseclib-phpseclib)[defuse/php-encryption

Secure PHP Encryption Library

3.9k170.7M239](/packages/defuse-php-encryption)[robrichards/xmlseclibs

A PHP library for XML Security

41582.2M138](/packages/robrichards-xmlseclibs)[spatie/laravel-csp

Add CSP headers to the responses of a Laravel app

85810.6M23](/packages/spatie-laravel-csp)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
