| /** |
| * 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.processor; |
| |
| import java.security.Principal; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import javax.crypto.SecretKey; |
| |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| |
| import org.apache.wss4j.common.bsp.BSPEnforcer; |
| import org.apache.wss4j.common.bsp.BSPRule; |
| import org.apache.wss4j.common.crypto.AlgorithmSuite; |
| import org.apache.wss4j.common.crypto.AlgorithmSuiteValidator; |
| import org.apache.wss4j.common.ext.WSSecurityException; |
| import org.apache.wss4j.common.principal.WSDerivedKeyTokenPrincipal; |
| import org.apache.wss4j.common.token.SecurityTokenReference; |
| import org.apache.wss4j.common.util.KeyUtils; |
| import org.apache.wss4j.common.util.XMLUtils; |
| import org.apache.wss4j.dom.WSConstants; |
| import org.apache.wss4j.dom.WSDataRef; |
| import org.apache.wss4j.dom.engine.WSSecurityEngineResult; |
| import org.apache.wss4j.dom.handler.RequestData; |
| import org.apache.wss4j.dom.str.STRParser; |
| import org.apache.wss4j.dom.str.STRParserParameters; |
| import org.apache.wss4j.dom.str.STRParserResult; |
| import org.apache.wss4j.dom.str.SecurityTokenRefSTRParser; |
| import org.apache.wss4j.dom.util.EncryptionUtils; |
| import org.apache.wss4j.dom.util.SignatureUtils; |
| import org.apache.wss4j.dom.util.X509Util; |
| |
| public class ReferenceListProcessor implements Processor { |
| private static final org.slf4j.Logger LOG = |
| org.slf4j.LoggerFactory.getLogger(ReferenceListProcessor.class); |
| |
| public List<WSSecurityEngineResult> handleToken( |
| Element elem, |
| RequestData data |
| ) throws WSSecurityException { |
| LOG.debug("Found reference list element"); |
| List<WSDataRef> dataRefs = handleReferenceList(elem, data); |
| WSSecurityEngineResult result = |
| new WSSecurityEngineResult(WSConstants.ENCR, dataRefs); |
| String tokenId = elem.getAttributeNS(null, "Id"); |
| if (!"".equals(tokenId)) { |
| result.put(WSSecurityEngineResult.TAG_ID, tokenId); |
| } |
| data.getWsDocInfo().addTokenElement(elem); |
| data.getWsDocInfo().addResult(result); |
| return Collections.singletonList(result); |
| } |
| |
| /** |
| * Dereferences and decodes encrypted data elements. |
| * |
| * @param elem contains the <code>ReferenceList</code> to the encrypted |
| * data elements |
| */ |
| private List<WSDataRef> handleReferenceList( |
| Element elem, |
| RequestData data |
| ) throws WSSecurityException { |
| List<WSDataRef> dataRefs = new ArrayList<>(); |
| for (Node node = elem.getFirstChild(); |
| node != null; |
| node = node.getNextSibling() |
| ) { |
| if (Node.ELEMENT_NODE == node.getNodeType() |
| && WSConstants.ENC_NS.equals(node.getNamespaceURI()) |
| && "DataReference".equals(node.getLocalName())) { |
| String dataRefURI = ((Element) node).getAttributeNS(null, "URI"); |
| dataRefURI = XMLUtils.getIDFromReference(dataRefURI); |
| |
| // See whether we have already processed the encrypted node |
| if (!data.getWsDocInfo().hasResult(WSConstants.ENCR, dataRefURI)) { |
| WSDataRef dataRef = |
| decryptDataRefEmbedded(elem.getOwnerDocument(), dataRefURI, data); |
| dataRefs.add(dataRef); |
| } |
| } |
| } |
| |
| return dataRefs; |
| } |
| |
| |
| /** |
| * Decrypt an (embedded) EncryptedData element referenced by dataRefURI. |
| */ |
| private WSDataRef decryptDataRefEmbedded( |
| Document doc, |
| String dataRefURI, |
| RequestData data |
| ) throws WSSecurityException { |
| LOG.debug("Found data reference: {}", dataRefURI); |
| // |
| // Find the encrypted data element referenced by dataRefURI |
| // |
| Element encryptedDataElement = |
| EncryptionUtils.findEncryptedDataElement(doc, data.getWsDocInfo(), dataRefURI); |
| |
| if (encryptedDataElement != null && data.isRequireSignedEncryptedDataElements()) { |
| List<WSSecurityEngineResult> signedResults = |
| data.getWsDocInfo().getResultsByTag(WSConstants.SIGN); |
| SignatureUtils.verifySignedElement(encryptedDataElement, signedResults); |
| } |
| // |
| // Prepare the SecretKey object to decrypt EncryptedData |
| // |
| String symEncAlgo = X509Util.getEncAlgo(encryptedDataElement); |
| Element keyInfoElement = |
| XMLUtils.getDirectChildElement( |
| encryptedDataElement, "KeyInfo", WSConstants.SIG_NS |
| ); |
| // KeyInfo cannot be null |
| if (keyInfoElement == null) { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "noKeyinfo"); |
| } |
| // Check BSP compliance |
| checkBSPCompliance(keyInfoElement, symEncAlgo, data.getBSPEnforcer()); |
| |
| // |
| // Try to get a security reference token, if none found try to get a |
| // shared key using a KeyName. |
| // |
| Element secRefToken = |
| XMLUtils.getDirectChildElement( |
| keyInfoElement, "SecurityTokenReference", WSConstants.WSSE_NS |
| ); |
| SecretKey symmetricKey = null; |
| Principal principal = null; |
| if (secRefToken == null) { |
| byte[] decryptedData = |
| X509Util.getSecretKey(keyInfoElement, symEncAlgo, data.getCallbackHandler(), null); |
| symmetricKey = KeyUtils.prepareSecretKey(symEncAlgo, decryptedData); |
| } else { |
| STRParserParameters parameters = new STRParserParameters(); |
| parameters.setData(data); |
| parameters.setStrElement(secRefToken); |
| if (symEncAlgo != null) { |
| parameters.setDerivationKeyLength(KeyUtils.getKeyLength(symEncAlgo)); |
| } |
| |
| STRParser strParser = new SecurityTokenRefSTRParser(); |
| STRParserResult parserResult = strParser.parseSecurityTokenReference(parameters); |
| byte[] secretKey = parserResult.getSecretKey(); |
| principal = parserResult.getPrincipal(); |
| symmetricKey = KeyUtils.prepareSecretKey(symEncAlgo, secretKey); |
| } |
| |
| // Check for compliance against the defined AlgorithmSuite |
| AlgorithmSuite algorithmSuite = data.getAlgorithmSuite(); |
| if (algorithmSuite != null) { |
| AlgorithmSuiteValidator algorithmSuiteValidator = new |
| AlgorithmSuiteValidator(algorithmSuite); |
| |
| if (principal instanceof WSDerivedKeyTokenPrincipal) { |
| algorithmSuiteValidator.checkDerivedKeyAlgorithm( |
| ((WSDerivedKeyTokenPrincipal)principal).getAlgorithm() |
| ); |
| algorithmSuiteValidator.checkEncryptionDerivedKeyLength( |
| ((WSDerivedKeyTokenPrincipal)principal).getLength() |
| ); |
| } |
| |
| algorithmSuiteValidator.checkSymmetricKeyLength(symmetricKey.getEncoded().length); |
| algorithmSuiteValidator.checkSymmetricEncryptionAlgorithm(symEncAlgo); |
| } |
| |
| return |
| EncryptionUtils.decryptEncryptedData( |
| doc, dataRefURI, encryptedDataElement, symmetricKey, symEncAlgo, data.getAttachmentCallbackHandler(), |
| data.getEncryptionSerializer() |
| ); |
| } |
| |
| /** |
| * Check for BSP compliance |
| * @param keyInfoElement The KeyInfo element child |
| * @param encAlgo The encryption algorithm |
| * @throws WSSecurityException |
| */ |
| private static void checkBSPCompliance( |
| Element keyInfoElement, |
| String encAlgo, |
| BSPEnforcer bspEnforcer |
| ) throws WSSecurityException { |
| // We can only have one token reference |
| int result = 0; |
| Node node = keyInfoElement.getFirstChild(); |
| Element child = null; |
| while (node != null) { |
| if (Node.ELEMENT_NODE == node.getNodeType()) { |
| result++; |
| child = (Element)node; |
| } |
| node = node.getNextSibling(); |
| } |
| if (result != 1) { |
| bspEnforcer.handleBSPRule(BSPRule.R5424); |
| } |
| |
| if (child == null || !WSConstants.WSSE_NS.equals(child.getNamespaceURI()) |
| || !SecurityTokenReference.SECURITY_TOKEN_REFERENCE.equals(child.getLocalName())) { |
| bspEnforcer.handleBSPRule(BSPRule.R5426); |
| } |
| |
| // EncryptionAlgorithm cannot be null |
| if (encAlgo == null) { |
| bspEnforcer.handleBSPRule(BSPRule.R5601); |
| } |
| // EncryptionAlgorithm must be 3DES, or AES128, or AES256 |
| if (!WSConstants.TRIPLE_DES.equals(encAlgo) |
| && !WSConstants.AES_128.equals(encAlgo) |
| && !WSConstants.AES_128_GCM.equals(encAlgo) |
| && !WSConstants.AES_256.equals(encAlgo) |
| && !WSConstants.AES_256_GCM.equals(encAlgo)) { |
| bspEnforcer.handleBSPRule(BSPRule.R5620); |
| } |
| } |
| |
| } |
| |