33
33
import org .apache .maven .plugins .annotations .LifecyclePhase ;
34
34
import org .apache .maven .plugins .annotations .Mojo ;
35
35
import org .apache .maven .plugins .annotations .Parameter ;
36
+ import org .apache .maven .plugins .jarsigner .TsaSelector .TsaServer ;
36
37
import org .apache .maven .shared .jarsigner .JarSigner ;
37
38
import org .apache .maven .shared .jarsigner .JarSignerRequest ;
38
39
import org .apache .maven .shared .jarsigner .JarSignerSignRequest ;
@@ -73,20 +74,107 @@ public class JarsignerSignMojo extends AbstractJarsignerMojo {
73
74
private boolean removeExistingSignatures ;
74
75
75
76
/**
77
+ * <p>URL(s) to Time Stamping Authority (TSA) server(s) to use to timestamp the signing.
76
78
* See <a href="https://docs.oracle.com/javase/7/docs/technotes/tools/windows/jarsigner.html#Options">options</a>.
79
+ * Separate multiple TSA URLs with comma (without space) or a nested XML tag.</p>
80
+ *
81
+ * <pre>{@code
82
+ * <configuration>
83
+ * <tsa>http://timestamp.digicert.com,http://timestamp.globalsign.com/tsa/r6advanced1</tsa>
84
+ * </configuration>
85
+ * }</pre>
86
+ *
87
+ * <pre>{@code
88
+ * <configuration>
89
+ * <tsa>
90
+ * <url>http://timestamp.digicert.com</url>
91
+ * <url>http://timestamp.globalsign.com/tsa/r6advanced1</url>
92
+ * </tsa>
93
+ * </configuration>
94
+ * }</pre>
95
+ *
96
+ * <p>Usage of multiple TSA servers only makes sense when {@link #maxTries} is more than 1. A different TSA server
97
+ * will only be used at retries.</p>
98
+ *
99
+ * <p>Changed to a list since 3.1.0. Single XML element (without comma) is still supported.</p>
77
100
*
78
101
* @since 1.3
79
102
*/
80
103
@ Parameter (property = "jarsigner.tsa" )
81
- private String tsa ;
104
+ private String [] tsa ;
82
105
83
106
/**
84
- * See <a href="https://docs.oracle.com/javase/7/docs/technotes/tools/windows/jarsigner.html#Options">options</a>.
107
+ * <p>Alias(es) for certificate(s) in the active keystore used to find a TSA URL. From the certificate the X509v3
108
+ * extension "Subject Information Access" field is examined to find the TSA server URL. See
109
+ * <a href="https://docs.oracle.com/javase/7/docs/technotes/tools/windows/jarsigner.html#Options">options</a>.
110
+ * Separate multiple aliases with comma (without space) or a nested XML tag.</p>
111
+ *
112
+ * <pre>{@code
113
+ * <configuration>
114
+ * <tsacert>alias1,alias2</tsacert>
115
+ * </configuration>
116
+ * }</pre>
117
+ *
118
+ * <pre>{@code
119
+ * <configuration>
120
+ * <tsacert>
121
+ * <alias>alias1</alias>
122
+ * <alias>alias2</alias>
123
+ * </tsacert>
124
+ * </configuration>
125
+ * }</pre>
126
+ *
127
+ * <p>Should not be used at the same time as the {@link #tsa} parameter (because jarsigner will typically ignore
128
+ * tsacert, if tsa is set).</p>
129
+ *
130
+ * <p>Usage of multiple aliases only makes sense when {@link #maxTries} is more than 1. A different TSA server
131
+ * will only be used at retries.</p>
132
+ *
133
+ * <p>Changed to a list since 3.1.0. Single XML element (without comma) is still supported.</p>
85
134
*
86
135
* @since 1.3
87
136
*/
88
137
@ Parameter (property = "jarsigner.tsacert" )
89
- private String tsacert ;
138
+ private String [] tsacert ;
139
+
140
+ /**
141
+ * <p>OID(s) to send to the TSA server to identify the policy ID the server should use. If not specified TSA server
142
+ * will choose a default policy ID. Each TSA server vendor will typically define their own policy OIDs. See
143
+ * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jarsigner.html#CCHIFIAD">options</a>.
144
+ * Separate multiple OIDs with comma (without space) or a nested XML tag.</p>
145
+ *
146
+ * <pre>{@code
147
+ * <configuration>
148
+ * <tsapolicyid>1.3.6.1.4.1.4146.2.3.1.2,2.16.840.1.114412.7.1</tsapolicyid>
149
+ * </configuration>
150
+ * }</pre>
151
+ *
152
+ * <pre>{@code
153
+ * <configuration>
154
+ * <tsapolicyid>
155
+ * <oid>1.3.6.1.4.1.4146.2.3.1.2</oid>
156
+ * <oid>2.16.840.1.114412.7.1</oid>
157
+ * </tsapolicyid>
158
+ * </configuration>
159
+ * }</pre>
160
+ *
161
+ * <p>If used, the number of OIDs should be the same as the number of elements in {@link #tsa} or {@link #tsacert}.
162
+ * The first OID will be used for the first TSA server, the second OID for the second TSA server and so on.</p>
163
+ *
164
+ * @since 3.1.0
165
+ */
166
+ @ Parameter (property = "jarsigner.tsapolicyid" )
167
+ private String [] tsapolicyid ;
168
+
169
+ /**
170
+ * The message digest algorithm to use in the messageImprint that the TSA server will timestamp. A default value
171
+ * (for example {@code SHA-384}) will be selected by jarsigner if this parameter is not set. Only available in
172
+ * Java 11 and later. See <a href="https://docs.oracle.com/en/java/javase/11/tools/jarsigner.html">options</a>.
173
+ *
174
+ * @since 3.1.0
175
+ */
176
+ @ Parameter (property = "jarsigner.tsadigestalg" )
177
+ private String tsadigestalg ;
90
178
91
179
/**
92
180
* Location of the extra certificate chain file. See
@@ -132,6 +220,8 @@ public class JarsignerSignMojo extends AbstractJarsignerMojo {
132
220
/** Current WaitStrategy, to allow for sleeping after a signing failure. */
133
221
private WaitStrategy waitStrategy = this ::defaultWaitStrategy ;
134
222
223
+ private TsaSelector tsaSelector ;
224
+
135
225
/** Exponent limit for exponential wait after failure function. 2^20 = 1048576 sec ~= 12 days. */
136
226
private static final int MAX_WAIT_EXPONENT_ATTEMPT = 20 ;
137
227
@@ -175,6 +265,20 @@ protected void validateParameters() throws MojoExecutionException {
175
265
getLog ().warn (getMessage ("invalidThreadCount" , threadCount ));
176
266
threadCount = 1 ;
177
267
}
268
+
269
+ if (tsa .length > 0 && tsacert .length > 0 ) {
270
+ getLog ().warn (getMessage ("warnUsageTsaAndTsacertSimultaneous" ));
271
+ }
272
+ if (tsapolicyid .length > tsa .length || tsapolicyid .length > tsacert .length ) {
273
+ getLog ().warn (getMessage ("warnUsageTsapolicyidTooMany" , tsapolicyid .length , tsa .length , tsacert .length ));
274
+ }
275
+ if (tsa .length > 1 && maxTries == 1 ) {
276
+ getLog ().warn (getMessage ("warnUsageMultiTsaWithoutRetry" , tsa .length ));
277
+ }
278
+ if (tsacert .length > 1 && maxTries == 1 ) {
279
+ getLog ().warn (getMessage ("warnUsageMultiTsacertWithoutRetry" , tsacert .length ));
280
+ }
281
+ tsaSelector = new TsaSelector (tsa , tsacert , tsapolicyid , tsadigestalg );
178
282
}
179
283
180
284
/**
@@ -184,15 +288,22 @@ protected void validateParameters() throws MojoExecutionException {
184
288
protected JarSignerRequest createRequest (File archive ) throws MojoExecutionException {
185
289
JarSignerSignRequest request = new JarSignerSignRequest ();
186
290
request .setSigfile (sigfile );
187
- request .setTsaLocation (tsa );
188
- request .setTsaAlias (tsacert );
291
+ updateJarSignerRequestWithTsa (request , tsaSelector .getServer ());
189
292
request .setCertchain (certchain );
190
293
191
294
// Special handling for passwords through the Maven Security Dispatcher
192
295
request .setKeypass (decrypt (keypass ));
193
296
return request ;
194
297
}
195
298
299
+ /** Modifies JarSignerRequest with TSA parameters */
300
+ private void updateJarSignerRequestWithTsa (JarSignerSignRequest request , TsaServer tsaServer ) {
301
+ request .setTsaLocation (tsaServer .getTsaUrl ());
302
+ request .setTsaAlias (tsaServer .getTsaAlias ());
303
+ request .setTsapolicyid (tsaServer .getTsaPolicyId ());
304
+ request .setTsadigestalg (tsaServer .getTsaDigestAlt ());
305
+ }
306
+
196
307
/**
197
308
* {@inheritDoc} Processing of files may be parallelized for increased performance.
198
309
*/
@@ -202,7 +313,7 @@ protected void processArchives(List<File> archives) throws MojoExecutionExceptio
202
313
List <Future <Void >> futures = archives .stream ()
203
314
.map (file -> executor .submit ((Callable <Void >) () -> {
204
315
processArchive (file );
205
- return null ;
316
+ return null ; // Return dummy value to conform with Void type
206
317
}))
207
318
.collect (Collectors .toList ());
208
319
try {
@@ -236,15 +347,18 @@ protected void executeJarSigner(JarSigner jarSigner, JarSignerRequest request)
236
347
for (int attempt = 0 ; attempt < maxTries ; attempt ++) {
237
348
JavaToolResult result = jarSigner .execute (request );
238
349
int resultCode = result .getExitCode ();
239
- Commandline commandLine = result .getCommandline ();
240
350
if (resultCode == 0 ) {
241
351
return ;
242
352
}
353
+ tsaSelector .registerFailure (); // Could be TSA server problem or something unrelated to TSA
354
+
243
355
if (attempt < maxTries - 1 ) { // If not last attempt
244
356
waitStrategy .waitAfterFailure (attempt , Duration .ofSeconds (maxRetryDelaySeconds ));
357
+ updateJarSignerRequestWithTsa ((JarSignerSignRequest ) request , tsaSelector .getServer ());
245
358
} else {
246
359
// Last attempt failed, use this failure as resulting failure
247
- throw new MojoExecutionException (getMessage ("failure" , getCommandlineInfo (commandLine ), resultCode ));
360
+ throw new MojoExecutionException (
361
+ getMessage ("failure" , getCommandlineInfo (result .getCommandline ()), resultCode ));
248
362
}
249
363
}
250
364
}
0 commit comments