/*FreeMind - A Program for creating and viewing Mindmaps
*Copyright (C) 2000-2008 Christian Foltin and others.
*
*See COPYING for Details
*
*This program is free software; you can redistribute it and/or
*modify it under the terms of the GNU General Public License
*as published by the Free Software Foundation; either version 2
*of the License, or (at your option) any later version.
*
*This program is distributed in the hope that it will be useful,
*but WITHOUT ANY WARRANTY; without even the implied warranty of
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*GNU General Public License for more details.
*
*You should have received a copy of the GNU General Public License
*along with this program; if not, write to the Free Software
*Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Created on 16.04.2008
*/
/*$Id: SignedScriptHandler.java,v 1.1.2.2 2008/04/18 21:18:27 christianfoltin Exp $*/
package plugins.script;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Collection;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import freemind.common.TextTranslator;
import freemind.main.FreeMind;
import freemind.main.FreeMindMain;
import freemind.main.Resources;
import freemind.main.Tools;
import freemind.modes.common.dialogs.EnterPasswordDialog;
/**
* @author foltin
*
*/
public class SignedScriptHandler {
public static final String FREEMIND_SCRIPT_KEY_NAME = "FreeMindScriptKey";
private static final String SIGN_PREFIX = "//SIGN:";
/** This is for / /SIGN(keyname):signature */
private static final String SIGN_PREFIX_REGEXP = "//SIGN\\((.*?)\\):(.*)";
public static class ScriptContents {
public String mScript;
public String mSignature;
public String mKeyName;
private static Pattern sSignWithKeyPattern = null;
public ScriptContents() {
if (sSignWithKeyPattern == null)
sSignWithKeyPattern = Pattern.compile(SIGN_PREFIX_REGEXP);
}
public ScriptContents(String pScript) {
this();
int indexOfSignaturePrefix = pScript.lastIndexOf(SIGN_PREFIX);
int indexOfSignature = indexOfSignaturePrefix
+ SIGN_PREFIX.length();
if (indexOfSignaturePrefix > 0
&& pScript.length() > indexOfSignature) {
mSignature = pScript.substring(indexOfSignature);
mScript = pScript.substring(0, indexOfSignaturePrefix);
mKeyName = null;
} else {
Matcher matcher = sSignWithKeyPattern.matcher(pScript);
if (matcher.find()) {
mScript = pScript.substring(0, matcher.start());
mKeyName = matcher.group(1);
mSignature = matcher.group(2);
} else {
mSignature = null;
mScript = pScript;
mKeyName = null;
}
}
}
public String toString() {
String prefix;
if (mKeyName != null)
prefix = "//SIGN(" + mKeyName + "):";
else
prefix = SIGN_PREFIX;
return mScript + prefix + mSignature + "\n";
}
}
private static KeyStore mKeyStore = null;
public SignedScriptHandler() {
}
private void initializeKeystore(char[] pPassword) {
if (mKeyStore != null)
return;
java.io.FileInputStream fis = null;
try {
mKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
fis = new java.io.FileInputStream(System.getProperty("user.home")
+ File.separator + ".keystore");
mKeyStore.load(fis, pPassword);
} catch (Exception e) {
Resources.getInstance().logException(e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
Resources.getInstance().logException(e);
}
}
}
}
public String signScript(String pScript, TextTranslator pTranslator,
FreeMindMain pFrame) {
ScriptContents content = new ScriptContents(pScript);
// it is assumed, that keystore and key password are identical.
EnterPasswordDialog pwdDialog = new EnterPasswordDialog(
pFrame.getJFrame(), pTranslator, false);
pwdDialog.setModal(true);
pwdDialog.setVisible(true);
if (pwdDialog.getResult() == EnterPasswordDialog.CANCEL) {
return content.mScript;
}
char[] password = pwdDialog.getPassword().toString().toCharArray();
initializeKeystore(password);
try {
Signature instance = Signature.getInstance("SHA1withDSA");
String keyName = FREEMIND_SCRIPT_KEY_NAME;
String propertyKeyName = Resources.getInstance().getProperty(
FreeMind.RESOURCES_SCRIPT_USER_KEY_NAME_FOR_SIGNING);
if (content.mKeyName != null) {
keyName = content.mKeyName;
} else if (propertyKeyName != null && propertyKeyName.length() > 0) {
content.mKeyName = propertyKeyName;
keyName = content.mKeyName;
}
instance.initSign((PrivateKey) mKeyStore.getKey(keyName, password));
instance.update(content.mScript.getBytes());
byte[] signature = instance.sign();
content.mSignature = Tools.toBase64(signature);
// System.out.println("Signed: " +content);
return content.toString();
} catch (Exception e) {
Resources.getInstance().logException(e);
pFrame.getController().errorMessage(e.getLocalizedMessage());
}
return content.mScript;
}
public boolean isScriptSigned(String pScript, OutputStream pOutStream) {
ScriptContents content = new ScriptContents(pScript);
if (content.mSignature != null) {
try {
Signature instanceVerify = Signature.getInstance("SHA1withDSA");
if (content.mKeyName == null) {
/**
* This is the FreeMind public key. keytool -v -rfc
* -exportcert -alias freemindscriptkey
*/
String cer = "-----BEGIN CERTIFICATE-----\n"
+ "MIIDKDCCAuWgAwIBAgIESAY2ADALBgcqhkjOOAQDBQAwdzELMAkGA1UEBhMCREUxCzAJBgNVBAgT"
+ "AkRFMRMwEQYDVQQHEwpPcGVuU291cmNlMRgwFgYDVQQKEw9zb3VyY2Vmb3JnZS5uZXQxETAPBgNV"
+ "BAsTCEZyZWVNaW5kMRkwFwYDVQQDExBDaHJpc3RpYW4gRm9sdGluMB4XDTA4MDQxNjE3MjMxMloX"
+ "DTA4MDcxNTE3MjMxMlowdzELMAkGA1UEBhMCREUxCzAJBgNVBAgTAkRFMRMwEQYDVQQHEwpPcGVu"
+ "U291cmNlMRgwFgYDVQQKEw9zb3VyY2Vmb3JnZS5uZXQxETAPBgNVBAsTCEZyZWVNaW5kMRkwFwYD"
+ "VQQDExBDaHJpc3RpYW4gRm9sdGluMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9K"
+ "nC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVCl"
+ "pJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3R"
+ "SAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdM"
+ "Cz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/"
+ "C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAZm5z5EZX"
+ "Vhtye5jY3X9w24DJ3yNJbNl2tfkOBIc0KfgyxONTSJKtUpmLI3btUxy3pQf/T8BShlY3PAC0fp3M"
+ "eDG8WRq1wM3luLd1V9SS8EG6tPJBZ3mciCUymTT7n9CZNzATIpqNIXHSD/wljRABedUi8PMg4KbV"
+ "Pnhu6Y6b1uAwCwYHKoZIzjgEAwUAAzAAMC0CFQCFHGwe+HHOvY0MmKYHbiq7fRxMGwIUC0voAGYU"
+ "u6vgVFqdLI5F96JLTqk="
+ "\n-----END CERTIFICATE-----\n";
CertificateFactory cf = CertificateFactory
.getInstance("X.509");
Collection c = cf
.generateCertificates(new ByteArrayInputStream(cer
.getBytes()));
Iterator i = c.iterator();
if (i.hasNext()) {
Certificate cert = (Certificate) i.next();
instanceVerify.initVerify(cert);
} else {
throw new IllegalArgumentException(
"Internal certificate wrong.");
}
} else {
initializeKeystore(null);
instanceVerify.initVerify(mKeyStore
.getCertificate(content.mKeyName));
}
instanceVerify.update(content.mScript.getBytes());
boolean verify = instanceVerify.verify(Tools
.fromBase64(content.mSignature));
// System.out.println("Signature result: " + verify);
return verify;
} catch (Exception e) {
Resources.getInstance().logException(e);
try {
pOutStream.write(e.toString().getBytes());
pOutStream.write("\n".getBytes());
} catch (Exception e1) {
Resources.getInstance().logException(e1);
}
}
}
return false;
}
}