View Javadoc
1   package org.codehaus.mojo.webstart.sign;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.plugin.MojoExecutionException;
23  import org.apache.maven.shared.jarsigner.JarSignerRequest;
24  import org.apache.maven.shared.jarsigner.JarSignerSignRequest;
25  import org.apache.maven.shared.jarsigner.JarSignerVerifyRequest;
26  import org.codehaus.mojo.keytool.requests.KeyToolGenerateKeyPairRequest;
27  import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
28  import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;
29  
30  import java.io.File;
31  import java.util.ArrayList;
32  import java.util.Collections;
33  import java.util.List;
34  
35  /**
36   * Bean that represents the JarSigner configuration.
37   *
38   * @author <a href="jerome@coffeebreaks.org">Jerome Lacoste</a>
39   * @version $Id$
40   */
41  public class SignConfig
42  {
43  
44      /**
45       *
46       */
47      private File workDirectory;
48  
49      /**
50       *
51       */
52      private boolean verbose;
53  
54      /**
55       *
56       */
57      private KeystoreConfig keystoreConfig;
58  
59      /**
60       */
61      private String keystore;
62  
63      /**
64       */
65      private File workingKeystore;
66  
67      /**
68       */
69      private String keyalg;
70  
71      /**
72       */
73      private String keysize;
74  
75      /**
76       */
77      private String sigalg;
78  
79      /**
80       */
81      private String sigfile;
82  
83      /**
84       */
85      private String storetype;
86  
87      /**
88       */
89      private String storepass;
90  
91      /**
92       */
93      private String keypass;
94  
95      /**
96       */
97      private String validity;
98  
99      /**
100      */
101     private String dnameCn;
102 
103     /**
104      */
105     private String dnameOu;
106 
107     /**
108      */
109     private String dnameL;
110 
111     /**
112      */
113     private String dnameSt;
114 
115     /**
116      */
117     private String dnameO;
118 
119     /**
120      */
121     private String dnameC;
122 
123     /**
124      */
125     private String alias;
126 
127     /**
128      * Whether we want to auto-verify the signed jars.
129      */
130     private boolean verify;
131 
132     /**
133      * Optinal max memory to use.
134      */
135     private String maxMemory;
136 
137     /**
138      * To use tsa location.
139      *
140      * @since 1.0-beta-5
141      */
142     private String tsaLocation;
143 
144     /**
145      * @since 1.0-beta-7
146      */
147     private SecDispatcher securityDispatcher;
148 
149     /**
150      * Provides custom arguements to pass to the signtool.
151      */
152     private List<String> arguments;
153 
154 
155     /**
156      * Optional host name of the HTTP proxy host used for accessing the
157      * {@link #tsaLocation trusted timestamping server}.
158      *
159      * @since 1.0-beta-7
160      */
161     private String httpProxyHost;
162 
163     /**
164      * Optional port of the HTTP proxy host used for accessing the
165      * {@link #tsaLocation trusted timestamping server}.
166      *
167      * @since 1.0-beta-7
168      */
169     private String httpProxyPort;
170 
171     /**
172      * Optional host name of the HTTPS proxy host used for accessing the
173      * {@link #tsaLocation trusted timestamping server}.
174      *
175      * @since 1.0-beta-7
176      */
177     private String httpsProxyHost;
178 
179     /**
180      * Optional port of the HTTPS proxy host used for accessing the
181      * {@link #tsaLocation trusted timestamping server}.
182      *
183      * @since 1.0-beta-7
184      */
185     private String httpsProxyPort;
186 
187     /**
188      * Called before any Jars get signed or verified.
189      * <p/>
190      * This method allows you to create any keys or perform any initialisation that the
191      * method of signature that you're implementing requires.
192      *
193      * @param workDirectory      working directory
194      * @param verbose            verbose flag coming from the mojo configuration
195      * @param signTool           the sign tool used eventually to create or delete key store
196      * @param securityDispatcher component to decrypt a string, passed to it
197      * @param classLoader        classloader where to find keystore (if not generating a new one)
198      * @throws MojoExecutionException if something wrong occurs while init (mainly when preparing keys)
199      */
200     public void init( File workDirectory, boolean verbose, SignTool signTool, SecDispatcher securityDispatcher,
201                       ClassLoader classLoader )
202         throws MojoExecutionException
203     {
204         this.workDirectory = workDirectory;
205         this.securityDispatcher = securityDispatcher;
206         setVerbose( verbose );
207 
208         if ( workingKeystore == null )
209         {
210             // use a default workingKeystore file
211             workingKeystore = new File( workDirectory, "workingKeystore" );
212         }
213 
214         if ( keystoreConfig != null && keystoreConfig.isGen() )
215         {
216             File keystoreFile = new File( getKeystore() );
217 
218             if ( keystoreConfig.isDelete() )
219             {
220                 signTool.deleteKeyStore( keystoreFile, isVerbose() );
221             }
222 
223             signTool.generateKey( this, keystoreFile );
224         }
225         else
226         {
227             // try to locate key store from any location
228             File keystoreFile = signTool.getKeyStoreFile( getKeystore(), workingKeystore, classLoader );
229 
230             // now we will use this key store path
231             setKeystore( keystoreFile.getAbsolutePath() );
232         }
233 
234         // at the end keystore file must exists
235         File keystoreFile = new File( getKeystore() );
236 
237         if ( !keystoreFile.exists() )
238         {
239             throw new MojoExecutionException( "Could not obtain key store location at " + keystore );
240         }
241 
242         // reset arguments
243         arguments = new ArrayList<String>();
244     }
245 
246 
247     /**
248      * Creates a jarsigner request to do a sign operation.
249      *
250      * @param jarToSign the location of the jar to sign
251      * @param signedJar the optional location of the signed jar to produce (if not set, will use the original location)
252      * @return the jarsigner request
253      * @throws MojoExecutionException if something wrong occurs
254      */
255     public JarSignerRequest createSignRequest( File jarToSign, File signedJar )
256         throws MojoExecutionException
257     {
258         JarSignerSignRequest request = new JarSignerSignRequest();
259         request.setAlias( getAlias() );
260         request.setKeystore( getKeystore() );
261         request.setSigfile( getSigfile() );
262         request.setStoretype( getStoretype() );
263         request.setWorkingDirectory( workDirectory );
264         request.setMaxMemory( getMaxMemory() );
265         request.setVerbose( isVerbose() );
266         request.setArchive( jarToSign );
267         request.setSignedjar( signedJar );
268         request.setTsaLocation( getTsaLocation() );
269 
270         // Special handling for passwords through the Maven Security Dispatcher
271         request.setKeypass( decrypt( keypass ) );
272         request.setStorepass( decrypt( storepass ) );
273 
274         // TODO: add support for proxy parameters to JarSigner / JarSignerSignRequest
275         // instead of using implementation-specific additional arguments
276         if ( httpProxyHost != null )
277         {
278             arguments.add( "-J-Dhttp.proxyHost=" + httpProxyHost );
279         }
280 
281         if ( httpProxyPort != null )
282         {
283             arguments.add( "-J-Dhttp.proxyPort=" + httpProxyPort );
284         }
285 
286         if ( httpsProxyHost != null )
287         {
288             arguments.add( "-J-Dhttps.proxyHost=" + httpsProxyHost );
289         }
290 
291         if ( httpsProxyPort != null )
292         {
293             arguments.add( "-J-Dhttps.proxyPort=" + httpsProxyPort );
294         }
295 
296         if ( !arguments.isEmpty() )
297         {
298             request.setArguments( arguments.toArray( new String[arguments.size()] ) );
299         }
300 
301         return request;
302     }
303 
304     /**
305      * Creates a jarsigner request to do a verify operation.
306      *
307      * @param jarFile the location of the jar to sign
308      * @param certs   flag to show certificates details
309      * @return the jarsigner request
310      */
311     public JarSignerRequest createVerifyRequest( File jarFile, boolean certs )
312     {
313         JarSignerVerifyRequest request = new JarSignerVerifyRequest();
314         request.setCerts( certs );
315         request.setWorkingDirectory( workDirectory );
316         request.setMaxMemory( getMaxMemory() );
317         request.setVerbose( isVerbose() );
318         request.setArchive( jarFile );
319         return request;
320     }
321 
322     /**
323      * Creates a keytool request to do a key store generation operation.
324      *
325      * @param keystoreFile the location of the key store file to generate
326      * @return the keytool request
327      */
328     public KeyToolGenerateKeyPairRequest createKeyGenRequest( File keystoreFile )
329     {
330         KeyToolGenerateKeyPairRequest request = new KeyToolGenerateKeyPairRequest();
331         request.setAlias( getAlias() );
332         request.setDname( getDname() );
333         request.setKeyalg( getKeyalg() );
334         request.setKeypass( getKeypass() );
335         request.setKeysize( getKeysize() );
336         request.setKeystore( getKeystore() );
337         request.setSigalg( getSigalg() );
338         request.setStorepass( getStorepass() );
339         request.setStoretype( getStoretype() );
340         request.setValidity( getValidity() );
341         request.setVerbose( isVerbose() );
342         request.setWorkingDirectory( workDirectory );
343         return request;
344     }
345 
346 
347     /**
348      * Gets the verbose state of the configuration.
349      *
350      * @return {@code true} if configuration state is on, {@code false} otherwise.
351      */
352     public boolean isVerbose()
353     {
354         return verbose;
355     }
356 
357     public void setWorkDirectory( File workDirectory )
358     {
359         this.workDirectory = workDirectory;
360     }
361 
362     public void setVerbose( boolean verbose )
363     {
364         this.verbose = verbose;
365     }
366 
367     public void setMaxMemory( String maxMemory )
368     {
369         this.maxMemory = maxMemory;
370     }
371 
372     public void setKeystoreConfig( KeystoreConfig keystoreConfig )
373     {
374         this.keystoreConfig = keystoreConfig;
375     }
376 
377     public void setKeystore( String keystore )
378     {
379         this.keystore = keystore;
380     }
381 
382     public void setWorkingKeystore( File workingKeystore )
383     {
384         this.workingKeystore = workingKeystore;
385     }
386 
387     public void setKeyalg( String keyalg )
388     {
389         this.keyalg = keyalg;
390     }
391 
392     public void setKeysize( String keysize )
393     {
394         this.keysize = keysize;
395     }
396 
397     public void setSigalg( String sigalg )
398     {
399         this.sigalg = sigalg;
400     }
401 
402     public void setSigfile( String sigfile )
403     {
404         this.sigfile = sigfile;
405     }
406 
407     public void setStoretype( String storetype )
408     {
409         this.storetype = storetype;
410     }
411 
412     public void setStorepass( String storepass )
413     {
414         this.storepass = storepass;
415     }
416 
417     public void setKeypass( String keypass )
418     {
419         this.keypass = keypass;
420     }
421 
422     public void setValidity( String validity )
423     {
424         this.validity = validity;
425     }
426 
427     public void setDnameCn( String dnameCn )
428     {
429         this.dnameCn = dnameCn;
430     }
431 
432     public void setDnameOu( String dnameOu )
433     {
434         this.dnameOu = dnameOu;
435     }
436 
437     public void setDnameL( String dnameL )
438     {
439         this.dnameL = dnameL;
440     }
441 
442     public void setDnameSt( String dnameSt )
443     {
444         this.dnameSt = dnameSt;
445     }
446 
447     public void setDnameO( String dnameO )
448     {
449         this.dnameO = dnameO;
450     }
451 
452     public void setDnameC( String dnameC )
453     {
454         this.dnameC = dnameC;
455     }
456 
457     public void setAlias( String alias )
458     {
459         this.alias = alias;
460     }
461 
462     public void setVerify( boolean verify )
463     {
464         this.verify = verify;
465     }
466 
467     public void setTsaLocation( String tsaLocation )
468     {
469         this.tsaLocation = tsaLocation;
470     }
471 
472     public void setArguments( String[] arguments )
473     {
474         Collections.addAll( this.arguments, arguments );
475     }
476 
477     public String getKeystore()
478     {
479         return keystore;
480     }
481 
482     public String getKeyalg()
483     {
484         return keyalg;
485     }
486 
487     public String getKeysize()
488     {
489         return keysize;
490     }
491 
492     public String getSigalg()
493     {
494         return sigalg;
495     }
496 
497     public String getSigfile()
498     {
499         return sigfile;
500     }
501 
502     public String getStoretype()
503     {
504         return storetype;
505     }
506 
507     public String getStorepass()
508     {
509         return storepass;
510     }
511 
512     public String getKeypass()
513     {
514         return keypass;
515     }
516 
517     public String getValidity()
518     {
519         return validity;
520     }
521 
522     public String getDnameCn()
523     {
524         return dnameCn;
525     }
526 
527     public String getDnameOu()
528     {
529         return dnameOu;
530     }
531 
532     public String getDnameL()
533     {
534         return dnameL;
535     }
536 
537     public String getDnameSt()
538     {
539         return dnameSt;
540     }
541 
542     public String getDnameO()
543     {
544         return dnameO;
545     }
546 
547     public String getDnameC()
548     {
549         return dnameC;
550     }
551 
552     public String getAlias()
553     {
554         return alias;
555     }
556 
557     public boolean isVerify()
558     {
559         return verify;
560     }
561 
562     public String getTsaLocation()
563     {
564         return tsaLocation;
565     }
566 
567     public String getMaxMemory()
568     {
569         return maxMemory;
570     }
571 
572     public String[] getArguments()
573     {
574         return arguments.toArray( new String[arguments.size()] );
575     }
576 
577     public String getHttpProxyHost()
578     {
579         return httpProxyHost;
580     }
581 
582     public void setHttpProxyHost( String httpProxyHost )
583     {
584         this.httpProxyHost = httpProxyHost;
585     }
586 
587     public String getHttpProxyPort()
588     {
589         return httpProxyPort;
590     }
591 
592     public void setHttpProxyPort( String httpProxyPort )
593     {
594         this.httpProxyPort = httpProxyPort;
595     }
596 
597     public String getHttpsProxyHost()
598     {
599         return httpsProxyHost;
600     }
601 
602     public void setHttpsProxyHost( String httpsProxyHost )
603     {
604         this.httpsProxyHost = httpsProxyHost;
605     }
606 
607     public String getHttpsProxyPort()
608     {
609         return httpsProxyPort;
610     }
611 
612     public void setHttpsProxyPort( String httpsProxyPort )
613     {
614         this.httpsProxyPort = httpsProxyPort;
615     }
616 
617     public String getDname()
618     {
619         StringBuffer buffer = new StringBuffer( 128 );
620 
621         appendToDnameBuffer( dnameCn, buffer, "CN" );
622         appendToDnameBuffer( dnameOu, buffer, "OU" );
623         appendToDnameBuffer( dnameL, buffer, "L" );
624         appendToDnameBuffer( dnameSt, buffer, "ST" );
625         appendToDnameBuffer( dnameO, buffer, "O" );
626         appendToDnameBuffer( dnameC, buffer, "C" );
627 
628         return buffer.toString();
629     }
630 
631     private void appendToDnameBuffer( final String property, StringBuffer buffer, final String prefix )
632     {
633         if ( property != null )
634         {
635             if ( buffer.length() > 0 )
636             {
637                 buffer.append( ", " );
638             }
639             // http://jira.codehaus.org/browse/MWEBSTART-112 : have commas in parts of dName (but them must be espace)
640             buffer.append( prefix ).append( "=" );
641             buffer.append( property.replaceAll( ",", "\\\\," ) );
642         }
643     }
644 
645     private String decrypt( String encoded )
646         throws MojoExecutionException
647     {
648         try
649         {
650             return securityDispatcher.decrypt( encoded );
651         }
652         catch ( SecDispatcherException e )
653         {
654             throw new MojoExecutionException( "error using security dispatcher: " + e.getMessage(), e );
655         }
656     }
657 }