diff --git a/INSTALL b/INSTALL index a5e51cb0..8dd50899 100644 --- a/INSTALL +++ b/INSTALL @@ -1,44 +1,36 @@ -/* - * $Source: /cvsroot/owasp/webscarab/INSTALL,v $ - * Copyright (c) 2002 owasp.org. - * This file is part of WebScarab. - * WebScarab 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. - * - * WebScarab 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. - * - * The valid license text for this file can be retrieved with - * the call: java -cp owasp.jar org.owasp.webscarab.LICENSE - * - * If you are not able to view the LICENSE that way, which should - * always be possible within a valid and working WebScarab release, - * please write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +INSTALL for OWASP WebScarab +=========================== + +=== 1. Requirements This is the WebScarab OpenSource project, hosted at -http://www.owasp.org/webscarab. +https://www.owasp.org/index.php/Category:OWASP_WebScarab_Project All source code and development stuff is done under -http://sourceforge.net/projects/owasp +https://github.com/OWASP/OWASP-WebScarab -Prior to building WebScarab, you should download the various -libraries that it depends on. You can see the list in the ant build.xml -file, in this directory. If you got this file by checking out the source -from the WebScarab CVS repository, you should have the required libraries -already. +Required tools are: +* Apache Maven 3.0.4+ for building +* NetBeans 7.3 for development (for the Swing forms) -WebScarab uses the Apache Ant build tool. In order to build WebScarab, you -should use a reasonably recent version of Ant. -There are two Ant build tasks that depend on external tools, IzPack and -ProGuard. You are only likely to need these tools if you plan to build -redistributable images of WebScarab. i.e. an installer, or the self-contained -jar. There should be no problem running the common build tasks if you do not -have these external tools. +=== 2. Maven + +Building WebScarab can be done via the Apache Maven build tool. +Simply do: + mvn clean install +will get you the one-jar JAR under the target directory. + +The WebScarab installer can be built via: + mvn clean install -Pinstaller -// end of $Source: /cvsroot/owasp/webscarab/INSTALL,v $ + +=== 3. Ant + +WebScarab can also be built via the Apache Ant build tool. +Prior to building WebScarab via Ant, you should download the various +libraries that it depends on. You can make Apache Maven to download the +various required libraries via: + mvn package -Pant + +WebScarab uses the Apache Ant build tool. In order to build WebScarab, you +should use a reasonably recent version of Ant. diff --git a/izpack/install.xml b/izpack/install.xml index e8ca9e16..e2cf505a 100644 --- a/izpack/install.xml +++ b/izpack/install.xml @@ -7,6 +7,10 @@ WebScarab ${project.version} 1.6 + https://www.owasp.org/index.php/Category:OWASP_WebScarab_Project + + true + @@ -37,6 +41,7 @@ - + + diff --git a/izpack/shortcutSpec.xml b/izpack/shortcutSpec.xml index e0d958ff..cfb44d21 100644 --- a/izpack/shortcutSpec.xml +++ b/izpack/shortcutSpec.xml @@ -25,7 +25,7 @@ startMenu="no" startup="no" target="java" - commandLine="-jar "$INSTALL_PATH/Uninstaller/uninstaller.jar"" + commandLine="-jar "$INSTALL_PATH/Uninstaller/WebScarab-${project.version}-uninstaller.jar"" type="Application" encoding="UTF-8" description="WebScarab uninstaller"> diff --git a/lib/bcpkix-jdk15on-148.jar b/lib/bcpkix-jdk15on-148.jar deleted file mode 100644 index 167eecfa..00000000 Binary files a/lib/bcpkix-jdk15on-148.jar and /dev/null differ diff --git a/lib/bcprov-jdk15on-148.jar b/lib/bcprov-jdk15on-148.jar deleted file mode 100644 index 3fcb136d..00000000 Binary files a/lib/bcprov-jdk15on-148.jar and /dev/null differ diff --git a/lib/bsf-2.3.0.jar b/lib/bsf-2.3.0.jar deleted file mode 100644 index caa4dea7..00000000 Binary files a/lib/bsf-2.3.0.jar and /dev/null differ diff --git a/lib/bsh-2.0b1.jar b/lib/bsh-2.0b1.jar deleted file mode 100644 index c005694c..00000000 Binary files a/lib/bsh-2.0b1.jar and /dev/null differ diff --git a/lib/chardet.jar b/lib/chardet.jar deleted file mode 100644 index c362d03c..00000000 Binary files a/lib/chardet.jar and /dev/null differ diff --git a/lib/commons-logging-1.0.4.jar b/lib/commons-logging-1.0.4.jar deleted file mode 100644 index b73a80fa..00000000 Binary files a/lib/commons-logging-1.0.4.jar and /dev/null differ diff --git a/lib/concurrent.jar b/lib/concurrent.jar deleted file mode 100644 index 49b2cd4e..00000000 Binary files a/lib/concurrent.jar and /dev/null differ diff --git a/lib/flex-messaging-common.jar b/lib/flex-messaging-common.jar deleted file mode 100644 index 381cdeba..00000000 Binary files a/lib/flex-messaging-common.jar and /dev/null differ diff --git a/lib/flex-messaging-core.jar b/lib/flex-messaging-core.jar deleted file mode 100644 index 4fdf6e29..00000000 Binary files a/lib/flex-messaging-core.jar and /dev/null differ diff --git a/lib/flex-messaging-remoting.jar b/lib/flex-messaging-remoting.jar deleted file mode 100644 index d809e51e..00000000 Binary files a/lib/flex-messaging-remoting.jar and /dev/null differ diff --git a/lib/htmlparser.jar b/lib/htmlparser.jar deleted file mode 100644 index 385dd877..00000000 Binary files a/lib/htmlparser.jar and /dev/null differ diff --git a/lib/jcifs-1.3.14.jar b/lib/jcifs-1.3.14.jar deleted file mode 100644 index c3d7f4e9..00000000 Binary files a/lib/jcifs-1.3.14.jar and /dev/null differ diff --git a/lib/jcommon-1.0.16.jar b/lib/jcommon-1.0.16.jar deleted file mode 100644 index 4cd68074..00000000 Binary files a/lib/jcommon-1.0.16.jar and /dev/null differ diff --git a/lib/jfreechart-1.0.13.jar b/lib/jfreechart-1.0.13.jar deleted file mode 100644 index 83c69931..00000000 Binary files a/lib/jfreechart-1.0.13.jar and /dev/null differ diff --git a/lib/jhall-2.0_02.jar b/lib/jhall-2.0_02.jar deleted file mode 100644 index 6b894bc2..00000000 Binary files a/lib/jhall-2.0_02.jar and /dev/null differ diff --git a/lib/joda-time-2.1.jar b/lib/joda-time-2.1.jar deleted file mode 100644 index b2aca95b..00000000 Binary files a/lib/joda-time-2.1.jar and /dev/null differ diff --git a/lib/openid4java-0.9.7.jar b/lib/openid4java-0.9.7.jar deleted file mode 100644 index c9590d04..00000000 Binary files a/lib/openid4java-0.9.7.jar and /dev/null differ diff --git a/lib/tagsoup-1.0rc2.jar b/lib/tagsoup-1.0rc2.jar deleted file mode 100755 index 6e3f76e0..00000000 Binary files a/lib/tagsoup-1.0rc2.jar and /dev/null differ diff --git a/lib/xalan-2.7.1.jar b/lib/xalan-2.7.1.jar deleted file mode 100644 index f3da5a17..00000000 Binary files a/lib/xalan-2.7.1.jar and /dev/null differ diff --git a/lib/xmlsec-1.4.3.jar b/lib/xmlsec-1.4.3.jar deleted file mode 100644 index f4ae4033..00000000 Binary files a/lib/xmlsec-1.4.3.jar and /dev/null differ diff --git a/pom.xml b/pom.xml index 522cc5f6..b5393dc7 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,15 @@ + + + + org.apache.maven.plugins + maven-install-plugin + 2.4 + + + @@ -85,6 +94,14 @@ ${project.build.directory}/staging true + + ${project.build.directory} + false + ${basedir} + + webscarab_logo.gif + + @@ -109,8 +126,37 @@ + + ant + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.7 + + + copy-lib + package + + copy-dependencies + + + ${basedir}/lib + + + + + + + + + org.codehaus.groovy + groovy-jsr223 + 2.0.0 + org.apache.santuario xmlsec @@ -131,6 +177,11 @@ flex-messaging-common 1.0 + + amf + flex-messaging-remoting + 1.0 + org.samba.jcifs jcifs @@ -211,6 +262,11 @@ commons-codec 1.5 + + commons-io + commons-io + 2.4 + junit junit @@ -248,7 +304,7 @@ dstovall.org - http://dstovall.org/maven2/ + http://onejar-maven-plugin.googlecode.com/svn/mavenrepo diff --git a/src/org/owasp/webscarab/WebScarab.java b/src/org/owasp/webscarab/WebScarab.java index d1d3cd8d..9c6cae83 100644 --- a/src/org/owasp/webscarab/WebScarab.java +++ b/src/org/owasp/webscarab/WebScarab.java @@ -141,9 +141,12 @@ public void run() { frame.toFront(); frame.requestFocus(); splash.close(); - if (session != null && session.isDirectory()) - ui.loadSession(session); - } + if (session != null && session.isDirectory()) + ui.loadSession(session); + else + ui.createTemporarySession(); + + } }); ui.run(); } catch (Exception e) { diff --git a/src/org/owasp/webscarab/httpclient/AbstractCertificateRepository.java b/src/org/owasp/webscarab/httpclient/AbstractCertificateRepository.java index 0a04af7c..f032ed97 100644 --- a/src/org/owasp/webscarab/httpclient/AbstractCertificateRepository.java +++ b/src/org/owasp/webscarab/httpclient/AbstractCertificateRepository.java @@ -30,24 +30,28 @@ public abstract class AbstractCertificateRepository implements CertificateReposi protected Logger _logger = Logger.getLogger(getClass().getName()); private String _defaultKey = null; - private Map _aliasPasswords = new HashMap(); - protected List _keyStores = new ArrayList(); - protected Map _keyStoreDescriptions = new HashMap(); + private Map> _aliasPasswords = new HashMap>(); + protected List _keyStores = new ArrayList(); + protected Map _keyStoreDescriptions = new HashMap(); + @Override public int getKeyStoreCount() { return _keyStores.size(); } + @Override public String getKeyStoreDescription(int keystoreIndex) { - return (String) _keyStoreDescriptions.get(_keyStores.get(keystoreIndex)); + return _keyStoreDescriptions.get(_keyStores.get(keystoreIndex)); } + @Override public int getAliasCount(int keystoreIndex) { - return getAliases((KeyStore) _keyStores.get(keystoreIndex)).length; + return getAliases(_keyStores.get(keystoreIndex)).length; } + @Override public String getAliasAt(int keystoreIndex, int aliasIndex) { - return getAliases((KeyStore) _keyStores.get(keystoreIndex))[aliasIndex]; + return getAliases(_keyStores.get(keystoreIndex))[aliasIndex]; } private String[] getAliases(KeyStore ks) { @@ -66,9 +70,10 @@ private String[] getAliases(KeyStore ks) { return (String[]) aliases.toArray(new String[0]); } + @Override public Certificate getCertificate(int keystoreIndex, int aliasIndex) { try { - KeyStore ks = (KeyStore) _keyStores.get(keystoreIndex); + KeyStore ks = _keyStores.get(keystoreIndex); String alias = getAliasAt(keystoreIndex, aliasIndex); return ks.getCertificate(alias); } catch (Exception e) { @@ -76,6 +81,7 @@ public Certificate getCertificate(int keystoreIndex, int aliasIndex) { } } + @Override public String getFingerPrint(Certificate cert) throws KeyStoreException { if (!(cert instanceof X509Certificate)) { return null; @@ -96,6 +102,7 @@ public String getFingerPrint(Certificate cert) throws KeyStoreException { return buff.toString().toUpperCase() + " " + dn; } + @Override public boolean isProviderAvailable(String type) { try { if (type.equals("PKCS11")) { @@ -107,8 +114,13 @@ public boolean isProviderAvailable(String type) { return true; } + @Override public boolean isKeyUnlocked(int keystoreIndex, int aliasIndex) { KeyStore ks = (KeyStore) _keyStores.get(keystoreIndex); + if (ks.getType().equals("PKCS11")) { + // we use the callback mechanism here + return true; + } String alias = getAliasAt(keystoreIndex, aliasIndex); Map pwmap = (Map) _aliasPasswords.get(ks); @@ -118,6 +130,7 @@ public boolean isKeyUnlocked(int keystoreIndex, int aliasIndex) { return pwmap.containsKey(alias); } + @Override public void setDefaultKey(String fingerprint) { _defaultKey = fingerprint; } @@ -136,7 +149,8 @@ private int addKeyStore(KeyStore ks, String description) { return index; } - public int initPKCS11(String name, String library, int slotListIndex, String kspassword) { + @Override + public int initPKCS11(String name, String library, int slotListIndex) { try { if (!isProviderAvailable("PKCS11")) { return -1; @@ -157,7 +171,7 @@ public int initPKCS11(String name, String library, int slotListIndex, String ksp // init the key store KeyStore ks = KeyStore.getInstance("PKCS11"); - ks.load(null, kspassword == null ? null : kspassword.toCharArray()); + ks.load(new Pkcs11LoadStoreParameter()); return addKeyStore(ks, name); } catch (Exception e) { System.err.println("Error instantiating the PKCS11 provider"); @@ -166,6 +180,7 @@ public int initPKCS11(String name, String library, int slotListIndex, String ksp } } + @Override public int loadPKCS12Certificate(String filename, String ksPassword) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException { // Open the file diff --git a/src/org/owasp/webscarab/httpclient/AliasKeyManager.java b/src/org/owasp/webscarab/httpclient/AliasKeyManager.java index 96baf427..ef9718f0 100644 --- a/src/org/owasp/webscarab/httpclient/AliasKeyManager.java +++ b/src/org/owasp/webscarab/httpclient/AliasKeyManager.java @@ -35,7 +35,7 @@ public class AliasKeyManager implements X509KeyManager { /** * Creates a new instance of AliasKeyManager * @param ks The KeyStore that contains the keypair to use - * @param password the password for the key (not the keystore) + * @param password the optional password for the key (not the keystore) * @param alias the alias of the certificate to use */ public AliasKeyManager(KeyStore ks, String alias, String keyPassword) { @@ -44,14 +44,17 @@ public AliasKeyManager(KeyStore ks, String alias, String keyPassword) { _keyPassword = keyPassword; } + @Override public String chooseClientAlias(String[] str, Principal[] principal, Socket socket) { return _alias; } + @Override public String chooseServerAlias(String str, Principal[] principal, Socket socket) { return _alias; } + @Override public X509Certificate[] getCertificateChain(String alias) { try { Certificate[] certs = _ks.getCertificateChain(alias); @@ -67,13 +70,21 @@ public X509Certificate[] getCertificateChain(String alias) { } } + @Override public String[] getClientAliases(String str, Principal[] principal) { return new String[] { _alias }; } + @Override public PrivateKey getPrivateKey(String alias) { try { - return (PrivateKey) _ks.getKey(alias, _keyPassword.toCharArray()); + char [] password; + if (_keyPassword == null) { + password = null; + } else { + password = _keyPassword.toCharArray(); + } + return (PrivateKey) _ks.getKey(alias, password); } catch (KeyStoreException kse) { kse.printStackTrace(); return null; @@ -86,6 +97,7 @@ public PrivateKey getPrivateKey(String alias) { } } + @Override public String[] getServerAliases(String str, Principal[] principal) { return new String[] { _alias }; } diff --git a/src/org/owasp/webscarab/httpclient/CertificateRepository.java b/src/org/owasp/webscarab/httpclient/CertificateRepository.java index 8c0a43ea..324a0ea9 100644 --- a/src/org/owasp/webscarab/httpclient/CertificateRepository.java +++ b/src/org/owasp/webscarab/httpclient/CertificateRepository.java @@ -30,7 +30,7 @@ int loadPKCS12Certificate(String filename, String ksPassword) String getKeyStoreDescription(int keystoreIndex); - int initPKCS11(String name, String library, int slotListIndex, String kspassword); + int initPKCS11(String name, String library, int slotListIndex); int getKeyStoreCount(); diff --git a/src/org/owasp/webscarab/httpclient/Pkcs11LoadStoreParameter.java b/src/org/owasp/webscarab/httpclient/Pkcs11LoadStoreParameter.java new file mode 100644 index 00000000..d9cde16e --- /dev/null +++ b/src/org/owasp/webscarab/httpclient/Pkcs11LoadStoreParameter.java @@ -0,0 +1,16 @@ +package org.owasp.webscarab.httpclient; + +import java.security.KeyStore; +import org.owasp.webscarab.ui.swing.PasswordCallbackHandler; + +/** + * + * @author Frank Cornelis + */ +public class Pkcs11LoadStoreParameter implements KeyStore.LoadStoreParameter { + + @Override + public KeyStore.ProtectionParameter getProtectionParameter() { + return new KeyStore.CallbackHandlerProtection(new PasswordCallbackHandler()); + } +} diff --git a/src/org/owasp/webscarab/httpclient/SSLContextManager.java b/src/org/owasp/webscarab/httpclient/SSLContextManager.java index 1734b60d..a4c53a13 100644 --- a/src/org/owasp/webscarab/httpclient/SSLContextManager.java +++ b/src/org/owasp/webscarab/httpclient/SSLContextManager.java @@ -52,7 +52,7 @@ public SSLContextManager() { } try { if (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) { - initPKCS11("P11-CAPI", "lib/p11-capi.dll", 0, ""); + initPKCS11("P11-CAPI", "lib/p11-capi.dll", 0); } } catch (Exception e) { e.printStackTrace(); diff --git a/src/org/owasp/webscarab/httpclient/URLFetcher.java b/src/org/owasp/webscarab/httpclient/URLFetcher.java index b9b903ac..c064dc3f 100644 --- a/src/org/owasp/webscarab/httpclient/URLFetcher.java +++ b/src/org/owasp/webscarab/httpclient/URLFetcher.java @@ -55,7 +55,10 @@ import javax.net.ssl.SSLContext; import java.util.logging.Logger; +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; import jcifs.ntlmssp.NtlmFlags; import jcifs.ntlmssp.NtlmMessage; import jcifs.ntlmssp.Type1Message; @@ -73,7 +76,7 @@ /** Creates a new instance of URLFetcher * @author rdawes */ -public class URLFetcher implements HTTPClient { +public class URLFetcher implements HTTPClient, HandshakeCompletedListener { // These represent the SSL classes required to connect to the server. private String _keyFingerprint = null; @@ -459,6 +462,7 @@ private void connect(HttpUrl url, boolean enableSNI) throws IOException { SSLSocket sslsocket = (SSLSocket) factory.createSocket(_socket, hostname, _socket.getPort(), true); sslsocket.setEnabledProtocols(new String[] {"TLSv1"}); sslsocket.setUseClientMode(true); + sslsocket.addHandshakeCompletedListener(this); _socket = sslsocket; _socket.setSoTimeout(_timeout); } catch (IOException ioe) { @@ -616,4 +620,14 @@ private String attemptNegotiation(String challenge, String credentials) { return authMethod + " " + Base64.encode(message.toByteArray()); } + @Override + public void handshakeCompleted(HandshakeCompletedEvent event) { + _logger.fine("handshake completed: " + _host); + String cipherSuite = event.getCipherSuite(); + _logger.fine("cipher suite: " + cipherSuite); + SSLSession sslSession = event.getSession(); + String protocol = sslSession.getProtocol(); + _logger.fine("protocol: " + protocol); + _logger.fine("local principal: " + sslSession.getLocalPrincipal()); + } } diff --git a/src/org/owasp/webscarab/plugin/fuzz/FuzzerModel.java b/src/org/owasp/webscarab/plugin/fuzz/FuzzerModel.java index 00f67521..30de0d01 100644 --- a/src/org/owasp/webscarab/plugin/fuzz/FuzzerModel.java +++ b/src/org/owasp/webscarab/plugin/fuzz/FuzzerModel.java @@ -73,6 +73,10 @@ public FuzzerModel(FrameworkModel model) { _model = model; _conversationModel = new FuzzConversationModel(model); } + + public ConversationModel getTemplateConversationModel() { + return _model.getConversationModel(); + } public ConversationModel getConversationModel() { return _conversationModel; diff --git a/src/org/owasp/webscarab/plugin/fuzz/swing/FuzzerPanel.form b/src/org/owasp/webscarab/plugin/fuzz/swing/FuzzerPanel.form index d5ba2666..baf1157f 100644 --- a/src/org/owasp/webscarab/plugin/fuzz/swing/FuzzerPanel.form +++ b/src/org/owasp/webscarab/plugin/fuzz/swing/FuzzerPanel.form @@ -1,6 +1,6 @@ - + -
+ @@ -199,7 +199,11 @@ + + + + @@ -211,7 +215,7 @@ - + @@ -532,7 +536,7 @@ - + @@ -567,9 +571,43 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/owasp/webscarab/plugin/fuzz/swing/FuzzerPanel.java b/src/org/owasp/webscarab/plugin/fuzz/swing/FuzzerPanel.java index a220bd49..963bab3c 100644 --- a/src/org/owasp/webscarab/plugin/fuzz/swing/FuzzerPanel.java +++ b/src/org/owasp/webscarab/plugin/fuzz/swing/FuzzerPanel.java @@ -40,6 +40,7 @@ package org.owasp.webscarab.plugin.fuzz.swing; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; @@ -52,12 +53,14 @@ import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.ComboBoxModel; import javax.swing.DefaultCellEditor; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListModel; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JOptionPane; +import javax.swing.ListModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; @@ -76,11 +79,14 @@ import org.owasp.webscarab.plugin.fuzz.FuzzerModel; import org.owasp.webscarab.plugin.fuzz.Parameter; import org.owasp.webscarab.ui.swing.ColumnWidthTracker; +import org.owasp.webscarab.ui.swing.ConversationListModel; +import org.owasp.webscarab.ui.swing.ConversationRenderer; import org.owasp.webscarab.ui.swing.ConversationTableModel; import org.owasp.webscarab.ui.swing.DateRenderer; import org.owasp.webscarab.ui.swing.ShowConversationAction; import org.owasp.webscarab.ui.swing.SwingPluginUI; import org.owasp.webscarab.util.swing.ColumnDataModel; +import org.owasp.webscarab.util.swing.ListComboBoxModel; /** * @@ -119,6 +125,18 @@ public FuzzerPanel(Fuzzer fuzzer) { _model.addPropertyChangeListener(listener); _model.addModelListener(listener); _fuzzFactory.addPropertyChangeListener(listener); + + ListModel conversationList = new ConversationListModel(_model.getTemplateConversationModel()); + ComboBoxModel requestModel = new ListComboBoxModel(conversationList); + requestComboBox.setModel(requestModel); + requestComboBox.setRenderer(new ConversationRenderer(_model.getTemplateConversationModel())); + + requestComboBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + requestComboBoxActionPerformed(e); + } + }); + } private void configureTables() { @@ -239,7 +257,7 @@ private void updateFields(PropertyChangeEvent evt) { * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ - // //GEN-BEGIN:initComponents + // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; @@ -296,10 +314,13 @@ private void initComponents() { jScrollPane5 = new javax.swing.JScrollPane(); conversationTable = new javax.swing.JTable(); statusLabel = new javax.swing.JLabel(); + previousRequestPanel = new javax.swing.JPanel(); + jLabel12 = new javax.swing.JLabel(); + requestComboBox = new javax.swing.JComboBox(); + fuzzDialog.setTitle("Fuzz Sources"); fuzzDialog.getContentPane().setLayout(new java.awt.GridBagLayout()); - fuzzDialog.setTitle("Fuzz Sources"); jPanel4.setLayout(new java.awt.GridBagLayout()); jLabel8.setText("Fuzz Sources"); @@ -313,6 +334,7 @@ private void initComponents() { jScrollPane3.setMaximumSize(new java.awt.Dimension(100, 32767)); jScrollPane3.setMinimumSize(new java.awt.Dimension(100, 50)); jScrollPane3.setPreferredSize(new java.awt.Dimension(100, 131)); + nameList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane3.setViewportView(nameList); @@ -372,14 +394,12 @@ private void initComponents() { gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2); fuzzDialog.getContentPane().add(jLabel11, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2); fuzzDialog.getContentPane().add(descriptionTextField, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 4; @@ -387,7 +407,6 @@ private void initComponents() { gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2); fuzzDialog.getContentPane().add(regexTextField, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 5; @@ -402,7 +421,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { browseButtonActionPerformed(evt); } }); - gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 5; @@ -417,7 +435,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { addButtonActionPerformed(evt); } }); - jPanel3.add(addButton); deleteButton.setText("Remove"); @@ -426,7 +443,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { deleteButtonActionPerformed(evt); } }); - jPanel3.add(deleteButton); closeButton.setText("Close"); @@ -435,7 +451,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { closeButtonActionPerformed(evt); } }); - jPanel3.add(closeButton); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -473,7 +488,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { methodTextFieldActionPerformed(evt); } }); - gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; @@ -496,7 +510,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { urlTextFieldActionPerformed(evt); } }); - gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; @@ -522,7 +535,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { versionTextFieldActionPerformed(evt); } }); - gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; @@ -537,10 +549,10 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; fuzzPanel.add(requestPanel, gridBagConstraints); - headerPanel.setLayout(new java.awt.GridBagLayout()); - headerPanel.setMinimumSize(new java.awt.Dimension(22, 50)); headerPanel.setPreferredSize(new java.awt.Dimension(527, 100)); + headerPanel.setLayout(new java.awt.GridBagLayout()); + headerTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { @@ -565,7 +577,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { addHeaderButtonActionPerformed(evt); } }); - jPanel1.add(addHeaderButton); deleteHeaderButton.setText("Delete"); @@ -574,7 +585,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { deleteHeaderButtonActionPerformed(evt); } }); - jPanel1.add(deleteHeaderButton); headerPanel.add(jPanel1, new java.awt.GridBagConstraints()); @@ -622,7 +632,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { addParameterButtonActionPerformed(evt); } }); - jPanel2.add(addParameterButton); deleteParameterButton.setText("Delete"); @@ -631,7 +640,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { deleteParameterButtonActionPerformed(evt); } }); - jPanel2.add(deleteParameterButton); parameterPanel.add(jPanel2, new java.awt.GridBagConstraints()); @@ -676,7 +684,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { sourcesButtonActionPerformed(evt); } }); - actionPanel.add(sourcesButton); startButton.setText("Start"); @@ -685,7 +692,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { startButtonActionPerformed(evt); } }); - actionPanel.add(startButton); stopButton.setText("Stop"); @@ -694,7 +700,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { stopButtonActionPerformed(evt); } }); - actionPanel.add(stopButton); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -703,6 +708,8 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { fuzzPanel.add(actionPanel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; @@ -724,7 +731,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; + gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weighty = 0.5; add(jScrollPane5, gridBagConstraints); @@ -734,13 +741,28 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { statusLabel.setPreferredSize(new java.awt.Dimension(150, 15)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 2; + gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; add(statusLabel, gridBagConstraints); - } - // //GEN-END:initComponents + previousRequestPanel.setLayout(new java.awt.BorderLayout()); + + jLabel12.setText("Previous Requests : "); + jLabel12.setMinimumSize(new java.awt.Dimension(135, 15)); + previousRequestPanel.add(jLabel12, java.awt.BorderLayout.WEST); + + requestComboBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + requestComboBoxActionPerformed(evt); + } + }); + previousRequestPanel.add(requestComboBox, java.awt.BorderLayout.CENTER); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + add(previousRequestPanel, gridBagConstraints); + }// //GEN-END:initComponents private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed fuzzDialog.setVisible(false); @@ -864,6 +886,14 @@ private void addHeaderButtonActionPerformed(java.awt.event.ActionEvent evt) {//G } _model.addFuzzHeader(row, new NamedValue("Header", "Value")); }//GEN-LAST:event_addHeaderButtonActionPerformed + + private void requestComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_requestComboBoxActionPerformed + Object o = requestComboBox.getSelectedItem(); + if (o instanceof ConversationID) { + ConversationID id = (ConversationID) o; + _fuzzer.loadTemplateFromConversation(id); + } + }//GEN-LAST:event_requestComboBoxActionPerformed public Action[] getConversationActions() { return new Action[] { new FuzzConversationAction() }; @@ -911,6 +941,7 @@ public ColumnDataModel[] getUrlColumns() { private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel10; private javax.swing.JLabel jLabel11; + private javax.swing.JLabel jLabel12; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; @@ -932,7 +963,9 @@ public ColumnDataModel[] getUrlColumns() { private javax.swing.JList nameList; private javax.swing.JTable paramTable; private javax.swing.JPanel parameterPanel; + private javax.swing.JPanel previousRequestPanel; private javax.swing.JTextField regexTextField; + private javax.swing.JComboBox requestComboBox; private javax.swing.JPanel requestPanel; private javax.swing.JButton sourcesButton; private javax.swing.JButton startButton; diff --git a/src/org/owasp/webscarab/plugin/saml/Saml.java b/src/org/owasp/webscarab/plugin/saml/Saml.java index 68ca3421..1b487492 100644 --- a/src/org/owasp/webscarab/plugin/saml/Saml.java +++ b/src/org/owasp/webscarab/plugin/saml/Saml.java @@ -1,41 +1,41 @@ -/*********************************************************************** +/** + * ********************************************************************* * * $CVSHeader$ * - * This file is part of WebScarab, an Open Web Application Security - * Project utility. For details, please see http://www.owasp.org/ + * This file is part of WebScarab, an Open Web Application Security Project + * utility. For details, please see http://www.owasp.org/ * - * Copyright (c) 2010 FedICT - * Copyright (c) 2010 Frank Cornelis + * Copyright (c) 2010 FedICT Copyright (c) 2010 Frank Cornelis + * * - * 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 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. + * 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. + * 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. * - * Getting Source - * ============== + * Getting Source ============== * - * Source for this application is maintained at Sourceforge.net, a - * repository for free software projects. + * Source for this application is maintained at Sourceforge.net, a repository + * for free software projects. * * For details, please see http://www.sourceforge.net/projects/owasp * */ - package org.owasp.webscarab.plugin.saml; import java.util.logging.Logger; import org.owasp.webscarab.model.ConversationID; +import org.owasp.webscarab.model.HttpUrl; import org.owasp.webscarab.model.NamedValue; import org.owasp.webscarab.model.Request; import org.owasp.webscarab.model.Response; @@ -45,9 +45,8 @@ import org.owasp.webscarab.plugin.Plugin; /** - * WebScarab SAML plugin. - * This plugin allows you to analyse SAML Messages. - * + * WebScarab SAML plugin. This plugin allows you to analyse SAML Messages. + * * @author Frank Cornelis */ public class Saml implements Plugin { @@ -93,6 +92,23 @@ public void analyse(ConversationID id, Request request, Response response, } } } + } else if (method.equals("GET")) { + HttpUrl url = request.getURL(); + String query = url.getQuery(); + if (null != query) { + NamedValue[] values = NamedValue.splitNamedValues(query, "&", "="); + for (int i = 0; i < values.length; i++) { + String name = values[i].getName(); + String value = values[i].getValue(); + if ("SAMLResponse".equals(name)) { + this._model.setSAMLResponse(id, value, true); + } else if ("SAMLRequest".equals(name)) { + this._model.setSAMLRequest(id, value, true); + } else if ("RelayState".equals(name)) { + this._model.setRelayState(id, value); + } + } + } } } diff --git a/src/org/owasp/webscarab/plugin/saml/SamlCertificateRepository.java b/src/org/owasp/webscarab/plugin/saml/SamlCertificateRepository.java index 53db9caa..110d66b0 100644 --- a/src/org/owasp/webscarab/plugin/saml/SamlCertificateRepository.java +++ b/src/org/owasp/webscarab/plugin/saml/SamlCertificateRepository.java @@ -38,6 +38,7 @@ import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStore.PrivateKeyEntry; +import java.security.PrivateKey; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableEntryException; @@ -56,6 +57,8 @@ public class SamlCertificateRepository extends AbstractCertificateRepository { private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); + private PrivateKey privateKey; + @Override public void unlockKey(int keystoreIndex, int aliasIndex, String keyPassword) throws KeyStoreException, KeyManagementException { String fingerprint = getFingerPrint(getCertificate(keystoreIndex, aliasIndex)); @@ -64,7 +67,8 @@ public void unlockKey(int keystoreIndex, int aliasIndex, String keyPassword) thr KeyStore keyStore = (KeyStore) this._keyStores.get(keystoreIndex); String alias = getAliasAt(keystoreIndex, aliasIndex); try { - PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) keyStore.getEntry(alias, null); + PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(keyPassword.toCharArray())); + this.privateKey = privateKeyEntry.getPrivateKey(); this.propertyChangeSupport.firePropertyChange(SELECTED_KEY_ENTRY, null, privateKeyEntry); } catch (NoSuchAlgorithmException ex) { Logger.getLogger(SamlCertificateRepository.class.getName()).log(Level.SEVERE, null, ex); @@ -80,4 +84,8 @@ public void addPropertyChangeListener(PropertyChangeListener listener) { public void removePropertyChangeListener(PropertyChangeListener listener) { this.propertyChangeSupport.removePropertyChangeListener(listener); } + + public PrivateKey getPrivateKey() { + return this.privateKey; + } } diff --git a/src/org/owasp/webscarab/plugin/saml/SamlHTTPClient.java b/src/org/owasp/webscarab/plugin/saml/SamlHTTPClient.java index dd514f91..b282996b 100644 --- a/src/org/owasp/webscarab/plugin/saml/SamlHTTPClient.java +++ b/src/org/owasp/webscarab/plugin/saml/SamlHTTPClient.java @@ -55,6 +55,8 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import org.apache.xml.security.encryption.XMLCipher; +import org.apache.xml.security.encryption.XMLEncryptionException; import org.apache.xml.security.exceptions.Base64DecodingException; import org.apache.xml.security.exceptions.XMLSecurityException; import org.apache.xml.security.keys.KeyInfo; @@ -151,6 +153,12 @@ private void changeSamlResponse(Request request) { samlProxyHeader += "replayed;"; } + if (this.samlProxyConfig.doDecryptAssertionAttack()) { + String newSamlResponse = decryptAssertion(namedValues[idx].getValue()); + namedValues[idx] = new NamedValue(namedValues[idx].getName(), newSamlResponse); + samlProxyHeader += "decrypt assertion;"; + } + if (this.samlProxyConfig.doSignWrapAttack()) { String newSamlResponse = signatureWrapping(namedValues[idx].getValue()); namedValues[idx] = new NamedValue(namedValues[idx].getName(), newSamlResponse); @@ -178,6 +186,11 @@ private void changeSamlResponse(Request request) { samlProxyHeader += "removed assertion signature;"; } + if (this.samlProxyConfig.doSignAssertionAttack()) { + String newSamlResponse = signAssertionMessage(namedValues[idx].getValue()); + namedValues[idx] = new NamedValue(namedValues[idx].getName(), newSamlResponse); + samlProxyHeader += "sign assertion;"; + } if (this.samlProxyConfig.doSignSamlMessage()) { String newSamlResponse = signSamlMessage(namedValues[idx].getValue()); namedValues[idx] = new NamedValue(namedValues[idx].getName(), newSamlResponse); @@ -476,6 +489,41 @@ private String injectPublicDoctype(String samlResponse) throws Base64DecodingExc return newSamlResponse; } + private String signAssertionMessage(String samlResponse) throws IOException, TransformerConfigurationException, ParserConfigurationException, SAXException, Base64DecodingException, TransformerException, XMLSecurityException { + Document document = parseDocument(samlResponse); + Element assertionSignatureElement = SamlModel.findAssertionSignatureElement(document); + if (null == assertionSignatureElement) { + return samlResponse; + } + Element assertionElement = (Element) assertionSignatureElement.getParentNode(); + Node beforeNode = assertionSignatureElement.getNextSibling(); + assertionElement.removeChild(assertionSignatureElement); + XMLSignature xmlSignature = new XMLSignature(document, null, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1); + assertionElement.insertBefore(xmlSignature.getElement(), beforeNode); + + String assertionId = assertionElement.getAttribute("ID"); + Transforms transforms = new Transforms(document); + transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE); + transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS); + xmlSignature.addDocument("#" + assertionId, transforms, Constants.ALGO_ID_DIGEST_SHA1); + + KeyStore.PrivateKeyEntry privateKeyEntry = this.samlProxyConfig.getPrivateKeyEntry(); + + KeyInfo keyInfo = xmlSignature.getKeyInfo(); + X509Data x509Data = new X509Data(document); + Certificate[] certificateChain = privateKeyEntry.getCertificateChain(); + for (int certIdx = 0; certIdx < certificateChain.length; certIdx++) { + Certificate certificate = certificateChain[certIdx]; + x509Data.addCertificate((X509Certificate) certificate); + } + keyInfo.add(x509Data); + + PrivateKey privateKey = privateKeyEntry.getPrivateKey(); + xmlSignature.sign(privateKey); + + return outputDocument(document); + } + private String signSamlMessage(String samlResponse) throws IOException, ParserConfigurationException, SAXException, Base64DecodingException, TransformerConfigurationException, TransformerException, XMLSecurityException { Document document = parseDocument(samlResponse); Element protocolSignatureElement = SamlModel.findProtocolSignatureElement(document); @@ -551,6 +599,15 @@ private String signatureWrapping(String samlResponse) throws IOException, Parser String newIdValue = "renamed-" + oldIdValue; idAttr.setValue(newIdValue); } + if (this.samlProxyConfig.doRenameLastAssertionId()) { + Attr idAttr = importedParentElement.getAttributeNode("ID"); // SAML 2 + if (null == idAttr) { + idAttr = importedParentElement.getAttributeNode("AssertionID"); // SAML 1.1 + } + String oldIdValue = idAttr.getValue(); + String newIdValue = "renamed-" + oldIdValue; + idAttr.setValue(newIdValue); + } } break; case SAMLP_EXTENSIONS: { @@ -567,6 +624,17 @@ private String signatureWrapping(String samlResponse) throws IOException, Parser Element importedSamlResponseElement = (Element) document.importNode(samlResponseElement, true); samlpExtensionsElement.appendChild(importedSamlResponseElement); samlResponseElement.appendChild(samlpExtensionsElement); + if (this.samlProxyConfig.doRenameAssertionId()) { + NodeList saml2AssertionNodeList = document.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:assertion", "Assertion"); + Element assertionElement = (Element) saml2AssertionNodeList.item(0); + Attr idAttr = assertionElement.getAttributeNode("ID"); // SAML 2 + if (null == idAttr) { + idAttr = assertionElement.getAttributeNode("AssertionID"); // SAML 1.1 + } + String oldIdValue = idAttr.getValue(); + String newIdValue = "renamed-" + oldIdValue; + idAttr.setValue(newIdValue); + } } break; case ASSERTION: { @@ -652,4 +720,34 @@ private List findAssertionSignatures(Document document) { return assertionSignatures; } + + private String decryptAssertion(String samlResponse) throws IOException, ParserConfigurationException, SAXException, Base64DecodingException, TransformerException, XMLEncryptionException, Exception { + Document document = parseDocument(samlResponse); + + NodeList encryptedAssertionNodeList = document.getElementsByTagNameNS( + "urn:oasis:names:tc:SAML:2.0:assertion", "EncryptedAssertion"); + if (encryptedAssertionNodeList.getLength() == 0) { + return samlResponse; + } + + Element encryptedAssertionElement = (Element) encryptedAssertionNodeList.item(0); + Element encryptedDataElement = (Element) encryptedAssertionElement.getElementsByTagNameNS("http://www.w3.org/2001/04/xmlenc#", "EncryptedData").item(0); + if (null == encryptedDataElement) { + return samlResponse; + } + XMLCipher xmlCipher = XMLCipher.getInstance(XMLCipher.AES_128); + xmlCipher.init(XMLCipher.DECRYPT_MODE, null); + xmlCipher.setKEK(this.samlProxyConfig.getDecryptionPrivateKeyEntry().getPrivateKey()); + document = xmlCipher.doFinal(document, encryptedDataElement); + + // remove the EncryptedAssertion container + encryptedAssertionNodeList = document.getElementsByTagNameNS( + "urn:oasis:names:tc:SAML:2.0:assertion", "EncryptedAssertion"); + encryptedAssertionElement = (Element) encryptedAssertionNodeList.item(0); + Element assertionElement = (Element) encryptedAssertionElement.getFirstChild(); + encryptedAssertionElement.getParentNode().appendChild(assertionElement); + encryptedAssertionElement.getParentNode().removeChild(encryptedAssertionElement); + + return outputDocument(document); + } } diff --git a/src/org/owasp/webscarab/plugin/saml/SamlModel.java b/src/org/owasp/webscarab/plugin/saml/SamlModel.java index fdd4d728..644fdd7d 100644 --- a/src/org/owasp/webscarab/plugin/saml/SamlModel.java +++ b/src/org/owasp/webscarab/plugin/saml/SamlModel.java @@ -1,32 +1,32 @@ -/*********************************************************************** +/** + * ********************************************************************* * * $CVSHeader$ * - * This file is part of WebScarab, an Open Web Application Security - * Project utility. For details, please see http://www.owasp.org/ + * This file is part of WebScarab, an Open Web Application Security Project + * utility. For details, please see http://www.owasp.org/ * - * Copyright (c) 2010 FedICT - * Copyright (c) 2010 Frank Cornelis + * Copyright (c) 2010 FedICT Copyright (c) 2010 Frank Cornelis + * * - * 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 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. + * 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. + * 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. * - * Getting Source - * ============== + * Getting Source ============== * - * Source for this application is maintained at Sourceforge.net, a - * repository for free software projects. + * Source for this application is maintained at Sourceforge.net, a repository + * for free software projects. * * For details, please see http://www.sourceforge.net/projects/owasp * @@ -35,20 +35,33 @@ import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.StringWriter; import java.net.MalformedURLException; +import java.security.PrivateKey; +import java.security.Key; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; import javax.crypto.spec.SecretKeySpec; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; import org.apache.xml.security.Init; import org.apache.xml.security.encryption.XMLCipher; -import org.apache.xml.security.exceptions.Base64DecodingException; +import org.apache.xml.security.encryption.XMLEncryptionException; import org.apache.xml.security.exceptions.XMLSecurityException; import org.apache.xml.security.keys.KeyInfo; import org.apache.xml.security.keys.content.X509Data; @@ -57,7 +70,6 @@ import org.apache.xml.security.signature.Manifest; import org.apache.xml.security.signature.XMLSignature; import org.apache.xml.security.signature.XMLSignatureException; -import org.apache.xml.security.utils.Base64; import org.bouncycastle.util.encoders.Hex; import org.htmlparser.tags.FormTag; import org.htmlparser.util.NodeIterator; @@ -85,7 +97,7 @@ * @author Frank Cornelis */ public class SamlModel extends AbstractPluginModel { - + private Logger _logger = Logger.getLogger(getClass().getName()); private final FrameworkModel model; private final ConversationModel samlConversationModel; @@ -95,7 +107,6 @@ public class SamlModel extends AbstractPluginModel { public SamlModel(FrameworkModel model) { this.model = model; this.samlConversationModel = new FilteredConversationModel(model, model.getConversationModel()) { - @Override public boolean shouldFilter(ConversationID id) { return !isSAMLMessage(id); @@ -116,16 +127,23 @@ public boolean shouldFilter(ConversationID id) { Init.init(); } + public void setSAMLResponse(ConversationID id, String encodedSamlResponse) { + setSAMLResponse(id, encodedSamlResponse, false); + } + /** * Mark this conversation message as being a SAML Response. * * @param id * @param encodedSamlResponse */ - public void setSAMLResponse(ConversationID id, String encodedSamlResponse) { + public void setSAMLResponse(ConversationID id, String encodedSamlResponse, boolean deflate) { this.model.setConversationProperty(id, "SAML-TYPE", "Response"); this.model.setConversationProperty(id, "SAML-MESSAGE", encodedSamlResponse); + if (deflate) { + this.model.setConversationProperty(id, "SAML-DEFLATE", Boolean.TRUE.toString()); + } } public void setRelayState(ConversationID id, String relayState) { @@ -202,23 +220,31 @@ public boolean isOverSSL(ConversationID id) { public String getDecodedSAMLMessage(ConversationID id) { String encodedSAMLMessage = getEncodedSAMLMessage(id); - String decodedSAMLMessage = getDecodedSAMLMessage(encodedSAMLMessage); + String decodedSAMLMessage = getDecodedSAMLMessage(encodedSAMLMessage, id); return decodedSAMLMessage; } - public String getDecodedSAMLMessage(String encodedSamlMessage) { + public String getDecodedSAMLMessage(String encodedSamlMessage, ConversationID id) { /* * Cannot use org.owasp.webscarab.util.Encoding here as SAML tickets not * always come with line-breaks. */ - String decodedSamlMessage; - try { - decodedSamlMessage = new String(Base64.decode(encodedSamlMessage)); - } catch (Base64DecodingException ex) { - decodedSamlMessage = "[ERROR WHILE DECODING THE BASE64 ENCODED SAML MESSAGE]"; + String deflate = this.model.getConversationProperty(id, "SAML-DEFLATE"); + if (null != deflate) { + _logger.fine("inflating SAML message"); + byte[] deflated = Base64.decodeBase64(encodedSamlMessage); + try { + Inflater inflater = new Inflater(true); + InflaterInputStream inflaterInputStream = new InflaterInputStream(new ByteArrayInputStream(deflated), inflater); + return new String(IOUtils.toByteArray(inflaterInputStream)); + } catch (IOException ex) { + return "[ERROR INFLATING SAML MESSAGE]: " + ex.getMessage(); + } } + String decodedSamlMessage = new String(Base64.decodeBase64(encodedSamlMessage)); + return decodedSamlMessage; } public static final int SAML_VERSION_2 = 2; @@ -231,7 +257,7 @@ private Document getSAMLDocument(ConversationID id) { } String encodedSamlMessage = getEncodedSAMLMessage(id); - String decodedSamlMessage = getDecodedSAMLMessage(encodedSamlMessage); + String decodedSamlMessage = getDecodedSAMLMessage(encodedSamlMessage, id); ByteArrayInputStream inputStream = new ByteArrayInputStream(decodedSamlMessage.getBytes()); try { @@ -304,7 +330,7 @@ public static Element findProtocolSignatureElement(Document document) { } return null; } - + public static Element findAssertionSignatureElement(Document document) { NodeList assertionNodeList = document.getElementsByTagNameNS("urn:oasis:names:tc:SAML:2.0:assertion", "Assertion"); if (0 == assertionNodeList.getLength()) { @@ -332,7 +358,6 @@ public static Element findAssertionSignatureElement(Document document) { return null; } - public List verifySAMLProtocolSignature(ConversationID id) throws SamlSignatureException { Document document = getSAMLDocument(id); if (null == document) { @@ -410,9 +435,16 @@ public String getSAMLType(ConversationID conversationId) { return samlType; } - public void setSAMLRequest(ConversationID id, String encodedSamlRequest) { + public void setSAMLRequest(ConversationID id, String encodedSamlRequest, boolean deflate) { this.model.setConversationProperty(id, "SAML-TYPE", "Request"); this.model.setConversationProperty(id, "SAML-MESSAGE", encodedSamlRequest); + if (deflate) { + this.model.setConversationProperty(id, "SAML-DEFLATE", Boolean.TRUE.toString()); + } + } + + public void setSAMLRequest(ConversationID id, String encodedSamlRequest) { + setSAMLRequest(id, encodedSamlRequest, false); } private boolean hasDestinationIndicationSaml2Response(Element responseElement) { @@ -673,7 +705,7 @@ public List getDecryptedAttributes(ConversationID id, String hexKey) throws Exce * We create a new DOM tree as XMLCipher will change the tree. */ String encodedSamlMessage = getEncodedSAMLMessage(id); - String decodedSamlMessage = getDecodedSAMLMessage(encodedSamlMessage); + String decodedSamlMessage = getDecodedSAMLMessage(encodedSamlMessage, id); ByteArrayInputStream inputStream = new ByteArrayInputStream(decodedSamlMessage.getBytes()); Document document = this.builder.parse(inputStream); @@ -709,4 +741,52 @@ public List getDecryptedAttributes(ConversationID id, String hexKey) throws Exce return samlAttributes; } + + public byte[] getEncryptedAssertion(ConversationID id) { + Document samlDocument = getSAMLDocument(id); + NodeList encryptedAssertionNodeList = samlDocument.getElementsByTagNameNS( + "urn:oasis:names:tc:SAML:2.0:assertion", "EncryptedAssertion"); + if (encryptedAssertionNodeList.getLength() == 0) { + return null; + } + Element encryptedAssertionElement = (Element) encryptedAssertionNodeList.item(0); + try { + return toString(encryptedAssertionElement).getBytes(); + } catch (TransformerException ex) { + return null; + } + } + + private String toString(Node node) throws TransformerConfigurationException, TransformerException { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + StringWriter stringWriter = new StringWriter(); + transformer.transform(new DOMSource(node), new StreamResult(stringWriter)); + return stringWriter.toString(); + } + + public byte[] getDecryptedAssertion(ConversationID id, PrivateKey privateKey) throws ParserConfigurationException, SAXException, IOException, TransformerException, XMLEncryptionException, Exception { + byte[] encryptedAssertion = getEncryptedAssertion(id); + if (null == encryptedAssertion) { + return null; + } + if (null == privateKey) { + return "null private key".getBytes(); + } + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document document = documentBuilder.parse(new ByteArrayInputStream(encryptedAssertion)); + + Element encryptedDataElement = (Element) document.getElementsByTagNameNS("http://www.w3.org/2001/04/xmlenc#", "EncryptedData").item(0); + if (null == encryptedDataElement) { + return "missing encrypted data element".getBytes(); + } + XMLCipher xmlCipher = XMLCipher.getInstance(XMLCipher.AES_128); + xmlCipher.init(XMLCipher.DECRYPT_MODE, null); + xmlCipher.setKEK(privateKey); + document = xmlCipher.doFinal(document, encryptedDataElement); + + return toString(document).getBytes(); + } } diff --git a/src/org/owasp/webscarab/plugin/saml/SamlProxy.java b/src/org/owasp/webscarab/plugin/saml/SamlProxy.java index 168e8759..681dfc01 100644 --- a/src/org/owasp/webscarab/plugin/saml/SamlProxy.java +++ b/src/org/owasp/webscarab/plugin/saml/SamlProxy.java @@ -1,32 +1,32 @@ -/*********************************************************************** +/** + * ********************************************************************* * * $CVSHeader$ * - * This file is part of WebScarab, an Open Web Application Security - * Project utility. For details, please see http://www.owasp.org/ + * This file is part of WebScarab, an Open Web Application Security Project + * utility. For details, please see http://www.owasp.org/ * - * Copyright (c) 2010 FedICT - * Copyright (c) 2010 Frank Cornelis + * Copyright (c) 2010 FedICT Copyright (c) 2010 Frank Cornelis + * * - * 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 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. + * 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. + * 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. * - * Getting Source - * ============== + * Getting Source ============== * - * Source for this application is maintained at Sourceforge.net, a - * repository for free software projects. + * Source for this application is maintained at Sourceforge.net, a repository + * for free software projects. * * For details, please see http://www.sourceforge.net/projects/owasp * @@ -35,6 +35,7 @@ import java.security.KeyStore; import java.security.KeyStore.PrivateKeyEntry; +import java.security.cert.X509Certificate; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -45,9 +46,9 @@ import org.owasp.webscarab.plugin.proxy.ProxyPlugin; /** - * WebScarab SAML Proxy plugin. - * This plugin allows to modify the SAML Messages so simulate certain attacks. - * + * WebScarab SAML Proxy plugin. This plugin allows to modify the SAML Messages + * so simulate certain attacks. + * * @author Frank Cornelis */ public class SamlProxy extends ProxyPlugin implements SamlProxyConfig { @@ -79,7 +80,10 @@ public class SamlProxy extends ProxyPlugin implements SamlProxyConfig { private boolean renameAssertionId; private boolean renameLastAssertionId; private boolean removeAssertionSignature; - + private boolean signAssertionAttack; + private boolean decryptAssertionAttack; + private KeyStore.PrivateKeyEntry decryptionPrivateKeyEntry; + private EventListenerList _listenerList = new EventListenerList(); private SamlModel samlModel; @@ -216,8 +220,9 @@ public boolean doSomething() { private void updateAttackState() { this.attack = this.corruptSignature | this.injectAttribute | this.injectRemoteReference - | this.injectSubject | this.removeSignature | this.replay | this.injectPublicDoctype | - this.injectRelayState | this.signSamlMessage | this.signWrapAttack | this.removeAssertionSignature; + | this.injectSubject | this.removeSignature | this.replay | this.injectPublicDoctype + | this.injectRelayState | this.signSamlMessage | this.signWrapAttack | this.removeAssertionSignature + | this.signAssertionAttack | this.decryptAssertionAttack; } public void setInjectPublicDoctype(boolean injectPublicDoctype) { @@ -272,7 +277,7 @@ public boolean doSignSamlMessage() { public PrivateKeyEntry getPrivateKeyEntry() { return this.privateKeyEntry; } - + public void setPrivateKeyEntry(PrivateKeyEntry privateKeyEntry) { this.privateKeyEntry = privateKeyEntry; } @@ -377,4 +382,33 @@ public void setAttributeOccurences(Occurences occurences) { public Occurences getAttributeOccurences() { return this.attributeOccurences; } + + public void setSignAssertionAttack(boolean signAssertionAttack) { + this.signAssertionAttack = signAssertionAttack; + updateAttackState(); + } + + @Override + public boolean doSignAssertionAttack() { + return this.signAssertionAttack; + } + + public void setDecryptAssertionAttack(boolean decryptAssertionAttack) { + this.decryptAssertionAttack = decryptAssertionAttack; + updateAttackState(); + } + + @Override + public boolean doDecryptAssertionAttack() { + return this.decryptAssertionAttack; + } + + public void setDecryptionPrivateKeyEntry(PrivateKeyEntry decryptionPrivateKeyEntry) { + this.decryptionPrivateKeyEntry = decryptionPrivateKeyEntry; + } + + @Override + public PrivateKeyEntry getDecryptionPrivateKeyEntry() { + return this.decryptionPrivateKeyEntry; + } } diff --git a/src/org/owasp/webscarab/plugin/saml/SamlProxyConfig.java b/src/org/owasp/webscarab/plugin/saml/SamlProxyConfig.java index 3072c6e2..a3281b01 100644 --- a/src/org/owasp/webscarab/plugin/saml/SamlProxyConfig.java +++ b/src/org/owasp/webscarab/plugin/saml/SamlProxyConfig.java @@ -35,6 +35,7 @@ package org.owasp.webscarab.plugin.saml; import java.security.KeyStore.PrivateKeyEntry; +import java.security.cert.X509Certificate; import java.util.List; import org.owasp.webscarab.model.NamedValue; @@ -78,7 +79,7 @@ public interface SamlProxyConfig { boolean doSignSamlMessage(); - public PrivateKeyEntry getPrivateKeyEntry(); + PrivateKeyEntry getPrivateKeyEntry(); boolean doSignWrapAttack(); @@ -95,4 +96,10 @@ public interface SamlProxyConfig { boolean doRemoveAssertionSignature(); Occurences getAttributeOccurences(); + + boolean doSignAssertionAttack(); + + boolean doDecryptAssertionAttack(); + + PrivateKeyEntry getDecryptionPrivateKeyEntry(); } diff --git a/src/org/owasp/webscarab/plugin/saml/swing/SamlPanel.form b/src/org/owasp/webscarab/plugin/saml/swing/SamlPanel.form index 50c86dac..a4fb45aa 100644 --- a/src/org/owasp/webscarab/plugin/saml/swing/SamlPanel.form +++ b/src/org/owasp/webscarab/plugin/saml/swing/SamlPanel.form @@ -298,6 +298,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -636,12 +728,7 @@ - - - - - - + @@ -826,7 +913,7 @@ - + @@ -839,18 +926,31 @@ - + - + - + + + + + + + + + + + + + + @@ -1534,6 +1634,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/owasp/webscarab/plugin/saml/swing/SamlPanel.java b/src/org/owasp/webscarab/plugin/saml/swing/SamlPanel.java index 7503667f..27bde277 100644 --- a/src/org/owasp/webscarab/plugin/saml/swing/SamlPanel.java +++ b/src/org/owasp/webscarab/plugin/saml/swing/SamlPanel.java @@ -100,6 +100,10 @@ public class SamlPanel extends javax.swing.JPanel implements SwingPluginUI, Saml private final AttributesTableModel encryptedAttributesTableModel; private final SamlCertificateRepository samlCertificateRepository; private final CertificateManager certificateManager; + private final CertificateManager assertionCertificateManager; + private final SamlCertificateRepository assertionCertificateRepository; + private final CertificateManager decryptionCertificateManager; + private final SamlCertificateRepository decryptionCertificateRepository; /** * Creates new form SamlPanel @@ -157,6 +161,38 @@ public void propertyChange(PropertyChangeEvent event) { }); this.certificateManager = new CertificateManager(this.samlCertificateRepository); + this.assertionCertificateRepository = new SamlCertificateRepository(); + this.assertionCertificateRepository.addPropertyChangeListener(new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent event) { + String propertyName = event.getPropertyName(); + if (propertyName.equals(SamlCertificateRepository.SELECTED_KEY)) { + String fingerprint = (String) event.getNewValue(); + SamlPanel.this.assertionDecryptionKeyTextField.setText(fingerprint); + SamlPanel.this.decryptAssertionButton.setEnabled(true); + } + } + }); + this.assertionCertificateManager = new CertificateManager(this.assertionCertificateRepository); + + this.decryptionCertificateRepository = new SamlCertificateRepository(); + this.decryptionCertificateRepository.addPropertyChangeListener(new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent event) { + String propertyName = event.getPropertyName(); + if (propertyName.equals(SamlCertificateRepository.SELECTED_KEY)) { + String fingerprint = (String) event.getNewValue(); + SamlPanel.this.decryptionKeyTextField.setText(fingerprint); + } else if (propertyName.equals(SamlCertificateRepository.SELECTED_KEY_ENTRY)) { + PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) event.getNewValue(); + SamlPanel.this.saml.getSamlProxy().setDecryptionPrivateKeyEntry(privateKeyEntry); + } + } + }); + this.decryptionCertificateManager = new CertificateManager(this.decryptionCertificateRepository); + addTableListeners(); addTreeListeners(); resetDisplay(); @@ -239,7 +275,7 @@ public void mouseClicked(MouseEvent e) { } } }); - + this.injectAttributesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { @@ -251,7 +287,7 @@ public void valueChanged(ListSelectionEvent e) { } } }); - + this.injectAttributesTableModel.addTableModelListener(new TableModelListener() { @Override public void tableChanged(TableModelEvent e) { @@ -287,13 +323,17 @@ private void resetDisplay() { this.attributesTableModel.resetAttributes(); this.encryptedAttributesTableModel.resetAttributes(); + + this.encryptedAssertionXMLPanel.setBytes(null, null); + this.decryptedAssertionXMLPanel.setBytes(null, null); + this.decryptedAssertionTextPanel.setText(null, ""); } private void displaySaml(ConversationID id) { resetDisplay(); String encodedSamlMessage = this.samlModel.getEncodedSAMLMessage(id); this.rawPanel.setText(null, encodedSamlMessage); - String decodedSamlMessage = this.samlModel.getDecodedSAMLMessage(encodedSamlMessage); + String decodedSamlMessage = this.samlModel.getDecodedSAMLMessage(encodedSamlMessage, id); this.textPanel.setText(null, decodedSamlMessage); this.xmlPanel.setBytes("text/xml", decodedSamlMessage.getBytes()); String relayState = this.samlModel.getRelayState(id); @@ -338,6 +378,8 @@ private void displaySaml(ConversationID id) { } else { this.decryptButton.setEnabled(false); } + + this.encryptedAssertionXMLPanel.setBytes("text/xml", this.samlModel.getEncryptedAssertion(id)); } private void displaySignature(ConversationID id) { @@ -395,6 +437,16 @@ private void initComponents() { decryptButton = new javax.swing.JButton(); jScrollPane4 = new javax.swing.JScrollPane(); encryptedAttributesTable = new javax.swing.JTable(); + encryptedAssertionPanel = new javax.swing.JPanel(); + jPanel38 = new javax.swing.JPanel(); + jLabel16 = new javax.swing.JLabel(); + assertionDecryptionKeyTextField = new javax.swing.JTextField(); + selectAssertionDecryptionKeyButton = new javax.swing.JButton(); + decryptAssertionButton = new javax.swing.JButton(); + jTabbedPane4 = new javax.swing.JTabbedPane(); + encryptedAssertionXMLPanel = new org.owasp.webscarab.ui.swing.editors.XMLPanel(); + decryptedAssertionXMLPanel = new org.owasp.webscarab.ui.swing.editors.XMLPanel(); + decryptedAssertionTextPanel = new org.owasp.webscarab.ui.swing.editors.TextPanel(); htmlFormPanel = new javax.swing.JPanel(); jPanel5 = new javax.swing.JPanel(); jLabel7 = new javax.swing.JLabel(); @@ -428,7 +480,7 @@ private void initComponents() { jPanel8 = new javax.swing.JPanel(); jScrollPane1 = new javax.swing.JScrollPane(); samlTable = new javax.swing.JTable(); - jPanel6 = new javax.swing.JPanel(); + signatureAttacksPanel = new javax.swing.JPanel(); jPanel10 = new javax.swing.JPanel(); jPanel7 = new javax.swing.JPanel(); jPanel11 = new javax.swing.JPanel(); @@ -446,6 +498,7 @@ private void initComponents() { jLabel21 = new javax.swing.JLabel(); selectKeyButton = new javax.swing.JButton(); keyTextField = new javax.swing.JTextField(); + signAssertionCheckBox = new javax.swing.JCheckBox(); jPanel30 = new javax.swing.JPanel(); jPanel32 = new javax.swing.JPanel(); signWrapAttackCheckBox = new javax.swing.JCheckBox(); @@ -502,6 +555,14 @@ private void initComponents() { samlReplayCheckBox = new javax.swing.JCheckBox(); jLabel1 = new javax.swing.JLabel(); samlReplayLabel = new javax.swing.JLabel(); + jPanel39 = new javax.swing.JPanel(); + jPanel40 = new javax.swing.JPanel(); + jPanel41 = new javax.swing.JPanel(); + jPanel42 = new javax.swing.JPanel(); + decryptAssertionCheckBox = new javax.swing.JCheckBox(); + jLabel24 = new javax.swing.JLabel(); + decryptionKeyTextField = new javax.swing.JTextField(); + decryptionSelectKeyButton = new javax.swing.JButton(); setLayout(new java.awt.BorderLayout()); @@ -604,6 +665,44 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { jTabbedPane1.addTab("Encrypted Attributes", encryptedAttributesPanel); + encryptedAssertionPanel.setLayout(new java.awt.BorderLayout()); + + jPanel38.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + + jLabel16.setText("Key:"); + jPanel38.add(jLabel16); + + assertionDecryptionKeyTextField.setEditable(false); + assertionDecryptionKeyTextField.setColumns(30); + jPanel38.add(assertionDecryptionKeyTextField); + + selectAssertionDecryptionKeyButton.setText("Select key..."); + selectAssertionDecryptionKeyButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectAssertionDecryptionKeyButtonActionPerformed(evt); + } + }); + jPanel38.add(selectAssertionDecryptionKeyButton); + + decryptAssertionButton.setText("Decrypt Assertion"); + decryptAssertionButton.setEnabled(false); + decryptAssertionButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + decryptAssertionButtonActionPerformed(evt); + } + }); + jPanel38.add(decryptAssertionButton); + + encryptedAssertionPanel.add(jPanel38, java.awt.BorderLayout.PAGE_START); + + jTabbedPane4.addTab("XML", encryptedAssertionXMLPanel); + jTabbedPane4.addTab("Decrypted Assertion XML", decryptedAssertionXMLPanel); + jTabbedPane4.addTab("Decrypted Assertion", decryptedAssertionTextPanel); + + encryptedAssertionPanel.add(jTabbedPane4, java.awt.BorderLayout.CENTER); + + jTabbedPane1.addTab("Encrypted Assertion", encryptedAssertionPanel); + htmlFormPanel.setLayout(new java.awt.BorderLayout()); jPanel5.setLayout(new javax.swing.BoxLayout(jPanel5, javax.swing.BoxLayout.LINE_AXIS)); @@ -776,8 +875,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { jTabbedPane3.addTab("SAML Browser POST Profile Messages", jPanel8); - jPanel6.setBorder(null); - jPanel6.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + signatureAttacksPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); jPanel10.setLayout(new java.awt.GridBagLayout()); @@ -894,7 +992,7 @@ public void itemStateChanged(java.awt.event.ItemEvent evt) { jLabel21.setText("Key: "); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; + gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; jPanel28.add(jLabel21, gridBagConstraints); @@ -906,17 +1004,32 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 2; + gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); jPanel28.add(selectKeyButton, gridBagConstraints); - keyTextField.setColumns(20); keyTextField.setEditable(false); + keyTextField.setColumns(20); gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; jPanel28.add(keyTextField, gridBagConstraints); + signAssertionCheckBox.setText("Resign SAML assertion"); + signAssertionCheckBox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + signAssertionCheckBoxItemStateChanged(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; + jPanel28.add(signAssertionCheckBox, gridBagConstraints); + jPanel27.add(jPanel28); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -925,9 +1038,9 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; jPanel10.add(jPanel27, gridBagConstraints); - jPanel6.add(jPanel10); + signatureAttacksPanel.add(jPanel10); - jTabbedPane3.addTab("Signature Attacks", jPanel6); + jTabbedPane3.addTab("Signature Attacks", signatureAttacksPanel); jPanel30.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); @@ -1384,6 +1497,62 @@ public void itemStateChanged(java.awt.event.ItemEvent evt) { jTabbedPane3.addTab("Replay Attacks", jPanel21); + jPanel39.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + + jPanel40.setBorder(javax.swing.BorderFactory.createTitledBorder("SAML Assertion Decryption Attack")); + jPanel40.setLayout(new java.awt.GridBagLayout()); + + jPanel41.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + + jPanel42.setLayout(new java.awt.GridBagLayout()); + + decryptAssertionCheckBox.setText("Decrypt encrypted assertion"); + decryptAssertionCheckBox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + decryptAssertionCheckBoxItemStateChanged(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; + jPanel42.add(decryptAssertionCheckBox, gridBagConstraints); + + jLabel24.setText("Key:"); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5); + jPanel42.add(jLabel24, gridBagConstraints); + + decryptionKeyTextField.setEditable(false); + decryptionKeyTextField.setColumns(20); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 1; + jPanel42.add(decryptionKeyTextField, gridBagConstraints); + + decryptionSelectKeyButton.setText("Select Key..."); + decryptionSelectKeyButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + decryptionSelectKeyButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; + gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0); + jPanel42.add(decryptionSelectKeyButton, gridBagConstraints); + + jPanel41.add(jPanel42); + + jPanel40.add(jPanel41, new java.awt.GridBagConstraints()); + + jPanel39.add(jPanel40); + + jTabbedPane3.addTab("Encryption Attacks", jPanel39); + jPanel1.add(jTabbedPane3, java.awt.BorderLayout.PAGE_START); jSplitPane1.setLeftComponent(jPanel1); @@ -1659,6 +1828,38 @@ private void lastAttributeRadioButtonItemStateChanged(java.awt.event.ItemEvent e } }//GEN-LAST:event_lastAttributeRadioButtonItemStateChanged + private void signAssertionCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_signAssertionCheckBoxItemStateChanged + SamlProxy samlProxy = this.saml.getSamlProxy(); + boolean signAssertionAttack = evt.getStateChange() == ItemEvent.SELECTED; + samlProxy.setSignAssertionAttack(signAssertionAttack); + }//GEN-LAST:event_signAssertionCheckBoxItemStateChanged + + private void selectAssertionDecryptionKeyButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectAssertionDecryptionKeyButtonActionPerformed + this.assertionCertificateManager.setVisible(true); + }//GEN-LAST:event_selectAssertionDecryptionKeyButtonActionPerformed + + private void decryptAssertionButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_decryptAssertionButtonActionPerformed + ConversationID id = (ConversationID) this.showConversationAction.getValue("CONVERSATION"); + try { + byte[] decryptedAssertion = this.samlModel.getDecryptedAssertion(id, + this.assertionCertificateRepository.getPrivateKey()); + this.decryptedAssertionXMLPanel.setBytes("text/xml", decryptedAssertion); + this.decryptedAssertionTextPanel.setText(null, new String(decryptedAssertion)); + } catch (Exception ex) { + this.decryptedAssertionXMLPanel.setBytes("text/xml", ("" + ex.getMessage() + "").getBytes()); + } + }//GEN-LAST:event_decryptAssertionButtonActionPerformed + + private void decryptionSelectKeyButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_decryptionSelectKeyButtonActionPerformed + this.decryptionCertificateManager.setVisible(true); + }//GEN-LAST:event_decryptionSelectKeyButtonActionPerformed + + private void decryptAssertionCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_decryptAssertionCheckBoxItemStateChanged + SamlProxy samlProxy = this.saml.getSamlProxy(); + boolean signAssertionAttack = evt.getStateChange() == ItemEvent.SELECTED; + samlProxy.setDecryptAssertionAttack(signAssertionAttack); + }//GEN-LAST:event_decryptAssertionCheckBoxItemStateChanged + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel aboutPanel; private javax.swing.JButton addInjectAttributeButton; @@ -1666,6 +1867,7 @@ private void lastAttributeRadioButtonItemStateChanged(java.awt.event.ItemEvent e private javax.swing.JRadioButton allSubjectRadioButton; private javax.swing.JPanel analysisDataPanel; private javax.swing.JPanel analysisPanel; + private javax.swing.JTextField assertionDecryptionKeyTextField; private javax.swing.JRadioButton assertionSignatureRadioButton; private javax.swing.JCheckBox assertionsDigestedCheckBox; private javax.swing.ButtonGroup attributeButtonGroup; @@ -1676,11 +1878,19 @@ private void lastAttributeRadioButtonItemStateChanged(java.awt.event.ItemEvent e private org.owasp.webscarab.ui.swing.editors.TextPanel certDetailTextPanel; private javax.swing.JTree certPathTree; private javax.swing.JCheckBox corruptSignatureCheckBox; + private javax.swing.JButton decryptAssertionButton; + private javax.swing.JCheckBox decryptAssertionCheckBox; private javax.swing.JButton decryptButton; + private org.owasp.webscarab.ui.swing.editors.TextPanel decryptedAssertionTextPanel; + private org.owasp.webscarab.ui.swing.editors.XMLPanel decryptedAssertionXMLPanel; + private javax.swing.JTextField decryptionKeyTextField; + private javax.swing.JButton decryptionSelectKeyButton; private javax.swing.JCheckBox destinationIndicationCheckBox; private javax.swing.JRadioButton dsObjectWrapperRadioButton; private javax.swing.JTextField dtdUriTextField; private javax.swing.JRadioButton duplicateAssertionRadioButton; + private javax.swing.JPanel encryptedAssertionPanel; + private org.owasp.webscarab.ui.swing.editors.XMLPanel encryptedAssertionXMLPanel; private javax.swing.JPanel encryptedAttributesPanel; private javax.swing.JTable encryptedAttributesTable; private javax.swing.JRadioButton firstAttributeRadioButton; @@ -1705,6 +1915,7 @@ private void lastAttributeRadioButtonItemStateChanged(java.awt.event.ItemEvent e private javax.swing.JLabel jLabel13; private javax.swing.JLabel jLabel14; private javax.swing.JLabel jLabel15; + private javax.swing.JLabel jLabel16; private javax.swing.JLabel jLabel17; private javax.swing.JLabel jLabel18; private javax.swing.JLabel jLabel19; @@ -1713,6 +1924,7 @@ private void lastAttributeRadioButtonItemStateChanged(java.awt.event.ItemEvent e private javax.swing.JLabel jLabel21; private javax.swing.JLabel jLabel22; private javax.swing.JLabel jLabel23; + private javax.swing.JLabel jLabel24; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; private javax.swing.JLabel jLabel5; @@ -1751,9 +1963,13 @@ private void lastAttributeRadioButtonItemStateChanged(java.awt.event.ItemEvent e private javax.swing.JPanel jPanel35; private javax.swing.JPanel jPanel36; private javax.swing.JPanel jPanel37; + private javax.swing.JPanel jPanel38; + private javax.swing.JPanel jPanel39; private javax.swing.JPanel jPanel4; + private javax.swing.JPanel jPanel40; + private javax.swing.JPanel jPanel41; + private javax.swing.JPanel jPanel42; private javax.swing.JPanel jPanel5; - private javax.swing.JPanel jPanel6; private javax.swing.JPanel jPanel7; private javax.swing.JPanel jPanel8; private javax.swing.JPanel jPanel9; @@ -1767,6 +1983,7 @@ private void lastAttributeRadioButtonItemStateChanged(java.awt.event.ItemEvent e private javax.swing.JTabbedPane jTabbedPane1; private javax.swing.JTabbedPane jTabbedPane2; private javax.swing.JTabbedPane jTabbedPane3; + private javax.swing.JTabbedPane jTabbedPane4; private javax.swing.JTextField keyTextField; private javax.swing.JRadioButton lastAttributeRadioButton; private javax.swing.JRadioButton lastSubjectRadioButton; @@ -1786,9 +2003,12 @@ private void lastAttributeRadioButtonItemStateChanged(java.awt.event.ItemEvent e private javax.swing.JTable samlTable; private javax.swing.JLabel samlVersionLabel; private javax.swing.JRadioButton samlpExtWrapperRadioButton; + private javax.swing.JButton selectAssertionDecryptionKeyButton; private javax.swing.JButton selectKeyButton; + private javax.swing.JCheckBox signAssertionCheckBox; private javax.swing.JCheckBox signCheckBox; private javax.swing.JCheckBox signWrapAttackCheckBox; + private javax.swing.JPanel signatureAttacksPanel; private javax.swing.ButtonGroup signatureButtonGroup; private javax.swing.JPanel signaturePanel; private javax.swing.JLabel signatureValidityLabel; diff --git a/src/org/owasp/webscarab/ui/swing/CertificateManager.form b/src/org/owasp/webscarab/ui/swing/CertificateManager.form index fbaab27a..3889bf5a 100644 --- a/src/org/owasp/webscarab/ui/swing/CertificateManager.form +++ b/src/org/owasp/webscarab/ui/swing/CertificateManager.form @@ -1,4 +1,4 @@ - +
@@ -141,23 +141,6 @@ - - - - - - - - - - - - - - - - - diff --git a/src/org/owasp/webscarab/ui/swing/CertificateManager.java b/src/org/owasp/webscarab/ui/swing/CertificateManager.java index 4a7ef5b1..c59af31b 100644 --- a/src/org/owasp/webscarab/ui/swing/CertificateManager.java +++ b/src/org/owasp/webscarab/ui/swing/CertificateManager.java @@ -19,6 +19,7 @@ import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.FileFilter; import javax.swing.table.AbstractTableModel; +import org.apache.commons.io.FilenameUtils; import org.owasp.webscarab.httpclient.CertificateRepository; import org.owasp.webscarab.httpclient.HTTPClientFactory; @@ -130,8 +131,6 @@ private void initComponents() { jLabel6 = new javax.swing.JLabel(); pkcs11LibraryTextField = new javax.swing.JTextField(); pkcs11BrowseButton = new javax.swing.JButton(); - jLabel7 = new javax.swing.JLabel(); - pkcs11PasswordField = new javax.swing.JPasswordField(); jLabel10 = new javax.swing.JLabel(); pkcs11SlotListIndexSpinner = new javax.swing.JSpinner(); buttonPanel = new javax.swing.JPanel(); @@ -234,20 +233,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 4); pkcs11Panel.add(pkcs11BrowseButton, gridBagConstraints); - jLabel7.setText("Password"); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 3; - gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; - gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 4); - pkcs11Panel.add(jLabel7, gridBagConstraints); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.weightx = 1.0; - pkcs11Panel.add(pkcs11PasswordField, gridBagConstraints); - jLabel10.setText("Slot List Index"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; @@ -392,8 +377,8 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; getContentPane().add(currentCertTextField, gridBagConstraints); - java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); - setBounds((screenSize.width-600)/2, (screenSize.height-400)/2, 600, 400); + setSize(new java.awt.Dimension(600, 400)); + setLocationRelativeTo(null); }// //GEN-END:initComponents private void setButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_setButtonActionPerformed @@ -401,15 +386,18 @@ private void setButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIR int alias = aliasTable.getSelectedRow(); String fingerprint = ""; if (ks > -1 && alias>-1) { + String password; if (!_certRepo.isKeyUnlocked(ks, alias)) { - String password = getPassword(); - try { + password = getPassword(); + } else { + password = null; + } + try { _certRepo.unlockKey(ks, alias, password); } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, new String[] {"Error accessing key store: ", e.toString()}, "Error", JOptionPane.ERROR_MESSAGE); } - } Certificate cert = _certRepo.getCertificate(ks, alias); try { fingerprint = _certRepo.getFingerPrint(cert); @@ -469,14 +457,17 @@ private void keystoreOkButtonActionPerformed(java.awt.event.ActionEvent evt) {// int ksIndex = _certRepo.loadPKCS12Certificate(file, kspass); _keystoreListModel.insertElementAt(_certRepo.getKeyStoreDescription(ksIndex), ksIndex); } else if (tab == 1) { //PKCS#11 - String name = pkcs11NameTextField.getText(); - if (name.equals("")) return; String library = pkcs11LibraryTextField.getText(); if (library.equals("")) return; - String kspass = new String(pkcs11PasswordField.getPassword()); - if (kspass.equals("")) kspass = null; + String name = pkcs11NameTextField.getText(); + if (name.equals("")) { + name = FilenameUtils.getBaseName(library); + } int slotListIndex = Integer.parseInt(pkcs11SlotListIndexSpinner.getValue().toString()); - int ksIndex = _certRepo.initPKCS11(name, library, slotListIndex, kspass); + int ksIndex = _certRepo.initPKCS11(name, library, slotListIndex); + if (ksIndex == -1) { + throw new RuntimeException("No PKCS11 token available."); + } _keystoreListModel.insertElementAt(_certRepo.getKeyStoreDescription(ksIndex), ksIndex); } } catch (Exception e) { @@ -532,7 +523,6 @@ public void run() { private javax.swing.JLabel jLabel4; private javax.swing.JLabel jLabel5; private javax.swing.JLabel jLabel6; - private javax.swing.JLabel jLabel7; private javax.swing.JLabel jLabel8; private javax.swing.JLabel jLabel9; private javax.swing.JPanel jPanel1; @@ -547,7 +537,6 @@ public void run() { private javax.swing.JTextField pkcs11LibraryTextField; private javax.swing.JTextField pkcs11NameTextField; private javax.swing.JPanel pkcs11Panel; - private javax.swing.JPasswordField pkcs11PasswordField; private javax.swing.JSpinner pkcs11SlotListIndexSpinner; private javax.swing.JButton pkcs12BrowseButton; private javax.swing.JTextField pkcs12FileTextField; diff --git a/src/org/owasp/webscarab/ui/swing/Lite.java b/src/org/owasp/webscarab/ui/swing/Lite.java index 976c7d7a..aad46c48 100644 --- a/src/org/owasp/webscarab/ui/swing/Lite.java +++ b/src/org/owasp/webscarab/ui/swing/Lite.java @@ -605,7 +605,7 @@ public void finished() { }.start(); } - private void createTemporarySession() { + public void createTemporarySession() { _tempDir = TempDir.createTempDir("webscarab", ".tmp", null); if (_tempDir != null) { loadSession(_tempDir); diff --git a/src/org/owasp/webscarab/ui/swing/PasswordCallbackHandler.java b/src/org/owasp/webscarab/ui/swing/PasswordCallbackHandler.java new file mode 100644 index 00000000..76f79635 --- /dev/null +++ b/src/org/owasp/webscarab/ui/swing/PasswordCallbackHandler.java @@ -0,0 +1,34 @@ +package org.owasp.webscarab.ui.swing; + +import java.io.IOException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.swing.JOptionPane; +import javax.swing.JPasswordField; + +/** + * Swing based password callback handler. + * + * @author Frank Cornelis + */ +public class PasswordCallbackHandler implements CallbackHandler { + + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (Callback callback : callbacks) { + if (callback instanceof PasswordCallback) { + PasswordCallback passwordCallback = (PasswordCallback) callback; + JPasswordField passwordField = new JPasswordField(20); + int result = JOptionPane.showConfirmDialog(null, passwordField, "Enter password", JOptionPane.OK_CANCEL_OPTION); + if (result == JOptionPane.OK_OPTION) { + char[] password = passwordField.getPassword(); + passwordCallback.setPassword(password); + } else { + passwordCallback.clearPassword(); + } + } + } + } +} diff --git a/src/org/owasp/webscarab/ui/swing/UIFramework.java b/src/org/owasp/webscarab/ui/swing/UIFramework.java index 06111d70..5fd2b02e 100644 --- a/src/org/owasp/webscarab/ui/swing/UIFramework.java +++ b/src/org/owasp/webscarab/ui/swing/UIFramework.java @@ -173,7 +173,6 @@ public void actionPerformed(ActionEvent evt) { } public void run() { - createTemporarySession(); synchronized(_exit) { try { _exit.wait(); @@ -697,7 +696,7 @@ public void finished() { }.start(); } - private void createTemporarySession() { + public void createTemporarySession() { _tempDir = TempDir.createTempDir("webscarab", ".tmp", null); if (_tempDir != null) { loadSession(_tempDir); diff --git a/src/org/owasp/webscarab/ui/swing/WebScarabUI.java b/src/org/owasp/webscarab/ui/swing/WebScarabUI.java index 14fc17a9..f7854f0f 100644 --- a/src/org/owasp/webscarab/ui/swing/WebScarabUI.java +++ b/src/org/owasp/webscarab/ui/swing/WebScarabUI.java @@ -11,5 +11,7 @@ public interface WebScarabUI extends Runnable { public void addPlugin(final SwingPluginUI plugin); public void loadSession(File session); + + public void createTemporarySession(); } diff --git a/test/java/test/unit/org/owasp/webscarab/plugin/saml/SamlTest.java b/test/java/test/unit/org/owasp/webscarab/plugin/saml/SamlTest.java index e0be43a1..9ef0edac 100644 --- a/test/java/test/unit/org/owasp/webscarab/plugin/saml/SamlTest.java +++ b/test/java/test/unit/org/owasp/webscarab/plugin/saml/SamlTest.java @@ -1,27 +1,29 @@ -/*********************************************************************** +/** + * ********************************************************************* * - * This file is part of WebScarab, an Open Web Application Security - * Project utility. For details, please see http://www.owasp.org/ + * This file is part of WebScarab, an Open Web Application Security Project + * utility. For details, please see http://www.owasp.org/ * * Copyright (c) 2011 Frank Cornelis * - * 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 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. + * 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. + * 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. * */ package test.unit.org.owasp.webscarab.plugin.saml; +import java.io.ByteArrayInputStream; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; @@ -29,6 +31,13 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.Result; import java.io.StringWriter; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.Key; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.RSAKeyGenParameterSpec; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.Source; import org.apache.xml.security.Init; @@ -44,7 +53,10 @@ import javax.crypto.KeyGenerator; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; +import org.apache.xml.security.encryption.EncryptedData; +import org.apache.xml.security.encryption.EncryptedKey; import org.apache.xml.security.encryption.XMLCipher; +import org.apache.xml.security.keys.KeyInfo; import org.bouncycastle.util.encoders.Hex; import org.junit.BeforeClass; import org.junit.Test; @@ -115,6 +127,49 @@ public void testEncryptedXML() throws Exception { assertEquals(1, attributeNodeList.getLength()); } + @Test + public void testKeyEncryptionKey() throws Exception { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document document = documentBuilder.newDocument(); + Element rootElement = document.createElement("hello-world"); + document.appendChild(rootElement); + rootElement.appendChild(document.createTextNode("hello world")); + + LOG.debug("original document: " + toString(document)); + + KeyPair keyPair = generateKeyPair(); + KeyGenerator keygen = KeyGenerator.getInstance("AES"); + keygen.init(128); + Key key = keygen.generateKey(); + // encrypt + XMLCipher xmlCipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5); + xmlCipher.init(XMLCipher.WRAP_MODE, keyPair.getPublic()); + EncryptedKey encryptedKey = xmlCipher.encryptKey(document, key); + + xmlCipher = XMLCipher.getInstance(XMLCipher.AES_128); + xmlCipher.init(XMLCipher.ENCRYPT_MODE, key); + EncryptedData encryptedData = xmlCipher.getEncryptedData(); + KeyInfo keyInfo = new KeyInfo(document); + encryptedData.setKeyInfo(keyInfo); + keyInfo.add(encryptedKey); + document = xmlCipher.doFinal(document, rootElement); + + LOG.debug("encrypted document: " + toString(document)); + + document = documentBuilder.parse(new ByteArrayInputStream(toString(document).getBytes())); + + Element encryptedDataElement = (Element) document.getElementsByTagName("xenc:EncryptedData").item(0); + xmlCipher = XMLCipher.getInstance(XMLCipher.AES_128); + xmlCipher.init(XMLCipher.DECRYPT_MODE, null); + xmlCipher.setKEK(keyPair.getPrivate()); + document = xmlCipher.doFinal(document, encryptedDataElement); + + // decrypt + LOG.debug("decrypted document: " + toString(document)); + } + private String toString(Node node) throws TransformerConfigurationException, TransformerException { Source source = new DOMSource(node); StringWriter stringWriter = new StringWriter(); @@ -124,4 +179,18 @@ private String toString(Node node) throws TransformerConfigurationException, Tra transformer.transform(source, result); return stringWriter.getBuffer().toString(); } + + private KeyPair generateKeyPair(int size) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + SecureRandom random = new SecureRandom(); + keyPairGenerator.initialize(new RSAKeyGenParameterSpec(size, + RSAKeyGenParameterSpec.F4), random); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + return keyPair; + } + + private KeyPair generateKeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + KeyPair keyPair = generateKeyPair(1024); + return keyPair; + } }