You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by co...@apache.org on 2017/01/31 13:37:51 UTC

svn commit: r1781081 - /webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/Encryptor.java

Author: coheigea
Date: Tue Jan 31 13:37:51 2017
New Revision: 1781081

URL: http://svn.apache.org/viewvc?rev=1781081&view=rev
Log:
Adding missing file

Added:
    webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/Encryptor.java

Added: webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/Encryptor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/Encryptor.java?rev=1781081&view=auto
==============================================================================
--- webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/Encryptor.java (added)
+++ webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/Encryptor.java Tue Jan 31 13:37:51 2017
@@ -0,0 +1,500 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.wss4j.dom.message;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.SecretKey;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.wss4j.common.WSEncryptionPart;
+import org.apache.wss4j.common.ext.Attachment;
+import org.apache.wss4j.common.ext.AttachmentRequestCallback;
+import org.apache.wss4j.common.ext.AttachmentResultCallback;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.util.AttachmentUtils;
+import org.apache.wss4j.common.util.XMLUtils;
+import org.apache.wss4j.dom.WSConstants;
+import org.apache.wss4j.dom.WsuIdAllocator;
+import org.apache.wss4j.dom.callback.CallbackLookup;
+import org.apache.wss4j.dom.callback.DOMCallbackLookup;
+import org.apache.wss4j.dom.util.WSSecurityUtil;
+import org.apache.xml.security.algorithms.JCEMapper;
+import org.apache.xml.security.c14n.Canonicalizer;
+import org.apache.xml.security.encryption.AbstractSerializer;
+import org.apache.xml.security.encryption.EncryptedData;
+import org.apache.xml.security.encryption.Serializer;
+import org.apache.xml.security.encryption.TransformSerializer;
+import org.apache.xml.security.encryption.XMLCipher;
+import org.apache.xml.security.encryption.XMLCipherUtil;
+import org.apache.xml.security.encryption.XMLEncryptionException;
+import org.apache.xml.security.keys.KeyInfo;
+import org.apache.xml.security.stax.ext.XMLSecurityConstants;
+import org.apache.xml.security.utils.EncryptionConstants;
+import org.w3c.dom.Attr;
+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;
+
+/**
+ * A class to encrypt references.
+ */
+public class Encryptor {
+    
+    private Document doc;
+    private WSSecHeader securityHeader;
+    private WsuIdAllocator idAllocator;
+    private CallbackLookup callbackLookup;
+    private CallbackHandler attachmentCallbackHandler;
+    private boolean storeBytesInAttachment;
+    private Serializer encryptionSerializer;
+
+    public List<String> doEncryption(
+        KeyInfo keyInfo,
+        SecretKey secretKey,
+        String encryptionAlgorithm,
+        List<WSEncryptionPart> references,
+        List<Element> attachmentEncryptedDataElements
+    ) throws WSSecurityException {
+
+        XMLCipher xmlCipher = null;
+        try {
+            xmlCipher = XMLCipher.getInstance(encryptionAlgorithm);
+        } catch (XMLEncryptionException ex) {
+            throw new WSSecurityException(
+                WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, ex
+            );
+        }
+        if (encryptionSerializer != null) {
+            xmlCipher.setSerializer(encryptionSerializer);
+        }
+
+        List<String> encDataRef = new ArrayList<>();
+        WSEncryptionPart attachmentEncryptionPart = null;
+        for (int part = 0; part < references.size(); part++) {
+            WSEncryptionPart encPart = references.get(part);
+
+            if (encPart.getId() != null && encPart.getId().startsWith("cid:")) {
+                attachmentEncryptionPart = encPart;
+                continue;
+            }
+
+            //
+            // Get the data to encrypt.
+            //
+            if (callbackLookup == null) {
+                callbackLookup = new DOMCallbackLookup(doc);
+            }
+            List<Element> elementsToEncrypt =
+                WSSecurityUtil.findElements(encPart, callbackLookup, doc);
+            if (elementsToEncrypt == null || elementsToEncrypt.size() == 0) {
+                if (!encPart.isRequired()) {
+                    continue;
+                }
+                throw new WSSecurityException(
+                    WSSecurityException.ErrorCode.FAILURE,
+                    "noEncElement",
+                    new Object[] {"{" + encPart.getNamespace() + "}" + encPart.getName()});
+            }
+
+            if (storeBytesInAttachment) {
+                for (Element elementToEncrypt : elementsToEncrypt) {
+                    try {
+                        String id =
+                            encryptElementInAttachment(keyInfo, secretKey, encryptionAlgorithm, encPart, elementToEncrypt);
+                        encPart.setEncId(id);
+                        encDataRef.add("#" + id);
+                    } catch (Exception ex) {
+                        throw new WSSecurityException(
+                            WSSecurityException.ErrorCode.FAILED_ENCRYPTION, ex
+                        );
+                    }
+                }
+            } else {
+                for (Element elementToEncrypt : elementsToEncrypt) {
+                    String id =
+                        encryptElement(elementToEncrypt, encPart.getEncModifier(), xmlCipher, secretKey, keyInfo);
+                    encPart.setEncId(id);
+                    encDataRef.add("#" + id);
+                }
+            }
+        }
+
+        if (attachmentEncryptionPart != null) {
+            encryptAttachment(keyInfo, secretKey, encryptionAlgorithm, attachmentEncryptionPart, encDataRef,
+                              attachmentEncryptedDataElements);
+        }
+
+        return encDataRef;
+    }
+
+    private String encryptElementInAttachment(
+        KeyInfo keyInfo,
+        SecretKey secretKey,
+        String encryptionAlgorithm,
+        WSEncryptionPart encryptionPart,
+        Element elementToEncrypt
+   ) throws Exception {
+
+        String type = EncryptionConstants.TYPE_ELEMENT;
+        if ("Content".equals(encryptionPart.getEncModifier())) {
+            type = EncryptionConstants.TYPE_CONTENT;
+        }
+
+        final String attachmentId = idAllocator.createId("", doc);
+        String encEncryptedDataId = idAllocator.createId("ED-", attachmentId);
+
+        if ("Header".equals(encryptionPart.getEncModifier())
+            && elementToEncrypt.getParentNode().equals(WSSecurityUtil.getSOAPHeader(doc))) {
+            createEncryptedHeaderElement(doc, securityHeader, elementToEncrypt, idAllocator);
+        }
+
+        Element encryptedData =
+            doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":EncryptedData");
+        encryptedData.setAttributeNS(null, "Id", encEncryptedDataId);
+        encryptedData.setAttributeNS(null, "Type", type);
+
+        Element encryptionMethod =
+            doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":EncryptionMethod");
+        encryptionMethod.setAttributeNS(null, "Algorithm", encryptionAlgorithm);
+
+        encryptedData.appendChild(encryptionMethod);
+        encryptedData.appendChild(keyInfo.getElement().cloneNode(true));
+
+        Element cipherData =
+            doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":CipherData");
+        Element cipherValue =
+            doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":CipherValue");
+        cipherData.appendChild(cipherValue);
+        encryptedData.appendChild(cipherData);
+
+        Cipher cipher = createCipher(encryptionAlgorithm, secretKey);
+
+        // Serialize and encrypt the element
+        AbstractSerializer serializer = new TransformSerializer();
+        serializer.setCanonicalizer(Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_PHYSICAL));
+        serializer.setSecureValidation(true);
+
+        byte[] serializedOctets = null;
+        if (type.equals(EncryptionConstants.TYPE_CONTENT)) {
+            NodeList children = elementToEncrypt.getChildNodes();
+            if (null != children) {
+                serializedOctets = serializer.serializeToByteArray(children);
+            } else {
+                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_ENCRYPTION, 
+                                              "Element has no content.");
+            }
+        } else {
+            serializedOctets = serializer.serializeToByteArray(elementToEncrypt);
+        }
+
+        byte[] encryptedBytes = null;
+        try {
+            encryptedBytes = cipher.doFinal(serializedOctets);
+        } catch (IllegalBlockSizeException ibse) {
+            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_ENCRYPTION, ibse);
+        } catch (BadPaddingException bpe) {
+            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_ENCRYPTION, bpe);
+        }
+
+        // Now build up to a properly XML Encryption encoded octet stream
+        byte[] iv = cipher.getIV();
+        byte[] finalEncryptedBytes = new byte[iv.length + encryptedBytes.length];
+        System.arraycopy(iv, 0, finalEncryptedBytes, 0, iv.length);
+        System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, iv.length, encryptedBytes.length);
+
+        if ("Content".equals(encryptionPart.getEncModifier())) {
+            Node child = elementToEncrypt.getFirstChild();
+            while (child != null) {
+                Node sibling = child.getNextSibling();
+                elementToEncrypt.removeChild(child);
+                child = sibling;
+            }
+            elementToEncrypt.appendChild(encryptedData);
+        } else {
+            elementToEncrypt.getParentNode().replaceChild(encryptedData, elementToEncrypt);
+        }
+
+        WSSecurityUtil.storeBytesInAttachment(cipherValue, doc, attachmentId,
+                                              finalEncryptedBytes, attachmentCallbackHandler);
+
+        return encEncryptedDataId;
+    }
+
+    private void encryptAttachment(
+        KeyInfo keyInfo,
+        SecretKey secretKey,
+        String encryptionAlgorithm,
+        WSEncryptionPart attachmentEncryptionPart,
+        List<String> encDataRef,
+        List<Element> attachmentEncryptedDataElements
+    ) throws WSSecurityException {
+        if (attachmentCallbackHandler == null) {
+            throw new WSSecurityException(
+                WSSecurityException.ErrorCode.FAILURE,
+                "empty", new Object[] {"no attachment callbackhandler supplied"}
+            );
+        }
+
+        AttachmentRequestCallback attachmentRequestCallback = new AttachmentRequestCallback();
+        String id = attachmentEncryptionPart.getId().substring(4);
+        attachmentRequestCallback.setAttachmentId(id);
+        try {
+            attachmentCallbackHandler.handle(new Callback[]{attachmentRequestCallback});
+        } catch (Exception e) {
+            throw new WSSecurityException(
+                WSSecurityException.ErrorCode.FAILED_ENCRYPTION, e
+            );
+        }
+        String attachmentEncryptedDataType = WSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_CONTENT_ONLY;
+        if ("Element".equals(attachmentEncryptionPart.getEncModifier())) {
+            attachmentEncryptedDataType = WSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_COMPLETE;
+        }
+
+        for (Attachment attachment : attachmentRequestCallback.getAttachments()) {
+
+            final String attachmentId = attachment.getId();
+            String encEncryptedDataId = idAllocator.createId("ED-", attachmentId);
+            encDataRef.add("#" + encEncryptedDataId);
+
+            Element encryptedData =
+                doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":EncryptedData");
+            encryptedData.setAttributeNS(null, "Id", encEncryptedDataId);
+            encryptedData.setAttributeNS(null, "MimeType", attachment.getMimeType());
+            encryptedData.setAttributeNS(null, "Type", attachmentEncryptedDataType);
+
+            Element encryptionMethod =
+                doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":EncryptionMethod");
+            encryptionMethod.setAttributeNS(null, "Algorithm", encryptionAlgorithm);
+
+            encryptedData.appendChild(encryptionMethod);
+            encryptedData.appendChild(keyInfo.getElement().cloneNode(true));
+
+            Element cipherData =
+                doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":CipherData");
+            Element cipherReference =
+                doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":CipherReference");
+            cipherReference.setAttributeNS(null, "URI", "cid:" + attachmentId);
+
+            Element transforms = doc.createElementNS(WSConstants.ENC_NS, WSConstants.ENC_PREFIX + ":Transforms");
+            Element transform = doc.createElementNS(WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":Transform");
+            transform.setAttributeNS(null, "Algorithm", WSConstants.SWA_ATTACHMENT_CIPHERTEXT_TRANS);
+            transforms.appendChild(transform);
+
+            cipherReference.appendChild(transforms);
+            cipherData.appendChild(cipherReference);
+            encryptedData.appendChild(cipherData);
+
+            attachmentEncryptedDataElements.add(encryptedData);
+
+            Attachment resultAttachment = new Attachment();
+            resultAttachment.setId(attachmentId);
+            resultAttachment.setMimeType("application/octet-stream");
+
+            Cipher cipher = createCipher(encryptionAlgorithm, secretKey);
+
+            Map<String, String> headers = new HashMap<>(attachment.getHeaders());
+            resultAttachment.setSourceStream(
+                AttachmentUtils.setupAttachmentEncryptionStream(
+                    cipher, "Element".equals(attachmentEncryptionPart.getEncModifier()),
+                    attachment, headers
+                )
+            );
+            resultAttachment.addHeaders(headers);
+
+            AttachmentResultCallback attachmentResultCallback = new AttachmentResultCallback();
+            attachmentResultCallback.setAttachmentId(attachmentId);
+            attachmentResultCallback.setAttachment(resultAttachment);
+            try {
+                attachmentCallbackHandler.handle(new Callback[]{attachmentResultCallback});
+            } catch (Exception e) {
+                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_ENCRYPTION, e);
+            }
+        }
+    }
+
+    private Cipher createCipher(String encryptionAlgorithm, SecretKey secretKey)
+        throws WSSecurityException {
+        String jceAlgorithm = JCEMapper.translateURItoJCEID(encryptionAlgorithm);
+        try {
+            Cipher cipher = Cipher.getInstance(jceAlgorithm);
+            
+            int ivLen = JCEMapper.getIVLengthFromURI(encryptionAlgorithm) / 8;
+            byte[] iv = XMLSecurityConstants.generateBytes(ivLen);
+            AlgorithmParameterSpec paramSpec = 
+                XMLCipherUtil.constructBlockCipherParameters(encryptionAlgorithm, iv, Encryptor.class);
+            cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
+
+            return cipher;
+        } catch (Exception e) {
+            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_ENCRYPTION, e);
+        }
+    }
+
+    /**
+     * Encrypt an element.
+     */
+    private String encryptElement(
+        Element elementToEncrypt,
+        String modifier,
+        XMLCipher xmlCipher,
+        SecretKey secretKey,
+        KeyInfo keyInfo
+    ) throws WSSecurityException {
+
+        boolean content = "Content".equals(modifier);
+        //
+        // Encrypt data, and set necessary attributes in xenc:EncryptedData
+        //
+        String xencEncryptedDataId = idAllocator.createId("ED-", elementToEncrypt);
+        try {
+            if ("Header".equals(modifier)
+                && elementToEncrypt.getParentNode().equals(WSSecurityUtil.getSOAPHeader(doc))) {
+                createEncryptedHeaderElement(doc, securityHeader, elementToEncrypt, idAllocator);
+            }
+
+            xmlCipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
+            EncryptedData encData = xmlCipher.getEncryptedData();
+            encData.setId(xencEncryptedDataId);
+            encData.setKeyInfo(keyInfo);
+            xmlCipher.doFinal(doc, elementToEncrypt, content);
+            return xencEncryptedDataId;
+        } catch (Exception ex) {
+            throw new WSSecurityException(
+                WSSecurityException.ErrorCode.FAILED_ENCRYPTION, ex
+            );
+        }
+    }
+
+    private static void createEncryptedHeaderElement(
+        Document doc,
+        WSSecHeader securityHeader,
+        Element elementToEncrypt,
+        WsuIdAllocator idAllocator
+    ) {
+        Element elem =
+            doc.createElementNS(
+                WSConstants.WSSE11_NS, "wsse11:" + WSConstants.ENCRYPTED_HEADER
+            );
+        XMLUtils.setNamespace(elem, WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX);
+        String wsuPrefix =
+            XMLUtils.setNamespace(elem, WSConstants.WSU_NS, WSConstants.WSU_PREFIX);
+        String headerId = idAllocator.createId("EH-", elementToEncrypt);
+        elem.setAttributeNS(
+            WSConstants.WSU_NS, wsuPrefix + ":Id", headerId
+        );
+
+        //
+        // Add the EncryptedHeader node to the element to be encrypted's parent
+        // (i.e. the SOAP header). Add the element to be encrypted to the Encrypted
+        // Header node as well
+        //
+        Node parent = elementToEncrypt.getParentNode();
+        elementToEncrypt = (Element)parent.replaceChild(elem, elementToEncrypt);
+        elem.appendChild(elementToEncrypt);
+
+        if (securityHeader != null) {
+            NamedNodeMap map = securityHeader.getSecurityHeaderElement().getAttributes();
+            for (int i = 0; i < map.getLength(); i++) {
+                Attr attr = (Attr)map.item(i);
+                if (WSConstants.URI_SOAP11_ENV.equals(attr.getNamespaceURI())
+                    || WSConstants.URI_SOAP12_ENV.equals(attr.getNamespaceURI())) {
+                    String soapEnvPrefix =
+                        XMLUtils.setNamespace(
+                            elem, attr.getNamespaceURI(), WSConstants.DEFAULT_SOAP_PREFIX
+                        );
+                    elem.setAttributeNS(
+                        attr.getNamespaceURI(),
+                        soapEnvPrefix + ":" + attr.getLocalName(),
+                        attr.getValue()
+                    );
+                }
+            }
+        }
+
+    }
+
+    public Document getDoc() {
+        return doc;
+    }
+
+    public void setDoc(Document doc) {
+        this.doc = doc;
+    }
+
+    public WSSecHeader getSecurityHeader() {
+        return securityHeader;
+    }
+
+    public void setSecurityHeader(WSSecHeader securityHeader) {
+        this.securityHeader = securityHeader;
+    }
+
+    public WsuIdAllocator getIdAllocator() {
+        return idAllocator;
+    }
+
+    public void setIdAllocator(WsuIdAllocator idAllocator) {
+        this.idAllocator = idAllocator;
+    }
+
+    public CallbackLookup getCallbackLookup() {
+        return callbackLookup;
+    }
+
+    public void setCallbackLookup(CallbackLookup callbackLookup) {
+        this.callbackLookup = callbackLookup;
+    }
+
+    public CallbackHandler getAttachmentCallbackHandler() {
+        return attachmentCallbackHandler;
+    }
+
+    public void setAttachmentCallbackHandler(CallbackHandler attachmentCallbackHandler) {
+        this.attachmentCallbackHandler = attachmentCallbackHandler;
+    }
+
+    public boolean isStoreBytesInAttachment() {
+        return storeBytesInAttachment;
+    }
+
+    public void setStoreBytesInAttachment(boolean storeBytesInAttachment) {
+        this.storeBytesInAttachment = storeBytesInAttachment;
+    }
+
+    public Serializer getEncryptionSerializer() {
+        return encryptionSerializer;
+    }
+
+    public void setEncryptionSerializer(Serializer encryptionSerializer) {
+        this.encryptionSerializer = encryptionSerializer;
+    }
+
+}