Skip to content

Commit cd71b05

Browse files
committed
Delegated targets support
- No support for succinct delegations - Removed eager download of all targets - SigstoreTufClient must now download the targets it wants explicitly - Rename update() to refresh() to match naming of other clients - Correctly handle url escaping in names NOTE: this was produced with the help of AI coding tools Signed-off-by: Appu Goundan <appu@google.com>
1 parent cdc01b9 commit cd71b05

39 files changed

Lines changed: 1814 additions & 140 deletions

sigstore-java/src/main/java/dev/sigstore/tuf/FileSystemTufStore.java

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
import java.io.BufferedWriter;
2424
import java.io.IOException;
2525
import java.io.InputStream;
26-
import java.net.URLEncoder;
27-
import java.nio.charset.StandardCharsets;
2826
import java.nio.file.Files;
2927
import java.nio.file.Path;
3028
import java.util.Optional;
@@ -69,26 +67,22 @@ public String getIdentifier() {
6967

7068
@Override
7169
public void writeTarget(String targetName, byte[] targetContents) throws IOException {
72-
var encoded = URLEncoder.encode(targetName, StandardCharsets.UTF_8);
73-
Files.write(targetsDir.resolve(encoded), targetContents);
70+
Files.write(targetsDir.resolve(TufNames.encode(targetName)), targetContents);
7471
}
7572

7673
@Override
7774
public byte[] readTarget(String targetName) throws IOException {
78-
var encoded = URLEncoder.encode(targetName, StandardCharsets.UTF_8);
79-
return Files.readAllBytes(targetsDir.resolve(encoded));
75+
return Files.readAllBytes(targetsDir.resolve(TufNames.encode(targetName)));
8076
}
8177

8278
@Override
8379
public InputStream getTargetInputSteam(String targetName) throws IOException {
84-
var encoded = URLEncoder.encode(targetName, StandardCharsets.UTF_8);
85-
return Files.newInputStream(targetsDir.resolve(encoded));
80+
return Files.newInputStream(targetsDir.resolve(TufNames.encode(targetName)));
8681
}
8782

8883
@Override
8984
public boolean hasTarget(String targetName) throws IOException {
90-
var encoded = URLEncoder.encode(targetName, StandardCharsets.UTF_8);
91-
return Files.isRegularFile(targetsDir.resolve(encoded));
85+
return Files.isRegularFile(targetsDir.resolve(TufNames.encode(targetName)));
9286
}
9387

9488
@Override
@@ -99,23 +93,23 @@ public void writeMeta(String roleName, SignedTufMeta<?> meta) throws IOException
9993
@Override
10094
public <T extends SignedTufMeta<?>> Optional<T> readMeta(String roleName, Class<T> tClass)
10195
throws IOException, JsonParseException {
102-
Path roleFile = repoBaseDir.resolve(roleName + ".json");
96+
Path roleFile = repoBaseDir.resolve(TufNames.encode(roleName) + ".json");
10397
if (!roleFile.toFile().exists()) {
10498
return Optional.empty();
10599
}
106100
return Optional.of(GSON.get().fromJson(Files.readString(roleFile), tClass));
107101
}
108102

109103
<T extends SignedTufMeta<?>> void storeRole(String roleName, T role) throws IOException {
110-
try (BufferedWriter fileWriter =
111-
Files.newBufferedWriter(repoBaseDir.resolve(roleName + ".json"))) {
104+
Path roleFile = repoBaseDir.resolve(TufNames.encode(roleName) + ".json");
105+
try (BufferedWriter fileWriter = Files.newBufferedWriter(roleFile)) {
112106
GSON.get().toJson(role, fileWriter);
113107
}
114108
}
115109

116110
@Override
117111
public void clearMeta(String role) throws IOException {
118-
Path metaFile = repoBaseDir.resolve(role + ".json");
112+
Path metaFile = repoBaseDir.resolve(TufNames.encode(role) + ".json");
119113
if (Files.isRegularFile(metaFile)) {
120114
Files.delete(metaFile);
121115
}

sigstore-java/src/main/java/dev/sigstore/tuf/MetaFetcher.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ public <T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>>
6565
}
6666

6767
private static String getFileName(String role, @Nullable Integer version) {
68+
String encodedRole = TufNames.encode(role);
6869
return version == null
69-
? role + ".json"
70-
: String.format(Locale.ROOT, "%d.%s.json", version, role);
70+
? encodedRole + ".json"
71+
: String.format(Locale.ROOT, "%d.%s.json", version, encodedRole);
7172
}
7273

7374
<T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(

sigstore-java/src/main/java/dev/sigstore/tuf/SigstoreTufClient.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@
2626
import java.net.URI;
2727
import java.nio.file.Files;
2828
import java.nio.file.Path;
29-
import java.security.InvalidKeyException;
30-
import java.security.NoSuchAlgorithmException;
31-
import java.security.spec.InvalidKeySpecException;
3229
import java.time.Duration;
3330
import java.time.Instant;
3431

@@ -149,12 +146,10 @@ public void update() throws SigstoreConfigurationException {
149146
/** Force an update, ignoring any cache validity. */
150147
public void forceUpdate() throws SigstoreConfigurationException {
151148
try {
152-
updater.update();
153-
} catch (IOException
154-
| NoSuchAlgorithmException
155-
| InvalidKeySpecException
156-
| InvalidKeyException
157-
| JsonParseException ex) {
149+
updater.refresh();
150+
updater.downloadTarget(TRUST_ROOT_FILENAME);
151+
updater.downloadTarget(SIGNING_CONFIG_FILENAME);
152+
} catch (IOException | JsonParseException ex) {
158153
throw new SigstoreConfigurationException("TUF repo failed to update", ex);
159154
}
160155
lastUpdate = Instant.now();

sigstore-java/src/main/java/dev/sigstore/tuf/TrustedMetaStore.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ public void setTargets(Targets targets) throws IOException {
110110
metaStore.writeMeta(RootRole.TARGETS, targets);
111111
}
112112

113+
public void setTargets(String roleName, Targets targets) throws IOException {
114+
metaStore.writeMeta(roleName, targets);
115+
}
116+
113117
public Targets getTargets() throws IOException, JsonParseException {
114118
return getMeta(RootRole.TARGETS, Targets.class);
115119
}
@@ -118,6 +122,10 @@ public Optional<Targets> findTargets() throws IOException, JsonParseException {
118122
return metaStore.readMeta(RootRole.TARGETS, Targets.class);
119123
}
120124

125+
public Optional<Targets> findTargets(String roleName) throws IOException, JsonParseException {
126+
return metaStore.readMeta(roleName, Targets.class);
127+
}
128+
121129
public void clearMetaDueToKeyRotation() throws IOException {
122130
metaStore.clearMeta(RootRole.TIMESTAMP);
123131
metaStore.clearMeta(RootRole.SNAPSHOT);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2022 The Sigstore Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package dev.sigstore.tuf;
17+
18+
import java.net.URLEncoder;
19+
import java.nio.charset.StandardCharsets;
20+
21+
/** URL-encodes TUF role and target names for safe use in file paths and URLs. */
22+
public class TufNames {
23+
24+
private TufNames() {}
25+
26+
/** URL-encode a name, using %20 for spaces (not +). */
27+
public static String encode(String name) {
28+
return URLEncoder.encode(name, StandardCharsets.UTF_8).replace("+", "%20");
29+
}
30+
}

0 commit comments

Comments
 (0)