| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.tools.jarsigner;  | 
 | 
 | 
 | 
import java.io.*;  | 
 | 
import java.security.cert.CertPathValidatorException;  | 
 | 
import java.security.cert.PKIXBuilderParameters;  | 
 | 
import java.util.*;  | 
 | 
import java.util.stream.Collectors;  | 
 | 
import java.util.zip.*;  | 
 | 
import java.util.jar.*;  | 
 | 
import java.math.BigInteger;  | 
 | 
import java.net.URI;  | 
 | 
import java.net.URISyntaxException;  | 
 | 
import java.text.Collator;  | 
 | 
import java.text.MessageFormat;  | 
 | 
import java.security.cert.Certificate;  | 
 | 
import java.security.cert.X509Certificate;  | 
 | 
import java.security.cert.CertificateException;  | 
 | 
import java.security.*;  | 
 | 
import java.lang.reflect.Constructor;  | 
 | 
 | 
 | 
import com.sun.jarsigner.ContentSigner;  | 
 | 
import com.sun.jarsigner.ContentSignerParameters;  | 
 | 
import java.net.SocketTimeoutException;  | 
 | 
import java.net.URL;  | 
 | 
import java.net.URLClassLoader;  | 
 | 
import java.security.cert.CertPath;  | 
 | 
import java.security.cert.CertificateExpiredException;  | 
 | 
import java.security.cert.CertificateFactory;  | 
 | 
import java.security.cert.CertificateNotYetValidException;  | 
 | 
import java.security.cert.TrustAnchor;  | 
 | 
import java.util.Map.Entry;  | 
 | 
import sun.security.pkcs.PKCS7;  | 
 | 
import sun.security.pkcs.SignerInfo;  | 
 | 
import sun.security.timestamp.TimestampToken;  | 
 | 
import sun.security.tools.KeyStoreUtil;  | 
 | 
import sun.security.tools.PathList;  | 
 | 
import sun.security.validator.Validator;  | 
 | 
import sun.security.validator.ValidatorException;  | 
 | 
import sun.security.x509.*;  | 
 | 
import sun.security.util.*;  | 
 | 
import java.util.Base64;  | 
 | 
 | 
 | 
 | 
 | 
/**  | 
 | 
 * <p>The jarsigner utility.  | 
 | 
 *  | 
 | 
 * The exit codes for the main method are:  | 
 | 
 *  | 
 | 
 * 0: success  | 
 | 
 * 1: any error that the jar cannot be signed or verified, including:  | 
 | 
 *      keystore loading error  | 
 | 
 *      TSP communication error  | 
 | 
 *      jarsigner command line error...  | 
 | 
 * otherwise: error codes from -strict  | 
 | 
 *  | 
 | 
 * @author Roland Schemers  | 
 | 
 * @author Jan Luehe  | 
 | 
 */  | 
 | 
 | 
 | 
