blob: d65505a00d309adb7da672de8930d1162d9658cd [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.harmony.tools.jarsigner;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.util.logging.Logger;
/**
* The class to parse the program arguments.
*/
class ArgParser {
// options names to compare to //
final static String sVerify = "-verify";
final static String sKeyStore = "-keystore";
final static String sStoreType = "-storetype";
final static String sStorePass = "-storepass";
final static String sKeyPass = "-keypass";
final static String sSigFile = "-sigfile";
final static String sSignedJAR = "-signedjar";
final static String sCerts = "-certs";
final static String sVerbose = "-verbose";
final static String sInternalSF = "-internalsf";
final static String sSectionsOnly = "-sectionsonly";
final static String sProvider = "-providerclass";
final static String sProviderName = "-providername";
final static String sCertProvider = "-certproviderclass";
final static String sCertProviderName = "-certprovidername";
final static String sSigProvider = "-sigproviderclass";
final static String sSigProviderName = "-sigprovidername";
final static String sKSProvider = "-ksproviderclass";
final static String sKSProviderName = "-ksprovidername";
final static String sMDProvider = "-mdproviderclass";
final static String sMDProviderName = "-mdprovidername";
final static String sTSA = "-tsa";
final static String sTSAcert = "-tsacert";
final static String sProxy = "-proxy";
final static String sProxyType = "-proxytype";
final static String sSilent = "-silent";
final static String sAltSigner = "-altsigner";
final static String sAltSignerPath = "-altsignerpath";
/**
* @param args
* @param param
* @return new instance of JSParameters if param is null or updated param
* object if it is non-null. Returns null if args is null or
* zero-sized, an unknown option is found or an expected option
* value is not given or not of an expected type. If null is
* returned, the param object contents is not defined.
*
* @throws JarSignerException
* @throws IOException
* @throws KeyStoreException
* @throws UnrecoverableKeyException
* @throws NoSuchAlgorithmException
*/
static JSParameters parseArgs(String[] args, JSParameters param)
throws JarSignerException, IOException, KeyStoreException,
UnrecoverableKeyException, NoSuchAlgorithmException {
if (args == null){
return null;
}
if (args.length == 0){
return null;
}
if (param == null){
param = new JSParameters();
} else {
// clean the param
param.setDefault();
}
try {
for (int i = 0; i < args.length; i++) {
if (args[i].equalsIgnoreCase(sVerify)) {
param.setVerify(true);
continue;
}
if (args[i].equalsIgnoreCase(sKeyStore)) {
param.setStoreURI(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sStoreType)) {
param.setStoreType(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sStorePass)) {
param.setStorePass(args[++i].toCharArray());
continue;
}
if (args[i].equalsIgnoreCase(sKeyPass)) {
param.setKeyPass(args[++i].toCharArray());
continue;
}
if (args[i].equalsIgnoreCase(sSigFile)) {
param.setSigFileName(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sSignedJAR)) {
param.setSignedJARName(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sCerts)) {
param.setCerts(true);
continue;
}
if (args[i].equalsIgnoreCase(sVerbose)) {
param.setVerbose(true);
continue;
}
if (args[i].equalsIgnoreCase(sSilent)) {
param.setSilent(true);
continue;
}
if (args[i].equalsIgnoreCase(sInternalSF)) {
param.setInternalSF(true);
continue;
}
if (args[i].equalsIgnoreCase(sSectionsOnly)) {
param.setSectionsOnly(true);
continue;
}
if (args[i].equalsIgnoreCase(sProvider)) {
param.setProvider(args[++i]);
addProvider(args[i]);
continue;
}
if (args[i].equalsIgnoreCase(sProviderName)) {
param.setProviderName(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sCertProvider)) {
param.setCertProvider(args[++i]);
addProvider(args[i]);
continue;
}
if (args[i].equalsIgnoreCase(sCertProviderName)) {
param.setCertProviderName(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sSigProvider)) {
param.setSigProvider(args[++i]);
addProvider(args[i]);
continue;
}
if (args[i].equalsIgnoreCase(sSigProviderName)) {
param.setSigProviderName(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sKSProvider)) {
param.setKsProvider(args[++i]);
addProvider(args[i]);
continue;
}
if (args[i].equalsIgnoreCase(sKSProviderName)) {
param.setKsProviderName(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sMDProvider)) {
param.setMdProvider(args[++i]);
addProvider(args[i]);
continue;
}
if (args[i].equalsIgnoreCase(sMDProviderName)) {
param.setMdProviderName(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sTSA)) {
try {
param.setTsaURI(new URI(args[++i]));
} catch (URISyntaxException e) {
throw new JarSignerException("Argument " + args[i]
+ " is not an URI");
}
continue;
}
if (args[i].equalsIgnoreCase(sTSAcert)) {
param.setTsaCertAlias(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sProxy)) {
int colonPos = args[++i].lastIndexOf(':');
if (colonPos == -1) {
param.setProxy(args[i]);
continue;
}
String proxy = args[i].substring(0, colonPos);
int port;
try {
port = Integer.parseInt(args[i].substring(colonPos + 1,
args[i].length()));
} catch (NumberFormatException e) {
throw new JarSignerException(
"Proxy port must be an integer value.");
}
param.setProxy(proxy);
param.setProxyPort(port);
continue;
}
if (args[i].equalsIgnoreCase(sAltSigner)) {
param.setAltSigner(args[++i]);
continue;
}
if (args[i].equalsIgnoreCase(sAltSignerPath)) {
param.setAltSignerPath(args[++i]);
continue;
}
if ((param.isVerify() && i == args.length - 1)
|| (!param.isVerify() && i == args.length - 2)) {
param.setJarURIorPath(args[i]);
continue;
}
if (!param.isVerify() && i == args.length - 1){
param.setAlias(args[i]);
continue;
}
System.out.println("Illegal option: " + args[i]);
return null;
}
} catch(ArrayIndexOutOfBoundsException e){
// ignore the last option if its value is not provided
}
// set specific provider names the same as the main provider name
// if their values are not set.
String providerName = param.getProviderName();
if (providerName != null){
if (param.getCertProviderName() == null){
param.setCertProviderName(providerName);
}
if (param.getSigProviderName() == null){
param.setSigProviderName(providerName);
}
if (param.getKsProviderName() == null){
param.setKsProviderName(providerName);
}
if (param.getMdProviderName() == null){
param.setMdProviderName(providerName);
}
}
// if the store password is not given, prompt for it
if (param.getStorePass() == null) {
param.setStorePass(UserInteractor
.getDataFromUser("Enter keystore password: "));
// check the password
param.getKeyStore();
}
if (param.getAlias() == null && !param.isVerify()) {
param.setAlias(new String(UserInteractor
.getDataFromUser("Enter alias name: ")));
}
if (!param.getKeyStore().containsAlias(param.getAlias())) {
throw new JarSignerException("The alias " + param.getAlias()
+ " does not exist in keystore");
}
// if key password is not given, try to inplace it with store password
if (param.getKeyPass() == null) {
param.setKeyPass(tryStorePassAsKeyPass(param.getKeyStore(), param
.getAlias(), param.getStorePass()));
}
// TODO: if decide to implement such abilities, remove this code
if (param.isInternalSF() || param.isSectionsOnly()
|| param.getAltSigner() != null
|| param.getAltSignerPath() != null) {
Logger.getLogger(JSParameters.loggerName).warning(
"Options " + sAltSigner + ", " + sAltSignerPath + ", "
+ sInternalSF + ", " + sSectionsOnly
+ " are currently ignored since they eliminate "
+ "useful optimizations. ");
}
return param;
}
// Method tries to get the key, associated with alias, using the storePass.
// If it can be recovered using the password, storePass is returned,
// otherwise - the password is prompted for. Another attempt to recover the
// key with entered password. If it is ok, it is returned, otherwise
// UnrecoverableKeyException is thrown.
private static char[] tryStorePassAsKeyPass(KeyStore keyStore,
String alias, char[] storePass) throws KeyStoreException,
IOException, UnrecoverableKeyException, NoSuchAlgorithmException {
try {
// try to get a key with keystore password
// if succeed set key password same as that for keystore
keyStore.getKey(alias, storePass);
// will not come here if exception is thrown
return storePass;
} catch (UnrecoverableKeyException e) {
// if key password is not equal to store password, ask for it.
char[] keyPass = UserInteractor
.getDataFromUser("Enter key password for <" + alias + ">: ");
// if the new password is incorrect an exception will be thrown
try {
keyStore.getKey(alias, keyPass);
} catch (NoSuchAlgorithmException nsae) {
throw new NoSuchAlgorithmException(
"Cannot find the algorithm to recover the key. ", e);
}
return keyPass;
} catch (NoSuchAlgorithmException e) {
throw new NoSuchAlgorithmException(
"Cannot find the algorithm to recover the key. ", e);
}
}
// method for adding providers to java.security.Security
static int addProvider(String provider) throws JarSignerException {
try {
return Security.addProvider(Class.forName(provider).asSubclass(
Provider.class).newInstance());
} catch (Exception e) {
throw new JarSignerException("Failed to load the provider "
+ provider, e);
}
}
}