blob: 0a0fa1afb5ad2aca786a81102887628e31896824 [file] [log] [blame]
/**
* 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);
}
}
}