| /** |
| * 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.LinkedList; |
| import java.util.List; |
| |
| import javax.crypto.SecretKey; |
| import javax.xml.namespace.QName; |
| |
| 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.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.WSSConfig; |
| 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; |
| import org.w3c.dom.Element; |
| |
| /** |
| * This will process incoming <code>xenc:EncryptedData</code> elements. |
| * This processor will not be invoked for encrypted content referenced by a |
| * <code>xenc:ReferenceList</code>. |
| */ |
| public class EncryptedDataProcessor implements Processor { |
| |
| private static final org.slf4j.Logger LOG = |
| org.slf4j.LoggerFactory.getLogger(EncryptedDataProcessor.class); |
| |
| public List<WSSecurityEngineResult> handleToken( |
| Element elem, |
| RequestData data |
| ) throws WSSecurityException { |
| LOG.debug("Found EncryptedData element"); |
| |
| final String encryptedDataId = elem.getAttributeNS(null, "Id"); |
| |
| Element kiElem = |
| XMLUtils.getDirectChildElement(elem, "KeyInfo", WSConstants.SIG_NS); |
| // KeyInfo cannot be null |
| if (kiElem == null) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, "noKeyinfo" |
| ); |
| } |
| |
| String symEncAlgo = X509Util.getEncAlgo(elem); |
| checkBSPCompliance(symEncAlgo, data.getBSPEnforcer()); |
| |
| // Get the Key either via a SecurityTokenReference or an EncryptedKey |
| Element secRefToken = |
| XMLUtils.getDirectChildElement( |
| kiElem, "SecurityTokenReference", WSConstants.WSSE_NS |
| ); |
| Element encryptedKeyElement = |
| XMLUtils.getDirectChildElement( |
| kiElem, WSConstants.ENC_KEY_LN, WSConstants.ENC_NS |
| ); |
| Element retrievalMethodElement = |
| XMLUtils.getDirectChildElement( |
| kiElem, "RetrievalMethod", WSConstants.SIG_NS |
| ); |
| |
| if (data.isRequireSignedEncryptedDataElements()) { |
| List<WSSecurityEngineResult> signedResults = |
| data.getWsDocInfo().getResultsByTag(WSConstants.SIGN); |
| SignatureUtils.verifySignedElement(elem, signedResults); |
| } |
| |
| SecretKey key = null; |
| List<WSSecurityEngineResult> encrKeyResults = null; |
| Principal principal = null; |
| if (secRefToken != null) { |
| 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(); |
| key = KeyUtils.prepareSecretKey(symEncAlgo, secretKey); |
| encrKeyResults = new ArrayList<>(); |
| } else if (encryptedKeyElement != null && data.getWssConfig() != null) { |
| WSSConfig wssConfig = data.getWssConfig(); |
| Processor encrKeyProc = wssConfig.getProcessor(WSConstants.ENCRYPTED_KEY); |
| encrKeyResults = encrKeyProc.handleToken(encryptedKeyElement, data); |
| byte[] symmKey = |
| (byte[])encrKeyResults.get(0).get(WSSecurityEngineResult.TAG_SECRET); |
| key = KeyUtils.prepareSecretKey(symEncAlgo, symmKey); |
| } else if (retrievalMethodElement != null |
| && "http://www.w3.org/2001/04/xmlenc#EncryptedKey".equals( |
| retrievalMethodElement.getAttributeNS(null, "Type"))) { |
| String uri = retrievalMethodElement.getAttributeNS(null, "URI"); |
| uri = XMLUtils.getIDFromReference(uri); |
| WSSecurityEngineResult result = data.getWsDocInfo().getResult(uri); |
| if (result != null) { |
| byte[] symmKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET); |
| key = KeyUtils.prepareSecretKey(symEncAlgo, symmKey); |
| } |
| } else { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, "noEncKey" |
| ); |
| } |
| |
| if (key == null) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, "noEncKey" |
| ); |
| } |
| |
| // 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(key.getEncoded().length); |
| algorithmSuiteValidator.checkSymmetricEncryptionAlgorithm(symEncAlgo); |
| } |
| |
| WSDataRef dataRef = EncryptionUtils.decryptEncryptedData( |
| elem.getOwnerDocument(), encryptedDataId, elem, key, symEncAlgo, |
| data.getAttachmentCallbackHandler(), data.getEncryptionSerializer()); |
| |
| WSSecurityEngineResult result = |
| new WSSecurityEngineResult(WSConstants.ENCR, Collections.singletonList(dataRef)); |
| if (!"".equals(encryptedDataId)) { |
| result.put(WSSecurityEngineResult.TAG_ID, encryptedDataId); |
| } |
| data.getWsDocInfo().addResult(result); |
| data.getWsDocInfo().addTokenElement(elem); |
| |
| List<WSSecurityEngineResult> completeResults = new LinkedList<>(); |
| if (encrKeyResults != null) { |
| completeResults.addAll(encrKeyResults); |
| } |
| completeResults.add(result); |
| |
| WSSConfig wssConfig = data.getWssConfig(); |
| if (wssConfig != null) { |
| // Get hold of the plain text element |
| Element decryptedElem = dataRef.getProtectedElement(); |
| if (decryptedElem != null) { //is null if we processed an attachment |
| QName el = new QName(decryptedElem.getNamespaceURI(), decryptedElem.getLocalName()); |
| Processor proc = data.getWssConfig().getProcessor(el); |
| if (proc != null) { |
| LOG.debug("Processing decrypted element with: {}", proc.getClass().getName()); |
| List<WSSecurityEngineResult> results = proc.handleToken(decryptedElem, data); |
| completeResults.addAll(0, results); |
| return completeResults; |
| } |
| } |
| } |
| return completeResults; |
| } |
| |
| /** |
| * Check for BSP compliance |
| * @param encAlgo The encryption algorithm |
| * @throws WSSecurityException |
| */ |
| private static void checkBSPCompliance( |
| String encAlgo, BSPEnforcer bspEnforcer |
| ) throws WSSecurityException { |
| // 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); |
| } |
| } |
| } |