Skip to content

Commit 28f0b57

Browse files
committed
fix: add support for multiple checksum algorithms
1 parent c8855e3 commit 28f0b57

5 files changed

Lines changed: 121 additions & 29 deletions

File tree

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,11 @@
199199
<artifactId>commons-compress</artifactId>
200200
<version>1.28.0</version>
201201
</dependency>
202+
<dependency>
203+
<groupId>org.apache.commons</groupId>
204+
<artifactId>commons-lang3</artifactId>
205+
<version>3.20.0</version>
206+
</dependency>
202207
<dependency>
203208
<groupId>org.apache.maven.plugins</groupId>
204209
<artifactId>maven-gpg-plugin</artifactId>

src/main/java/org/apache/commons/release/plugin/internal/ArtifactUtils.java

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
package org.apache.commons.release.plugin.internal;
1818

1919
import java.io.IOException;
20+
import java.util.Collections;
2021
import java.util.HashMap;
2122
import java.util.Map;
2223

2324
import org.apache.commons.codec.digest.DigestUtils;
25+
import org.apache.commons.lang3.StringUtils;
2426
import org.apache.commons.release.plugin.slsa.v1_2.ResourceDescriptor;
2527
import org.apache.maven.artifact.Artifact;
2628
import org.apache.maven.plugin.MojoExecutionException;
@@ -30,6 +32,35 @@
3032
*/
3133
public final class ArtifactUtils {
3234

35+
/**
36+
* Maps standard JDK {@link java.security.MessageDigest} algorithm names to the in-toto digest names used in SLSA {@link ResourceDescriptor} digest sets.
37+
*
38+
* <p>JDK algorithms that have no in-toto equivalent (such as {@code MD2}) are omitted.</p>
39+
*
40+
* @see <a href="https://docs.oracle.com/en/java/javase/25/docs/specs/security/standard-names.html#messagedigest-algorithms">
41+
* JDK standard {@code MessageDigest} algorithm names</a>
42+
* @see <a href="https://github.com/in-toto/attestation/blob/main/spec/v1/digest_set.md">
43+
* in-toto digest set specification</a>
44+
*/
45+
private static final Map<String, String> IN_TOTO_DIGEST_NAMES;
46+
47+
static {
48+
final Map<String, String> m = new HashMap<>();
49+
m.put("MD5", "md5");
50+
m.put("SHA-1", "sha1");
51+
m.put("SHA-224", "sha224");
52+
m.put("SHA-256", "sha256");
53+
m.put("SHA-384", "sha384");
54+
m.put("SHA-512", "sha512");
55+
m.put("SHA-512/224", "sha512_224");
56+
m.put("SHA-512/256", "sha512_256");
57+
m.put("SHA3-224", "sha3_224");
58+
m.put("SHA3-256", "sha3_256");
59+
m.put("SHA3-384", "sha3_384");
60+
m.put("SHA3-512", "sha3_512");
61+
IN_TOTO_DIGEST_NAMES = Collections.unmodifiableMap(m);
62+
}
63+
3364
/** No instances. */
3465
private ArtifactUtils() {
3566
// prevent instantiation
@@ -84,31 +115,40 @@ public static String getPackageUrl(Artifact artifact) {
84115
* Gets a map of checksum algorithm names to hex-encoded digest values for the given artifact file.
85116
*
86117
* @param artifact A Maven artifact.
118+
* @param algorithms JSSE names of algorithms to use
87119
* @return A map of checksum algorithm names to hex-encoded digest values.
88120
* @throws IOException If an I/O error occurs reading the artifact file.
121+
* @throws IllegalArgumentException If any of the algorithms is not supported.
89122
*/
90-
private static Map<String, String> getChecksums(Artifact artifact) throws IOException {
123+
private static Map<String, String> getChecksums(Artifact artifact, String... algorithms) throws IOException {
91124
Map<String, String> checksums = new HashMap<>();
92-
DigestUtils digest = new DigestUtils(DigestUtils.getSha256Digest());
93-
String sha256sum = digest.digestAsHex(artifact.getFile());
94-
checksums.put("sha256", sha256sum);
125+
for (String algorithm : algorithms) {
126+
String key = IN_TOTO_DIGEST_NAMES.get(algorithm);
127+
if (key == null) {
128+
throw new IllegalArgumentException("Invalid algorithm name for in-toto attestation: " + algorithm);
129+
}
130+
DigestUtils digest = new DigestUtils(DigestUtils.getDigest(algorithm));
131+
String checksum = digest.digestAsHex(artifact.getFile());
132+
checksums.put(key, checksum);
133+
}
95134
return checksums;
96135
}
97136

98137
/**
99138
* Converts a Maven artifact to a SLSA {@link ResourceDescriptor}.
100139
*
101140
* @param artifact A Maven artifact.
141+
* @param algorithms A comma-separated list of checksum algorithms to use.
102142
* @return A SLSA resource descriptor.
103143
* @throws MojoExecutionException If an I/O error occurs retrieving the artifact.
104144
*/
105-
public static ResourceDescriptor toResourceDescriptor(Artifact artifact) throws MojoExecutionException {
145+
public static ResourceDescriptor toResourceDescriptor(Artifact artifact, String algorithms) throws MojoExecutionException {
106146
ResourceDescriptor descriptor = new ResourceDescriptor();
107147
descriptor.setName(getFileName(artifact));
108148
descriptor.setUri(getPackageUrl(artifact));
109149
if (artifact.getFile() != null) {
110150
try {
111-
descriptor.setDigest(getChecksums(artifact));
151+
descriptor.setDigest(getChecksums(artifact, StringUtils.split(algorithms, ",")));
112152
} catch (IOException e) {
113153
throw new MojoExecutionException("Unable to compute hash for artifact file: " + artifact.getFile(), e);
114154
}

src/main/java/org/apache/commons/release/plugin/mojos/BuildAttestationMojo.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ public class BuildAttestationMojo extends AbstractMojo {
128128
@Parameter(property = "commons.release.signAttestation", defaultValue = "true")
129129
private boolean signAttestation;
130130

131+
/**
132+
* Checksum algorithms used in the generated attestation.
133+
*/
134+
@Parameter(property = "commons.release.checksums.algorithms", defaultValue = "SHA-512,SHA-256,SHA-1,MD5")
135+
private String algorithmNames;
136+
131137
/**
132138
* Path to the GPG executable; if not set, {@code gpg} is resolved from {@code PATH}.
133139
*/
@@ -278,6 +284,15 @@ void setSigner(final AbstractGpgSigner signer) {
278284
this.signer = signer;
279285
}
280286

287+
/**
288+
* Sets the list of checksum algorithms to use.
289+
*
290+
* @param algorithmNames A comma-separated list of {@link java.security.MessageDigest} algorithm names to use.
291+
*/
292+
void setAlgorithmNames(String algorithmNames) {
293+
this.algorithmNames = algorithmNames;
294+
}
295+
281296
/**
282297
* Gets the GPG signer, creating and preparing it from plugin parameters if not already set.
283298
*
@@ -413,9 +428,9 @@ private void writeAndAttach(final Object value, final Path artifactPath) throws
413428
*/
414429
private List<ResourceDescriptor> getSubjects() throws MojoExecutionException {
415430
List<ResourceDescriptor> subjects = new ArrayList<>();
416-
subjects.add(ArtifactUtils.toResourceDescriptor(project.getArtifact()));
431+
subjects.add(ArtifactUtils.toResourceDescriptor(project.getArtifact(), algorithmNames));
417432
for (Artifact artifact : project.getAttachedArtifacts()) {
418-
subjects.add(ArtifactUtils.toResourceDescriptor(artifact));
433+
subjects.add(ArtifactUtils.toResourceDescriptor(artifact, algorithmNames));
419434
}
420435
return subjects;
421436
}
@@ -449,7 +464,7 @@ private List<ResourceDescriptor> getBuildDependencies() throws MojoExecutionExce
449464
private List<ResourceDescriptor> getProjectDependencies() throws MojoExecutionException {
450465
List<ResourceDescriptor> dependencies = new ArrayList<>();
451466
for (Artifact artifact : project.getArtifacts()) {
452-
dependencies.add(ArtifactUtils.toResourceDescriptor(artifact));
467+
dependencies.add(ArtifactUtils.toResourceDescriptor(artifact, algorithmNames));
453468
}
454469
return dependencies;
455470
}

src/test/java/org/apache/commons/release/plugin/mojos/BuildAttestationMojoTest.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ private static BuildAttestationMojo createBuildAttestationMojo(MavenProject proj
112112
createMavenSession(createMavenExecutionRequest(), new DefaultMavenExecutionResult()), projectHelper);
113113
}
114114

115+
private static void configureBuildAttestationMojo(BuildAttestationMojo mojo, boolean signAttestation) {
116+
mojo.setOutputDirectory(new File("target/attestations"));
117+
mojo.setScmDirectory(new File("."));
118+
mojo.setScmConnectionUrl("scm:git:https://github.com/apache/commons-text.git");
119+
mojo.setMavenHome(new File(System.getProperty("maven.home", ".")));
120+
mojo.setAlgorithmNames("SHA-512,SHA-256,SHA-1,MD5");
121+
mojo.setSignAttestation(signAttestation);
122+
mojo.setSigner(createMockSigner());
123+
}
124+
115125
private static MavenProject createMavenProject(MavenProjectHelper projectHelper, MavenRepositorySystem repoSystem) throws Exception {
116126
File pomFile = new File(ARTIFACTS_DIR + "commons-text-1.4.pom");
117127
Model model;
@@ -209,10 +219,7 @@ void attestationTest() throws Exception {
209219
MavenProject project = createMavenProject(projectHelper, repoSystem);
210220

211221
BuildAttestationMojo mojo = createBuildAttestationMojo(project, projectHelper);
212-
mojo.setOutputDirectory(new File("target/attestations"));
213-
mojo.setScmDirectory(new File("."));
214-
mojo.setScmConnectionUrl("scm:git:https://github.com/apache/commons-text.git");
215-
mojo.setMavenHome(new File(System.getProperty("maven.home", ".")));
222+
configureBuildAttestationMojo(mojo, false);
216223
mojo.execute();
217224

218225
JsonNode statement = OBJECT_MAPPER.readTree(getAttestation(project).getFile());
@@ -226,12 +233,7 @@ void signingTest() throws Exception {
226233
MavenProject project = createMavenProject(projectHelper, repoSystem);
227234

228235
BuildAttestationMojo mojo = createBuildAttestationMojo(project, projectHelper);
229-
mojo.setOutputDirectory(new File("target/attestations"));
230-
mojo.setScmDirectory(new File("."));
231-
mojo.setScmConnectionUrl("scm:git:https://github.com/apache/commons-text.git");
232-
mojo.setMavenHome(new File(System.getProperty("maven.home", ".")));
233-
mojo.setSignAttestation(true);
234-
mojo.setSigner(createMockSigner());
236+
configureBuildAttestationMojo(mojo, true);
235237
mojo.execute();
236238

237239
String envelopeJson = new String(Files.readAllBytes(getAttestation(project).getFile().toPath()), StandardCharsets.UTF_8);

src/test/resources/attestations/commons-text-1.4.intoto.json

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,70 +4,100 @@
44
"name": "commons-text-1.4.jar",
55
"uri": "pkg:maven/commons-text/commons-text@1.4?type=jar",
66
"digest": {
7-
"sha256": "ad2d2eacf15ab740c115294afc1192603d8342004a6d7d0ad35446f7dda8a134"
7+
"md5": "9cbe22bb0ce86c70779213dfb7f3eb5a",
8+
"sha1": "c81f089b3542485d4d09b02aae822906e5d2f209",
9+
"sha256": "ad2d2eacf15ab740c115294afc1192603d8342004a6d7d0ad35446f7dda8a134",
10+
"sha512": "126302c5f6865733774eb41fecc10ba8d0bb5ba11d14b9562047429abeb13bf8cdcdbfdf5e7d7708e2a40f67f4265cbbce609164f57abcd676067a840aa48e6a"
811
}
912
},
1013
{
1114
"name": "commons-text-1.4.pom",
1215
"uri": "pkg:maven/commons-text/commons-text@1.4?type=pom",
1316
"digest": {
14-
"sha256": "4d6277b1e0720bb054c640620679a9da120f753029342150e714095f48934d76"
17+
"md5": "00045f652e3dc8970442ce819806db34",
18+
"sha1": "26fa30e496321e74c77ad66781ba53448e6e3a68",
19+
"sha256": "4d6277b1e0720bb054c640620679a9da120f753029342150e714095f48934d76",
20+
"sha512": "db8934f3062ea9c965ea27cfe4517a25513fb7cebe35ed02bedc1d8287b01c7ba64c93a8a261325fe12ab6957cbd80dbc8c06ec34c9a23c5a5c89ef6bace88fe"
1521
}
1622
},
1723
{
1824
"name": "commons-text-1.4-sources.jar",
1925
"uri": "pkg:maven/commons-text/commons-text@1.4?classifier=sources&type=jar",
2026
"digest": {
21-
"sha256": "58a95591fe7fc94db94a0a9e64b4a5bcc1c49edf17f2b24d7c0747357d855761"
27+
"md5": "21af10902cea10cf54bc9acf956863d4",
28+
"sha1": "cadbe9d3980a21e6eaec3aad629bbcdb7714aa3f",
29+
"sha256": "58a95591fe7fc94db94a0a9e64b4a5bcc1c49edf17f2b24d7c0747357d855761",
30+
"sha512": "c91ed209fa97c5e69e21d3a29d1f2ea90f2f77451762b3c387a8cb94dea167b4d3f04ea1a8635232476d804f40935698b4f8884fd43520bcc79b3a0f9a757716"
2231
}
2332
},
2433
{
2534
"name": "commons-text-1.4-javadoc.jar",
2635
"uri": "pkg:maven/commons-text/commons-text@1.4?classifier=javadoc&type=jar",
2736
"digest": {
28-
"sha256": "42f5b341d0fbeaa30b06aed90612840bc513fb39792c3d39446510670216e8b1"
37+
"md5": "2ad93e1d99c0b80cbf6872d1762d7297",
38+
"sha1": "9f06cdf753e1bb512e7640ec5fcce83f5a19ba2c",
39+
"sha256": "42f5b341d0fbeaa30b06aed90612840bc513fb39792c3d39446510670216e8b1",
40+
"sha512": "052ab4e9facfc64f265a567607d40d37620b616908ce71405cae9cd30ad6ac9f2558663029933f90df67c1e748ac81451a32e28975dc773c2c7476c489146c30"
2941
}
3042
},
3143
{
3244
"name": "commons-text-1.4-tests.jar",
3345
"uri": "pkg:maven/commons-text/commons-text@1.4?classifier=tests&type=jar",
3446
"digest": {
35-
"sha256": "e4e365d08d601a4bda44be2a31f748b96762504d301742d4a0f7f5953d4c793a"
47+
"md5": "9820547734aff2c17c4a696bbd7d8d5e",
48+
"sha1": "dbfb945a12375e9fe06558840b43f35374c391ff",
49+
"sha256": "e4e365d08d601a4bda44be2a31f748b96762504d301742d4a0f7f5953d4c793a",
50+
"sha512": "a8e373cf10a9dc2d3c1cfdd43b23910c9ca9d83dea4e566772dd1ebe5e28419777e0d83b002e8cf950f7bde3218b714e0cc3718464ee34ecda77f603e260ab20"
3651
}
3752
},
3853
{
3954
"name": "commons-text-1.4-test-sources.jar",
4055
"uri": "pkg:maven/commons-text/commons-text@1.4?classifier=test-sources&type=jar",
4156
"digest": {
42-
"sha256": "9200a2a41b35f2d6d30c1c698308591cf577547ec39514657dff0e2f7dff18ca"
57+
"md5": "340231a697e2862c8d820de419a91d3e",
58+
"sha1": "5e107fc877c67992948620a8a2d9bb94cab21aa0",
59+
"sha256": "9200a2a41b35f2d6d30c1c698308591cf577547ec39514657dff0e2f7dff18ca",
60+
"sha512": "02b405eb9aff57959a3e066030745be47b76c71af71f86e06fd5004602a399cdf86b1149554e92e9922d9da2fd2239dcf6e8c783462167320838dd7662405b30"
4361
}
4462
},
4563
{
4664
"name": "commons-text-1.4-bin.tar.gz",
4765
"uri": "pkg:maven/commons-text/commons-text@1.4?classifier=bin&type=tar.gz",
4866
"digest": {
49-
"sha256": "8b9393f7ddc2efb69d8c2b6f4d85d8711dddfe77009799cf21619fc9b8411897"
67+
"md5": "9fe25162590be6fa684a9d9cdc0b505d",
68+
"sha1": "6f46fd82d5ccf9644a37bcec6f2158a52ebdbab8",
69+
"sha256": "8b9393f7ddc2efb69d8c2b6f4d85d8711dddfe77009799cf21619fc9b8411897",
70+
"sha512": "c76f4e5814c0533030fecf0ef7639ce68df54b76ebc1320d9c4e3b8dff0a90c95ce0a425b8df6a0d742f6e9fca8dce6f08632d576c6a99357fdd54b9435fed6c"
5071
}
5172
},
5273
{
5374
"name": "commons-text-1.4-bin.zip",
5475
"uri": "pkg:maven/commons-text/commons-text@1.4?classifier=bin&type=zip",
5576
"digest": {
56-
"sha256": "ad3732dcb38e510b1dbb1544115d0eb797fab61afe0008fdb187cd4ef1706cd7"
77+
"md5": "e29e5290b7420ba1908c418fc5bc7f8a",
78+
"sha1": "447a051d6c8292c7e4d7641ca6586b335ef13bd6",
79+
"sha256": "ad3732dcb38e510b1dbb1544115d0eb797fab61afe0008fdb187cd4ef1706cd7",
80+
"sha512": "040634b27146e2008bf953f1bb63f8ccbb63cdaaaf24beb17acc6782d31452214e755539c2df737e46e7ede5d4e376cb3de5bbf72ceba5409b43f25612c2bf40"
5781
}
5882
},
5983
{
6084
"name": "commons-text-1.4-src.tar.gz",
6185
"uri": "pkg:maven/commons-text/commons-text@1.4?classifier=src&type=tar.gz",
6286
"digest": {
63-
"sha256": "1cb8536c375c3cff66757fd40c2bf878998254ba0a247866a6536bd48ba2e88a"
87+
"md5": "be130c23d3b6630824e2a08530bd4581",
88+
"sha1": "0dcee421c4e03d6bc098a61a5cdcc90656856611",
89+
"sha256": "1cb8536c375c3cff66757fd40c2bf878998254ba0a247866a6536bd48ba2e88a",
90+
"sha512": "8279eb7f45009f11658c256b07cfb06c5a45ef89949e78a67e5d64520d957707f90a9614c95e8aac350a07a54f9160f0802dbd1efc0769a5b1391e52ee4cd51b"
6491
}
6592
},
6693
{
6794
"name": "commons-text-1.4-src.zip",
6895
"uri": "pkg:maven/commons-text/commons-text@1.4?classifier=src&type=zip",
6996
"digest": {
70-
"sha256": "e4a6c992153faae4f7faff689b899073000364e376736b9746a5d0acb9d8b980"
97+
"md5": "fd65603e930f2b0805c809aa2deb1498",
98+
"sha1": "ca1cc6fbb4e46b44f8bb09b70c9e3a2ae3c5fce8",
99+
"sha256": "e4a6c992153faae4f7faff689b899073000364e376736b9746a5d0acb9d8b980",
100+
"sha512": "79ca61ff7b287407428bbb6ae13c6d372dcd0665114c55cd5bc57978a6fa760305e32feabef62cfeb0c4181220a59406239f6cccaa9a25c68773eef0250cb3a9"
71101
}
72102
}
73103
],

0 commit comments

Comments
 (0)