SignatureParameters.java

/* 
 * Copyright (C) 2016 Hobrasoft s.r.o.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package cz.hobrasoft.pdfmu.operation.signature;

import com.itextpdf.text.pdf.security.MakeSignature;
import cz.hobrasoft.pdfmu.operation.OperationException;
import cz.hobrasoft.pdfmu.operation.args.ArgsConfiguration;
import net.sourceforge.argparse4j.inf.Argument;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.Namespace;
import org.apache.commons.lang3.StringUtils;

/**
 *
 * @author <a href="mailto:filip.bartek@hobrasoft.cz">Filip Bartek</a>
 */
class SignatureParameters implements ArgsConfiguration {

    public SignatureAppearanceParameters appearance = new SignatureAppearanceParameters();
    public KeystoreParameters keystore = new KeystoreParameters("signing keystore");
    public KeyParameters key = new KeyParameters();
    public TimestampParameters timestamp = new TimestampParameters();

    private final ArgsConfiguration[] configurations = {appearance, keystore, key, timestamp};

    // digitalsignatures20130304.pdf : Code sample 2.19; Section 2.1.4; Code sample 2.2
    public String digestAlgorithm = "SHA256";
    public MakeSignature.CryptoStandard format = MakeSignature.CryptoStandard.CMS;

    private static final String[] digestAlgorithmChoices = {
        // Source: {@link DigestAlgorithms#digestNames}
        // Alternative source:
        // digitalsignatures20130304.pdf : Section 1.2.2; Code sample 1.5
        // TODO?: Add dashes in the algorithm names
        "MD2",
        "MD5",
        "SHA1",
        "SHA224",
        "SHA256",
        "SHA384",
        "SHA512",
        "RIPEMD128",
        "RIPEMD160",
        "RIPEMD256",
        "GOST3411"
    };

    private Argument digestAlgorithmArgument;
    private Argument formatArgument;

    @Override
    public void addArguments(ArgumentParser parser) {
        keystore.fileArgument = parser.addArgument("--keystore")
                .help("keystore file that contains the signing private key");
        // Valid types:
        // https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore
        // Type "pkcs12" file extensions: P12, PFX
        // Source: https://en.wikipedia.org/wiki/PKCS_12
        // Another type: "Windows-MY" - Windows Certificate Store
        // TODO?: Guess type from file extension by default
        // TODO?: Default to "pkcs12"
        // TODO: Do not allow "Windows-MY" when running in a different OS than Windows
        keystore.typeArgument = parser.addArgument("--keystore-type")
                .help("type of the signing keystore")
                .choices(new String[]{"jceks", "jks", "pkcs12", "Windows-MY"});
        keystore.passwordArgs.passwordArgument = parser.addArgument("--keystore-password")
                .help("signing keystore password (default: <empty>)");
        keystore.passwordArgs.environmentVariableArgument = parser.addArgument("--keystore-password-envvar")
                .help("signing keystore password environment variable")
                .setDefault("PDFMU_STOREPASS");

        for (ArgsConfiguration configuration : configurations) {
            configuration.addArguments(parser);
        }

        // Possible names:
        // - digest algorithm
        // - Hash Algorithm
        // - hash algorithm for making the signature
        digestAlgorithmArgument = parser.addArgument("--digest-algorithm")
                .help("hash algorithm for making the signature")
                // Java 8 (using `String.join`):
                //.metavar(String.format("{%s}", String.join(",", digestAlgorithmChoices)))
                // Java 7 (using `org.apache.commons.lang3.StringUtils.join`):
                .metavar(String.format("{%s}", StringUtils.join(digestAlgorithmChoices, ",")))
                // TODO?: Limit the choices to `digestAlgorithmChoices`
                .type(String.class)
                .setDefault(digestAlgorithm);

        formatArgument = parser.addArgument("--format")
                .help("signature format (CMS: adbe.pkcs7.detached, CADES: ETSI.CAdES.detached)")
                .type(MakeSignature.CryptoStandard.class)
                .choices(MakeSignature.CryptoStandard.values())
                .setDefault(format);
    }

    @Override
    public void setFromNamespace(Namespace namespace) throws OperationException {
        for (ArgsConfiguration configuration : configurations) {
            configuration.setFromNamespace(namespace);
        }

        assert digestAlgorithmArgument != null;
        digestAlgorithm = namespace.getString(digestAlgorithmArgument.getDest());
        assert formatArgument != null;
        format = namespace.get(formatArgument.getDest());
    }

}