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.MakeSignature;
20  import cz.hobrasoft.pdfmu.operation.OperationException;
21  import cz.hobrasoft.pdfmu.operation.args.ArgsConfiguration;
22  import net.sourceforge.argparse4j.inf.Argument;
23  import net.sourceforge.argparse4j.inf.ArgumentParser;
24  import net.sourceforge.argparse4j.inf.Namespace;
25  import org.apache.commons.lang3.StringUtils;
26  
27  /**
28   *
29   * @author <a href="mailto:filip.bartek@hobrasoft.cz">Filip Bartek</a>
30   */
31  class SignatureParameters implements ArgsConfiguration {
32  
33      public SignatureAppearanceParameters appearance = new SignatureAppearanceParameters();
34      public KeystoreParameters keystore = new KeystoreParameters("signing keystore");
35      public KeyParameters key = new KeyParameters();
36      public TimestampParameters timestamp = new TimestampParameters();
37  
38      private final ArgsConfiguration[] configurations = {appearance, keystore, key, timestamp};
39  
40      // digitalsignatures20130304.pdf : Code sample 2.19; Section 2.1.4; Code sample 2.2
41      public String digestAlgorithm = "SHA256";
42      public MakeSignature.CryptoStandard format = MakeSignature.CryptoStandard.CMS;
43  
44      private static final String[] digestAlgorithmChoices = {
45          // Source: {@link DigestAlgorithms#digestNames}
46          // Alternative source:
47          // digitalsignatures20130304.pdf : Section 1.2.2; Code sample 1.5
48          // TODO?: Add dashes in the algorithm names
49          "MD2",
50          "MD5",
51          "SHA1",
52          "SHA224",
53          "SHA256",
54          "SHA384",
55          "SHA512",
56          "RIPEMD128",
57          "RIPEMD160",
58          "RIPEMD256",
59          "GOST3411"
60      };
61  
62      private Argument digestAlgorithmArgument;
63      private Argument formatArgument;
64  
65      @Override
66      public void addArguments(ArgumentParser parser) {
67          keystore.fileArgument = parser.addArgument("--keystore")
68                  .help("keystore file that contains the signing private key");
69          // Valid types:
70          // https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore
71          // Type "pkcs12" file extensions: P12, PFX
72          // Source: https://en.wikipedia.org/wiki/PKCS_12
73          // Another type: "Windows-MY" - Windows Certificate Store
74          // TODO?: Guess type from file extension by default
75          // TODO?: Default to "pkcs12"
76          // TODO: Do not allow "Windows-MY" when running in a different OS than Windows
77          keystore.typeArgument = parser.addArgument("--keystore-type")
78                  .help("type of the signing keystore")
79                  .choices(new String[]{"jceks", "jks", "pkcs12", "Windows-MY"});
80          keystore.passwordArgs.passwordArgument = parser.addArgument("--keystore-password")
81                  .help("signing keystore password (default: <empty>)");
82          keystore.passwordArgs.environmentVariableArgument = parser.addArgument("--keystore-password-envvar")
83                  .help("signing keystore password environment variable")
84                  .setDefault("PDFMU_STOREPASS");
85  
86          for (ArgsConfiguration configuration : configurations) {
87              configuration.addArguments(parser);
88          }
89  
90          // Possible names:
91          // - digest algorithm
92          // - Hash Algorithm
93          // - hash algorithm for making the signature
94          digestAlgorithmArgument = parser.addArgument("--digest-algorithm")
95                  .help("hash algorithm for making the signature")
96                  // Java 8 (using `String.join`):
97                  //.metavar(String.format("{%s}", String.join(",", digestAlgorithmChoices)))
98                  // Java 7 (using `org.apache.commons.lang3.StringUtils.join`):
99                  .metavar(String.format("{%s}", StringUtils.join(digestAlgorithmChoices, ",")))
100                 // TODO?: Limit the choices to `digestAlgorithmChoices`
101                 .type(String.class)
102                 .setDefault(digestAlgorithm);
103 
104         formatArgument = parser.addArgument("--format")
105                 .help("signature format (CMS: adbe.pkcs7.detached, CADES: ETSI.CAdES.detached)")
106                 .type(MakeSignature.CryptoStandard.class)
107                 .choices(MakeSignature.CryptoStandard.values())
108                 .setDefault(format);
109     }
110 
111     @Override
112     public void setFromNamespace(Namespace namespace) throws OperationException {
113         for (ArgsConfiguration configuration : configurations) {
114             configuration.setFromNamespace(namespace);
115         }
116 
117         assert digestAlgorithmArgument != null;
118         digestAlgorithm = namespace.getString(digestAlgorithmArgument.getDest());
119         assert formatArgument != null;
120         format = namespace.get(formatArgument.getDest());
121     }
122 
123 }