View Javadoc
1   /* 
2    * Copyright (C) 2016 Hobrasoft s.r.o.
3    *
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU Affero General Public License as published by
6    * the Free Software Foundation, either version 3 of the License, or
7    * (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU Affero General Public License for more details.
13   *
14   * You should have received a copy of the GNU Affero General Public License
15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16   */
17  package cz.hobrasoft.pdfmu.operation.signature;
18  
19  import com.itextpdf.text.pdf.security.TSAClient;
20  import com.itextpdf.text.pdf.security.TSAClientBouncyCastle;
21  import static cz.hobrasoft.pdfmu.error.ErrorType.SIGNATURE_ADD_TSA_INVALID_URL;
22  import cz.hobrasoft.pdfmu.operation.OperationException;
23  import cz.hobrasoft.pdfmu.operation.args.ArgsConfiguration;
24  import cz.hobrasoft.pdfmu.operation.args.PasswordArgs;
25  import java.util.logging.Logger;
26  import net.sourceforge.argparse4j.inf.ArgumentGroup;
27  import net.sourceforge.argparse4j.inf.ArgumentParser;
28  import net.sourceforge.argparse4j.inf.Namespace;
29  import org.apache.commons.validator.routines.UrlValidator;
30  
31  /**
32   * Parameters of timestamping process.
33   *
34   * @author <a href="mailto:filip.bartek@hobrasoft.cz">Filip Bartek</a>
35   */
36  public class TimestampParameters implements ArgsConfiguration {
37  
38      private static final Logger LOGGER = Logger.getLogger(TimestampParameters.class.getName());
39  
40      /**
41       * Timestamp authority URL.
42       */
43      public String url;
44  
45      /**
46       * Timestamp authority login username.
47       */
48      public String username;
49  
50      private final PasswordArgs passwordArgs = new PasswordArgs("TSA password");
51  
52      private final KeystoreParameters sslKeystore = new KeystoreParameters(SslKeystore.PRIVATE.getName());
53      private final KeystoreParameters sslTruststore = new KeystoreParameters(SslKeystore.TRUSTSTORE.getName());
54  
55      @Override
56      public void addArguments(ArgumentParser parser) {
57          ArgumentGroup group = parser.addArgumentGroup("timestamp");
58          // TODO: Add description
59  
60          group.addArgument("--tsa-url")
61                  .help("timestamp authority URL (set to enable timestamp)")
62                  .type(String.class);
63  
64          group.addArgument("--tsa-username")
65                  .help("timestamp authority username (set to enable TSA authorization)")
66                  .type(String.class);
67  
68          passwordArgs.passwordArgument = group.addArgument("--tsa-password")
69                  .help("timestamp authority password (default: <none>)");
70          passwordArgs.environmentVariableArgument = group.addArgument("--tsa-password-envvar")
71                  .help("timestamp authority password environment variable")
72                  .setDefault("PDFMU_TSA_PASSWORD");
73          passwordArgs.finalizeArguments();
74  
75          sslKeystore.fileArgument = group.addArgument("--ssl-keystore")
76                  .help("The keystore file that contains the private keys used for SSL authorization. Must be protected by a non-empty password.");
77          sslKeystore.typeArgument = group.addArgument("--ssl-keystore-type")
78                  .help("SSL KeyStore type")
79                  .choices(new String[]{"jks", "jceks", "pkcs12"});
80          sslKeystore.passwordArgs.passwordArgument = group.addArgument("--ssl-keystore-password")
81                  .help("SSL KeyStore password (default: <none>)");
82          sslKeystore.passwordArgs.environmentVariableArgument = group.addArgument("--ssl-keystore-password-envvar")
83                  .help("SSL KeyStore password environment variable")
84                  .setDefault("PDFMU_SSL_KEYSTORE_PASSWORD");
85          sslKeystore.finalizeArguments();
86  
87          sslTruststore.fileArgument = group.addArgument("--ssl-truststore")
88                  .help("The keystore file that contains the certificates of the trusted certificate authorities");
89          // TODO: Add support for type "pkcs12"
90          sslTruststore.typeArgument = group.addArgument("--ssl-truststore-type")
91                  .help("SSL TrustStore type")
92                  .choices(new String[]{"jks", "jceks"});
93          sslTruststore.passwordArgs.passwordArgument = group.addArgument("--ssl-truststore-password")
94                  .help("SSL TrustStore password (default: <none>)");
95          sslTruststore.passwordArgs.environmentVariableArgument = group.addArgument("--ssl-truststore-password-envvar")
96                  .help("SSL TrustStore password environment variable")
97                  .setDefault("PDFMU_SSL_TRUSTSTORE_PASSWORD");
98          sslTruststore.finalizeArguments();
99      }
100 
101     @Override
102     public void setFromNamespace(Namespace namespace) throws OperationException {
103         url = namespace.get("tsa_url");
104 
105         if (url != null) {
106             UrlValidator urlValidator = new UrlValidator();
107             if (!urlValidator.isValid(url)) {
108                 throw new OperationException(SIGNATURE_ADD_TSA_INVALID_URL);
109             }
110         }
111 
112         username = namespace.getString("tsa_username");
113 
114         passwordArgs.setFromNamespace(namespace);
115 
116         sslKeystore.setFromNamespace(namespace);
117         if (sslKeystore.file != null) {
118             String password = sslKeystore.getPassword();
119             if (password == null || password.isEmpty()) {
120                 LOGGER.warning("SSL KeyStore: Location has been set but password has not. Only KeyStores protected by a non-empty password are supported.");
121             }
122         }
123         sslKeystore.setSystemProperties(SslKeystore.PRIVATE);
124 
125         sslTruststore.setFromNamespace(namespace);
126         sslTruststore.setSystemProperties(SslKeystore.TRUSTSTORE);
127     }
128 
129     /**
130      * Returns the {@link TSAClient} that corresponds to these parameters.
131      *
132      * @return null if the timestamp authority has not been configured
133      */
134     public TSAClient getTSAClient() {
135         if (url == null) {
136             return null;
137         }
138         LOGGER.info("TSA URL has been set. Will attempt to attach a timestamp to the signature.");
139         String password = getPassword();
140         if (username != null && password == null) {
141             LOGGER.warning("TSA username has been set but password has not.");
142         }
143         if (password != null && username == null) {
144             LOGGER.warning("TSA password has been set but username has not.");
145         }
146         return new TSAClientBouncyCastle(url, username, password);
147     }
148 
149     private String getPassword() {
150         assert passwordArgs != null;
151         return passwordArgs.getPassword();
152     }
153 
154 }