public class Main { | 
 | 
 | 
 | 
      | 
 | 
    private static final java.util.ResourceBundle rb =  | 
 | 
        java.util.ResourceBundle.getBundle  | 
 | 
        ("sun.security.tools.jarsigner.Resources"); | 
 | 
    private static final Collator collator = Collator.getInstance();  | 
 | 
    static { | 
 | 
          | 
 | 
        collator.setStrength(Collator.PRIMARY);  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final String META_INF = "META-INF/";  | 
 | 
 | 
 | 
    private static final Class<?>[] PARAM_STRING = { String.class }; | 
 | 
 | 
 | 
    private static final String NONE = "NONE";  | 
 | 
    private static final String P11KEYSTORE = "PKCS11";  | 
 | 
 | 
 | 
    private static final long SIX_MONTHS = 180*24*60*60*1000L;   | 
 | 
    private static final long ONE_YEAR = 366*24*60*60*1000L;  | 
 | 
 | 
 | 
    private static final DisabledAlgorithmConstraints DISABLED_CHECK =  | 
 | 
            new DisabledAlgorithmConstraints(  | 
 | 
                    DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);  | 
 | 
 | 
 | 
    private static final DisabledAlgorithmConstraints LEGACY_CHECK =  | 
 | 
            new DisabledAlgorithmConstraints(  | 
 | 
                    DisabledAlgorithmConstraints.PROPERTY_SECURITY_LEGACY_ALGS);  | 
 | 
 | 
 | 
    private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET = Collections  | 
 | 
            .unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));  | 
 | 
    private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections  | 
 | 
            .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));  | 
 | 
 | 
 | 
    static final String VERSION = "1.0";  | 
 | 
 | 
 | 
    static final int IN_KEYSTORE = 0x01;          | 
 | 
    static final int IN_SCOPE = 0x02;  | 
 | 
    static final int NOT_ALIAS = 0x04;            | 
 | 
    // signer is not in alias list  | 
 | 
    static final int SIGNED_BY_ALIAS = 0x08;      | 
 | 
 | 
 | 
    // Attention:  | 
 | 
      | 
 | 
    public static void main(String args[]) throws Exception { | 
 | 
        Main js = new Main();  | 
 | 
        js.run(args);  | 
 | 
    }  | 
 | 
 | 
 | 
    X509Certificate[] certChain;      | 
 | 
    PrivateKey privateKey;            | 
 | 
    KeyStore store;                   | 
 | 
                                    // or the default keystore, never null  | 
 | 
 | 
 | 
    String keystore;   | 
 | 
    boolean nullStream = false;   | 
 | 
    boolean token = false;   | 
 | 
    String jarfile;    | 
 | 
    String alias;      | 
 | 
    List<String> ckaliases = new ArrayList<>();   | 
 | 
    char[] storepass;   | 
 | 
    boolean protectedPath;   | 
 | 
    String storetype;   | 
 | 
    String providerName;   | 
 | 
    Vector<String> providers = null;   | 
 | 
      | 
 | 
    HashMap<String,String> providerArgs = new HashMap<>();  | 
 | 
    char[] keypass;   | 
 | 
    String sigfile;   | 
 | 
    String sigalg;   | 
 | 
    String digestalg = "SHA-256";   | 
 | 
    String signedjar;   | 
 | 
    String tsaUrl;   | 
 | 
    String tsaAlias;   | 
 | 
    String altCertChain;   | 
 | 
    String tSAPolicyID;  | 
 | 
    String tSADigestAlg = "SHA-256";  | 
 | 
    boolean verify = false;   | 
 | 
    String verbose = null;   | 
 | 
    boolean showcerts = false;   | 
 | 
    boolean debug = false;   | 
 | 
    boolean signManifest = true;   | 
 | 
    boolean externalSF = true;   | 
 | 
    boolean strict = false;    | 
 | 
 | 
 | 
      | 
 | 
    private ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);  | 
 | 
    private byte[] buffer = new byte[8192];  | 
 | 
    private ContentSigner signingMechanism = null;  | 
 | 
    private String altSignerClass = null;  | 
 | 
    private String altSignerClasspath = null;  | 
 | 
    private ZipFile zipFile = null;  | 
 | 
 | 
 | 
      | 
 | 
    private boolean hasExpiringCert = false;  | 
 | 
    private boolean hasExpiringTsaCert = false;  | 
 | 
    private boolean noTimestamp = true;  | 
 | 
 | 
 | 
      | 
 | 
    private Date expireDate = null;  | 
 | 
    private Date tsaExpireDate = null;  | 
 | 
 | 
 | 
      | 
 | 
    boolean hasTimestampBlock = false;  | 
 | 
 | 
 | 
    private PublicKey weakPublicKey = null;  | 
 | 
    private boolean disabledAlgFound = false;  | 
 | 
    private String legacyDigestAlg = null;  | 
 | 
    private String legacyTsaDigestAlg = null;  | 
 | 
    private String legacySigAlg = null;  | 
 | 
 | 
 | 
    // Severe warnings.  | 
 | 
 | 
 | 
    // jarsigner used to check signer cert chain validity and key usages  | 
 | 
    // itself and set various warnings. Later CertPath validation is  | 
 | 
    // added but chainNotValidated is only flagged when no other existing  | 
 | 
    // warnings are set. TSA cert chain check is added separately and  | 
 | 
    // only tsaChainNotValidated is set, i.e. has no affect on hasExpiredCert,  | 
 | 
    // notYetValidCert, or any badXyzUsage.  | 
 | 
 | 
 | 
    private int legacyAlg = 0;   | 
 | 
    private int disabledAlg = 0;   | 
 | 
    private boolean hasExpiredCert = false;  | 
 | 
    private boolean hasExpiredTsaCert = false;  | 
 | 
    private boolean notYetValidCert = false;  | 
 | 
    private boolean chainNotValidated = false;  | 
 | 
    private boolean tsaChainNotValidated = false;  | 
 | 
    private boolean notSignedByAlias = false;  | 
 | 
    private boolean aliasNotInStore = false;  | 
 | 
    private boolean hasUnsignedEntry = false;  | 
 | 
    private boolean badKeyUsage = false;  | 
 | 
    private boolean badExtendedKeyUsage = false;  | 
 | 
    private boolean badNetscapeCertType = false;  | 
 | 
    private boolean signerSelfSigned = false;  | 
 | 
 | 
 | 
    private Throwable chainNotValidatedReason = null;  | 
 | 
    private Throwable tsaChainNotValidatedReason = null;  | 
 | 
 | 
 | 
    PKIXBuilderParameters pkixParameters;  | 
 | 
    Set<X509Certificate> trustedCerts = new HashSet<>();  | 
 | 
 | 
 | 
    public void run(String args[]) { | 
 | 
        try { | 
 | 
            parseArgs(args);  | 
 | 
 | 
 | 
              | 
 | 
            if (providers != null) { | 
 | 
                ClassLoader cl = ClassLoader.getSystemClassLoader();  | 
 | 
                Enumeration<String> e = providers.elements();  | 
 | 
                while (e.hasMoreElements()) { | 
 | 
                    String provName = e.nextElement();  | 
 | 
                    Class<?> provClass;  | 
 | 
                    if (cl != null) { | 
 | 
                        provClass = cl.loadClass(provName);  | 
 | 
                    } else { | 
 | 
                        provClass = Class.forName(provName);  | 
 | 
                    }  | 
 | 
 | 
 | 
                    String provArg = providerArgs.get(provName);  | 
 | 
                    Object obj;  | 
 | 
                    if (provArg == null) { | 
 | 
                        obj = provClass.newInstance();  | 
 | 
                    } else { | 
 | 
                        Constructor<?> c =  | 
 | 
                                provClass.getConstructor(PARAM_STRING);  | 
 | 
                        obj = c.newInstance(provArg);  | 
 | 
                    }  | 
 | 
 | 
 | 
                    if (!(obj instanceof Provider)) { | 
 | 
                        MessageFormat form = new MessageFormat(rb.getString  | 
 | 
                            ("provName.not.a.provider")); | 
 | 
                        Object[] source = {provName}; | 
 | 
                        throw new Exception(form.format(source));  | 
 | 
                    }  | 
 | 
                    Security.addProvider((Provider)obj);  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            if (verify) { | 
 | 
                try { | 
 | 
                    loadKeyStore(keystore, false);  | 
 | 
                } catch (Exception e) { | 
 | 
                    if ((keystore != null) || (storepass != null)) { | 
 | 
                        System.out.println(rb.getString("jarsigner.error.") + | 
 | 
                                        e.getMessage());  | 
 | 
                        System.exit(1);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
                */  | 
 | 
                verifyJar(jarfile);  | 
 | 
            } else { | 
 | 
                loadKeyStore(keystore, true);  | 
 | 
                getAliasInfo(alias);  | 
 | 
 | 
 | 
                  | 
 | 
                if (altSignerClass != null) { | 
 | 
                    signingMechanism = loadSigningMechanism(altSignerClass,  | 
 | 
                        altSignerClasspath);  | 
 | 
                }  | 
 | 
                signJar(jarfile, alias, args);  | 
 | 
            }  | 
 | 
        } catch (Exception e) { | 
 | 
            System.out.println(rb.getString("jarsigner.error.") + e); | 
 | 
            if (debug) { | 
 | 
                e.printStackTrace();  | 
 | 
            }  | 
 | 
            System.exit(1);  | 
 | 
        } finally { | 
 | 
              | 
 | 
            if (keypass != null) { | 
 | 
                Arrays.fill(keypass, ' ');  | 
 | 
                keypass = null;  | 
 | 
            }  | 
 | 
              | 
 | 
            if (storepass != null) { | 
 | 
                Arrays.fill(storepass, ' ');  | 
 | 
                storepass = null;  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        if (strict) { | 
 | 
            int exitCode = 0;  | 
 | 
            if (disabledAlg != 0 || chainNotValidated || hasExpiredCert  | 
 | 
                    || hasExpiredTsaCert || notYetValidCert || signerSelfSigned) { | 
 | 
                exitCode |= 4;  | 
 | 
            }  | 
 | 
            if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) { | 
 | 
                exitCode |= 8;  | 
 | 
            }  | 
 | 
            if (hasUnsignedEntry) { | 
 | 
                exitCode |= 16;  | 
 | 
            }  | 
 | 
            if (notSignedByAlias || aliasNotInStore) { | 
 | 
                exitCode |= 32;  | 
 | 
            }  | 
 | 
            if (tsaChainNotValidated) { | 
 | 
                exitCode |= 64;  | 
 | 
            }  | 
 | 
            if (exitCode != 0) { | 
 | 
                System.exit(exitCode);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    void parseArgs(String args[]) { | 
 | 
          | 
 | 
        int n = 0;  | 
 | 
 | 
 | 
        if (args.length == 0) fullusage();  | 
 | 
        for (n=0; n < args.length; n++) { | 
 | 
 | 
 | 
            String flags = args[n];  | 
 | 
            String modifier = null;  | 
 | 
 | 
 | 
            if (flags.startsWith("-")) { | 
 | 
                int pos = flags.indexOf(':'); | 
 | 
                if (pos > 0) { | 
 | 
                    modifier = flags.substring(pos+1);  | 
 | 
                    flags = flags.substring(0, pos);  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            if (!flags.startsWith("-")) { | 
 | 
                if (jarfile == null) { | 
 | 
                    jarfile = flags;  | 
 | 
                } else { | 
 | 
                    alias = flags;  | 
 | 
                    ckaliases.add(alias);  | 
 | 
                }  | 
 | 
            } else if (collator.compare(flags, "-keystore") == 0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                keystore = args[n];  | 
 | 
            } else if (collator.compare(flags, "-storepass") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                storepass = getPass(modifier, args[n]);  | 
 | 
            } else if (collator.compare(flags, "-storetype") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                storetype = args[n];  | 
 | 
            } else if (collator.compare(flags, "-providerName") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                providerName = args[n];  | 
 | 
            } else if ((collator.compare(flags, "-provider") == 0) ||  | 
 | 
                        (collator.compare(flags, "-providerClass") == 0)) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                if (providers == null) { | 
 | 
                    providers = new Vector<String>(3);  | 
 | 
                }  | 
 | 
                providers.add(args[n]);  | 
 | 
 | 
 | 
                if (args.length > (n+1)) { | 
 | 
                    flags = args[n+1];  | 
 | 
                    if (collator.compare(flags, "-providerArg") == 0) { | 
 | 
                        if (args.length == (n+2)) usageNoArg();  | 
 | 
                        providerArgs.put(args[n], args[n+2]);  | 
 | 
                        n += 2;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            } else if (collator.compare(flags, "-protected") ==0) { | 
 | 
                protectedPath = true;  | 
 | 
            } else if (collator.compare(flags, "-certchain") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                altCertChain = args[n];  | 
 | 
            } else if (collator.compare(flags, "-tsapolicyid") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                tSAPolicyID = args[n];  | 
 | 
            } else if (collator.compare(flags, "-tsadigestalg") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                tSADigestAlg = args[n];  | 
 | 
            } else if (collator.compare(flags, "-debug") ==0) { | 
 | 
                debug = true;  | 
 | 
            } else if (collator.compare(flags, "-keypass") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                keypass = getPass(modifier, args[n]);  | 
 | 
            } else if (collator.compare(flags, "-sigfile") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                sigfile = args[n];  | 
 | 
            } else if (collator.compare(flags, "-signedjar") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                signedjar = args[n];  | 
 | 
            } else if (collator.compare(flags, "-tsa") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                tsaUrl = args[n];  | 
 | 
            } else if (collator.compare(flags, "-tsacert") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                tsaAlias = args[n];  | 
 | 
            } else if (collator.compare(flags, "-altsigner") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                altSignerClass = args[n];  | 
 | 
            } else if (collator.compare(flags, "-altsignerpath") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                altSignerClasspath = args[n];  | 
 | 
            } else if (collator.compare(flags, "-sectionsonly") ==0) { | 
 | 
                signManifest = false;  | 
 | 
            } else if (collator.compare(flags, "-internalsf") ==0) { | 
 | 
                externalSF = false;  | 
 | 
            } else if (collator.compare(flags, "-verify") ==0) { | 
 | 
                verify = true;  | 
 | 
            } else if (collator.compare(flags, "-verbose") ==0) { | 
 | 
                verbose = (modifier != null) ? modifier : "all";  | 
 | 
            } else if (collator.compare(flags, "-sigalg") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                sigalg = args[n];  | 
 | 
            } else if (collator.compare(flags, "-digestalg") ==0) { | 
 | 
                if (++n == args.length) usageNoArg();  | 
 | 
                digestalg = args[n];  | 
 | 
            } else if (collator.compare(flags, "-certs") ==0) { | 
 | 
                showcerts = true;  | 
 | 
            } else if (collator.compare(flags, "-strict") ==0) { | 
 | 
                strict = true;  | 
 | 
            } else if (collator.compare(flags, "-h") == 0 ||  | 
 | 
                        collator.compare(flags, "-help") == 0) { | 
 | 
                fullusage();  | 
 | 
            } else { | 
 | 
                System.err.println(  | 
 | 
                        rb.getString("Illegal.option.") + flags); | 
 | 
                usage();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        if (verbose == null) showcerts = false;  | 
 | 
 | 
 | 
        if (jarfile == null) { | 
 | 
            System.err.println(rb.getString("Please.specify.jarfile.name")); | 
 | 
            usage();  | 
 | 
        }  | 
 | 
        if (!verify && alias == null) { | 
 | 
            System.err.println(rb.getString("Please.specify.alias.name")); | 
 | 
            usage();  | 
 | 
        }  | 
 | 
        if (!verify && ckaliases.size() > 1) { | 
 | 
            System.err.println(rb.getString("Only.one.alias.can.be.specified")); | 
 | 
            usage();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (storetype == null) { | 
 | 
            storetype = KeyStore.getDefaultType();  | 
 | 
        }  | 
 | 
        storetype = KeyStoreUtil.niceStoreTypeName(storetype);  | 
 | 
 | 
 | 
        try { | 
 | 
            if (signedjar != null && new File(signedjar).getCanonicalPath().equals(  | 
 | 
                    new File(jarfile).getCanonicalPath())) { | 
 | 
                signedjar = null;  | 
 | 
            }  | 
 | 
        } catch (IOException ioe) { | 
 | 
            // File system error?  | 
 | 
            // Just ignore it.  | 
 | 
        }  | 
 | 
 | 
 | 
        if (P11KEYSTORE.equalsIgnoreCase(storetype) ||  | 
 | 
                KeyStoreUtil.isWindowsKeyStore(storetype)) { | 
 | 
            token = true;  | 
 | 
            if (keystore == null) { | 
 | 
                keystore = NONE;  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        if (NONE.equals(keystore)) { | 
 | 
            nullStream = true;  | 
 | 
        }  | 
 | 
 | 
 | 
        if (token && !nullStream) { | 
 | 
            System.err.println(MessageFormat.format(rb.getString  | 
 | 
                (".keystore.must.be.NONE.if.storetype.is.{0}"), storetype)); | 
 | 
            usage();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (token && keypass != null) { | 
 | 
            System.err.println(MessageFormat.format(rb.getString  | 
 | 
                (".keypass.can.not.be.specified.if.storetype.is.{0}"), storetype)); | 
 | 
            usage();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (protectedPath) { | 
 | 
            if (storepass != null || keypass != null) { | 
 | 
                System.err.println(rb.getString  | 
 | 
                        ("If.protected.is.specified.then.storepass.and.keypass.must.not.be.specified")); | 
 | 
                usage();  | 
 | 
            }  | 
 | 
        }  | 
 | 
        if (KeyStoreUtil.isWindowsKeyStore(storetype)) { | 
 | 
            if (storepass != null || keypass != null) { | 
 | 
                System.err.println(rb.getString  | 
 | 
                        ("If.keystore.is.not.password.protected.then.storepass.and.keypass.must.not.be.specified")); | 
 | 
                usage();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    static char[] getPass(String modifier, String arg) { | 
 | 
        char[] output = KeyStoreUtil.getPassWithModifier(modifier, arg, rb);  | 
 | 
        if (output != null) return output;  | 
 | 
        usage();  | 
 | 
        return null;      | 
 | 
    }  | 
 | 
 | 
 | 
    static void usageNoArg() { | 
 | 
        System.out.println(rb.getString("Option.lacks.argument")); | 
 | 
        usage();  | 
 | 
    }  | 
 | 
 | 
 | 
    static void usage() { | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString("Please.type.jarsigner.help.for.usage")); | 
 | 
        System.exit(1);  | 
 | 
    }  | 
 | 
 | 
 | 
    static void fullusage() { | 
 | 
        System.out.println(rb.getString  | 
 | 
                ("Usage.jarsigner.options.jar.file.alias")); | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".jarsigner.verify.options.jar.file.alias.")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".keystore.url.keystore.location")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".storepass.password.password.for.keystore.integrity")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".storetype.type.keystore.type")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".keypass.password.password.for.private.key.if.different.")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".certchain.file.name.of.alternative.certchain.file")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".sigfile.file.name.of.SF.DSA.file")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".signedjar.file.name.of.signed.JAR.file")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".digestalg.algorithm.name.of.digest.algorithm")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".sigalg.algorithm.name.of.signature.algorithm")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".verify.verify.a.signed.JAR.file")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".verbose.suboptions.verbose.output.when.signing.verifying.")); | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".suboptions.can.be.all.grouped.or.summary")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".certs.display.certificates.when.verbose.and.verifying")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".tsa.url.location.of.the.Timestamping.Authority")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".tsacert.alias.public.key.certificate.for.Timestamping.Authority")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".tsapolicyid.tsapolicyid.for.Timestamping.Authority")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".tsadigestalg.algorithm.of.digest.data.in.timestamping.request")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".altsigner.class.class.name.of.an.alternative.signing.mechanism")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".altsignerpath.pathlist.location.of.an.alternative.signing.mechanism")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".internalsf.include.the.SF.file.inside.the.signature.block")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".sectionsonly.don.t.compute.hash.of.entire.manifest")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".protected.keystore.has.protected.authentication.path")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".providerName.name.provider.name")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".providerClass.class.name.of.cryptographic.service.provider.s")); | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".providerArg.arg.master.class.file.and.constructor.argument")); | 
 | 
        System.out.println();  | 
 | 
        System.out.println(rb.getString  | 
 | 
                (".strict.treat.warnings.as.errors")); | 
 | 
        System.out.println();  | 
 | 
 | 
 | 
        System.exit(0);  | 
 | 
    }  | 
 | 
 | 
 | 
    void verifyJar(String jarName)  | 
 | 
        throws Exception  | 
 | 
    { | 
 | 
        boolean anySigned = false;    | 
 | 
        JarFile jf = null;  | 
 | 
        Map<String,String> digestMap = new HashMap<>();  | 
 | 
        Map<String,PKCS7> sigMap = new HashMap<>();  | 
 | 
        Map<String,String> sigNameMap = new HashMap<>();  | 
 | 
        Map<String,String> unparsableSignatures = new HashMap<>();  | 
 | 
 | 
 | 
        try { | 
 | 
            jf = new JarFile(jarName, true);  | 
 | 
            Vector<JarEntry> entriesVec = new Vector<>();  | 
 | 
            byte[] buffer = new byte[8192];  | 
 | 
 | 
 | 
            Enumeration<JarEntry> entries = jf.entries();  | 
 | 
            while (entries.hasMoreElements()) { | 
 | 
                JarEntry je = entries.nextElement();  | 
 | 
                entriesVec.addElement(je);  | 
 | 
                try (InputStream is = jf.getInputStream(je)) { | 
 | 
                    String name = je.getName();  | 
 | 
                    if (signatureRelated(name)  | 
 | 
                            && SignatureFileVerifier.isBlockOrSF(name)) { | 
 | 
                        String alias = name.substring(name.lastIndexOf('/') + 1, | 
 | 
                                name.lastIndexOf('.')); | 
 | 
                try { | 
 | 
                            if (name.endsWith(".SF")) { | 
 | 
                                Manifest sf = new Manifest(is);  | 
 | 
                                boolean found = false;  | 
 | 
                                for (Object obj : sf.getMainAttributes().keySet()) { | 
 | 
                                    String key = obj.toString();  | 
 | 
                                    if (key.endsWith("-Digest-Manifest")) { | 
 | 
                                        digestMap.put(alias,  | 
 | 
                                                key.substring(0, key.length() - 16));  | 
 | 
                                        found = true;  | 
 | 
                                        break;  | 
 | 
                                    }  | 
 | 
                                }  | 
 | 
                                if (!found) { | 
 | 
                                    unparsableSignatures.putIfAbsent(alias,  | 
 | 
                                        String.format(  | 
 | 
                                            rb.getString("history.unparsable"), | 
 | 
                                            name));  | 
 | 
                                }  | 
 | 
                            } else { | 
 | 
                                sigNameMap.put(alias, name);  | 
 | 
                                sigMap.put(alias, new PKCS7(is));  | 
 | 
                            }  | 
 | 
                        } catch (IOException ioe) { | 
 | 
                            unparsableSignatures.putIfAbsent(alias, String.format(  | 
 | 
                                    rb.getString("history.unparsable"), name)); | 
 | 
                        }  | 
 | 
                    } else { | 
 | 
                        while (is.read(buffer, 0, buffer.length) != -1) { | 
 | 
                        // we just read. this will throw a SecurityException  | 
 | 
                        // if  a signature/digest check fails.  | 
 | 
                    }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            Manifest man = jf.getManifest();  | 
 | 
            boolean hasSignature = false;  | 
 | 
 | 
 | 
            // The map to record display info, only used when -verbose provided  | 
 | 
            //      key: signer info string  | 
 | 
              | 
 | 
            Map<String,List<String>> output = new LinkedHashMap<>();  | 
 | 
 | 
 | 
            if (man != null) { | 
 | 
                if (verbose != null) System.out.println();  | 
 | 
                Enumeration<JarEntry> e = entriesVec.elements();  | 
 | 
 | 
 | 
                String tab = rb.getString("6SPACE"); | 
 | 
 | 
 | 
                while (e.hasMoreElements()) { | 
 | 
                    JarEntry je = e.nextElement();  | 
 | 
                    String name = je.getName();  | 
 | 
 | 
 | 
                    hasSignature = hasSignature  | 
 | 
                            || SignatureFileVerifier.isBlockOrSF(name);  | 
 | 
 | 
 | 
                    CodeSigner[] signers = je.getCodeSigners();  | 
 | 
                    boolean isSigned = (signers != null);  | 
 | 
                    anySigned |= isSigned;  | 
 | 
                    hasUnsignedEntry |= !je.isDirectory() && !isSigned  | 
 | 
                                        && !signatureRelated(name);  | 
 | 
 | 
 | 
                    int inStoreOrScope = inKeyStore(signers);  | 
 | 
 | 
 | 
                    boolean inStore = (inStoreOrScope & IN_KEYSTORE) != 0;  | 
 | 
                    boolean inScope = (inStoreOrScope & IN_SCOPE) != 0;  | 
 | 
 | 
 | 
                    notSignedByAlias |= (inStoreOrScope & NOT_ALIAS) != 0;  | 
 | 
                    if (keystore != null) { | 
 | 
                        aliasNotInStore |= isSigned && (!inStore && !inScope);  | 
 | 
                    }  | 
 | 
 | 
 | 
                      | 
 | 
                    StringBuffer sb = null;  | 
 | 
                    if (verbose != null) { | 
 | 
                        sb = new StringBuffer();  | 
 | 
                        boolean inManifest =  | 
 | 
                            ((man.getAttributes(name) != null) ||  | 
 | 
                             (man.getAttributes("./"+name) != null) || | 
 | 
                             (man.getAttributes("/"+name) != null)); | 
 | 
                        sb.append(  | 
 | 
                          (isSigned ? rb.getString("s") : rb.getString("SPACE")) + | 
 | 
                          (inManifest ? rb.getString("m") : rb.getString("SPACE")) + | 
 | 
                          (inStore ? rb.getString("k") : rb.getString("SPACE")) + | 
 | 
                          (inScope ? rb.getString("i") : rb.getString("SPACE")) + | 
 | 
                          ((inStoreOrScope & NOT_ALIAS) != 0 ?"X":" ") +  | 
 | 
                          rb.getString("SPACE")); | 
 | 
                        sb.append("|"); | 
 | 
                    }  | 
 | 
 | 
 | 
                    // When -certs provided, display info has extra empty  | 
 | 
                      | 
 | 
                    if (isSigned) { | 
 | 
                        if (showcerts) sb.append('\n'); | 
 | 
                        for (CodeSigner signer: signers) { | 
 | 
                            // signerInfo() must be called even if -verbose  | 
 | 
                            // not provided. The method updates various  | 
 | 
                              | 
 | 
                            String si = signerInfo(signer, tab);  | 
 | 
                            if (showcerts) { | 
 | 
                                sb.append(si);  | 
 | 
                                sb.append('\n'); | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                    } else if (showcerts && !verbose.equals("all")) { | 
 | 
                        // Print no info for unsigned entries when -verbose:all,  | 
 | 
                          | 
 | 
                        if (signatureRelated(name)) { | 
 | 
                            sb.append("\n" + tab + rb.getString( | 
 | 
                                    ".Signature.related.entries.") + "\n\n");  | 
 | 
                        } else { | 
 | 
                            sb.append("\n" + tab + rb.getString( | 
 | 
                                    ".Unsigned.entries.") + "\n\n");  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
 | 
 | 
                    if (verbose != null) { | 
 | 
                        String label = sb.toString();  | 
 | 
                        if (signatureRelated(name)) { | 
 | 
                            // Entries inside META-INF and other unsigned  | 
 | 
                              | 
 | 
                            label = "-" + label;  | 
 | 
                        }  | 
 | 
 | 
 | 
                        // The label finally contains 2 parts separated by '|':  | 
 | 
                        // The legend displayed before the entry names, and  | 
 | 
                        // the cert info (if -certs specified).  | 
 | 
 | 
 | 
                        if (!output.containsKey(label)) { | 
 | 
                            output.put(label, new ArrayList<String>());  | 
 | 
                        }  | 
 | 
 | 
 | 
                        StringBuffer fb = new StringBuffer();  | 
 | 
                        String s = Long.toString(je.getSize());  | 
 | 
                        for (int i = 6 - s.length(); i > 0; --i) { | 
 | 
                            fb.append(' '); | 
 | 
                        }  | 
 | 
                        fb.append(s).append(' '). | 
 | 
                                append(new Date(je.getTime()).toString());  | 
 | 
                        fb.append(' ').append(name); | 
 | 
 | 
 | 
                        output.get(label).add(fb.toString());  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (verbose != null) { | 
 | 
                for (Entry<String,List<String>> s: output.entrySet()) { | 
 | 
                    List<String> files = s.getValue();  | 
 | 
                    String key = s.getKey();  | 
 | 
                    if (key.charAt(0) == '-') {  | 
 | 
                        key = key.substring(1);  | 
 | 
                    }  | 
 | 
                    int pipe = key.indexOf('|'); | 
 | 
                    if (verbose.equals("all")) { | 
 | 
                        for (String f: files) { | 
 | 
                            System.out.println(key.substring(0, pipe) + f);  | 
 | 
                            System.out.printf(key.substring(pipe+1));  | 
 | 
                        }  | 
 | 
                    } else { | 
 | 
                        if (verbose.equals("grouped")) { | 
 | 
                            for (String f: files) { | 
 | 
                                System.out.println(key.substring(0, pipe) + f);  | 
 | 
                            }  | 
 | 
                        } else if (verbose.equals("summary")) { | 
 | 
                            System.out.print(key.substring(0, pipe));  | 
 | 
                            if (files.size() > 1) { | 
 | 
                                System.out.println(files.get(0) + " " +  | 
 | 
                                        String.format(rb.getString(  | 
 | 
                                        ".and.d.more."), files.size()-1));  | 
 | 
                            } else { | 
 | 
                                System.out.println(files.get(0));  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                        System.out.printf(key.substring(pipe+1));  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                System.out.println();  | 
 | 
                System.out.println(rb.getString(  | 
 | 
                    ".s.signature.was.verified."));  | 
 | 
                System.out.println(rb.getString(  | 
 | 
                    ".m.entry.is.listed.in.manifest"));  | 
 | 
                System.out.println(rb.getString(  | 
 | 
                    ".k.at.least.one.certificate.was.found.in.keystore"));  | 
 | 
                System.out.println(rb.getString(  | 
 | 
                    ".i.at.least.one.certificate.was.found.in.identity.scope"));  | 
 | 
                if (ckaliases.size() > 0) { | 
 | 
                    System.out.println(rb.getString(  | 
 | 
                        ".X.not.signed.by.specified.alias.es."));  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (man == null) { | 
 | 
                System.out.println();  | 
 | 
                System.out.println(rb.getString("no.manifest.")); | 
 | 
            }  | 
 | 
 | 
 | 
            // Even if the verbose option is not specified, all out strings  | 
 | 
              | 
 | 
            if (!digestMap.isEmpty()  | 
 | 
                    || !sigMap.isEmpty()  | 
 | 
                    || !unparsableSignatures.isEmpty()) { | 
 | 
                if (verbose != null) { | 
 | 
                System.out.println();  | 
 | 
            }  | 
 | 
                for (String s : sigMap.keySet()) { | 
 | 
                    if (!digestMap.containsKey(s)) { | 
 | 
                        unparsableSignatures.putIfAbsent(s, String.format(  | 
 | 
                                rb.getString("history.nosf"), s)); | 
 | 
                    }  | 
 | 
                }  | 
 | 
                for (String s : digestMap.keySet()) { | 
 | 
                    PKCS7 p7 = sigMap.get(s);  | 
 | 
                    if (p7 != null) { | 
 | 
                        String history;  | 
 | 
                        try { | 
 | 
                            SignerInfo si = p7.getSignerInfos()[0];  | 
 | 
                            X509Certificate signer = si.getCertificate(p7);  | 
 | 
                            String digestAlg = digestMap.get(s);  | 
 | 
                            String sigAlg = AlgorithmId.makeSigAlg(  | 
 | 
                                    si.getDigestAlgorithmId().getName(),  | 
 | 
                                    si.getDigestEncryptionAlgorithmId().getName());  | 
 | 
                            PublicKey key = signer.getPublicKey();  | 
 | 
                            PKCS7 tsToken = si.getTsToken();  | 
 | 
                            if (tsToken != null) { | 
 | 
                                hasTimestampBlock = true;  | 
 | 
                                SignerInfo tsSi = tsToken.getSignerInfos()[0];  | 
 | 
                                X509Certificate tsSigner = tsSi.getCertificate(tsToken);  | 
 | 
                                byte[] encTsTokenInfo = tsToken.getContentInfo().getData();  | 
 | 
                                TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);  | 
 | 
                                PublicKey tsKey = tsSigner.getPublicKey();  | 
 | 
                                String tsDigestAlg = tsTokenInfo.getHashAlgorithm().getName();  | 
 | 
                                String tsSigAlg = AlgorithmId.makeSigAlg(  | 
 | 
                                        tsSi.getDigestAlgorithmId().getName(),  | 
 | 
                                        tsSi.getDigestEncryptionAlgorithmId().getName());  | 
 | 
                                Calendar c = Calendar.getInstance(  | 
 | 
                                        TimeZone.getTimeZone("UTC"), | 
 | 
                                        Locale.getDefault(Locale.Category.FORMAT));  | 
 | 
                                c.setTime(tsTokenInfo.getDate());  | 
 | 
                                history = String.format(  | 
 | 
                                        rb.getString("history.with.ts"), | 
 | 
                                        signer.getSubjectX500Principal(),  | 
 | 
                                        verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false),  | 
 | 
                                        verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false),  | 
 | 
                                        verifyWithWeak(key),  | 
 | 
                                        c,  | 
 | 
                                        tsSigner.getSubjectX500Principal(),  | 
 | 
                                        verifyWithWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET, true),  | 
 | 
                                        verifyWithWeak(tsSigAlg, SIG_PRIMITIVE_SET, true),  | 
 | 
                                        verifyWithWeak(tsKey));  | 
 | 
                            } else { | 
 | 
                                history = String.format(  | 
 | 
                                        rb.getString("history.without.ts"), | 
 | 
                                        signer.getSubjectX500Principal(),  | 
 | 
                                        verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false),  | 
 | 
                                        verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false),  | 
 | 
                                        verifyWithWeak(key));  | 
 | 
                            }  | 
 | 
                        } catch (Exception e) { | 
 | 
                            // The only usage of sigNameMap, remember the name  | 
 | 
                              | 
 | 
                            history = String.format(  | 
 | 
                                    rb.getString("history.unparsable"), | 
 | 
                                    sigNameMap.get(s));  | 
 | 
                        }  | 
 | 
                        if (verbose != null) { | 
 | 
                            System.out.println(history);  | 
 | 
                        }  | 
 | 
                    } else { | 
 | 
                        unparsableSignatures.putIfAbsent(s, String.format(  | 
 | 
                                rb.getString("history.nobk"), s)); | 
 | 
                    }  | 
 | 
                }  | 
 | 
                if (verbose != null) { | 
 | 
                    for (String s : unparsableSignatures.keySet()) { | 
 | 
                        System.out.println(unparsableSignatures.get(s));  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
            System.out.println();  | 
 | 
 | 
 | 
            // If signer is a trusted cert or private entry in user's own  | 
 | 
            // keystore, it can be self-signed. Please note aliasNotInStore  | 
 | 
              | 
 | 
            if (!aliasNotInStore && keystore != null) { | 
 | 
                signerSelfSigned = false;  | 
 | 
            }  | 
 | 
 | 
 | 
            if (!anySigned) { | 
 | 
                if (disabledAlgFound) { | 
 | 
                    if (verbose != null) { | 
 | 
                        System.out.println(rb.getString("jar.treated.unsigned.see.weak.verbose")); | 
 | 
                        System.out.println("\n  " + | 
 | 
                                DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS +  | 
 | 
                                "=" + Security.getProperty(DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS));  | 
 | 
                    } else { | 
 | 
                        System.out.println(rb.getString("jar.treated.unsigned.see.weak")); | 
 | 
                    }  | 
 | 
                } else if (hasSignature) { | 
 | 
                    System.out.println(rb.getString("jar.treated.unsigned")); | 
 | 
                } else { | 
 | 
                    System.out.println(rb.getString("jar.is.unsigned")); | 
 | 
                }  | 
 | 
            } else { | 
 | 
                displayMessagesAndResult(false);  | 
 | 
            }  | 
 | 
            return;  | 
 | 
        } catch (Exception e) { | 
 | 
            System.out.println(rb.getString("jarsigner.") + e); | 
 | 
            if (debug) { | 
 | 
                e.printStackTrace();  | 
 | 
            }  | 
 | 
        } finally {  | 
 | 
            if (jf != null) { | 
 | 
                jf.close();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        System.exit(1);  | 
 | 
    }  | 
 | 
 | 
 | 
    private void displayMessagesAndResult(boolean isSigning) { | 
 | 
        String result;  | 
 | 
        List<String> errors = new ArrayList<>();  | 
 | 
        List<String> warnings = new ArrayList<>();  | 
 | 
        List<String> info = new ArrayList<>();  | 
 | 
 | 
 | 
        boolean signerNotExpired = expireDate == null  | 
 | 
                || expireDate.after(new Date());  | 
 | 
 | 
 | 
        if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||  | 
 | 
                notYetValidCert || chainNotValidated || hasExpiredCert ||  | 
 | 
                hasUnsignedEntry || signerSelfSigned || (legacyAlg != 0) ||  | 
 | 
                (disabledAlg != 0) || aliasNotInStore || notSignedByAlias ||  | 
 | 
                tsaChainNotValidated ||  | 
 | 
                (hasExpiredTsaCert && !signerNotExpired)) { | 
 | 
 | 
 | 
            if (strict) { | 
 | 
                result = rb.getString(isSigning  | 
 | 
                        ? "jar.signed.with.signer.errors."  | 
 | 
                        : "jar.verified.with.signer.errors.");  | 
 | 
            } else { | 
 | 
                result = rb.getString(isSigning  | 
 | 
                        ? "jar.signed."  | 
 | 
                        : "jar.verified.");  | 
 | 
            }  | 
 | 
 | 
 | 
            if (badKeyUsage) { | 
 | 
                errors.add(rb.getString(isSigning  | 
 | 
                        ? "The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."  | 
 | 
                        : "This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));  | 
 | 
            }  | 
 | 
 | 
 | 
            if (badExtendedKeyUsage) { | 
 | 
                errors.add(rb.getString(isSigning  | 
 | 
                        ? "The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."  | 
 | 
                        : "This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));  | 
 | 
            }  | 
 | 
 | 
 | 
            if (badNetscapeCertType) { | 
 | 
                errors.add(rb.getString(isSigning  | 
 | 
                        ? "The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."  | 
 | 
                        : "This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (hasUnsignedEntry) { | 
 | 
                errors.add(rb.getString(  | 
 | 
                        "This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));  | 
 | 
            }  | 
 | 
            if (hasExpiredCert) { | 
 | 
                errors.add(rb.getString(isSigning  | 
 | 
                        ? "The.signer.certificate.has.expired."  | 
 | 
                        : "This.jar.contains.entries.whose.signer.certificate.has.expired."));  | 
 | 
            }  | 
 | 
            if (notYetValidCert) { | 
 | 
                errors.add(rb.getString(isSigning  | 
 | 
                        ? "The.signer.certificate.is.not.yet.valid."  | 
 | 
                        : "This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));  | 
 | 
            }  | 
 | 
 | 
 | 
            if (chainNotValidated) { | 
 | 
                errors.add(String.format(rb.getString(isSigning  | 
 | 
                                ? "The.signer.s.certificate.chain.is.invalid.reason.1"  | 
 | 
                                : "This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"),  | 
 | 
                        chainNotValidatedReason.getLocalizedMessage()));  | 
 | 
            }  | 
 | 
 | 
 | 
            if (hasExpiredTsaCert) { | 
 | 
                errors.add(rb.getString("The.timestamp.has.expired.")); | 
 | 
            }  | 
 | 
            if (tsaChainNotValidated) { | 
 | 
                errors.add(String.format(rb.getString(isSigning  | 
 | 
                                ? "The.tsa.certificate.chain.is.invalid.reason.1"  | 
 | 
                                : "This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"),  | 
 | 
                        tsaChainNotValidatedReason.getLocalizedMessage()));  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (notSignedByAlias) { | 
 | 
                errors.add(  | 
 | 
                        rb.getString("This.jar.contains.signed.entries.which.is.not.signed.by.the.specified.alias.es.")); | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (aliasNotInStore) { | 
 | 
                errors.add(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore.")); | 
 | 
            }  | 
 | 
 | 
 | 
            if (signerSelfSigned) { | 
 | 
                errors.add(rb.getString(isSigning  | 
 | 
                        ? "The.signer.s.certificate.is.self.signed."  | 
 | 
                        : "This.jar.contains.entries.whose.signer.certificate.is.self.signed."));  | 
 | 
            }  | 
 | 
 | 
 | 
            if (isSigning) { | 
 | 
                if ((legacyAlg & 1) == 1) { | 
 | 
                    warnings.add(String.format(  | 
 | 
                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."), | 
 | 
                            digestalg, "-digestalg"));  | 
 | 
                }  | 
 | 
 | 
 | 
                if ((disabledAlg & 1) == 1) { | 
 | 
                    errors.add(String.format(  | 
 | 
                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.and.is.disabled."), | 
 | 
                            digestalg, "-digestalg"));  | 
 | 
                }  | 
 | 
 | 
 | 
                if ((legacyAlg & 2) == 2) { | 
 | 
                    warnings.add(String.format(  | 
 | 
                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."), | 
 | 
                            sigalg, "-sigalg"));  | 
 | 
                }  | 
 | 
                if ((disabledAlg & 2) == 2) { | 
 | 
                    errors.add(String.format(  | 
 | 
                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.and.is.disabled."), | 
 | 
                            sigalg, "-sigalg"));  | 
 | 
                }  | 
 | 
 | 
 | 
                if ((legacyAlg & 4) == 4) { | 
 | 
                    warnings.add(String.format(  | 
 | 
                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."), | 
 | 
                            tSADigestAlg, "-tsadigestalg"));  | 
 | 
                }  | 
 | 
                if ((disabledAlg & 4) == 4) { | 
 | 
                    errors.add(String.format(  | 
 | 
                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.and.is.disabled."), | 
 | 
                            tSADigestAlg, "-tsadigestalg"));  | 
 | 
                }  | 
 | 
 | 
 | 
                if ((legacyAlg & 8) == 8) { | 
 | 
                    warnings.add(String.format(  | 
 | 
                            rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."), | 
 | 
                            privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));  | 
 | 
                }  | 
 | 
                if ((disabledAlg & 8) == 8) { | 
 | 
                    errors.add(String.format(  | 
 | 
                            rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk.and.is.disabled."), | 
 | 
                            privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                if ((legacyAlg & 1) != 0) { | 
 | 
                    warnings.add(String.format(  | 
 | 
                            rb.getString("The.digest.algorithm.1.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."), | 
 | 
                            legacyDigestAlg));  | 
 | 
                }  | 
 | 
 | 
 | 
                if ((legacyAlg & 2) == 2) { | 
 | 
                     warnings.add(String.format(  | 
 | 
                             rb.getString("The.signature.algorithm.1.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."), | 
 | 
                             legacySigAlg));  | 
 | 
                }  | 
 | 
 | 
 | 
                if ((legacyAlg & 4) != 0) { | 
 | 
                    warnings.add(String.format(  | 
 | 
                            rb.getString("The.digest.algorithm.1.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."), | 
 | 
                            legacyTsaDigestAlg));  | 
 | 
                }  | 
 | 
 | 
 | 
                if ((legacyAlg & 8) == 8) { | 
 | 
                    warnings.add(String.format(  | 
 | 
                            rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."), | 
 | 
                            weakPublicKey.getAlgorithm(), KeyUtil.getKeySize(weakPublicKey)));  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } else { | 
 | 
            result = rb.getString(isSigning ? "jar.signed." : "jar.verified.");  | 
 | 
        }  | 
 | 
 | 
 | 
        if (hasExpiredTsaCert) { | 
 | 
              | 
 | 
            hasExpiringTsaCert = false;  | 
 | 
        }  | 
 | 
 | 
 | 
        if (hasExpiringCert ||  | 
 | 
                (hasExpiringTsaCert  && expireDate != null) ||  | 
 | 
                (noTimestamp && expireDate != null) ||  | 
 | 
                (hasExpiredTsaCert && signerNotExpired)) { | 
 | 
 | 
 | 
            if (hasExpiredTsaCert && signerNotExpired) { | 
 | 
                if (expireDate != null) { | 
 | 
                    warnings.add(String.format(  | 
 | 
                            rb.getString("The.timestamp.expired.1.but.usable.2"), | 
 | 
                            tsaExpireDate,  | 
 | 
                            expireDate));  | 
 | 
                }  | 
 | 
                  | 
 | 
                hasExpiredTsaCert = false;  | 
 | 
            }  | 
 | 
            if (hasExpiringCert) { | 
 | 
                warnings.add(rb.getString(isSigning  | 
 | 
                        ? "The.signer.certificate.will.expire.within.six.months."  | 
 | 
                        : "This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months."));  | 
 | 
            }  | 
 | 
            if (hasExpiringTsaCert && expireDate != null) { | 
 | 
                if (expireDate.after(tsaExpireDate)) { | 
 | 
                    warnings.add(String.format(rb.getString(  | 
 | 
                            "The.timestamp.will.expire.within.one.year.on.1.but.2"), tsaExpireDate, expireDate));  | 
 | 
                } else { | 
 | 
                    warnings.add(String.format(rb.getString(  | 
 | 
                            "The.timestamp.will.expire.within.one.year.on.1"), tsaExpireDate));  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (noTimestamp && expireDate != null) { | 
 | 
                if (hasTimestampBlock) { | 
 | 
                    warnings.add(String.format(rb.getString(isSigning  | 
 | 
                            ? "invalid.timestamp.signing"  | 
 | 
                            : "bad.timestamp.verifying"), expireDate));  | 
 | 
                } else { | 
 | 
                    warnings.add(String.format(rb.getString(isSigning  | 
 | 
                            ? "no.timestamp.signing"  | 
 | 
                            : "no.timestamp.verifying"), expireDate));  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        System.out.println(result);  | 
 | 
        if (strict) { | 
 | 
            if (!errors.isEmpty()) { | 
 | 
                System.out.println();  | 
 | 
                System.out.println(rb.getString("Error.")); | 
 | 
                errors.forEach(System.out::println);  | 
 | 
            }  | 
 | 
            if (!warnings.isEmpty()) { | 
 | 
                System.out.println();  | 
 | 
                System.out.println(rb.getString("Warning.")); | 
 | 
                warnings.forEach(System.out::println);  | 
 | 
            }  | 
 | 
        } else { | 
 | 
            if (!errors.isEmpty() || !warnings.isEmpty()) { | 
 | 
                System.out.println();  | 
 | 
                System.out.println(rb.getString("Warning.")); | 
 | 
                errors.forEach(System.out::println);  | 
 | 
                warnings.forEach(System.out::println);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        if (!isSigning && (!errors.isEmpty() || !warnings.isEmpty())) { | 
 | 
            if (! (verbose != null && showcerts)) { | 
 | 
                System.out.println();  | 
 | 
                System.out.println(rb.getString(  | 
 | 
                        "Re.run.with.the.verbose.and.certs.options.for.more.details."));  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        if (isSigning || verbose != null) { | 
 | 
              | 
 | 
            if (!hasExpiringCert && !hasExpiredCert  | 
 | 
                    && expireDate != null && signerNotExpired) { | 
 | 
                info.add(String.format(rb.getString(  | 
 | 
                        "The.signer.certificate.will.expire.on.1."), expireDate));  | 
 | 
            }  | 
 | 
            if (!noTimestamp) { | 
 | 
                if (!hasExpiringTsaCert && !hasExpiredTsaCert && tsaExpireDate != null) { | 
 | 
                    if (signerNotExpired) { | 
 | 
                        info.add(String.format(rb.getString(  | 
 | 
                                "The.timestamp.will.expire.on.1."), tsaExpireDate));  | 
 | 
                    } else { | 
 | 
                        info.add(String.format(rb.getString(  | 
 | 
                                "signer.cert.expired.1.but.timestamp.good.2."),  | 
 | 
                                expireDate,  | 
 | 
                                tsaExpireDate));  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        if (!info.isEmpty()) { | 
 | 
            System.out.println();  | 
 | 
            info.forEach(System.out::println);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private String verifyWithWeak(String alg, Set<CryptoPrimitive> primitiveSet, boolean tsa) { | 
 | 
        if (DISABLED_CHECK.permits(primitiveSet, alg, null)) { | 
 | 
            if (LEGACY_CHECK.permits(primitiveSet, alg, null)) { | 
 | 
                return alg;  | 
 | 
            } else { | 
 | 
                if (primitiveSet == SIG_PRIMITIVE_SET) { | 
 | 
                   legacyAlg |= 2;  | 
 | 
                   legacySigAlg = alg;  | 
 | 
                } else { | 
 | 
                    if (tsa) { | 
 | 
                        legacyAlg |= 4;  | 
 | 
                        legacyTsaDigestAlg = alg;  | 
 | 
                    } else { | 
 | 
                        legacyAlg |= 1;  | 
 | 
                        legacyDigestAlg = alg;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                return String.format(rb.getString("with.weak"), alg); | 
 | 
            }  | 
 | 
        } else { | 
 | 
            disabledAlgFound = true;  | 
 | 
            return String.format(rb.getString("with.disabled"), alg); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private String verifyWithWeak(PublicKey key) { | 
 | 
        int kLen = KeyUtil.getKeySize(key);  | 
 | 
        if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) { | 
 | 
            if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) { | 
 | 
                if (kLen >= 0) { | 
 | 
                    return String.format(rb.getString("key.bit"), kLen); | 
 | 
                } else { | 
 | 
                    return rb.getString("unknown.size"); | 
 | 
                }  | 
 | 
            } else { | 
 | 
                weakPublicKey = key;  | 
 | 
                legacyAlg |= 8;  | 
 | 
                return String.format(rb.getString("key.bit.weak"), kLen); | 
 | 
            }  | 
 | 
        } else { | 
 | 
           disabledAlgFound = true;  | 
 | 
           return String.format(rb.getString("key.bit.disabled"), kLen); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void checkWeakSign(String alg, Set<CryptoPrimitive> primitiveSet, boolean tsa) { | 
 | 
        if (DISABLED_CHECK.permits(primitiveSet, alg, null)) { | 
 | 
            if (!LEGACY_CHECK.permits(primitiveSet, alg, null)) { | 
 | 
                if (primitiveSet == SIG_PRIMITIVE_SET) { | 
 | 
                   legacyAlg |= 2;  | 
 | 
                } else { | 
 | 
                    if (tsa) { | 
 | 
                        legacyAlg |= 4;  | 
 | 
                    } else { | 
 | 
                        legacyAlg |= 1;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } else { | 
 | 
           if (primitiveSet == SIG_PRIMITIVE_SET) { | 
 | 
               disabledAlg |= 2;  | 
 | 
           } else { | 
 | 
               if (tsa) { | 
 | 
                   disabledAlg |= 4;  | 
 | 
               } else { | 
 | 
                   disabledAlg |= 1;  | 
 | 
               }  | 
 | 
           }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void checkWeakSign(PrivateKey key) { | 
 | 
        if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) { | 
 | 
            if (!LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) { | 
 | 
                legacyAlg |= 8;  | 
 | 
            }  | 
 | 
        } else { | 
 | 
            disabledAlg |= 8;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static MessageFormat validityTimeForm = null;  | 
 | 
    private static MessageFormat notYetTimeForm = null;  | 
 | 
    private static MessageFormat expiredTimeForm = null;  | 
 | 
    private static MessageFormat expiringTimeForm = null;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    String printCert(boolean isTsCert, String tab, Certificate c,  | 
 | 
        Date timestamp, boolean checkUsage) throws Exception { | 
 | 
 | 
 | 
        StringBuilder certStr = new StringBuilder();  | 
 | 
        String space = rb.getString("SPACE"); | 
 | 
        X509Certificate x509Cert = null;  | 
 | 
 | 
 | 
        if (c instanceof X509Certificate) { | 
 | 
            x509Cert = (X509Certificate) c;  | 
 | 
            certStr.append(tab).append(x509Cert.getType())  | 
 | 
                .append(rb.getString("COMMA")) | 
 | 
                .append(x509Cert.getSubjectDN().getName());  | 
 | 
        } else { | 
 | 
            certStr.append(tab).append(c.getType());  | 
 | 
        }  | 
 | 
 | 
 | 
        String alias = storeHash.get(c);  | 
 | 
        if (alias != null) { | 
 | 
            certStr.append(space).append(alias);  | 
 | 
        }  | 
 | 
 | 
 | 
        if (x509Cert != null) { | 
 | 
 | 
 | 
            certStr.append("\n").append(tab).append("["); | 
 | 
 | 
 | 
            if (trustedCerts.contains(x509Cert)) { | 
 | 
                certStr.append(rb.getString("trusted.certificate")); | 
 | 
            } else { | 
 | 
                Date notAfter = x509Cert.getNotAfter();  | 
 | 
                try { | 
 | 
                    boolean printValidity = true;  | 
 | 
                    if (isTsCert) { | 
 | 
                        if (tsaExpireDate == null || tsaExpireDate.after(notAfter)) { | 
 | 
                            tsaExpireDate = notAfter;  | 
 | 
                        }  | 
 | 
                    } else { | 
 | 
                        if (expireDate == null || expireDate.after(notAfter)) { | 
 | 
                            expireDate = notAfter;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    if (timestamp == null) { | 
 | 
                        x509Cert.checkValidity();  | 
 | 
                          | 
 | 
                        long age = isTsCert ? ONE_YEAR : SIX_MONTHS;  | 
 | 
                        if (notAfter.getTime() < System.currentTimeMillis() + age) { | 
 | 
                            if (isTsCert) { | 
 | 
                                hasExpiringTsaCert = true;  | 
 | 
                            } else { | 
 | 
                                hasExpiringCert = true;  | 
 | 
                            }  | 
 | 
                            if (expiringTimeForm == null) { | 
 | 
                                expiringTimeForm = new MessageFormat(  | 
 | 
                                        rb.getString("certificate.will.expire.on")); | 
 | 
                            }  | 
 | 
                            Object[] source = {notAfter}; | 
 | 
                            certStr.append(expiringTimeForm.format(source));  | 
 | 
                            printValidity = false;  | 
 | 
                        }  | 
 | 
                    } else { | 
 | 
                        x509Cert.checkValidity(timestamp);  | 
 | 
                    }  | 
 | 
                    if (printValidity) { | 
 | 
                        if (validityTimeForm == null) { | 
 | 
                            validityTimeForm = new MessageFormat(  | 
 | 
                                    rb.getString("certificate.is.valid.from")); | 
 | 
                        }  | 
 | 
                        Object[] source = {x509Cert.getNotBefore(), notAfter}; | 
 | 
                        certStr.append(validityTimeForm.format(source));  | 
 | 
                    }  | 
 | 
                } catch (CertificateExpiredException cee) { | 
 | 
                    if (isTsCert) { | 
 | 
                        hasExpiredTsaCert = true;  | 
 | 
                    } else { | 
 | 
                        hasExpiredCert = true;  | 
 | 
                    }  | 
 | 
 | 
 | 
                    if (expiredTimeForm == null) { | 
 | 
                        expiredTimeForm = new MessageFormat(  | 
 | 
                                rb.getString("certificate.expired.on")); | 
 | 
                    }  | 
 | 
                    Object[] source = {notAfter}; | 
 | 
                    certStr.append(expiredTimeForm.format(source));  | 
 | 
 | 
 | 
                } catch (CertificateNotYetValidException cnyve) { | 
 | 
                    if (!isTsCert) notYetValidCert = true;  | 
 | 
 | 
 | 
                    if (notYetTimeForm == null) { | 
 | 
                        notYetTimeForm = new MessageFormat(  | 
 | 
                                rb.getString("certificate.is.not.valid.until")); | 
 | 
                    }  | 
 | 
                    Object[] source = {x509Cert.getNotBefore()}; | 
 | 
                    certStr.append(notYetTimeForm.format(source));  | 
 | 
                }  | 
 | 
            }  | 
 | 
            certStr.append("]"); | 
 | 
 | 
 | 
            if (checkUsage) { | 
 | 
                boolean[] bad = new boolean[3];  | 
 | 
                checkCertUsage(x509Cert, bad);  | 
 | 
                if (bad[0] || bad[1] || bad[2]) { | 
 | 
                    String x = "";  | 
 | 
                    if (bad[0]) { | 
 | 
                        x ="KeyUsage";  | 
 | 
                    }  | 
 | 
                    if (bad[1]) { | 
 | 
                        if (x.length() > 0) x = x + ", ";  | 
 | 
                        x = x + "ExtendedKeyUsage";  | 
 | 
                    }  | 
 | 
                    if (bad[2]) { | 
 | 
                        if (x.length() > 0) x = x + ", ";  | 
 | 
                        x = x + "NetscapeCertType";  | 
 | 
                    }  | 
 | 
                    certStr.append("\n").append(tab) | 
 | 
                        .append(MessageFormat.format(rb.getString(  | 
 | 
                        ".{0}.extension.does.not.support.code.signing."), x)); | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return certStr.toString();  | 
 | 
    }  | 
 | 
 | 
 | 
    private static MessageFormat signTimeForm = null;  | 
 | 
 | 
 | 
    private String printTimestamp(String tab, Timestamp timestamp) { | 
 | 
 | 
 | 
        if (signTimeForm == null) { | 
 | 
            signTimeForm =  | 
 | 
                new MessageFormat(rb.getString("entry.was.signed.on")); | 
 | 
        }  | 
 | 
        Object[] source = { timestamp.getTimestamp() }; | 
 | 
 | 
 | 
        return new StringBuilder().append(tab).append("[") | 
 | 
            .append(signTimeForm.format(source)).append("]").toString(); | 
 | 
    }  | 
 | 
 | 
 | 
    private Map<CodeSigner,Integer> cacheForInKS = new IdentityHashMap<>();  | 
 | 
 | 
 | 
    private int inKeyStoreForOneSigner(CodeSigner signer) { | 
 | 
        if (cacheForInKS.containsKey(signer)) { | 
 | 
            return cacheForInKS.get(signer);  | 
 | 
        }  | 
 | 
 | 
 | 
        boolean found = false;  | 
 | 
        int result = 0;  | 
 | 
        List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates();  | 
 | 
        for (Certificate c : certs) { | 
 | 
            String alias = storeHash.get(c);  | 
 | 
            if (alias != null) { | 
 | 
                if (alias.startsWith("(")) { | 
 | 
                    result |= IN_KEYSTORE;  | 
 | 
                } else if (alias.startsWith("[")) { | 
 | 
                    result |= IN_SCOPE;  | 
 | 
                }  | 
 | 
                if (ckaliases.contains(alias.substring(1, alias.length() - 1))) { | 
 | 
                    result |= SIGNED_BY_ALIAS;  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                if (store != null) { | 
 | 
                    try { | 
 | 
                        alias = store.getCertificateAlias(c);  | 
 | 
                    } catch (KeyStoreException kse) { | 
 | 
                        // never happens, because keystore has been loaded  | 
 | 
                    }  | 
 | 
                    if (alias != null) { | 
 | 
                        storeHash.put(c, "(" + alias + ")"); | 
 | 
                        found = true;  | 
 | 
                        result |= IN_KEYSTORE;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                if (ckaliases.contains(alias)) { | 
 | 
                    result |= SIGNED_BY_ALIAS;  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        cacheForInKS.put(signer, result);  | 
 | 
        return result;  | 
 | 
    }  | 
 | 
 | 
 | 
    Hashtable<Certificate, String> storeHash = new Hashtable<>();  | 
 | 
 | 
 | 
    int inKeyStore(CodeSigner[] signers) { | 
 | 
 | 
 | 
        if (signers == null)  | 
 | 
            return 0;  | 
 | 
 | 
 | 
        int output = 0;  | 
 | 
 | 
 | 
        for (CodeSigner signer: signers) { | 
 | 
            int result = inKeyStoreForOneSigner(signer);  | 
 | 
            output |= result;  | 
 | 
        }  | 
 | 
        if (ckaliases.size() > 0 && (output & SIGNED_BY_ALIAS) == 0) { | 
 | 
            output |= NOT_ALIAS;  | 
 | 
        }  | 
 | 
        return output;  | 
 | 
    }  | 
 | 
 | 
 | 
    void signJar(String jarName, String alias, String[] args)  | 
 | 
            throws Exception { | 
 | 
 | 
 | 
        checkWeakSign(digestalg, DIGEST_PRIMITIVE_SET, false);  | 
 | 
        checkWeakSign(tSADigestAlg, DIGEST_PRIMITIVE_SET, true);  | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        if (sigalg == null) { | 
 | 
            sigalg = getDefaultSignatureAlgorithm(privateKey);  | 
 | 
        }  | 
 | 
        checkWeakSign(sigalg, SIG_PRIMITIVE_SET, false);  | 
 | 
 | 
 | 
        checkWeakSign(privateKey);  | 
 | 
 | 
 | 
        boolean aliasUsed = false;  | 
 | 
        X509Certificate tsaCert = null;  | 
 | 
 | 
 | 
        if (sigfile == null) { | 
 | 
            sigfile = alias;  | 
 | 
            aliasUsed = true;  | 
 | 
        }  | 
 | 
 | 
 | 
        if (sigfile.length() > 8) { | 
 | 
            sigfile = sigfile.substring(0, 8).toUpperCase(Locale.ENGLISH);  | 
 | 
        } else { | 
 | 
            sigfile = sigfile.toUpperCase(Locale.ENGLISH);  | 
 | 
        }  | 
 | 
 | 
 | 
        StringBuilder tmpSigFile = new StringBuilder(sigfile.length());  | 
 | 
        for (int j = 0; j < sigfile.length(); j++) { | 
 | 
            char c = sigfile.charAt(j);  | 
 | 
            if (!  | 
 | 
                ((c>= 'A' && c<= 'Z') ||  | 
 | 
                (c>= '0' && c<= '9') ||  | 
 | 
                (c == '-') ||  | 
 | 
                (c == '_'))) { | 
 | 
                if (aliasUsed) { | 
 | 
                      | 
 | 
                    c = '_';  | 
 | 
                } else { | 
 | 
                 throw new  | 
 | 
                   RuntimeException(rb.getString  | 
 | 
                        ("signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.")); | 
 | 
                }  | 
 | 
            }  | 
 | 
            tmpSigFile.append(c);  | 
 | 
        }  | 
 | 
 | 
 | 
        sigfile = tmpSigFile.toString();  | 
 | 
 | 
 | 
        String tmpJarName;  | 
 | 
        if (signedjar == null) tmpJarName = jarName+".sig";  | 
 | 
        else tmpJarName = signedjar;  | 
 | 
 | 
 | 
        File jarFile = new File(jarName);  | 
 | 
        File signedJarFile = new File(tmpJarName);  | 
 | 
 | 
 | 
          | 
 | 
        try { | 
 | 
            zipFile = new ZipFile(jarName);  | 
 | 
        } catch (IOException ioe) { | 
 | 
            error(rb.getString("unable.to.open.jar.file.")+jarName, ioe); | 
 | 
        }  | 
 | 
 | 
 | 
        FileOutputStream fos = null;  | 
 | 
        try { | 
 | 
            fos = new FileOutputStream(signedJarFile);  | 
 | 
        } catch (IOException ioe) { | 
 | 
            error(rb.getString("unable.to.create.")+tmpJarName, ioe); | 
 | 
        }  | 
 | 
 | 
 | 
        PrintStream ps = new PrintStream(fos);  | 
 | 
        ZipOutputStream zos = new ZipOutputStream(ps);  | 
 | 
 | 
 | 
          | 
 | 
        String sfFilename = (META_INF + sigfile + ".SF").toUpperCase(Locale.ENGLISH);  | 
 | 
        String bkFilename = (META_INF + sigfile + ".DSA").toUpperCase(Locale.ENGLISH);  | 
 | 
 | 
 | 
        Manifest manifest = new Manifest();  | 
 | 
        Map<String,Attributes> mfEntries = manifest.getEntries();  | 
 | 
 | 
 | 
          | 
 | 
        Attributes oldAttr = null;  | 
 | 
 | 
 | 
        boolean mfModified = false;  | 
 | 
        boolean mfCreated = false;  | 
 | 
        byte[] mfRawBytes = null;  | 
 | 
 | 
 | 
        try { | 
 | 
            MessageDigest digests[] = { MessageDigest.getInstance(digestalg) }; | 
 | 
 | 
 | 
              | 
 | 
            ZipEntry mfFile;  | 
 | 
            if ((mfFile = getManifestFile(zipFile)) != null) { | 
 | 
                  | 
 | 
                mfRawBytes = getBytes(zipFile, mfFile);  | 
 | 
                manifest.read(new ByteArrayInputStream(mfRawBytes));  | 
 | 
                oldAttr = (Attributes)(manifest.getMainAttributes().clone());  | 
 | 
            } else { | 
 | 
                  | 
 | 
                Attributes mattr = manifest.getMainAttributes();  | 
 | 
                mattr.putValue(Attributes.Name.MANIFEST_VERSION.toString(),  | 
 | 
                               "1.0");  | 
 | 
                String javaVendor = System.getProperty("java.vendor"); | 
 | 
                String jdkVersion = System.getProperty("java.version"); | 
 | 
                mattr.putValue("Created-By", jdkVersion + " (" +javaVendor | 
 | 
                               + ")");  | 
 | 
                mfFile = new ZipEntry(JarFile.MANIFEST_NAME);  | 
 | 
                mfCreated = true;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
             */  | 
 | 
            Vector<ZipEntry> mfFiles = new Vector<>();  | 
 | 
 | 
 | 
            boolean wasSigned = false;  | 
 | 
 | 
 | 
            for (Enumeration<? extends ZipEntry> enum_=zipFile.entries();  | 
 | 
                        enum_.hasMoreElements();) { | 
 | 
                ZipEntry ze = enum_.nextElement();  | 
 | 
 | 
 | 
                if (ze.getName().startsWith(META_INF)) { | 
 | 
                    // Store META-INF files in vector, so they can be written  | 
 | 
                      | 
 | 
                    mfFiles.addElement(ze);  | 
 | 
 | 
 | 
                    if (SignatureFileVerifier.isBlockOrSF(  | 
 | 
                            ze.getName().toUpperCase(Locale.ENGLISH))) { | 
 | 
                        wasSigned = true;  | 
 | 
                    }  | 
 | 
 | 
 | 
                    if (signatureRelated(ze.getName())) { | 
 | 
                          | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
 | 
 | 
                if (manifest.getAttributes(ze.getName()) != null) { | 
 | 
                    // jar entry is contained in manifest, check and  | 
 | 
                      | 
 | 
                    if (updateDigests(ze, zipFile, digests,  | 
 | 
                                      manifest) == true) { | 
 | 
                        mfModified = true;  | 
 | 
                    }  | 
 | 
                } else if (!ze.isDirectory()) { | 
 | 
                      | 
 | 
                    Attributes attrs = getDigestAttributes(ze, zipFile,  | 
 | 
                                                           digests);  | 
 | 
                    mfEntries.put(ze.getName(), attrs);  | 
 | 
                    mfModified = true;  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (mfModified) { | 
 | 
                ByteArrayOutputStream baos = new ByteArrayOutputStream();  | 
 | 
                manifest.write(baos);  | 
 | 
                if (wasSigned) { | 
 | 
                    byte[] newBytes = baos.toByteArray();  | 
 | 
                    if (mfRawBytes != null  | 
 | 
                            && oldAttr.equals(manifest.getMainAttributes())) { | 
 | 
 | 
 | 
                        /*  | 
 | 
                         * Note:  | 
 | 
                         *  | 
 | 
                         * The Attributes object is based on HashMap and can handle  | 
 | 
                         * continuation columns. Therefore, even if the contents are  | 
 | 
                         * not changed (in a Map view), the bytes that it write()  | 
 | 
                         * may be different from the original bytes that it read()  | 
 | 
                         * from. Since the signature on the main attributes is based  | 
 | 
                         * on raw bytes, we must retain the exact bytes.  | 
 | 
                         */  | 
 | 
 | 
 | 
                        int newPos = findHeaderEnd(newBytes);  | 
 | 
                        int oldPos = findHeaderEnd(mfRawBytes);  | 
 | 
 | 
 | 
                        if (newPos == oldPos) { | 
 | 
                            System.arraycopy(mfRawBytes, 0, newBytes, 0, oldPos);  | 
 | 
                        } else { | 
 | 
                              | 
 | 
                            byte[] lastBytes = new byte[oldPos +  | 
 | 
                                    newBytes.length - newPos];  | 
 | 
                            System.arraycopy(mfRawBytes, 0, lastBytes, 0, oldPos);  | 
 | 
                            System.arraycopy(newBytes, newPos, lastBytes, oldPos,  | 
 | 
                                    newBytes.length - newPos);  | 
 | 
                            newBytes = lastBytes;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    mfRawBytes = newBytes;  | 
 | 
                } else { | 
 | 
                    mfRawBytes = baos.toByteArray();  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (mfModified) { | 
 | 
                  | 
 | 
                mfFile = new ZipEntry(JarFile.MANIFEST_NAME);  | 
 | 
            }  | 
 | 
            if (verbose != null) { | 
 | 
                if (mfCreated) { | 
 | 
                    System.out.println(rb.getString(".adding.") + | 
 | 
                                        mfFile.getName());  | 
 | 
                } else if (mfModified) { | 
 | 
                    System.out.println(rb.getString(".updating.") + | 
 | 
                                        mfFile.getName());  | 
 | 
                }  | 
 | 
            }  | 
 | 
            zos.putNextEntry(mfFile);  | 
 | 
            zos.write(mfRawBytes);  | 
 | 
 | 
 | 
              | 
 | 
            ManifestDigester manDig = new ManifestDigester(mfRawBytes);  | 
 | 
            SignatureFile sf = new SignatureFile(digests, manifest, manDig,  | 
 | 
                                                 sigfile, signManifest);  | 
 | 
 | 
 | 
            if (tsaAlias != null) { | 
 | 
                tsaCert = getTsaCert(tsaAlias);  | 
 | 
            }  | 
 | 
 | 
 | 
            if (tsaUrl == null && tsaCert == null) { | 
 | 
                noTimestamp = true;  | 
 | 
            }  | 
 | 
 | 
 | 
            SignatureFile.Block block = null;  | 
 | 
 | 
 | 
            try { | 
 | 
                block =  | 
 | 
                    sf.generateBlock(privateKey, sigalg, certChain,  | 
 | 
                        externalSF, tsaUrl, tsaCert, tSAPolicyID, tSADigestAlg,  | 
 | 
                        signingMechanism, args, zipFile);  | 
 | 
            } catch (SocketTimeoutException e) { | 
 | 
                  | 
 | 
                error(rb.getString("unable.to.sign.jar.") + | 
 | 
                rb.getString("no.response.from.the.Timestamping.Authority.") + | 
 | 
                "\n  -J-Dhttp.proxyHost=<hostname>" +  | 
 | 
                "\n  -J-Dhttp.proxyPort=<portnumber>\n" +  | 
 | 
                rb.getString("or") + | 
 | 
                "\n  -J-Dhttps.proxyHost=<hostname> " +  | 
 | 
                "\n  -J-Dhttps.proxyPort=<portnumber> ", e);  | 
 | 
            }  | 
 | 
 | 
 | 
            sfFilename = sf.getMetaName();  | 
 | 
            bkFilename = block.getMetaName();  | 
 | 
 | 
 | 
            ZipEntry sfFile = new ZipEntry(sfFilename);  | 
 | 
            ZipEntry bkFile = new ZipEntry(bkFilename);  | 
 | 
 | 
 | 
            long time = System.currentTimeMillis();  | 
 | 
            sfFile.setTime(time);  | 
 | 
            bkFile.setTime(time);  | 
 | 
 | 
 | 
              | 
 | 
            zos.putNextEntry(sfFile);  | 
 | 
            sf.write(zos);  | 
 | 
            if (verbose != null) { | 
 | 
                if (zipFile.getEntry(sfFilename) != null) { | 
 | 
                    System.out.println(rb.getString(".updating.") + | 
 | 
                                sfFilename);  | 
 | 
                } else { | 
 | 
                    System.out.println(rb.getString(".adding.") + | 
 | 
                                sfFilename);  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            if (verbose != null) { | 
 | 
                if (tsaUrl != null || tsaCert != null) { | 
 | 
                    System.out.println(  | 
 | 
                        rb.getString("requesting.a.signature.timestamp")); | 
 | 
                }  | 
 | 
                if (tsaUrl != null) { | 
 | 
                    System.out.println(rb.getString("TSA.location.") + tsaUrl); | 
 | 
                }  | 
 | 
                if (tsaCert != null) { | 
 | 
                    URI tsaURI = TimestampedSigner.getTimestampingURI(tsaCert);  | 
 | 
                    if (tsaURI != null) { | 
 | 
                        System.out.println(rb.getString("TSA.location.") + | 
 | 
                            tsaURI);  | 
 | 
                    }  | 
 | 
                    System.out.println(rb.getString("TSA.certificate.") + | 
 | 
                            printCert(true, "", tsaCert, null, false));  | 
 | 
                }  | 
 | 
                if (signingMechanism != null) { | 
 | 
                    System.out.println(  | 
 | 
                        rb.getString("using.an.alternative.signing.mechanism")); | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            zos.putNextEntry(bkFile);  | 
 | 
            block.write(zos);  | 
 | 
            if (verbose != null) { | 
 | 
                if (zipFile.getEntry(bkFilename) != null) { | 
 | 
                    System.out.println(rb.getString(".updating.") + | 
 | 
                        bkFilename);  | 
 | 
                } else { | 
 | 
                    System.out.println(rb.getString(".adding.") + | 
 | 
                        bkFilename);  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            // Write out all other META-INF files that we stored in the  | 
 | 
              | 
 | 
            for (int i=0; i<mfFiles.size(); i++) { | 
 | 
                ZipEntry ze = mfFiles.elementAt(i);  | 
 | 
                if (!ze.getName().equalsIgnoreCase(JarFile.MANIFEST_NAME)  | 
 | 
                    && !ze.getName().equalsIgnoreCase(sfFilename)  | 
 | 
                    && !ze.getName().equalsIgnoreCase(bkFilename)) { | 
 | 
                    writeEntry(zipFile, zos, ze);  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            for (Enumeration<? extends ZipEntry> enum_=zipFile.entries();  | 
 | 
                        enum_.hasMoreElements();) { | 
 | 
                ZipEntry ze = enum_.nextElement();  | 
 | 
 | 
 | 
                if (!ze.getName().startsWith(META_INF)) { | 
 | 
                    if (verbose != null) { | 
 | 
                        if (manifest.getAttributes(ze.getName()) != null)  | 
 | 
                          System.out.println(rb.getString(".signing.") + | 
 | 
                                ze.getName());  | 
 | 
                        else  | 
 | 
                          System.out.println(rb.getString(".adding.") + | 
 | 
                                ze.getName());  | 
 | 
                    }  | 
 | 
                    writeEntry(zipFile, zos, ze);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } catch(IOException ioe) { | 
 | 
            error(rb.getString("unable.to.sign.jar.")+ioe, ioe); | 
 | 
        } finally { | 
 | 
              | 
 | 
            if (zipFile != null) { | 
 | 
                zipFile.close();  | 
 | 
                zipFile = null;  | 
 | 
            }  | 
 | 
 | 
 | 
            if (zos != null) { | 
 | 
                zos.close();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        // The JarSigner API always accepts the timestamp received.  | 
 | 
        // We need to extract the certs from the signed jar to  | 
 | 
          | 
 | 
        try (JarFile check = new JarFile(signedJarFile)) { | 
 | 
            PKCS7 p7 = new PKCS7(check.getInputStream(check.getEntry(  | 
 | 
                    "META-INF/" + sigfile + "." + privateKey.getAlgorithm())));  | 
 | 
            Timestamp ts = null;  | 
 | 
            try { | 
 | 
                SignerInfo si = p7.getSignerInfos()[0];  | 
 | 
                if (si.getTsToken() != null) { | 
 | 
                    hasTimestampBlock = true;  | 
 | 
                }  | 
 | 
                ts = si.getTimestamp();  | 
 | 
            } catch (Exception e) { | 
 | 
                tsaChainNotValidated = true;  | 
 | 
                tsaChainNotValidatedReason = e;  | 
 | 
            }  | 
 | 
              | 
 | 
            String result = certsAndTSInfo("", "    ", Arrays.asList(certChain), ts); | 
 | 
            if (verbose != null) { | 
 | 
                System.out.println(result);  | 
 | 
            }  | 
 | 
        } catch (Exception e) { | 
 | 
            if (debug) { | 
 | 
                e.printStackTrace();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        if (signedjar == null) { | 
 | 
            // attempt an atomic rename. If that fails,  | 
 | 
            // rename the original jar file, then the signed  | 
 | 
              | 
 | 
            if (!signedJarFile.renameTo(jarFile)) { | 
 | 
                File origJar = new File(jarName+".orig");  | 
 | 
 | 
 | 
                if (jarFile.renameTo(origJar)) { | 
 | 
                    if (signedJarFile.renameTo(jarFile)) { | 
 | 
                        origJar.delete();  | 
 | 
                    } else { | 
 | 
                        MessageFormat form = new MessageFormat(rb.getString  | 
 | 
                    ("attempt.to.rename.signedJarFile.to.jarFile.failed")); | 
 | 
                        Object[] source = {signedJarFile, jarFile}; | 
 | 
                        error(form.format(source));  | 
 | 
                    }  | 
 | 
                } else { | 
 | 
                    MessageFormat form = new MessageFormat(rb.getString  | 
 | 
                        ("attempt.to.rename.jarFile.to.origJar.failed")); | 
 | 
                    Object[] source = {jarFile, origJar}; | 
 | 
                    error(form.format(source));  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        displayMessagesAndResult(true);  | 
 | 
    }  | 
 | 
 | 
 | 
    private static String getDefaultSignatureAlgorithm(PrivateKey privateKey) { | 
 | 
        String keyAlgorithm = privateKey.getAlgorithm();  | 
 | 
        if (keyAlgorithm.equalsIgnoreCase("DSA")) | 
 | 
            return "SHA256withDSA";  | 
 | 
        else if (keyAlgorithm.equalsIgnoreCase("RSA")) | 
 | 
            return "SHA256withRSA";  | 
 | 
        else if (keyAlgorithm.equalsIgnoreCase("EC")) | 
 | 
            return "SHA256withECDSA";  | 
 | 
        throw new RuntimeException("private key is not a DSA or " | 
 | 
                                           + "RSA key");  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @SuppressWarnings("fallthrough") | 
 | 
    private int findHeaderEnd(byte[] bs) { | 
 | 
        // Initial state true to deal with empty header  | 
 | 
        boolean newline = true;       | 
 | 
        int len = bs.length;  | 
 | 
        for (int i=0; i<len; i++) { | 
 | 
            switch (bs[i]) { | 
 | 
                case '\r':  | 
 | 
                    if (i < len - 1 && bs[i+1] == '\n') i++;  | 
 | 
                      | 
 | 
                case '\n':  | 
 | 
                    if (newline) return i+1;      | 
 | 
                    newline = true;  | 
 | 
                    break;  | 
 | 
                default:  | 
 | 
                    newline = false;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        // If header end is not found, it means the MANIFEST.MF has only  | 
 | 
        // the main attributes section and it does not end with 2 newlines.  | 
 | 
          | 
 | 
        return len;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private boolean signatureRelated(String name) { | 
 | 
        return SignatureFileVerifier.isSigningRelated(name);  | 
 | 
    }  | 
 | 
 | 
 | 
    Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<>();  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private String signerInfo(CodeSigner signer, String tab) throws Exception { | 
 | 
        if (cacheForSignerInfo.containsKey(signer)) { | 
 | 
            return cacheForSignerInfo.get(signer);  | 
 | 
        }  | 
 | 
        List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates();  | 
 | 
          | 
 | 
        Timestamp ts = signer.getTimestamp();  | 
 | 
        String tsLine = "";  | 
 | 
        if (ts != null) { | 
 | 
            tsLine = printTimestamp(tab, ts) + "\n";  | 
 | 
        }  | 
 | 
        // Spaces before the ">>> Signer" and other lines are the same.  | 
 | 
 | 
 | 
        String result = certsAndTSInfo(tab, tab, certs, ts);  | 
 | 
        cacheForSignerInfo.put(signer, tsLine + result);  | 
 | 
        return result;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private String certsAndTSInfo(  | 
 | 
            String tab1,  | 
 | 
            String tab2,  | 
 | 
            List<? extends Certificate> certs, Timestamp ts)  | 
 | 
            throws Exception { | 
 | 
 | 
 | 
        Date timestamp;  | 
 | 
        if (ts != null) { | 
 | 
            timestamp = ts.getTimestamp();  | 
 | 
            noTimestamp = false;  | 
 | 
        } else { | 
 | 
            timestamp = null;  | 
 | 
        }  | 
 | 
        // display the certificate(s). The first one is end-entity cert and  | 
 | 
          | 
 | 
        boolean first = true;  | 
 | 
        StringBuilder sb = new StringBuilder();  | 
 | 
        sb.append(tab1).append(rb.getString("...Signer")).append('\n'); | 
 | 
        for (Certificate c : certs) { | 
 | 
            sb.append(printCert(false, tab2, c, timestamp, first));  | 
 | 
            sb.append('\n'); | 
 | 
            first = false;  | 
 | 
        }  | 
 | 
        try { | 
 | 
            validateCertChain(Validator.VAR_CODE_SIGNING, certs, ts);  | 
 | 
        } catch (Exception e) { | 
 | 
            chainNotValidated = true;  | 
 | 
            chainNotValidatedReason = e;  | 
 | 
            sb.append(tab2).append(rb.getString(".Invalid.certificate.chain.")) | 
 | 
                    .append(e.getLocalizedMessage()).append("]\n"); | 
 | 
        }  | 
 | 
        if (ts != null) { | 
 | 
            sb.append(tab1).append(rb.getString("...TSA")).append('\n'); | 
 | 
            for (Certificate c : ts.getSignerCertPath().getCertificates()) { | 
 | 
                sb.append(printCert(true, tab2, c, null, false));  | 
 | 
                sb.append('\n'); | 
 | 
            }  | 
 | 
            try { | 
 | 
                validateCertChain(Validator.VAR_TSA_SERVER,  | 
 | 
                        ts.getSignerCertPath().getCertificates(), null);  | 
 | 
            } catch (Exception e) { | 
 | 
                tsaChainNotValidated = true;  | 
 | 
                tsaChainNotValidatedReason = e;  | 
 | 
                sb.append(tab2).append(rb.getString(".Invalid.TSA.certificate.chain.")) | 
 | 
                        .append(e.getLocalizedMessage()).append("]\n"); | 
 | 
            }  | 
 | 
        }  | 
 | 
        if (certs.size() == 1  | 
 | 
                && KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) { | 
 | 
            signerSelfSigned = true;  | 
 | 
        }  | 
 | 
 | 
 | 
        return sb.toString();  | 
 | 
    }  | 
 | 
 | 
 | 
    private void writeEntry(ZipFile zf, ZipOutputStream os, ZipEntry ze)  | 
 | 
    throws IOException  | 
 | 
    { | 
 | 
        ZipEntry ze2 = new ZipEntry(ze.getName());  | 
 | 
        ze2.setMethod(ze.getMethod());  | 
 | 
        ze2.setTime(ze.getTime());  | 
 | 
        ze2.setComment(ze.getComment());  | 
 | 
        ze2.setExtra(ze.getExtra());  | 
 | 
        if (ze.getMethod() == ZipEntry.STORED) { | 
 | 
            ze2.setSize(ze.getSize());  | 
 | 
            ze2.setCrc(ze.getCrc());  | 
 | 
        }  | 
 | 
        os.putNextEntry(ze2);  | 
 | 
        writeBytes(zf, ze, os);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private synchronized void writeBytes  | 
 | 
        (ZipFile zf, ZipEntry ze, ZipOutputStream os) throws IOException { | 
 | 
        int n;  | 
 | 
 | 
 | 
        InputStream is = null;  | 
 | 
        try { | 
 | 
            is = zf.getInputStream(ze);  | 
 | 
            long left = ze.getSize();  | 
 | 
 | 
 | 
            while((left > 0) && (n = is.read(buffer, 0, buffer.length)) != -1) { | 
 | 
                os.write(buffer, 0, n);  | 
 | 
                left -= n;  | 
 | 
            }  | 
 | 
        } finally { | 
 | 
            if (is != null) { | 
 | 
                is.close();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    void loadKeyStore(String keyStoreName, boolean prompt) { | 
 | 
 | 
 | 
        if (!nullStream && keyStoreName == null) { | 
 | 
            keyStoreName = System.getProperty("user.home") + File.separator | 
 | 
                + ".keystore";  | 
 | 
        }  | 
 | 
 | 
 | 
        try { | 
 | 
            try { | 
 | 
                KeyStore caks = KeyStoreUtil.getCacertsKeyStore();  | 
 | 
                if (caks != null) { | 
 | 
                    Enumeration<String> aliases = caks.aliases();  | 
 | 
                    while (aliases.hasMoreElements()) { | 
 | 
                        String a = aliases.nextElement();  | 
 | 
                        try { | 
 | 
                            trustedCerts.add((X509Certificate)caks.getCertificate(a));  | 
 | 
                        } catch (Exception e2) { | 
 | 
                            // ignore, when a SecretkeyEntry does not include a cert  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            } catch (Exception e) { | 
 | 
                // Ignore, if cacerts cannot be loaded  | 
 | 
            }  | 
 | 
 | 
 | 
            if (providerName == null) { | 
 | 
                store = KeyStore.getInstance(storetype);  | 
 | 
            } else { | 
 | 
                store = KeyStore.getInstance(storetype, providerName);  | 
 | 
            }  | 
 | 
 | 
 | 
            // Get pass phrase  | 
 | 
            // XXX need to disable echo; on UNIX, call getpass(char *prompt)Z  | 
 | 
              | 
 | 
            if (token && storepass == null && !protectedPath  | 
 | 
                    && !KeyStoreUtil.isWindowsKeyStore(storetype)) { | 
 | 
                storepass = getPass  | 
 | 
                        (rb.getString("Enter.Passphrase.for.keystore.")); | 
 | 
            } else if (!token && storepass == null && prompt) { | 
 | 
                storepass = getPass  | 
 | 
                        (rb.getString("Enter.Passphrase.for.keystore.")); | 
 | 
            }  | 
 | 
 | 
 | 
            try { | 
 | 
                if (nullStream) { | 
 | 
                    store.load(null, storepass);  | 
 | 
                } else { | 
 | 
                    keyStoreName = keyStoreName.replace(File.separatorChar, '/');  | 
 | 
                    URL url = null;  | 
 | 
                    try { | 
 | 
                        url = new URL(keyStoreName);  | 
 | 
                    } catch (java.net.MalformedURLException e) { | 
 | 
                          | 
 | 
                        url = new File(keyStoreName).toURI().toURL();  | 
 | 
                    }  | 
 | 
                    InputStream is = null;  | 
 | 
                    try { | 
 | 
                        is = url.openStream();  | 
 | 
                        store.load(is, storepass);  | 
 | 
                    } finally { | 
 | 
                        if (is != null) { | 
 | 
                            is.close();  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                Enumeration<String> aliases = store.aliases();  | 
 | 
                while (aliases.hasMoreElements()) { | 
 | 
                    String a = aliases.nextElement();  | 
 | 
                    try { | 
 | 
                        X509Certificate c = (X509Certificate)store.getCertificate(a);  | 
 | 
                        // Only add TrustedCertificateEntry and self-signed  | 
 | 
                          | 
 | 
                        if (store.isCertificateEntry(a) ||  | 
 | 
                                c.getSubjectDN().equals(c.getIssuerDN())) { | 
 | 
                            trustedCerts.add(c);  | 
 | 
                        }  | 
 | 
                    } catch (Exception e2) { | 
 | 
                        // ignore, when a SecretkeyEntry does not include a cert  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            } finally { | 
 | 
                try { | 
 | 
                    pkixParameters = new PKIXBuilderParameters(  | 
 | 
                            trustedCerts.stream()  | 
 | 
                                    .map(c -> new TrustAnchor(c, null))  | 
 | 
                                    .collect(Collectors.toSet()),  | 
 | 
                            null);  | 
 | 
                    pkixParameters.setRevocationEnabled(false);  | 
 | 
                } catch (InvalidAlgorithmParameterException ex) { | 
 | 
                    // Only if tas is empty  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } catch (IOException ioe) { | 
 | 
            throw new RuntimeException(rb.getString("keystore.load.") + | 
 | 
                                        ioe.getMessage());  | 
 | 
        } catch (java.security.cert.CertificateException ce) { | 
 | 
            throw new RuntimeException(rb.getString("certificate.exception.") + | 
 | 
                                        ce.getMessage());  | 
 | 
        } catch (NoSuchProviderException pe) { | 
 | 
            throw new RuntimeException(rb.getString("keystore.load.") + | 
 | 
                                        pe.getMessage());  | 
 | 
        } catch (NoSuchAlgorithmException nsae) { | 
 | 
            throw new RuntimeException(rb.getString("keystore.load.") + | 
 | 
                                        nsae.getMessage());  | 
 | 
        } catch (KeyStoreException kse) { | 
 | 
            throw new RuntimeException  | 
 | 
                (rb.getString("unable.to.instantiate.keystore.class.") + | 
 | 
                kse.getMessage());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    X509Certificate getTsaCert(String alias) { | 
 | 
 | 
 | 
        java.security.cert.Certificate cs = null;  | 
 | 
 | 
 | 
        try { | 
 | 
            cs = store.getCertificate(alias);  | 
 | 
        } catch (KeyStoreException kse) { | 
 | 
            // this never happens, because keystore has been loaded  | 
 | 
        }  | 
 | 
        if (cs == null || (!(cs instanceof X509Certificate))) { | 
 | 
            MessageFormat form = new MessageFormat(rb.getString  | 
 | 
                ("Certificate.not.found.for.alias.alias.must.reference.a.valid.KeyStore.entry.containing.an.X.509.public.key.certificate.for.the")); | 
 | 
            Object[] source = {alias, alias}; | 
 | 
            error(form.format(source));  | 
 | 
        }  | 
 | 
        return (X509Certificate) cs;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    void checkCertUsage(X509Certificate userCert, boolean[] bad) { | 
 | 
 | 
 | 
        // Can act as a signer?  | 
 | 
        // 1. if KeyUsage, then [0:digitalSignature] or  | 
 | 
        //    [1:nonRepudiation] should be true  | 
 | 
        // 2. if ExtendedKeyUsage, then should contains ANY or CODE_SIGNING  | 
 | 
        // 3. if NetscapeCertType, then should contains OBJECT_SIGNING  | 
 | 
        // 1,2,3 must be true  | 
 | 
 | 
 | 
        if (bad != null) { | 
 | 
            bad[0] = bad[1] = bad[2] = false;  | 
 | 
        }  | 
 | 
 | 
 | 
        boolean[] keyUsage = userCert.getKeyUsage();  | 
 | 
        if (keyUsage != null) { | 
 | 
            keyUsage = Arrays.copyOf(keyUsage, 9);  | 
 | 
            if (!keyUsage[0] && !keyUsage[1]) { | 
 | 
                if (bad != null) { | 
 | 
                    bad[0] = true;  | 
 | 
                    badKeyUsage = true;  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        try { | 
 | 
            List<String> xKeyUsage = userCert.getExtendedKeyUsage();  | 
 | 
            if (xKeyUsage != null) { | 
 | 
                if (!xKeyUsage.contains("2.5.29.37.0")  | 
 | 
                        && !xKeyUsage.contains("1.3.6.1.5.5.7.3.3")) {   | 
 | 
                    if (bad != null) { | 
 | 
                        bad[1] = true;  | 
 | 
                        badExtendedKeyUsage = true;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } catch (java.security.cert.CertificateParsingException e) { | 
 | 
            // shouldn't happen  | 
 | 
        }  | 
 | 
 | 
 | 
        try { | 
 | 
              | 
 | 
            byte[] netscapeEx = userCert.getExtensionValue  | 
 | 
                    ("2.16.840.1.113730.1.1"); | 
 | 
            if (netscapeEx != null) { | 
 | 
                DerInputStream in = new DerInputStream(netscapeEx);  | 
 | 
                byte[] encoded = in.getOctetString();  | 
 | 
                encoded = new DerValue(encoded).getUnalignedBitString()  | 
 | 
                        .toByteArray();  | 
 | 
 | 
 | 
                NetscapeCertTypeExtension extn =  | 
 | 
                        new NetscapeCertTypeExtension(encoded);  | 
 | 
 | 
 | 
                Boolean val = extn.get(NetscapeCertTypeExtension.OBJECT_SIGNING);  | 
 | 
                if (!val) { | 
 | 
                    if (bad != null) { | 
 | 
                        bad[2] = true;  | 
 | 
                        badNetscapeCertType = true;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } catch (IOException e) { | 
 | 
            //  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    void getAliasInfo(String alias) throws Exception { | 
 | 
 | 
 | 
        Key key = null;  | 
 | 
 | 
 | 
        try { | 
 | 
            java.security.cert.Certificate[] cs = null;  | 
 | 
            if (altCertChain != null) { | 
 | 
                try (FileInputStream fis = new FileInputStream(altCertChain)) { | 
 | 
                    cs = CertificateFactory.getInstance("X.509"). | 
 | 
                            generateCertificates(fis).  | 
 | 
                            toArray(new Certificate[0]);  | 
 | 
                } catch (FileNotFoundException ex) { | 
 | 
                    error(rb.getString("File.specified.by.certchain.does.not.exist")); | 
 | 
                } catch (CertificateException | IOException ex) { | 
 | 
                    error(rb.getString("Cannot.restore.certchain.from.file.specified")); | 
 | 
                }  | 
 | 
            } else { | 
 | 
                try { | 
 | 
                    cs = store.getCertificateChain(alias);  | 
 | 
                } catch (KeyStoreException kse) { | 
 | 
                    // this never happens, because keystore has been loaded  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (cs == null || cs.length == 0) { | 
 | 
                if (altCertChain != null) { | 
 | 
                    error(rb.getString  | 
 | 
                            ("Certificate.chain.not.found.in.the.file.specified.")); | 
 | 
                } else { | 
 | 
                    MessageFormat form = new MessageFormat(rb.getString  | 
 | 
                        ("Certificate.chain.not.found.for.alias.alias.must.reference.a.valid.KeyStore.key.entry.containing.a.private.key.and")); | 
 | 
                    Object[] source = {alias, alias}; | 
 | 
                    error(form.format(source));  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            certChain = new X509Certificate[cs.length];  | 
 | 
            for (int i=0; i<cs.length; i++) { | 
 | 
                if (!(cs[i] instanceof X509Certificate)) { | 
 | 
                    error(rb.getString  | 
 | 
                        ("found.non.X.509.certificate.in.signer.s.chain")); | 
 | 
                }  | 
 | 
                certChain[i] = (X509Certificate)cs[i];  | 
 | 
            }  | 
 | 
 | 
 | 
            try { | 
 | 
                if (!token && keypass == null)  | 
 | 
                    key = store.getKey(alias, storepass);  | 
 | 
                else  | 
 | 
                    key = store.getKey(alias, keypass);  | 
 | 
            } catch (UnrecoverableKeyException e) { | 
 | 
                if (token) { | 
 | 
                    throw e;  | 
 | 
                } else if (keypass == null) { | 
 | 
                      | 
 | 
                    MessageFormat form = new MessageFormat(rb.getString  | 
 | 
                        ("Enter.key.password.for.alias.")); | 
 | 
                    Object[] source = {alias}; | 
 | 
                    keypass = getPass(form.format(source));  | 
 | 
                    key = store.getKey(alias, keypass);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } catch (NoSuchAlgorithmException e) { | 
 | 
            error(e.getMessage());  | 
 | 
        } catch (UnrecoverableKeyException e) { | 
 | 
            error(rb.getString("unable.to.recover.key.from.keystore")); | 
 | 
        } catch (KeyStoreException kse) { | 
 | 
            // this never happens, because keystore has been loaded  | 
 | 
        }  | 
 | 
 | 
 | 
        if (!(key instanceof PrivateKey)) { | 
 | 
            MessageFormat form = new MessageFormat(rb.getString  | 
 | 
                ("key.associated.with.alias.not.a.private.key")); | 
 | 
            Object[] source = {alias}; | 
 | 
            error(form.format(source));  | 
 | 
        } else { | 
 | 
            privateKey = (PrivateKey)key;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    void error(String message)  | 
 | 
    { | 
 | 
        System.out.println(rb.getString("jarsigner.")+message); | 
 | 
        System.exit(1);  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    void error(String message, Exception e)  | 
 | 
    { | 
 | 
        System.out.println(rb.getString("jarsigner.")+message); | 
 | 
        if (debug) { | 
 | 
            e.printStackTrace();  | 
 | 
        }  | 
 | 
        System.exit(1);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    void validateCertChain(String variant, List<? extends Certificate> certs,  | 
 | 
                           Timestamp parameter)  | 
 | 
            throws Exception { | 
 | 
        try { | 
 | 
            Validator.getInstance(Validator.TYPE_PKIX,  | 
 | 
                    variant,  | 
 | 
                    pkixParameters)  | 
 | 
                    .validate(certs.toArray(new X509Certificate[certs.size()]),  | 
 | 
                            null, parameter);  | 
 | 
        } catch (Exception e) { | 
 | 
            if (debug) { | 
 | 
                e.printStackTrace();  | 
 | 
            }  | 
 | 
 | 
 | 
            // Exception might be dismissed if another warning flag  | 
 | 
            // is already set by printCert.  | 
 | 
 | 
 | 
            if (variant.equals(Validator.VAR_TSA_SERVER) &&  | 
 | 
                    e instanceof ValidatorException) { | 
 | 
                  | 
 | 
                if (e.getCause() != null &&  | 
 | 
                        e.getCause() instanceof CertPathValidatorException) { | 
 | 
                    e = (Exception) e.getCause();  | 
 | 
                    Throwable t = e.getCause();  | 
 | 
                    if ((t instanceof CertificateExpiredException &&  | 
 | 
                            hasExpiredTsaCert)) { | 
 | 
                          | 
 | 
                        return;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            if (variant.equals(Validator.VAR_CODE_SIGNING) &&  | 
 | 
                    e instanceof ValidatorException) { | 
 | 
                  | 
 | 
                if (e.getCause() != null &&  | 
 | 
                        e.getCause() instanceof CertPathValidatorException) { | 
 | 
                    e = (Exception) e.getCause();  | 
 | 
                    Throwable t = e.getCause();  | 
 | 
                    if ((t instanceof CertificateExpiredException &&  | 
 | 
                                hasExpiredCert) ||  | 
 | 
                            (t instanceof CertificateNotYetValidException &&  | 
 | 
                                    notYetValidCert)) { | 
 | 
                          | 
 | 
                        return;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                if (e instanceof ValidatorException) { | 
 | 
                    ValidatorException ve = (ValidatorException)e;  | 
 | 
                    if (ve.getErrorType() == ValidatorException.T_EE_EXTENSIONS &&  | 
 | 
                            (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType)) { | 
 | 
                        // We already have badKeyUsage, badExtendedKeyUsage  | 
 | 
                          | 
 | 
                        return;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
            throw e;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    char[] getPass(String prompt)  | 
 | 
    { | 
 | 
        System.err.print(prompt);  | 
 | 
        System.err.flush();  | 
 | 
        try { | 
 | 
            char[] pass = Password.readPassword(System.in);  | 
 | 
 | 
 | 
            if (pass == null) { | 
 | 
                error(rb.getString("you.must.enter.key.password")); | 
 | 
            } else { | 
 | 
                return pass;  | 
 | 
            }  | 
 | 
        } catch (IOException ioe) { | 
 | 
            error(rb.getString("unable.to.read.password.")+ioe.getMessage()); | 
 | 
        }  | 
 | 
          | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private synchronized byte[] getBytes(ZipFile zf,  | 
 | 
                                         ZipEntry ze) throws IOException { | 
 | 
        int n;  | 
 | 
 | 
 | 
        InputStream is = null;  | 
 | 
        try { | 
 | 
            is = zf.getInputStream(ze);  | 
 | 
            baos.reset();  | 
 | 
            long left = ze.getSize();  | 
 | 
 | 
 | 
            while((left > 0) && (n = is.read(buffer, 0, buffer.length)) != -1) { | 
 | 
                baos.write(buffer, 0, n);  | 
 | 
                left -= n;  | 
 | 
            }  | 
 | 
        } finally { | 
 | 
            if (is != null) { | 
 | 
                is.close();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        return baos.toByteArray();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private ZipEntry getManifestFile(ZipFile zf) { | 
 | 
        ZipEntry ze = zf.getEntry(JarFile.MANIFEST_NAME);  | 
 | 
        if (ze == null) { | 
 | 
              | 
 | 
            Enumeration<? extends ZipEntry> enum_ = zf.entries();  | 
 | 
            while (enum_.hasMoreElements() && ze == null) { | 
 | 
                ze = enum_.nextElement();  | 
 | 
                if (!JarFile.MANIFEST_NAME.equalsIgnoreCase  | 
 | 
                    (ze.getName())) { | 
 | 
                    ze = null;  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return ze;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private synchronized String[] getDigests(ZipEntry ze, ZipFile zf,  | 
 | 
                                             MessageDigest[] digests)  | 
 | 
        throws IOException { | 
 | 
 | 
 | 
        int n, i;  | 
 | 
        InputStream is = null;  | 
 | 
        try { | 
 | 
            is = zf.getInputStream(ze);  | 
 | 
            long left = ze.getSize();  | 
 | 
            while((left > 0)  | 
 | 
                && (n = is.read(buffer, 0, buffer.length)) != -1) { | 
 | 
                for (i=0; i<digests.length; i++) { | 
 | 
                    digests[i].update(buffer, 0, n);  | 
 | 
                }  | 
 | 
                left -= n;  | 
 | 
            }  | 
 | 
        } finally { | 
 | 
            if (is != null) { | 
 | 
                is.close();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        String[] base64Digests = new String[digests.length];  | 
 | 
        for (i=0; i<digests.length; i++) { | 
 | 
            base64Digests[i] = Base64.getEncoder().encodeToString(digests[i].digest());  | 
 | 
        }  | 
 | 
        return base64Digests;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private Attributes getDigestAttributes(ZipEntry ze, ZipFile zf,  | 
 | 
                                           MessageDigest[] digests)  | 
 | 
        throws IOException { | 
 | 
 | 
 | 
        String[] base64Digests = getDigests(ze, zf, digests);  | 
 | 
        Attributes attrs = new Attributes();  | 
 | 
 | 
 | 
        for (int i=0; i<digests.length; i++) { | 
 | 
            attrs.putValue(digests[i].getAlgorithm()+"-Digest",  | 
 | 
                           base64Digests[i]);  | 
 | 
        }  | 
 | 
        return attrs;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private boolean updateDigests(ZipEntry ze, ZipFile zf,  | 
 | 
                                  MessageDigest[] digests,  | 
 | 
                                  Manifest mf) throws IOException { | 
 | 
        boolean update = false;  | 
 | 
 | 
 | 
        Attributes attrs = mf.getAttributes(ze.getName());  | 
 | 
        String[] base64Digests = getDigests(ze, zf, digests);  | 
 | 
 | 
 | 
        for (int i=0; i<digests.length; i++) { | 
 | 
              | 
 | 
            String name = null;  | 
 | 
            try { | 
 | 
                  | 
 | 
                AlgorithmId aid = AlgorithmId.get(digests[i].getAlgorithm());  | 
 | 
                for (Object key: attrs.keySet()) { | 
 | 
                    if (key instanceof Attributes.Name) { | 
 | 
                        String n = ((Attributes.Name)key).toString();  | 
 | 
                        if (n.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST")) { | 
 | 
                            String tmp = n.substring(0, n.length() - 7);  | 
 | 
                            if (AlgorithmId.get(tmp).equals(aid)) { | 
 | 
                                name = n;  | 
 | 
                                break;  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            } catch (NoSuchAlgorithmException nsae) { | 
 | 
                // Ignored. Writing new digest entry.  | 
 | 
            }  | 
 | 
 | 
 | 
            if (name == null) { | 
 | 
                name = digests[i].getAlgorithm()+"-Digest";  | 
 | 
                attrs.putValue(name, base64Digests[i]);  | 
 | 
                update=true;  | 
 | 
            } else { | 
 | 
                // compare digests, and replace the one in the manifest  | 
 | 
                  | 
 | 
                String mfDigest = attrs.getValue(name);  | 
 | 
                if (!mfDigest.equalsIgnoreCase(base64Digests[i])) { | 
 | 
                    attrs.putValue(name, base64Digests[i]);  | 
 | 
                    update=true;  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return update;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private ContentSigner loadSigningMechanism(String signerClassName,  | 
 | 
        String signerClassPath) throws Exception { | 
 | 
 | 
 | 
        // construct class loader  | 
 | 
        String cpString = null;     | 
 | 
 | 
 | 
          | 
 | 
        cpString = PathList.appendPath(System.getProperty("env.class.path"), cpString); | 
 | 
        cpString = PathList.appendPath(System.getProperty("java.class.path"), cpString); | 
 | 
        cpString = PathList.appendPath(signerClassPath, cpString);  | 
 | 
        URL[] urls = PathList.pathToURLs(cpString);  | 
 | 
        ClassLoader appClassLoader = new URLClassLoader(urls);  | 
 | 
 | 
 | 
          | 
 | 
        Class<?> signerClass = appClassLoader.loadClass(signerClassName);  | 
 | 
 | 
 | 
          | 
 | 
        Object signer = signerClass.newInstance();  | 
 | 
        if (!(signer instanceof ContentSigner)) { | 
 | 
            MessageFormat form = new MessageFormat(  | 
 | 
                rb.getString("signerClass.is.not.a.signing.mechanism")); | 
 | 
            Object[] source = {signerClass.getName()}; | 
 | 
            throw new IllegalArgumentException(form.format(source));  | 
 | 
        }  | 
 | 
        return (ContentSigner)signer;  | 
 | 
    }  | 
 | 
}  | 
 | 
 | 
 | 
class SignatureFile { | 
 | 
 | 
 | 
      | 
 | 
    Manifest sf;  | 
 | 
 | 
 | 
      | 
 | 
    String baseName;  | 
 | 
 | 
 | 
    public SignatureFile(MessageDigest digests[],  | 
 | 
                         Manifest mf,  | 
 | 
                         ManifestDigester md,  | 
 | 
                         String baseName,  | 
 | 
                         boolean signManifest)  | 
 | 
 | 
 | 
    { | 
 | 
        this.baseName = baseName;  | 
 | 
 | 
 | 
        String version = System.getProperty("java.version"); | 
 | 
        String javaVendor = System.getProperty("java.vendor"); | 
 | 
 | 
 | 
        sf = new Manifest();  | 
 | 
        Attributes mattr = sf.getMainAttributes();  | 
 | 
 | 
 | 
        mattr.putValue(Attributes.Name.SIGNATURE_VERSION.toString(), "1.0");  | 
 | 
        mattr.putValue("Created-By", version + " (" + javaVendor + ")"); | 
 | 
 | 
 | 
        if (signManifest) { | 
 | 
              | 
 | 
            for (int i=0; i < digests.length; i++) { | 
 | 
                mattr.putValue(digests[i].getAlgorithm()+"-Digest-Manifest",  | 
 | 
                               Base64.getEncoder().encodeToString(md.manifestDigest(digests[i])));  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        ManifestDigester.Entry mde =  | 
 | 
                md.get(ManifestDigester.MF_MAIN_ATTRS, false);  | 
 | 
        if (mde != null) { | 
 | 
            for (int i=0; i < digests.length; i++) { | 
 | 
                mattr.putValue(digests[i].getAlgorithm() +  | 
 | 
                        "-Digest-" + ManifestDigester.MF_MAIN_ATTRS,  | 
 | 
                        Base64.getEncoder().encodeToString(mde.digest(digests[i])));  | 
 | 
            }  | 
 | 
        } else { | 
 | 
            throw new IllegalStateException  | 
 | 
                ("ManifestDigester failed to create " + | 
 | 
                "Manifest-Main-Attribute entry");  | 
 | 
        }  | 
 | 
 | 
 | 
        /* go through the manifest entries and create the digests */  | 
 | 
 | 
 | 
        Map<String,Attributes> entries = sf.getEntries();  | 
 | 
        Iterator<Map.Entry<String,Attributes>> mit =  | 
 | 
                                mf.getEntries().entrySet().iterator();  | 
 | 
        while(mit.hasNext()) { | 
 | 
            Map.Entry<String,Attributes> e = mit.next();  | 
 | 
            String name = e.getKey();  | 
 | 
            mde = md.get(name, false);  | 
 | 
            if (mde != null) { | 
 | 
                Attributes attr = new Attributes();  | 
 | 
                for (int i=0; i < digests.length; i++) { | 
 | 
                    attr.putValue(digests[i].getAlgorithm()+"-Digest",  | 
 | 
                                  Base64.getEncoder().encodeToString(mde.digest(digests[i])));  | 
 | 
                }  | 
 | 
                entries.put(name, attr);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * Writes the SignatureFile to the specified OutputStream.  | 
 | 
     *  | 
 | 
     * @param out the output stream  | 
 | 
     * @exception IOException if an I/O error has occurred  | 
 | 
     */  | 
 | 
 | 
 | 
    public void write(OutputStream out) throws IOException  | 
 | 
    { | 
 | 
        sf.write(out);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public String getMetaName()  | 
 | 
    { | 
 | 
        return "META-INF/"+ baseName + ".SF";  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public String getBaseName()  | 
 | 
    { | 
 | 
        return baseName;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Block generateBlock(PrivateKey privateKey,  | 
 | 
                               String sigalg,  | 
 | 
                               X509Certificate[] certChain,  | 
 | 
                               boolean externalSF, String tsaUrl,  | 
 | 
                               X509Certificate tsaCert,  | 
 | 
                               String tSAPolicyID,  | 
 | 
                               String tSADigestAlg,  | 
 | 
                               ContentSigner signingMechanism,  | 
 | 
                               String[] args, ZipFile zipFile)  | 
 | 
        throws NoSuchAlgorithmException, InvalidKeyException, IOException,  | 
 | 
            SignatureException, CertificateException  | 
 | 
    { | 
 | 
        return new Block(this, privateKey, sigalg, certChain, externalSF,  | 
 | 
                tsaUrl, tsaCert, tSAPolicyID, tSADigestAlg, signingMechanism, args, zipFile);  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    public static class Block { | 
 | 
 | 
 | 
        private byte[] block;  | 
 | 
        private String blockFileName;  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        Block(SignatureFile sfg, PrivateKey privateKey, String sigalg,  | 
 | 
            X509Certificate[] certChain, boolean externalSF, String tsaUrl,  | 
 | 
            X509Certificate tsaCert, String tSAPolicyID, String tSADigestAlg,  | 
 | 
            ContentSigner signingMechanism, String[] args, ZipFile zipFile)  | 
 | 
            throws NoSuchAlgorithmException, InvalidKeyException, IOException,  | 
 | 
            SignatureException, CertificateException { | 
 | 
 | 
 | 
            Principal issuerName = certChain[0].getIssuerDN();  | 
 | 
            if (!(issuerName instanceof X500Name)) { | 
 | 
                // must extract the original encoded form of DN for subsequent  | 
 | 
                // name comparison checks (converting to a String and back to  | 
 | 
                // an encoded DN could cause the types of String attribute  | 
 | 
                  | 
 | 
                X509CertInfo tbsCert = new  | 
 | 
                    X509CertInfo(certChain[0].getTBSCertificate());  | 
 | 
                issuerName = (Principal)  | 
 | 
                    tbsCert.get(X509CertInfo.ISSUER + "." +  | 
 | 
                                X509CertInfo.DN_NAME);  | 
 | 
                }  | 
 | 
            BigInteger serial = certChain[0].getSerialNumber();  | 
 | 
 | 
 | 
            String signatureAlgorithm = sigalg;  | 
 | 
            String keyAlgorithm = privateKey.getAlgorithm();  | 
 | 
 | 
 | 
              | 
 | 
            String sigAlgUpperCase = signatureAlgorithm.toUpperCase(Locale.ENGLISH);  | 
 | 
            if ((sigAlgUpperCase.endsWith("WITHRSA") && | 
 | 
                !keyAlgorithm.equalsIgnoreCase("RSA")) || | 
 | 
                (sigAlgUpperCase.endsWith("WITHECDSA") && | 
 | 
                !keyAlgorithm.equalsIgnoreCase("EC")) || | 
 | 
                (sigAlgUpperCase.endsWith("WITHDSA") && | 
 | 
                !keyAlgorithm.equalsIgnoreCase("DSA"))) { | 
 | 
                throw new SignatureException  | 
 | 
                    ("private key algorithm is not compatible with signature algorithm"); | 
 | 
            }  | 
 | 
 | 
 | 
            blockFileName = "META-INF/"+sfg.getBaseName()+"."+keyAlgorithm;  | 
 | 
 | 
 | 
            AlgorithmId sigAlg = AlgorithmId.get(signatureAlgorithm);  | 
 | 
            AlgorithmId digEncrAlg = AlgorithmId.get(keyAlgorithm);  | 
 | 
 | 
 | 
            Signature sig = Signature.getInstance(signatureAlgorithm);  | 
 | 
            sig.initSign(privateKey);  | 
 | 
 | 
 | 
            ByteArrayOutputStream baos = new ByteArrayOutputStream();  | 
 | 
            sfg.write(baos);  | 
 | 
 | 
 | 
            byte[] content = baos.toByteArray();  | 
 | 
 | 
 | 
            sig.update(content);  | 
 | 
            byte[] signature = sig.sign();  | 
 | 
 | 
 | 
              | 
 | 
            if (signingMechanism == null) { | 
 | 
                signingMechanism = new TimestampedSigner();  | 
 | 
            }  | 
 | 
            URI tsaUri = null;  | 
 | 
            try { | 
 | 
                if (tsaUrl != null) { | 
 | 
                    tsaUri = new URI(tsaUrl);  | 
 | 
                }  | 
 | 
            } catch (URISyntaxException e) { | 
 | 
                throw new IOException(e);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            ContentSignerParameters params =  | 
 | 
                new JarSignerParameters(args, tsaUri, tsaCert, tSAPolicyID,  | 
 | 
                        tSADigestAlg, signature,  | 
 | 
                    signatureAlgorithm, certChain, content, zipFile);  | 
 | 
 | 
 | 
              | 
 | 
            block = signingMechanism.generateSignedData(  | 
 | 
                    params, externalSF, (tsaUrl != null || tsaCert != null));  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        public String getMetaName()  | 
 | 
        { | 
 | 
            return blockFileName;  | 
 | 
        }  | 
 | 
 | 
 | 
        /**  | 
 | 
         * Writes the block file to the specified OutputStream.  | 
 | 
         *  | 
 | 
         * @param out the output stream  | 
 | 
         * @exception IOException if an I/O error has occurred  | 
 | 
         */  | 
 | 
 | 
 | 
        public void write(OutputStream out) throws IOException  | 
 | 
        { | 
 | 
            out.write(block);  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |