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 f266dbd1..6cd04628 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/Updater.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/Updater.java @@ -22,6 +22,7 @@ import dev.sigstore.encryption.Keys; import dev.sigstore.encryption.signers.Verifiers; import dev.sigstore.tuf.model.*; +import dev.sigstore.tuf.model.TargetMeta.TargetData; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; @@ -91,13 +92,15 @@ public static Builder builder() { return new Builder(); } + /** Update metadata and download all targets. */ public void update() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException { updateMeta(); downloadTargets(trustedMetaStore.getTargets()); } - void updateMeta() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { + /** Update just metadata but do not download targets. */ + public void updateMeta() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { updateRoot(); var oldTimestamp = trustedMetaStore.findTimestamp(); updateTimestamp(); @@ -112,6 +115,16 @@ void updateMeta() throws IOException, NoSuchAlgorithmException, InvalidKeySpecEx updateTargets(); } + /** Download a single target defined in targets. Does not handle delegated targets. */ + public void downloadTarget(String targetName) + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { + var targetData = trustedMetaStore.getTargets().getSignedMeta().getTargets().get(targetName); + if (targetData == null) { + throw new TargetMetadataMissingException(targetName); + } + downloadTarget(targetName, targetData); + } + // https://theupdateframework.github.io/specification/latest/#detailed-client-workflow void updateRoot() throws IOException, RoleExpiredException, NoSuchAlgorithmException, InvalidKeySpecException, @@ -304,7 +317,6 @@ void updateTimestamp() localTimestamp.getSignedMeta().getVersion(), timestamp.getSignedMeta().getVersion()); } if (localTimestamp.getSignedMeta().getVersion() == timestamp.getSignedMeta().getVersion()) { - trustedMetaStore.setTimestamp(localTimestamp); return; } } @@ -459,24 +471,28 @@ void downloadTargets(Targets targets) throw new TargetMetadataMissingException(targetName); } TargetMeta.TargetData targetData = entry.getValue(); - // 9) Download target up to length specified in bytes. verify against hash. - String versionedTargetName; - if (targetData.getHashes().getSha512() != null) { - versionedTargetName = targetData.getHashes().getSha512() + "." + targetName; - } else { - versionedTargetName = targetData.getHashes().getSha256() + "." + targetName; - } + downloadTarget(targetName, targetData); + } + } - var targetBytes = targetFetcher.fetchResource(versionedTargetName, targetData.getLength()); - if (targetBytes == null) { - throw new FileNotFoundException(targetName, targetFetcher.getSource()); - } - verifyHashes(entry.getKey(), targetBytes, targetData.getHashes()); + void downloadTarget(String targetName, TargetData targetData) throws IOException { + // 9) Download target up to length specified in bytes. verify against hash. + String versionedTargetName; + if (targetData.getHashes().getSha512() != null) { + versionedTargetName = targetData.getHashes().getSha512() + "." + targetName; + } else { + versionedTargetName = targetData.getHashes().getSha256() + "." + targetName; + } - // when persisting targets use the targetname without sha512 prefix - // https://theupdateframework.github.io/specification/latest/index.html#fetch-target - targetStore.writeTarget(targetName, targetBytes); + var targetBytes = targetFetcher.fetchResource(versionedTargetName, targetData.getLength()); + if (targetBytes == null) { + throw new FileNotFoundException(targetName, targetFetcher.getSource()); } + verifyHashes(targetName, targetBytes, targetData.getHashes()); + + // when persisting targets use the targetname without sha512 prefix + // https://theupdateframework.github.io/specification/latest/index.html#fetch-target + targetStore.writeTarget(targetName, targetBytes); } @VisibleForTesting diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Root.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Root.java index f93b1a9f..ece796c1 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Root.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Root.java @@ -24,6 +24,7 @@ @Value.Immutable public interface Root extends SignedTufMeta { @Override + @Gson.Ignore @Derived default RootMeta getSignedMeta() { return getSignedMeta(RootMeta.class); diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/SignedTufMeta.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/SignedTufMeta.java index 3504a639..0c532c7b 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/SignedTufMeta.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/SignedTufMeta.java @@ -38,6 +38,7 @@ public interface SignedTufMeta { /** An internal helper to translate raw signed json to a useable type. */ @Derived + @Gson.Ignore default T getSignedMeta(Class type) { return GsonSupplier.GSON.get().fromJson(getRawSignedMeta(), type); } diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Snapshot.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Snapshot.java index 4d54656d..fba892d5 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Snapshot.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Snapshot.java @@ -25,6 +25,7 @@ public interface Snapshot extends SignedTufMeta { @Override @Derived + @Gson.Ignore default SnapshotMeta getSignedMeta() { return getSignedMeta(SnapshotMeta.class); } diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/SnapshotMeta.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/SnapshotMeta.java index e3363ea0..b51e576d 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/SnapshotMeta.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/SnapshotMeta.java @@ -59,6 +59,7 @@ interface SnapshotTarget { /** The length in bytes of the given target's metadata, or a default if not present */ @Derived + @Gson.Ignore default Integer getLengthOrDefault() { return getLength().orElse(DEFAULT_MAX_LENGTH); } diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Targets.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Targets.java index 5b2aeff3..e45f74b5 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Targets.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Targets.java @@ -25,6 +25,7 @@ public interface Targets extends SignedTufMeta { @Override @Derived + @Gson.Ignore default TargetMeta getSignedMeta() { return getSignedMeta(TargetMeta.class); } diff --git a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Timestamp.java b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Timestamp.java index d3417d8c..5f5d3cee 100644 --- a/sigstore-java/src/main/java/dev/sigstore/tuf/model/Timestamp.java +++ b/sigstore-java/src/main/java/dev/sigstore/tuf/model/Timestamp.java @@ -26,6 +26,7 @@ public interface Timestamp extends SignedTufMeta { @Override @Derived + @Gson.Ignore default TimestampMeta getSignedMeta() { return getSignedMeta(TimestampMeta.class); }