From 004f18a2df93e3d4a5ff15d8c992b46b5b5d39b6 Mon Sep 17 00:00:00 2001 From: Appu Goundan Date: Mon, 7 Oct 2024 15:19:24 -0400 Subject: [PATCH] Move known roles in TUF Roles were a bit too tightly coupled to the root roles, change this around a tiny bit so we can add delegations support Signed-off-by: Appu Goundan --- .../dev/sigstore/tuf/FileSystemTufStore.java | 10 ++++----- .../dev/sigstore/tuf/HttpMetaFetcher.java | 17 +++++++-------- .../java/dev/sigstore/tuf/MetaFetcher.java | 10 ++++----- .../main/java/dev/sigstore/tuf/Updater.java | 21 +++++++++---------- .../java/dev/sigstore/tuf/model/Role.java | 13 ------------ .../java/dev/sigstore/tuf/model/RootMeta.java | 4 ---- .../java/dev/sigstore/tuf/model/RootRole.java | 7 ++++++- .../dev/sigstore/tuf/model/TimestampMeta.java | 2 +- 8 files changed, 35 insertions(+), 49 deletions(-) diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/FileSystemTufStore.java b/sigstore-java/src/main/java/dev/sigstore/tuf/FileSystemTufStore.java index 0ad4c2c3..ae507588 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/FileSystemTufStore.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/FileSystemTufStore.java @@ -70,22 +70,22 @@ public String getIdentifier() { @Override public Optional loadTrustedRoot() throws IOException { - return loadRole(Role.Name.ROOT, Root.class); + return loadRole(RootRole.ROOT, Root.class); } @Override public Optional loadTimestamp() throws IOException { - return loadRole(Role.Name.TIMESTAMP, Timestamp.class); + return loadRole(RootRole.TIMESTAMP, Timestamp.class); } @Override public Optional loadSnapshot() throws IOException { - return loadRole(Role.Name.SNAPSHOT, Snapshot.class); + return loadRole(RootRole.SNAPSHOT, Snapshot.class); } @Override public Optional loadTargets() throws IOException { - return loadRole(Role.Name.TARGETS, Targets.class); + return loadRole(RootRole.TARGETS, Targets.class); } @Override @@ -103,7 +103,7 @@ public void storeMeta(SignedTufMeta timestamp) throws IOException { storeRole(timestamp); } - > Optional loadRole(Role.Name roleName, Class tClass) + > Optional loadRole(String roleName, Class tClass) throws IOException { Path roleFile = repoBaseDir.resolve(roleName + ".json"); if (!roleFile.toFile().exists()) { diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/HttpMetaFetcher.java b/sigstore-java/src/main/java/dev/sigstore/tuf/HttpMetaFetcher.java index 4a4ac631..23cc30b7 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/HttpMetaFetcher.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/HttpMetaFetcher.java @@ -22,9 +22,9 @@ import com.google.common.base.Preconditions; import dev.sigstore.http.HttpClients; import dev.sigstore.http.ImmutableHttpParams; -import dev.sigstore.tuf.model.Role; import dev.sigstore.tuf.model.Root; import dev.sigstore.tuf.model.SignedTufMeta; +import dev.sigstore.tuf.model.TufMeta; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -62,24 +62,23 @@ public Optional> getRootAtVersion(int version) } @Override - public Optional> getMeta(Role.Name role, Class t) - throws IOException, FileExceedsMaxLengthException { + public > Optional> getMeta( + String role, Class t) throws IOException, FileExceedsMaxLengthException { return getMeta(getFileName(role, null), t, null); } @Override - public Optional> getMeta( - Role.Name role, int version, Class t, Integer maxSize) + public > Optional> getMeta( + String role, int version, Class t, Integer maxSize) throws IOException, FileExceedsMaxLengthException { Preconditions.checkArgument(version > 0, "version should be positive, got: %s", version); return getMeta(getFileName(role, version), t, maxSize); } - private static String getFileName(Role.Name role, @Nullable Integer version) { - String normalizeRoleName = role.name().toLowerCase(Locale.ROOT); + private static String getFileName(String role, @Nullable Integer version) { return version == null - ? normalizeRoleName + ".json" - : String.format(Locale.ROOT, "%d.%s.json", version, normalizeRoleName); + ? role + ".json" + : String.format(Locale.ROOT, "%d.%s.json", version, role); } Optional> getMeta( diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/MetaFetcher.java b/sigstore-java/src/main/java/dev/sigstore/tuf/MetaFetcher.java index 4abdfd96..e66b2a1a 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/MetaFetcher.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/MetaFetcher.java @@ -15,9 +15,9 @@ */ package dev.sigstore.tuf; -import dev.sigstore.tuf.model.Role; import dev.sigstore.tuf.model.Root; import dev.sigstore.tuf.model.SignedTufMeta; +import dev.sigstore.tuf.model.TufMeta; import java.io.IOException; import java.util.Optional; @@ -49,8 +49,8 @@ Optional> getRootAtVersion(int version) * @throws FileExceedsMaxLengthException if the role meta at source exceeds client specified max * size */ - Optional> getMeta(Role.Name name, Class roleType) - throws IOException, FileExceedsMaxLengthException; + > Optional> getMeta( + String name, Class roleType) throws IOException, FileExceedsMaxLengthException; /** * Fetches the specified role meta from the source @@ -64,8 +64,8 @@ Optional> getMeta(Role.Name name, C * @throws FileExceedsMaxLengthException if the role meta at source exceeds client specified max * size */ - Optional> getMeta( - Role.Name name, int version, Class roleType, Integer maxSize) + > Optional> getMeta( + String name, int version, Class roleType, Integer maxSize) throws IOException, FileExceedsMaxLengthException; byte[] fetchResource(String filename, int maxLength) diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/Updater.java b/sigstore-java/src/main/java/dev/sigstore/tuf/Updater.java index a8734d97..0808b539 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/Updater.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/Updater.java @@ -156,9 +156,11 @@ Root updateRoot() throwIfExpired(expires); // 5.3.11) If the timestamp and / or snapshot keys have been rotated, then delete the trusted // timestamp and snapshot metadata files. - if (hasNewKeys(preUpdateSnapshotRole, trustedRoot.getSignedMeta().getRole(Role.Name.SNAPSHOT)) + if (hasNewKeys( + preUpdateSnapshotRole, trustedRoot.getSignedMeta().getRoles().get(RootRole.SNAPSHOT)) || hasNewKeys( - preUpdateTimestampRole, trustedRoot.getSignedMeta().getRole(Role.Name.TIMESTAMP))) { + preUpdateTimestampRole, + trustedRoot.getSignedMeta().getRoles().get(RootRole.TIMESTAMP))) { localStore.clearMetaDueToKeyRotation(); } return trustedRoot; @@ -174,16 +176,13 @@ private boolean hasNewKeys(RootRole oldRole, RootRole newRole) { return !newRole.getKeyids().stream().allMatch(key -> oldRole.getKeyids().contains(key)); } - void verifyDelegate(Root trustedRoot, SignedTufMeta delegate) + void verifyDelegate(Root trustedRoot, SignedTufMeta delegate) throws SignatureVerificationException, IOException, NoSuchAlgorithmException, - InvalidKeySpecException, InvalidKeyException { + InvalidKeySpecException { verifyDelegate( delegate.getSignatures(), trustedRoot.getSignedMeta().getKeys(), - trustedRoot - .getSignedMeta() - .getRole( - Role.Name.valueOf(delegate.getSignedMeta().getType().toUpperCase(Locale.ROOT))), + trustedRoot.getSignedMeta().getRoles().get(delegate.getSignedMeta().getType()), delegate.getCanonicalSignedBytes()); } @@ -269,7 +268,7 @@ Optional updateTimestamp(Root root) // 1) download the timestamp.json bytes. var timestamp = fetcher - .getMeta(Role.Name.TIMESTAMP, Timestamp.class) + .getMeta(RootRole.TIMESTAMP, Timestamp.class) .orElseThrow(() -> new FileNotFoundException("timestamp.json", fetcher.getSource())) .getMetaResource(); @@ -305,7 +304,7 @@ Snapshot updateSnapshot(Root root, Timestamp timestamp) int timestampSnapshotVersion = timestamp.getSignedMeta().getSnapshotMeta().getVersion(); var snapshotResult = fetcher.getMeta( - Role.Name.SNAPSHOT, + RootRole.SNAPSHOT, timestampSnapshotVersion, Snapshot.class, timestamp.getSignedMeta().getSnapshotMeta().getLengthOrDefault()); @@ -395,7 +394,7 @@ Targets updateTargets(Root root, Snapshot snapshot) SnapshotMeta.SnapshotTarget targetMeta = snapshot.getSignedMeta().getTargetMeta("targets.json"); var targetsResultMaybe = fetcher.getMeta( - Role.Name.TARGETS, + RootRole.TARGETS, targetMeta.getVersion(), Targets.class, targetMeta.getLengthOrDefault()); diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Role.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Role.java index a628deeb..89755439 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Role.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Role.java @@ -16,7 +16,6 @@ package dev.sigstore.tuf.model; import java.util.List; -import java.util.Locale; /** * TUF uses roles to define the set of actions a party can perform. The concept of roles allows TUF @@ -27,18 +26,6 @@ */ public interface Role { - enum Name { - ROOT, - SNAPSHOT, - TIMESTAMP, - TARGETS; - - @Override - public String toString() { - return super.toString().toLowerCase(Locale.ROOT); - } - } - /** A list of trusted keys for this role. */ List getKeyids(); diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/RootMeta.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/RootMeta.java index 8751862c..2dc30ed6 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/RootMeta.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/RootMeta.java @@ -54,8 +54,4 @@ public interface RootMeta extends TufMeta { * href="https://theupdateframework.io/metadata/#root-metadata-rootjson">role. */ Map getRoles(); - - default RootRole getRole(Role.Name name) { - return getRoles().get(name.toString()); - } } diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/RootRole.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/RootRole.java index a871ec26..38532d78 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/RootRole.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/RootRole.java @@ -27,4 +27,9 @@ */ @Gson.TypeAdapters @Value.Immutable -public interface RootRole extends Role {} +public interface RootRole extends Role { + String ROOT = "root"; + String SNAPSHOT = "snapshot"; + String TIMESTAMP = "timestamp"; + String TARGETS = "targets"; +} diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/TimestampMeta.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/TimestampMeta.java index 4b7d7c36..cecfb29d 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/TimestampMeta.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/TimestampMeta.java @@ -33,6 +33,6 @@ public interface TimestampMeta extends TufMeta { Map getMeta(); default SnapshotMeta.SnapshotTarget getSnapshotMeta() { - return getMeta().get(Role.Name.SNAPSHOT.toString() + ".json"); + return getMeta().get(RootRole.SNAPSHOT + ".json"); } }