You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

SignJar.java 10 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. * Copyright 2000-2004 The Apache Software Foundation
  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. */
  17. package org.apache.tools.ant.taskdefs;
  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.util.Enumeration;
  21. import java.util.Vector;
  22. import java.util.zip.ZipEntry;
  23. import java.util.zip.ZipFile;
  24. import org.apache.tools.ant.BuildException;
  25. import org.apache.tools.ant.DirectoryScanner;
  26. import org.apache.tools.ant.Project;
  27. import org.apache.tools.ant.Task;
  28. import org.apache.tools.ant.taskdefs.condition.IsSigned;
  29. import org.apache.tools.ant.types.FileSet;
  30. import org.apache.tools.ant.util.JavaEnvUtils;
  31. import org.apache.tools.ant.util.FileUtils;
  32. /**
  33. * Signs JAR or ZIP files with the javasign command line tool. The
  34. * tool detailed dependency checking: files are only signed if they
  35. * are not signed. The <tt>signjar</tt> attribute can point to the file to
  36. * generate; if this file exists then
  37. * its modification date is used as a cue as to whether to resign any JAR file.
  38. *
  39. * @since Ant 1.1
  40. * @ant.task category="java"
  41. */
  42. public class SignJar extends Task {
  43. /**
  44. * The name of the jar file.
  45. */
  46. protected File jar;
  47. /**
  48. * The alias of signer.
  49. */
  50. protected String alias;
  51. /**
  52. * The name of keystore file.
  53. */
  54. private String keystore;
  55. protected String storepass;
  56. protected String storetype;
  57. protected String keypass;
  58. protected String sigfile;
  59. protected File signedjar;
  60. protected boolean verbose;
  61. protected boolean internalsf;
  62. protected boolean sectionsonly;
  63. protected boolean preserveLastModified;
  64. /** The maximum amount of memory to use for Jar signer */
  65. private String maxMemory;
  66. /**
  67. * the filesets of the jars to sign
  68. */
  69. protected Vector filesets = new Vector();
  70. /**
  71. * Whether to assume a jar which has an appropriate .SF file in is already
  72. * signed.
  73. */
  74. protected boolean lazy;
  75. /**
  76. * Set the maximum memory to be used by the jarsigner process
  77. *
  78. * @param max a string indicating the maximum memory according to the
  79. * JVM conventions (e.g. 128m is 128 Megabytes)
  80. */
  81. public void setMaxmemory(String max) {
  82. maxMemory = max;
  83. }
  84. /**
  85. * the jar file to sign; required
  86. */
  87. public void setJar(final File jar) {
  88. this.jar = jar;
  89. }
  90. /**
  91. * the alias to sign under; required
  92. */
  93. public void setAlias(final String alias) {
  94. this.alias = alias;
  95. }
  96. /**
  97. * keystore location; required
  98. */
  99. public void setKeystore(final String keystore) {
  100. this.keystore = keystore;
  101. }
  102. /**
  103. * password for keystore integrity; required
  104. */
  105. public void setStorepass(final String storepass) {
  106. this.storepass = storepass;
  107. }
  108. /**
  109. * keystore type; optional
  110. */
  111. public void setStoretype(final String storetype) {
  112. this.storetype = storetype;
  113. }
  114. /**
  115. * password for private key (if different); optional
  116. */
  117. public void setKeypass(final String keypass) {
  118. this.keypass = keypass;
  119. }
  120. /**
  121. * name of .SF/.DSA file; optional
  122. */
  123. public void setSigfile(final String sigfile) {
  124. this.sigfile = sigfile;
  125. }
  126. /**
  127. * name of signed JAR file; optional
  128. */
  129. public void setSignedjar(final File signedjar) {
  130. this.signedjar = signedjar;
  131. }
  132. /**
  133. * Enable verbose output when signing
  134. * ; optional: default false
  135. */
  136. public void setVerbose(final boolean verbose) {
  137. this.verbose = verbose;
  138. }
  139. /**
  140. * Flag to include the .SF file inside the signature;
  141. * optional; default false
  142. */
  143. public void setInternalsf(final boolean internalsf) {
  144. this.internalsf = internalsf;
  145. }
  146. /**
  147. * flag to compute hash of entire manifest;
  148. * optional, default false
  149. */
  150. public void setSectionsonly(final boolean sectionsonly) {
  151. this.sectionsonly = sectionsonly;
  152. }
  153. /**
  154. * flag to control whether the presence of a signature
  155. * file means a JAR is signed;
  156. * optional, default false
  157. */
  158. public void setLazy(final boolean lazy) {
  159. this.lazy = lazy;
  160. }
  161. /**
  162. * Adds a set of files to sign
  163. * @since Ant 1.4
  164. */
  165. public void addFileset(final FileSet set) {
  166. filesets.addElement(set);
  167. }
  168. /**
  169. * sign the jar(s)
  170. */
  171. public void execute() throws BuildException {
  172. if (null == jar && filesets.size() == 0) {
  173. throw new BuildException("jar must be set through jar attribute "
  174. + "or nested filesets");
  175. }
  176. if (null != jar) {
  177. if (filesets.size() != 0) {
  178. log("nested filesets will be ignored if the jar attribute has"
  179. + " been specified.", Project.MSG_WARN);
  180. }
  181. doOneJar(jar, signedjar);
  182. return;
  183. } else {
  184. // deal with the filesets
  185. for (int i = 0; i < filesets.size(); i++) {
  186. FileSet fs = (FileSet) filesets.elementAt(i);
  187. DirectoryScanner ds = fs.getDirectoryScanner(getProject());
  188. String[] jarFiles = ds.getIncludedFiles();
  189. for (int j = 0; j < jarFiles.length; j++) {
  190. doOneJar(new File(fs.getDir(getProject()), jarFiles[j]), null);
  191. }
  192. }
  193. }
  194. }
  195. /**
  196. * sign one jar
  197. */
  198. private void doOneJar(File jarSource, File jarTarget)
  199. throws BuildException {
  200. if (null == alias) {
  201. throw new BuildException("alias attribute must be set");
  202. }
  203. if (null == storepass) {
  204. throw new BuildException("storepass attribute must be set");
  205. }
  206. if (isUpToDate(jarSource, jarTarget)) {
  207. return;
  208. }
  209. long lastModified = jarSource.lastModified();
  210. final ExecTask cmd = (ExecTask) getProject().createTask("exec");
  211. cmd.setExecutable(JavaEnvUtils.getJdkExecutable("jarsigner"));
  212. if (maxMemory != null) {
  213. cmd.createArg().setValue("-J-Xmx" + maxMemory);
  214. }
  215. if (null != keystore) {
  216. // is the keystore a file
  217. File keystoreFile = getProject().resolveFile(keystore);
  218. if (keystoreFile.exists()) {
  219. cmd.createArg().setValue("-keystore");
  220. cmd.createArg().setValue(keystoreFile.getPath());
  221. } else {
  222. // must be a URL - just pass as is
  223. cmd.createArg().setValue("-keystore");
  224. cmd.createArg().setValue(keystore);
  225. }
  226. }
  227. if (null != storepass) {
  228. cmd.createArg().setValue("-storepass");
  229. cmd.createArg().setValue(storepass);
  230. }
  231. if (null != storetype) {
  232. cmd.createArg().setValue("-storetype");
  233. cmd.createArg().setValue(storetype);
  234. }
  235. if (null != keypass) {
  236. cmd.createArg().setValue("-keypass");
  237. cmd.createArg().setValue(keypass);
  238. }
  239. if (null != sigfile) {
  240. cmd.createArg().setValue("-sigfile");
  241. cmd.createArg().setValue(sigfile);
  242. }
  243. if (null != jarTarget) {
  244. cmd.createArg().setValue("-signedjar");
  245. cmd.createArg().setValue(jarTarget.toString());
  246. }
  247. if (verbose) {
  248. cmd.createArg().setValue("-verbose");
  249. }
  250. if (internalsf) {
  251. cmd.createArg().setValue("-internalsf");
  252. }
  253. if (sectionsonly) {
  254. cmd.createArg().setValue("-sectionsonly");
  255. }
  256. cmd.createArg().setValue(jarSource.toString());
  257. cmd.createArg().setValue(alias);
  258. log("Signing JAR: " + jarSource.getAbsolutePath());
  259. cmd.setFailonerror(true);
  260. cmd.setTaskName(getTaskName());
  261. cmd.execute();
  262. // restore the lastModified attribute
  263. if (preserveLastModified) {
  264. if (jarTarget != null) {
  265. jarTarget.setLastModified(lastModified);
  266. } else {
  267. jarSource.setLastModified(lastModified);
  268. }
  269. }
  270. }
  271. protected boolean isUpToDate(File jarFile, File signedjarFile) {
  272. if (null == jarFile) {
  273. return false;
  274. }
  275. if (null != signedjarFile) {
  276. if (!jarFile.exists()) {
  277. return false;
  278. }
  279. if (!signedjarFile.exists()) {
  280. return false;
  281. }
  282. if (jarFile.equals(signedjarFile)) {
  283. return false;
  284. }
  285. if (FileUtils.newFileUtils().isUpToDate(jarFile, signedjarFile)) {
  286. return true;
  287. }
  288. } else {
  289. if (lazy) {
  290. return isSigned(jarFile);
  291. }
  292. }
  293. return false;
  294. }
  295. /**
  296. * test for a file being signed, by looking for a signature in the META-INF
  297. * directory
  298. * @param file
  299. * @return true if the file is signed
  300. */
  301. protected boolean isSigned(File file) {
  302. try {
  303. return IsSigned.isSigned(file, alias);
  304. } catch (IOException e) {
  305. return false;
  306. }
  307. }
  308. /**
  309. * true to indicate that the signed jar modification date remains the same as the original.
  310. * Defaults to false
  311. * @param preserveLastModified if true preserve the last modified time
  312. */
  313. public void setPreserveLastModified(boolean preserveLastModified) {
  314. this.preserveLastModified = preserveLastModified;
  315. }
  316. }