Renamed translator ItoopieTranslator -> Transl.
Changed http into https. Added support storing ssl certs. Added a GUI for confirming/denying/overwriting certs.
This commit is contained in:
@ -13,6 +13,13 @@ import java.util.regex.*;
|
|||||||
|
|
||||||
import javax.net.ssl.*;
|
import javax.net.ssl.*;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import net.i2p.itoopie.i2pcontrol.JSONInterface;
|
||||||
|
import net.i2p.itoopie.security.CertificateHelper;
|
||||||
|
import net.i2p.itoopie.security.CertificateManager;
|
||||||
|
|
||||||
import com.thetransactioncompany.jsonrpc2.*;
|
import com.thetransactioncompany.jsonrpc2.*;
|
||||||
|
|
||||||
|
|
||||||
@ -106,7 +113,11 @@ import com.thetransactioncompany.jsonrpc2.*;
|
|||||||
* @version 1.2 (2011-03-29)
|
* @version 1.2 (2011-03-29)
|
||||||
*/
|
*/
|
||||||
public class JSONRPC2Session {
|
public class JSONRPC2Session {
|
||||||
|
private static final Log _log;
|
||||||
|
|
||||||
|
static {
|
||||||
|
_log = LogFactory.getLog(JSONRPC2Session.class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The server URL, which protocol must be HTTP or HTTPS.
|
* The server URL, which protocol must be HTTP or HTTPS.
|
||||||
@ -429,6 +440,7 @@ public class JSONRPC2Session {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SSLContext sc = SSLContext.getInstance("SSL");
|
SSLContext sc = SSLContext.getInstance("SSL");
|
||||||
sc.init(null, trustAllCerts, new SecureRandom());
|
sc.init(null, trustAllCerts, new SecureRandom());
|
||||||
|
@ -6,6 +6,7 @@ package net.i2p.itoopie;
|
|||||||
|
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.UnsupportedLookAndFeelException;
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
@ -16,6 +17,7 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
|
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
|
||||||
|
|
||||||
import net.i2p.itoopie.i2pcontrol.JSONInterface;
|
import net.i2p.itoopie.i2pcontrol.JSONInterface;
|
||||||
|
import net.i2p.itoopie.security.CertificateHelper;
|
||||||
import net.i2p.itoopie.util.ConfigurationManager;
|
import net.i2p.itoopie.util.ConfigurationManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,6 +29,7 @@ public class Main {
|
|||||||
private TrayManager trayManager = null;
|
private TrayManager trayManager = null;
|
||||||
private static ConfigurationManager _conf;
|
private static ConfigurationManager _conf;
|
||||||
private static Log _log;
|
private static Log _log;
|
||||||
|
public static final boolean isDebug = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the tray icon code (loads tray icon in the tray area).
|
* Start the tray icon code (loads tray icon in the tray area).
|
||||||
@ -62,6 +65,7 @@ public class Main {
|
|||||||
System.setProperty("java.awt.headless", "false");
|
System.setProperty("java.awt.headless", "false");
|
||||||
_conf = ConfigurationManager.getInstance();
|
_conf = ConfigurationManager.getInstance();
|
||||||
_log = LogFactory.getLog(Main.class);
|
_log = LogFactory.getLog(Main.class);
|
||||||
|
HttpsURLConnection.setDefaultHostnameVerifier(CertificateHelper.getHostnameVerifier());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
@ -75,20 +79,11 @@ public class Main {
|
|||||||
//log.log(Log.ERROR, null, ex);
|
//log.log(Log.ERROR, null, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
_conf.parseConfigStr("server-name=localhost");
|
_conf.parseConfigStr("server-name=127.0.0.1");
|
||||||
_conf.parseConfigStr("server-port=7656");
|
_conf.parseConfigStr("server-port=5555");
|
||||||
_conf.parseConfigStr("server-target=jsonrpc");
|
_conf.parseConfigStr("server-target=jsonrpc");
|
||||||
|
|
||||||
|
|
||||||
for (java.security.Provider p : Security.getProviders()){
|
|
||||||
System.out.println("Provider: " + p.getName());
|
|
||||||
}
|
|
||||||
for (String p : Security.getAlgorithms("KeyStore")){
|
|
||||||
System.out.println("KeyStore algorithm: " + p);
|
|
||||||
}
|
|
||||||
for (String p : Security.getAlgorithms("Cipher")){
|
|
||||||
System.out.println("Cipher algorithm: " + p);
|
|
||||||
}
|
|
||||||
|
|
||||||
String str = null;
|
String str = null;
|
||||||
try {
|
try {
|
||||||
|
@ -11,10 +11,12 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
|
|
||||||
import net.i2p.itoopie.i18n.ItoopieTranslator;
|
import net.i2p.itoopie.i18n.Transl;
|
||||||
import net.i2p.itoopie.util.BrowseException;
|
import net.i2p.itoopie.util.BrowseException;
|
||||||
|
import net.i2p.itoopie.util.IsJar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the tray icon life.
|
* Manages the tray icon life.
|
||||||
@ -81,14 +83,12 @@ public class TrayManager {
|
|||||||
desiredHeight = 512;
|
desiredHeight = 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsJar.isRunningJar()){
|
||||||
URL url = getClass().getResource("/resources/images/itoopie-"+desiredHeight+".png");
|
URL url = getClass().getResource("/resources/images/itoopie-"+desiredHeight+".png");
|
||||||
Image image = Toolkit.getDefaultToolkit().getImage(url);
|
return Toolkit.getDefaultToolkit().getImage(url);
|
||||||
//Image image = Toolkit.getDefaultToolkit().getImage("resources/images/itoopie-"+desiredHeight+".png");
|
} else {
|
||||||
return image;
|
return Toolkit.getDefaultToolkit().getImage("resources/images/itoopie-"+desiredHeight+".png");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static String _(String s) {
|
|
||||||
return ItoopieTranslator._(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ public class TrayManager {
|
|||||||
public PopupMenu getMainMenu() {
|
public PopupMenu getMainMenu() {
|
||||||
PopupMenu popup = new PopupMenu();
|
PopupMenu popup = new PopupMenu();
|
||||||
|
|
||||||
MenuItem browserLauncher = new MenuItem(_("Launch I2P Browser"));
|
MenuItem browserLauncher = new MenuItem(Transl._("Launch I2P Browser"));
|
||||||
browserLauncher.addActionListener(new ActionListener() {
|
browserLauncher.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -119,25 +119,7 @@ public class TrayManager {
|
|||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
MenuItem restartItem = new MenuItem(_("Restart I2P"));
|
MenuItem stopItem = new MenuItem(Transl._("Exit itoopie"));
|
||||||
restartItem.addActionListener(new ActionListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
|
||||||
new SwingWorker<Object, Object>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object doInBackground() throws Exception {
|
|
||||||
//RouterManager.restart();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}.execute();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
MenuItem stopItem = new MenuItem(_("Stop I2P"));
|
|
||||||
stopItem.addActionListener(new ActionListener() {
|
stopItem.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -146,19 +128,13 @@ public class TrayManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object doInBackground() throws Exception {
|
protected Object doInBackground() throws Exception {
|
||||||
//RouterManager.shutDown();
|
System.exit(0);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}.execute();
|
}.execute();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
popup.add(browserLauncher);
|
|
||||||
popup.addSeparator();
|
|
||||||
popup.add(restartItem);
|
|
||||||
popup.add(stopItem);
|
popup.add(stopItem);
|
||||||
|
|
||||||
return popup;
|
return popup;
|
||||||
|
109
src/net/i2p/itoopie/gui/CertificateGUI.java
Normal file
109
src/net/i2p/itoopie/gui/CertificateGUI.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package net.i2p.itoopie.gui;
|
||||||
|
|
||||||
|
import javax.security.cert.X509Certificate;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
|
import net.i2p.itoopie.i18n.Transl;
|
||||||
|
import net.i2p.itoopie.security.CertificateHelper;
|
||||||
|
import net.i2p.itoopie.security.CertificateManager;
|
||||||
|
|
||||||
|
public class CertificateGUI {
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
System.out.println("Save new cert: " + saveNewCert(null,null));
|
||||||
|
System.out.println("Overwrite cert: " + overwriteCert(null,null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean saveNewCert(String hostname, X509Certificate cert){
|
||||||
|
JFrame frame = new JFrame();
|
||||||
|
|
||||||
|
String title = Transl._("New remote host detected");
|
||||||
|
String hostString = Transl._("Would you like permanently trust the certificate from the remote host " + hostname + "?");
|
||||||
|
|
||||||
|
String certName = "N/A";
|
||||||
|
String certAlgo = "N/A";
|
||||||
|
String certSerial = "N/A";
|
||||||
|
String certThumb = "N/A";
|
||||||
|
if (cert != null){
|
||||||
|
certName = cert.getSubjectDN().getName();
|
||||||
|
String certString = cert.getPublicKey().toString();
|
||||||
|
certAlgo = certString.substring(0,certString.indexOf("\n"));
|
||||||
|
certSerial = String.valueOf(cert.getPublicKey().serialVersionUID);
|
||||||
|
certThumb = CertificateHelper.getThumbPrint(cert);
|
||||||
|
}
|
||||||
|
String certInfo = "<html>"+Transl._("Certificate info") + "<br><br>" +
|
||||||
|
Transl._("Name: ") + certName + "<br>" +
|
||||||
|
Transl._("Algorithm: ") + certAlgo + "<br>" +
|
||||||
|
Transl._("Serial: ") + certSerial + "<br>" +
|
||||||
|
Transl._("SHA-1 ID-hash: ") + certThumb;
|
||||||
|
|
||||||
|
String textContent = certInfo + "<br><br>" + hostString;
|
||||||
|
|
||||||
|
int n = JOptionPane.showConfirmDialog(
|
||||||
|
frame,
|
||||||
|
textContent,
|
||||||
|
title,
|
||||||
|
JOptionPane.YES_NO_OPTION,
|
||||||
|
JOptionPane.INFORMATION_MESSAGE);
|
||||||
|
|
||||||
|
if (n == JOptionPane.YES_OPTION){
|
||||||
|
CertificateManager.forcePutServerCert(hostname, CertificateHelper.convert(cert));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean overwriteCert(String hostname, X509Certificate cert){
|
||||||
|
JFrame frame = new JFrame();
|
||||||
|
|
||||||
|
String title = Transl._("Warning, new remote host detected");
|
||||||
|
String hostString = Transl._("The certificate of " + hostname + " has changed! <br>" +
|
||||||
|
"Are you sure you like permanently trust the new certificate from the remote host?");
|
||||||
|
|
||||||
|
String certName = "N/A";
|
||||||
|
String certAlgo = "N/A";
|
||||||
|
String certSerial = "N/A";
|
||||||
|
String certThumb = "N/A";
|
||||||
|
if (cert != null){
|
||||||
|
certName = cert.getSubjectDN().getName();
|
||||||
|
String certString = cert.getPublicKey().toString();
|
||||||
|
certAlgo = certString.substring(0,certString.indexOf("\n"));
|
||||||
|
certSerial = String.valueOf(cert.getPublicKey().serialVersionUID);
|
||||||
|
certThumb = CertificateHelper.getThumbPrint(cert);
|
||||||
|
}
|
||||||
|
String certInfo = "<html>"+Transl._("Certificate info") + "<br><br>" +
|
||||||
|
Transl._("Name: ") + certName + "<br>" +
|
||||||
|
Transl._("Algorithm: ") + certAlgo + "<br>" +
|
||||||
|
Transl._("Serial: ") + certSerial + "<br>" +
|
||||||
|
Transl._("SHA-1 ID-hash: ") + certThumb;
|
||||||
|
|
||||||
|
String textContent = certInfo + "<br><br>" + hostString;
|
||||||
|
|
||||||
|
int n = JOptionPane.showConfirmDialog(
|
||||||
|
frame,
|
||||||
|
textContent,
|
||||||
|
title,
|
||||||
|
JOptionPane.YES_NO_OPTION,
|
||||||
|
JOptionPane.WARNING_MESSAGE);
|
||||||
|
|
||||||
|
if (n == JOptionPane.YES_OPTION){
|
||||||
|
n = JOptionPane.showConfirmDialog(
|
||||||
|
frame,
|
||||||
|
Transl._("Are you sure that you trust the new certificate?"),
|
||||||
|
Transl._("Is that you final answer?"),
|
||||||
|
JOptionPane.YES_NO_OPTION,
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
|
if (n == JOptionPane.YES_OPTION){
|
||||||
|
CertificateManager.forcePutServerCert(hostname, CertificateHelper.convert(cert));
|
||||||
|
return true; // Confirmation positive
|
||||||
|
} else {
|
||||||
|
return false; // Confirmation negative
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false; // No
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ import javax.swing.JButton;
|
|||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
|
|
||||||
import net.i2p.itoopie.i18n.ItoopieTranslator;
|
import net.i2p.itoopie.i18n.Transl;
|
||||||
import net.i2p.itoopie.i2pcontrol.JSONInterface;
|
import net.i2p.itoopie.i2pcontrol.JSONInterface;
|
||||||
import net.i2p.itoopie.util.BrowseException;
|
import net.i2p.itoopie.util.BrowseException;
|
||||||
|
|
||||||
@ -50,35 +50,35 @@ public class Main {
|
|||||||
frame.getContentPane().setLayout(null);
|
frame.getContentPane().setLayout(null);
|
||||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
JButton btnStop = new JButton(ItoopieTranslator._("Stop I2P"));
|
JButton btnStop = new JButton(Transl._("Stop I2P"));
|
||||||
btnStop.setBounds(293, 91, 125, 25);
|
btnStop.setBounds(293, 91, 125, 25);
|
||||||
frame.getContentPane().add(btnStop);
|
frame.getContentPane().add(btnStop);
|
||||||
|
|
||||||
JLabel lblStop = new JLabel(ItoopieTranslator._("Push to stop I2P"));
|
JLabel lblStop = new JLabel(Transl._("Push to stop I2P"));
|
||||||
lblStop.setBounds(293, 78, 125, 15);
|
lblStop.setBounds(293, 78, 125, 15);
|
||||||
frame.getContentPane().add(lblStop);
|
frame.getContentPane().add(lblStop);
|
||||||
|
|
||||||
JButton btnStart = new JButton(ItoopieTranslator._("Start I2P"));
|
JButton btnStart = new JButton(Transl._("Start I2P"));
|
||||||
btnStart.setBounds(43, 91, 125, 25);
|
btnStart.setBounds(43, 91, 125, 25);
|
||||||
frame.getContentPane().add(btnStart);
|
frame.getContentPane().add(btnStart);
|
||||||
|
|
||||||
JLabel lblStart = new JLabel(ItoopieTranslator._("Push to start I2P"));
|
JLabel lblStart = new JLabel(Transl._("Push to start I2P"));
|
||||||
lblStart.setBounds(42, 78, 125, 15);
|
lblStart.setBounds(42, 78, 125, 15);
|
||||||
frame.getContentPane().add(lblStart);
|
frame.getContentPane().add(lblStart);
|
||||||
|
|
||||||
JLabel lblGetRate = new JLabel(ItoopieTranslator._("Get bwSend rate"));
|
JLabel lblGetRate = new JLabel(Transl._("Get bwSend rate"));
|
||||||
lblGetRate.setBounds(293, 172, 125, 15);
|
lblGetRate.setBounds(293, 172, 125, 15);
|
||||||
frame.getContentPane().add(lblGetRate);
|
frame.getContentPane().add(lblGetRate);
|
||||||
|
|
||||||
final JLabel lblDispRate = new JLabel(ItoopieTranslator._("Rate not update yet, push button."));
|
final JLabel lblDispRate = new JLabel(Transl._("Rate not update yet, push button."));
|
||||||
lblDispRate.setBounds(0,255,450,15);
|
lblDispRate.setBounds(0,255,450,15);
|
||||||
frame.getContentPane().add(lblDispRate);
|
frame.getContentPane().add(lblDispRate);
|
||||||
|
|
||||||
JButton btnGetRate = new JButton(ItoopieTranslator._("Update"));
|
JButton btnGetRate = new JButton(Transl._("Update"));
|
||||||
btnGetRate.setBounds(293, 185, 125, 25);
|
btnGetRate.setBounds(293, 185, 125, 25);
|
||||||
frame.getContentPane().add(btnGetRate);
|
frame.getContentPane().add(btnGetRate);
|
||||||
|
|
||||||
JButton btnConnect = new JButton(ItoopieTranslator._("Connect"));
|
JButton btnConnect = new JButton(Transl._("Connect"));
|
||||||
btnConnect.addActionListener(new ActionListener() {
|
btnConnect.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ public class Main {
|
|||||||
btnConnect.setBounds(43, 185, 125, 25);
|
btnConnect.setBounds(43, 185, 125, 25);
|
||||||
frame.getContentPane().add(btnConnect);
|
frame.getContentPane().add(btnConnect);
|
||||||
|
|
||||||
JLabel lblConnect = new JLabel(ItoopieTranslator._("Connect to I2P"));
|
JLabel lblConnect = new JLabel(Transl._("Connect to I2P"));
|
||||||
lblConnect.setBounds(43, 172, 125, 15);
|
lblConnect.setBounds(43, 172, 125, 15);
|
||||||
frame.getContentPane().add(lblConnect);
|
frame.getContentPane().add(lblConnect);
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ public class Main {
|
|||||||
@Override
|
@Override
|
||||||
protected Object doInBackground() throws Exception {
|
protected Object doInBackground() throws Exception {
|
||||||
double rate = JSONInterface.getRateStat("bw.sendRate", 3600000L);
|
double rate = JSONInterface.getRateStat("bw.sendRate", 3600000L);
|
||||||
lblDispRate.setText(ItoopieTranslator._("Current bw.sendRate: " + rate));
|
lblDispRate.setText(Transl._("Current bw.sendRate: " + rate));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.i2p.itoopie.i18n;
|
package net.i2p.itoopie.i18n;
|
||||||
|
|
||||||
public class ItoopieTranslator {
|
public class Transl {
|
||||||
|
|
||||||
private static final String BUNDLE_NAME = "net.i2p.itoopie.messages";
|
private static final String BUNDLE_NAME = "net.i2p.itoopie.messages";
|
||||||
|
|
@ -48,6 +48,7 @@ public class JSONInterface{
|
|||||||
_log.error("Bad URL: https://"+srvHost+":"+srvPort+"/"+srvTarget, e);
|
_log.error("Bad URL: https://"+srvHost+":"+srvPort+"/"+srvTarget, e);
|
||||||
}
|
}
|
||||||
session = new JSONRPC2Session(srvURL);
|
session = new JSONRPC2Session(srvURL);
|
||||||
|
session.trustAllCerts(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -98,4 +99,22 @@ public class JSONInterface{
|
|||||||
throw resp.getError();
|
throw resp.getError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static String getServerCert(String str) throws JSONRPC2Error{
|
||||||
|
|
||||||
|
JSONRPC2Request req = new JSONRPC2Request("echo", incrNonce());
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
Map params = new HashMap();
|
||||||
|
params.put("echo", str);
|
||||||
|
req.setParams(params);
|
||||||
|
|
||||||
|
JSONRPC2Response resp = sendReq(req);
|
||||||
|
if (resp.indicatesSuccess()){
|
||||||
|
Map inParams = (HashMap)resp.getResult();
|
||||||
|
return (String) inParams.get("serverCert");
|
||||||
|
} else {
|
||||||
|
throw resp.getError();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,21 @@
|
|||||||
package net.i2p.itoopie.security;
|
package net.i2p.itoopie.security;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||||
|
import javax.net.ssl.SSLSession;
|
||||||
|
import javax.security.cert.CertificateEncodingException;
|
||||||
|
|
||||||
|
import net.i2p.itoopie.gui.CertificateGUI;
|
||||||
|
import net.i2p.itoopie.i18n.Transl;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
@ -31,4 +42,100 @@ public class CertificateHelper {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converts to java.security
|
||||||
|
public static java.security.cert.X509Certificate convert(javax.security.cert.X509Certificate cert) {
|
||||||
|
try {
|
||||||
|
byte[] encoded = cert.getEncoded();
|
||||||
|
ByteArrayInputStream bis = new ByteArrayInputStream(encoded);
|
||||||
|
java.security.cert.CertificateFactory cf
|
||||||
|
= java.security.cert.CertificateFactory.getInstance("X.509");
|
||||||
|
return (java.security.cert.X509Certificate)cf.generateCertificate(bis);
|
||||||
|
} catch (java.security.cert.CertificateEncodingException e) {
|
||||||
|
} catch (javax.security.cert.CertificateEncodingException e) {
|
||||||
|
} catch (java.security.cert.CertificateException e) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts to javax.security
|
||||||
|
public static javax.security.cert.X509Certificate convert(java.security.cert.X509Certificate cert) {
|
||||||
|
try {
|
||||||
|
byte[] encoded = cert.getEncoded();
|
||||||
|
return javax.security.cert.X509Certificate.getInstance(encoded);
|
||||||
|
} catch (java.security.cert.CertificateEncodingException e) {
|
||||||
|
} catch (javax.security.cert.CertificateEncodingException e) {
|
||||||
|
} catch (javax.security.cert.CertificateException e) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String getThumbPrint(javax.security.cert.X509Certificate cert){
|
||||||
|
try {
|
||||||
|
return getThumbPrint(convert(cert));
|
||||||
|
} catch (Exception e){
|
||||||
|
return Transl._("Unable to create hash of the given cert, ") + cert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getThumbPrint(java.security.cert.X509Certificate cert)
|
||||||
|
throws NoSuchAlgorithmException, CertificateEncodingException {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||||
|
byte[] der = null;
|
||||||
|
try {
|
||||||
|
der = cert.getEncoded();
|
||||||
|
} catch (java.security.cert.CertificateEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
md.update(der);
|
||||||
|
byte[] digest = md.digest();
|
||||||
|
return hexify(digest);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String hexify (byte bytes[]) {
|
||||||
|
|
||||||
|
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||||
|
|
||||||
|
StringBuffer buf = new StringBuffer(bytes.length * 2);
|
||||||
|
|
||||||
|
for (int i = 0; i < bytes.length; ++i) {
|
||||||
|
buf.append(hexDigits[(bytes[i] & 0xf0) >> 4]);
|
||||||
|
buf.append(hexDigits[bytes[i] & 0x0f]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static HostnameVerifier getHostnameVerifier(){
|
||||||
|
return new HostnameVerifier(){
|
||||||
|
|
||||||
|
public boolean verify(String urlHostName, SSLSession session) {
|
||||||
|
String serverHost = session.getPeerHost();
|
||||||
|
try {
|
||||||
|
javax.security.cert.X509Certificate[] certs = session.getPeerCertificateChain();
|
||||||
|
|
||||||
|
if (CertificateManager.contains(serverHost)){
|
||||||
|
if (CertificateManager.verifyCert(serverHost, CertificateHelper.convert(certs[0]))){
|
||||||
|
return true; // Remote host has provided valid certificate that is store locally.
|
||||||
|
} else {
|
||||||
|
// Remote host has provided a certificate that != the stored certificate for this host
|
||||||
|
return CertificateGUI.overwriteCert(serverHost, certs[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// GUI, Add new host! new host
|
||||||
|
return CertificateGUI.saveNewCert(serverHost, certs[0]);
|
||||||
|
}
|
||||||
|
} catch (SSLPeerUnverifiedException e) {
|
||||||
|
_log.fatal("Remote host could not be verified, possibly due to using not using athentication");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,21 @@ package net.i2p.itoopie.security;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.SignatureException;
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
@ -37,39 +41,16 @@ public class CertificateManager {
|
|||||||
_log = LogFactory.getLog(CertificateManager.class);
|
_log = LogFactory.getLog(CertificateManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Export X509Certificate as a file.
|
|
||||||
*
|
|
||||||
* @param cert - X509Certificate to export
|
|
||||||
* @param file - Destination file for certificate
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static void export(X509Certificate cert, File file) {
|
|
||||||
try {
|
|
||||||
// Get the encoded form which is suitable for exporting
|
|
||||||
byte[] buf = cert.getEncoded();
|
|
||||||
|
|
||||||
FileOutputStream os = new FileOutputStream(file);
|
public static boolean verifyCert(String storedCertAlias, X509Certificate cert){
|
||||||
// Never write certificate in binary form.
|
try {
|
||||||
if (false) {
|
X509Certificate storedCert = (X509Certificate) getDefaultKeyStore().getCertificate(storedCertAlias);
|
||||||
// Write in binary form
|
storedCert.verify(cert.getPublicKey());
|
||||||
os.write(buf);
|
return true;
|
||||||
} else {
|
} catch (KeyStoreException e) {
|
||||||
// Write in text form
|
return false; // Was unable to read cert with given alias. Which is fine.
|
||||||
Writer wr = new OutputStreamWriter(os, Charset.forName("UTF-8"));
|
} catch (Exception e) {
|
||||||
wr.write("-----BEGIN CERTIFICATE-----\n");
|
return false; // Something is wrong with the provided key.
|
||||||
wr.write(new sun.misc.BASE64Encoder().encode(buf));
|
|
||||||
wr.write("\n-----END CERTIFICATE-----\n");
|
|
||||||
wr.flush();
|
|
||||||
}
|
|
||||||
os.close();
|
|
||||||
} catch (CertificateEncodingException e) {
|
|
||||||
_log.error(
|
|
||||||
"Bad certificate, can't be base64 encoded as a X509Certificate",
|
|
||||||
e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
_log.error("File " + file.getAbsolutePath().toString()
|
|
||||||
+ " couldn't be written", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,11 +72,13 @@ public class CertificateManager {
|
|||||||
* @return - True if store was successful, false in other cases.
|
* @return - True if store was successful, false in other cases.
|
||||||
*/
|
*/
|
||||||
public static boolean putServerCert(String name, X509Certificate cert) {
|
public static boolean putServerCert(String name, X509Certificate cert) {
|
||||||
|
KeyStore ks = getDefaultKeyStore();
|
||||||
try {
|
try {
|
||||||
if (getDefaultKeyStore().containsAlias(name)){
|
if (ks.containsAlias(name)){
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
getDefaultKeyStore().setCertificateEntry(name, cert);
|
ks.setCertificateEntry(name, cert);
|
||||||
|
saveKeyStore(ks);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (KeyStoreException e) {
|
} catch (KeyStoreException e) {
|
||||||
@ -105,6 +88,26 @@ public class CertificateManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force store server X509Certificate under the name provided even if a certificate with the given alias already exists.
|
||||||
|
*
|
||||||
|
* @param name - Name of the certificate
|
||||||
|
* @param cert - X509Certificate to store
|
||||||
|
* @return - True if store was successful, false in other cases.
|
||||||
|
*/
|
||||||
|
public static boolean forcePutServerCert(String name, X509Certificate cert) {
|
||||||
|
KeyStore ks = getDefaultKeyStore();
|
||||||
|
try {
|
||||||
|
ks.setCertificateEntry(name, cert);
|
||||||
|
saveKeyStore(ks);
|
||||||
|
return true;
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overwrite current X509Certificate with this name. Will only work if the
|
* Overwrite current X509Certificate with this name. Will only work if the
|
||||||
* name already has a certificate associated with it.
|
* name already has a certificate associated with it.
|
||||||
@ -114,11 +117,13 @@ public class CertificateManager {
|
|||||||
* @return - True if the overwrite was successful, false in other cases
|
* @return - True if the overwrite was successful, false in other cases
|
||||||
*/
|
*/
|
||||||
public static boolean overwriteServerCert(String name, X509Certificate cert){
|
public static boolean overwriteServerCert(String name, X509Certificate cert){
|
||||||
|
KeyStore ks = getDefaultKeyStore();
|
||||||
try {
|
try {
|
||||||
if (getDefaultKeyStore().containsAlias(name)){
|
if (ks.containsAlias(name)){
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
getDefaultKeyStore().setCertificateEntry(name, cert);
|
getDefaultKeyStore().setCertificateEntry(name, cert);
|
||||||
|
saveKeyStore(ks);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (KeyStoreException e) {
|
} catch (KeyStoreException e) {
|
||||||
@ -153,13 +158,12 @@ public class CertificateManager {
|
|||||||
*/
|
*/
|
||||||
private static synchronized KeyStore getDefaultKeyStore(){
|
private static synchronized KeyStore getDefaultKeyStore(){
|
||||||
if (_ks == null){
|
if (_ks == null){
|
||||||
KeyStore ks = null;
|
|
||||||
try {
|
try {
|
||||||
ks = KeyStore.getInstance(DEFAULT_KEYSTORE_TYPE);
|
_ks = KeyStore.getInstance(DEFAULT_KEYSTORE_TYPE);
|
||||||
if ((new File(DEFAULT_KEYSTORE_LOCATION)).exists()){
|
if ((new File(DEFAULT_KEYSTORE_LOCATION)).exists()){
|
||||||
InputStream is = new FileInputStream(DEFAULT_KEYSTORE_LOCATION);
|
InputStream is = new FileInputStream(DEFAULT_KEYSTORE_LOCATION);
|
||||||
ks.load(is, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
|
_ks.load(is, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
|
||||||
return ks;
|
return _ks;
|
||||||
} else {
|
} else {
|
||||||
throw new IOException("KeyStore file " + DEFAULT_KEYSTORE_LOCATION + "wasn't readable");
|
throw new IOException("KeyStore file " + DEFAULT_KEYSTORE_LOCATION + "wasn't readable");
|
||||||
}
|
}
|
||||||
@ -167,10 +171,10 @@ public class CertificateManager {
|
|||||||
// Ignore. Not an issue. Let's just create a new keystore instead.
|
// Ignore. Not an issue. Let's just create a new keystore instead.
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ks = KeyStore.getInstance(DEFAULT_KEYSTORE_TYPE);
|
_ks = KeyStore.getInstance(DEFAULT_KEYSTORE_TYPE);
|
||||||
ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
|
_ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
|
||||||
ks.store(new FileOutputStream(DEFAULT_KEYSTORE_LOCATION), DEFAULT_KEYSTORE_PASSWORD.toCharArray());
|
saveKeyStore(_ks);
|
||||||
return ks;
|
return _ks;
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
// Log perhaps?
|
// Log perhaps?
|
||||||
}
|
}
|
||||||
@ -179,4 +183,25 @@ public class CertificateManager {
|
|||||||
return _ks;
|
return _ks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void saveKeyStore(KeyStore ks){
|
||||||
|
try {
|
||||||
|
ks.store(new FileOutputStream(DEFAULT_KEYSTORE_LOCATION), DEFAULT_KEYSTORE_PASSWORD.toCharArray());
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
14
src/net/i2p/itoopie/util/IsJar.java
Normal file
14
src/net/i2p/itoopie/util/IsJar.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package net.i2p.itoopie.util;
|
||||||
|
|
||||||
|
public abstract class IsJar {
|
||||||
|
|
||||||
|
public static boolean isRunningJar(){
|
||||||
|
IsJarTester isJar = new IsJarTester();
|
||||||
|
String className = isJar.getClass().getName().replace('.', '/');
|
||||||
|
String classJar = isJar.getClass().getResource("/" + className + ".class").toString();
|
||||||
|
if (classJar.startsWith("jar:"))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
5
src/net/i2p/itoopie/util/IsJarTester.java
Normal file
5
src/net/i2p/itoopie/util/IsJarTester.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package net.i2p.itoopie.util;
|
||||||
|
|
||||||
|
public class IsJarTester {
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user