| /** |
| * 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.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| import java.security.PrivateKey; |
| import java.security.PublicKey; |
| import java.security.cert.X509Certificate; |
| import java.security.spec.MGF1ParameterSpec; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import javax.crypto.Cipher; |
| import javax.crypto.KeyGenerator; |
| import javax.crypto.SecretKey; |
| import javax.crypto.spec.OAEPParameterSpec; |
| import javax.crypto.spec.PSource; |
| import javax.xml.crypto.dsig.XMLSignatureFactory; |
| |
| 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.crypto.CryptoType; |
| import org.apache.wss4j.common.crypto.Merlin; |
| import org.apache.wss4j.common.ext.WSSecurityException; |
| import org.apache.wss4j.common.token.DOMX509IssuerSerial; |
| 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.WSDocInfo; |
| import org.apache.wss4j.dom.engine.WSSecurityEngineResult; |
| import org.apache.wss4j.dom.handler.RequestData; |
| import org.apache.wss4j.dom.str.EncryptedKeySTRParser; |
| 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.util.EncryptionUtils; |
| import org.apache.wss4j.dom.util.SignatureUtils; |
| import org.apache.wss4j.dom.util.WSSecurityUtil; |
| import org.apache.wss4j.dom.util.X509Util; |
| import org.apache.xml.security.algorithms.JCEMapper; |
| import org.apache.xml.security.encryption.XMLCipher; |
| |
| public class EncryptedKeyProcessor implements Processor { |
| private static final org.slf4j.Logger LOG = |
| org.slf4j.LoggerFactory.getLogger(EncryptedKeyProcessor.class); |
| |
| public List<WSSecurityEngineResult> handleToken( |
| Element elem, |
| RequestData data, |
| WSDocInfo wsDocInfo |
| ) throws WSSecurityException { |
| return handleToken(elem, data, wsDocInfo, data.getAlgorithmSuite()); |
| } |
| |
| public List<WSSecurityEngineResult> handleToken( |
| Element elem, |
| RequestData data, |
| WSDocInfo wsDocInfo, |
| AlgorithmSuite algorithmSuite |
| ) throws WSSecurityException { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Found encrypted key element"); |
| } |
| |
| // See if this key has already been processed. If so then just return the result |
| String id = elem.getAttributeNS(null, "Id"); |
| if (!"".equals(id)) { |
| WSSecurityEngineResult result = wsDocInfo.getResult(id); |
| if (result != null |
| && WSConstants.ENCR == (Integer)result.get(WSSecurityEngineResult.TAG_ACTION) |
| ) { |
| return Collections.singletonList(result); |
| } |
| } |
| |
| if (data.getCallbackHandler() == null) { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noCallback"); |
| } |
| // |
| // lookup xenc:EncryptionMethod, get the Algorithm attribute to determine |
| // how the key was encrypted. Then check if we support the algorithm |
| // |
| String encryptedKeyTransportMethod = X509Util.getEncAlgo(elem); |
| if (encryptedKeyTransportMethod == null) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, "noEncAlgo" |
| ); |
| } |
| if (WSConstants.KEYTRANSPORT_RSA15.equals(encryptedKeyTransportMethod) |
| && !data.isAllowRSA15KeyTransportAlgorithm() |
| && (algorithmSuite == null |
| || !algorithmSuite.getKeyWrapAlgorithms().contains(WSConstants.KEYTRANSPORT_RSA15))) { |
| LOG.debug( |
| "The Key transport method does not match the requirement" |
| ); |
| throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY); |
| } |
| |
| // Check BSP Compliance |
| checkBSPCompliance(elem, encryptedKeyTransportMethod, data.getBSPEnforcer()); |
| |
| // |
| // Now lookup CipherValue. |
| // |
| Element xencCipherValue = EncryptionUtils.getCipherValueFromEncryptedData(elem); |
| if (xencCipherValue == null) { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "noCipher"); |
| } |
| |
| Element keyInfoChildElement = getKeyInfoChildElement(elem, data); |
| |
| X509Certificate[] certs = null; |
| STRParser.REFERENCE_TYPE referenceType = null; |
| PublicKey publicKey = null; |
| boolean symmetricKeyWrap = isSymmetricKeyWrap(encryptedKeyTransportMethod); |
| if (!symmetricKeyWrap) { |
| if (SecurityTokenReference.SECURITY_TOKEN_REFERENCE.equals(keyInfoChildElement.getLocalName()) |
| && WSConstants.WSSE_NS.equals(keyInfoChildElement.getNamespaceURI())) { |
| STRParserParameters parameters = new STRParserParameters(); |
| parameters.setData(data); |
| parameters.setWsDocInfo(wsDocInfo); |
| parameters.setStrElement(keyInfoChildElement); |
| |
| STRParser strParser = new EncryptedKeySTRParser(); |
| STRParserResult parserResult = strParser.parseSecurityTokenReference(parameters); |
| |
| certs = parserResult.getCertificates(); |
| publicKey = parserResult.getPublicKey(); |
| referenceType = parserResult.getCertificatesReferenceType(); |
| } else { |
| certs = getCertificatesFromX509Data(keyInfoChildElement, data); |
| if (certs == null) { |
| XMLSignatureFactory signatureFactory; |
| try { |
| signatureFactory = XMLSignatureFactory.getInstance("DOM", "ApacheXMLDSig"); |
| } catch (NoSuchProviderException ex) { |
| signatureFactory = XMLSignatureFactory.getInstance("DOM"); |
| } |
| |
| publicKey = X509Util.parseKeyValue((Element)keyInfoChildElement.getParentNode(), |
| signatureFactory); |
| } |
| } |
| |
| if (publicKey == null && (certs == null || certs.length < 1 || certs[0] == null)) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.FAILURE, |
| "noCertsFound", |
| new Object[] {"decryption (KeyId)"}); |
| } |
| if (certs != null && certs.length > 0) { |
| publicKey = certs[0].getPublicKey(); |
| } |
| } |
| |
| // Check for compliance against the defined AlgorithmSuite |
| if (algorithmSuite != null) { |
| AlgorithmSuiteValidator algorithmSuiteValidator = new |
| AlgorithmSuiteValidator(algorithmSuite); |
| |
| if (!symmetricKeyWrap) { |
| algorithmSuiteValidator.checkAsymmetricKeyLength(publicKey); |
| } |
| algorithmSuiteValidator.checkEncryptionKeyWrapAlgorithm( |
| encryptedKeyTransportMethod |
| ); |
| } |
| |
| byte[] encryptedEphemeralKey = null; |
| byte[] decryptedBytes = null; |
| Element refList = |
| XMLUtils.getDirectChildElement(elem, "ReferenceList", WSConstants.ENC_NS); |
| |
| // Get the key bytes from CipherValue directly or via an attachment |
| String xopUri = EncryptionUtils.getXOPURIFromCipherValue(xencCipherValue); |
| if (xopUri != null && xopUri.startsWith("cid:")) { |
| encryptedEphemeralKey = WSSecurityUtil.getBytesFromAttachment(xopUri, data); |
| } else { |
| encryptedEphemeralKey = EncryptionUtils.getDecodedBase64EncodedData(xencCipherValue); |
| } |
| |
| if (symmetricKeyWrap) { |
| decryptedBytes = getSymmetricDecryptedBytes(data, wsDocInfo, keyInfoChildElement, |
| refList, encryptedEphemeralKey); |
| } else { |
| PrivateKey privateKey = getPrivateKey(data, certs, publicKey); |
| decryptedBytes = getAsymmetricDecryptedBytes(data, wsDocInfo, encryptedKeyTransportMethod, |
| encryptedEphemeralKey, refList, |
| elem, privateKey); |
| } |
| |
| List<WSDataRef> dataRefs = decryptDataRefs(refList, wsDocInfo, decryptedBytes, data); |
| |
| WSSecurityEngineResult result = new WSSecurityEngineResult( |
| WSConstants.ENCR, |
| decryptedBytes, |
| encryptedEphemeralKey, |
| dataRefs, |
| certs |
| ); |
| result.put( |
| WSSecurityEngineResult.TAG_ENCRYPTED_KEY_TRANSPORT_METHOD, |
| encryptedKeyTransportMethod |
| ); |
| result.put(WSSecurityEngineResult.TAG_TOKEN_ELEMENT, elem); |
| String tokenId = elem.getAttributeNS(null, "Id"); |
| if (!"".equals(tokenId)) { |
| result.put(WSSecurityEngineResult.TAG_ID, tokenId); |
| } |
| if (referenceType != null) { |
| result.put(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE, referenceType); |
| } |
| if (publicKey != null) { |
| result.put(WSSecurityEngineResult.TAG_PUBLIC_KEY, publicKey); |
| } |
| wsDocInfo.addResult(result); |
| wsDocInfo.addTokenElement(elem); |
| return Collections.singletonList(result); |
| } |
| |
| private PrivateKey getPrivateKey( |
| RequestData data, X509Certificate[] certs, PublicKey publicKey |
| ) throws WSSecurityException { |
| try { |
| if (certs != null) { |
| return data.getDecCrypto().getPrivateKey(certs[0], data.getCallbackHandler()); |
| } else if (data.getDecCrypto() instanceof Merlin) { |
| return ((Merlin)data.getDecCrypto()).getPrivateKey(publicKey, data.getCallbackHandler()); |
| } |
| throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK); |
| } catch (WSSecurityException ex) { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK, ex); |
| } |
| } |
| |
| private static byte[] getSymmetricDecryptedBytes( |
| RequestData data, |
| WSDocInfo wsDocInfo, |
| Element keyInfoChildElement, |
| Element refList, |
| byte[] encryptedEphemeralKey |
| ) throws WSSecurityException { |
| // Get the (first) encryption algorithm |
| String uri = getFirstDataRefURI(refList); |
| String algorithmURI = null; |
| if (uri != null) { |
| Element ee = |
| EncryptionUtils.findEncryptedDataElement(refList.getOwnerDocument(), |
| wsDocInfo, uri); |
| algorithmURI = X509Util.getEncAlgo(ee); |
| } |
| return X509Util.getSecretKey(keyInfoChildElement, algorithmURI, |
| data.getCallbackHandler(), encryptedEphemeralKey); |
| } |
| |
| private static byte[] getAsymmetricDecryptedBytes( |
| RequestData data, |
| WSDocInfo wsDocInfo, |
| String encryptedKeyTransportMethod, |
| byte[] encryptedEphemeralKey, |
| Element refList, |
| Element encryptedKeyElement, |
| PrivateKey privateKey |
| ) throws WSSecurityException { |
| if (data.getDecCrypto() == null) { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noDecCryptoFile"); |
| } |
| String cryptoProvider = data.getDecCrypto().getCryptoProvider(); |
| Cipher cipher = KeyUtils.getCipherInstance(encryptedKeyTransportMethod, cryptoProvider); |
| try { |
| OAEPParameterSpec oaepParameterSpec = null; |
| if (WSConstants.KEYTRANSPORT_RSAOAEP.equals(encryptedKeyTransportMethod) |
| || WSConstants.KEYTRANSPORT_RSAOAEP_XENC11.equals(encryptedKeyTransportMethod)) { |
| // Get the DigestMethod if it exists |
| String digestAlgorithm = EncryptionUtils.getDigestAlgorithm(encryptedKeyElement); |
| String jceDigestAlgorithm = "SHA-1"; |
| if (digestAlgorithm != null && !"".equals(digestAlgorithm)) { |
| jceDigestAlgorithm = JCEMapper.translateURItoJCEID(digestAlgorithm); |
| } |
| |
| MGF1ParameterSpec mgfParameterSpec = new MGF1ParameterSpec("SHA-1"); |
| if (WSConstants.KEYTRANSPORT_RSAOAEP_XENC11.equals(encryptedKeyTransportMethod)) { |
| String mgfAlgorithm = EncryptionUtils.getMGFAlgorithm(encryptedKeyElement); |
| if (WSConstants.MGF_SHA224.equals(mgfAlgorithm)) { |
| mgfParameterSpec = new MGF1ParameterSpec("SHA-224"); |
| } else if (WSConstants.MGF_SHA256.equals(mgfAlgorithm)) { |
| mgfParameterSpec = new MGF1ParameterSpec("SHA-256"); |
| } else if (WSConstants.MGF_SHA384.equals(mgfAlgorithm)) { |
| mgfParameterSpec = new MGF1ParameterSpec("SHA-384"); |
| } else if (WSConstants.MGF_SHA512.equals(mgfAlgorithm)) { |
| mgfParameterSpec = new MGF1ParameterSpec("SHA-512"); |
| } |
| } |
| |
| PSource.PSpecified pSource = PSource.PSpecified.DEFAULT; |
| byte[] pSourceBytes = EncryptionUtils.getPSource(encryptedKeyElement); |
| if (pSourceBytes != null) { |
| pSource = new PSource.PSpecified(pSourceBytes); |
| } |
| |
| oaepParameterSpec = |
| new OAEPParameterSpec( |
| jceDigestAlgorithm, "MGF1", mgfParameterSpec, pSource |
| ); |
| } |
| |
| if (oaepParameterSpec == null) { |
| cipher.init(Cipher.UNWRAP_MODE, privateKey); |
| } else { |
| cipher.init(Cipher.UNWRAP_MODE, privateKey, oaepParameterSpec); |
| } |
| } catch (Exception ex) { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK, ex); |
| } |
| |
| try { |
| String keyAlgorithm = JCEMapper.translateURItoJCEID(encryptedKeyTransportMethod); |
| return cipher.unwrap(encryptedEphemeralKey, keyAlgorithm, Cipher.SECRET_KEY).getEncoded(); |
| } catch (IllegalStateException ex) { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK, ex); |
| } catch (Exception ex) { |
| return getRandomKey(refList, wsDocInfo); |
| } |
| } |
| |
| private static boolean isSymmetricKeyWrap(String transportAlgorithm) { |
| return XMLCipher.AES_128_KeyWrap.equals(transportAlgorithm) |
| || XMLCipher.AES_192_KeyWrap.equals(transportAlgorithm) |
| || XMLCipher.AES_256_KeyWrap.equals(transportAlgorithm) |
| || XMLCipher.TRIPLEDES_KeyWrap.equals(transportAlgorithm) |
| || XMLCipher.CAMELLIA_128_KeyWrap.equals(transportAlgorithm) |
| || XMLCipher.CAMELLIA_192_KeyWrap.equals(transportAlgorithm) |
| || XMLCipher.CAMELLIA_256_KeyWrap.equals(transportAlgorithm) |
| || XMLCipher.SEED_128_KeyWrap.equals(transportAlgorithm); |
| } |
| |
| /** |
| * Generates a random secret key using the algorithm specified in the |
| * first DataReference URI |
| */ |
| private static byte[] getRandomKey(Element refList, WSDocInfo wsDocInfo) throws WSSecurityException { |
| try { |
| String alg = "AES"; |
| int size = 16; |
| String uri = getFirstDataRefURI(refList); |
| |
| if (uri != null) { |
| Element ee = |
| EncryptionUtils.findEncryptedDataElement(refList.getOwnerDocument(), |
| wsDocInfo, uri); |
| String algorithmURI = X509Util.getEncAlgo(ee); |
| alg = JCEMapper.getJCEKeyAlgorithmFromURI(algorithmURI); |
| size = KeyUtils.getKeyLength(algorithmURI); |
| } |
| KeyGenerator kgen = KeyGenerator.getInstance(alg); |
| kgen.init(size * 8); |
| SecretKey k = kgen.generateKey(); |
| return k.getEncoded(); |
| } catch (Throwable ex) { |
| // Fallback to just using AES to avoid attacks on EncryptedData algorithms |
| try { |
| KeyGenerator kgen = KeyGenerator.getInstance("AES"); |
| kgen.init(128); |
| SecretKey k = kgen.generateKey(); |
| return k.getEncoded(); |
| } catch (NoSuchAlgorithmException e) { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK, e); |
| } |
| } |
| } |
| |
| private static String getFirstDataRefURI(Element refList) { |
| // Lookup the references that are encrypted with this key |
| if (refList != null) { |
| for (Node node = refList.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"); |
| return XMLUtils.getIDFromReference(dataRefURI); |
| } |
| } |
| } |
| return null; |
| } |
| |
| private Element getKeyInfoChildElement( |
| Element xencEncryptedKey, RequestData data |
| ) throws WSSecurityException { |
| Element keyInfo = |
| XMLUtils.getDirectChildElement(xencEncryptedKey, "KeyInfo", WSConstants.SIG_NS); |
| if (keyInfo != null) { |
| Element strElement = null; |
| |
| int result = 0; |
| Node node = keyInfo.getFirstChild(); |
| while (node != null) { |
| if (Node.ELEMENT_NODE == node.getNodeType()) { |
| result++; |
| strElement = (Element)node; |
| } |
| node = node.getNextSibling(); |
| } |
| if (result != 1) { |
| data.getBSPEnforcer().handleBSPRule(BSPRule.R5424); |
| } |
| |
| if (strElement == null) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.INVALID_SECURITY, "noSecTokRef" |
| ); |
| } |
| |
| return strElement; |
| } else { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "noKeyinfo"); |
| } |
| } |
| |
| private X509Certificate[] getCertificatesFromX509Data( |
| Element keyInfoChildElement, |
| RequestData data |
| ) throws WSSecurityException { |
| |
| if (WSConstants.SIG_NS.equals(keyInfoChildElement.getNamespaceURI()) |
| && WSConstants.X509_DATA_LN.equals(keyInfoChildElement.getLocalName())) { |
| data.getBSPEnforcer().handleBSPRule(BSPRule.R5426); |
| |
| Element x509Child = getFirstElement(keyInfoChildElement); |
| |
| if (x509Child != null && WSConstants.SIG_NS.equals(x509Child.getNamespaceURI())) { |
| if (WSConstants.X509_ISSUER_SERIAL_LN.equals(x509Child.getLocalName())) { |
| DOMX509IssuerSerial issuerSerial = new DOMX509IssuerSerial(x509Child); |
| CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ISSUER_SERIAL); |
| cryptoType.setIssuerSerial(issuerSerial.getIssuer(), issuerSerial.getSerialNumber()); |
| return data.getDecCrypto().getX509Certificates(cryptoType); |
| } else if (WSConstants.X509_CERT_LN.equals(x509Child.getLocalName())) { |
| byte[] token = EncryptionUtils.getDecodedBase64EncodedData(x509Child); |
| if (token == null) { |
| throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidCertData", |
| new Object[] {"0"}); |
| } |
| try (InputStream in = new ByteArrayInputStream(token)) { |
| X509Certificate cert = data.getDecCrypto().loadCertificate(in); |
| if (cert != null) { |
| return new X509Certificate[]{cert}; |
| } |
| } catch (IOException e) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, e, "parseError" |
| ); |
| } |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| private Element getFirstElement(Element element) { |
| for (Node currentChild = element.getFirstChild(); |
| currentChild != null; |
| currentChild = currentChild.getNextSibling() |
| ) { |
| if (Node.ELEMENT_NODE == currentChild.getNodeType()) { |
| return (Element) currentChild; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Decrypt all data references |
| */ |
| private List<WSDataRef> decryptDataRefs(Element refList, WSDocInfo docInfo, |
| byte[] decryptedBytes, RequestData data |
| ) throws WSSecurityException { |
| // |
| // At this point we have the decrypted session (symmetric) key. According |
| // to W3C XML-Enc this key is used to decrypt _any_ references contained in |
| // the reference list |
| if (refList == null) { |
| return null; |
| } |
| |
| List<WSDataRef> dataRefs = new ArrayList<>(); |
| for (Node node = refList.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); |
| |
| WSDataRef dataRef = |
| decryptDataRef(refList.getOwnerDocument(), dataRefURI, docInfo, decryptedBytes, data); |
| dataRefs.add(dataRef); |
| } |
| } |
| |
| return dataRefs; |
| } |
| |
| /** |
| * Decrypt an EncryptedData element referenced by dataRefURI |
| */ |
| private WSDataRef decryptDataRef( |
| Document doc, |
| String dataRefURI, |
| WSDocInfo docInfo, |
| byte[] decryptedData, |
| RequestData data |
| ) throws WSSecurityException { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("found data reference: " + dataRefURI); |
| } |
| // |
| // Find the encrypted data element referenced by dataRefURI |
| // |
| Element encryptedDataElement = |
| EncryptionUtils.findEncryptedDataElement(doc, docInfo, dataRefURI); |
| if (encryptedDataElement != null && data.isRequireSignedEncryptedDataElements()) { |
| List<WSSecurityEngineResult> signedResults = |
| docInfo.getResultsByTag(WSConstants.SIGN); |
| SignatureUtils.verifySignedElement(encryptedDataElement, signedResults); |
| } |
| // |
| // Prepare the SecretKey object to decrypt EncryptedData |
| // |
| String symEncAlgo = X509Util.getEncAlgo(encryptedDataElement); |
| |
| // EncryptionAlgorithm cannot be null |
| if (symEncAlgo == null) { |
| LOG.debug("No encryption algorithm was specified in the request"); |
| throw new WSSecurityException(WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, "badEncAlgo", |
| new Object[] {null}); |
| |
| } |
| // EncryptionAlgorithm must be 3DES, or AES128, or AES256 |
| if (!WSConstants.TRIPLE_DES.equals(symEncAlgo) |
| && !WSConstants.AES_128.equals(symEncAlgo) |
| && !WSConstants.AES_128_GCM.equals(symEncAlgo) |
| && !WSConstants.AES_256.equals(symEncAlgo) |
| && !WSConstants.AES_256_GCM.equals(symEncAlgo)) { |
| data.getBSPEnforcer().handleBSPRule(BSPRule.R5620); |
| } |
| |
| SecretKey symmetricKey = null; |
| try { |
| symmetricKey = KeyUtils.prepareSecretKey(symEncAlgo, decryptedData); |
| } catch (IllegalArgumentException ex) { |
| throw new WSSecurityException( |
| WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, ex, "badEncAlgo", |
| new Object[] {symEncAlgo}); |
| } |
| |
| // Check for compliance against the defined AlgorithmSuite |
| AlgorithmSuite algorithmSuite = data.getAlgorithmSuite(); |
| if (algorithmSuite != null) { |
| AlgorithmSuiteValidator algorithmSuiteValidator = new |
| AlgorithmSuiteValidator(algorithmSuite); |
| |
| algorithmSuiteValidator.checkSymmetricKeyLength(symmetricKey.getEncoded().length); |
| algorithmSuiteValidator.checkSymmetricEncryptionAlgorithm(symEncAlgo); |
| } |
| |
| return EncryptionUtils.decryptEncryptedData( |
| doc, dataRefURI, encryptedDataElement, symmetricKey, symEncAlgo, data.getAttachmentCallbackHandler() |
| ); |
| } |
| |
| /** |
| * A method to check that the EncryptedKey is compliant with the BSP spec. |
| * @throws WSSecurityException |
| */ |
| private void checkBSPCompliance( |
| Element elem, String encAlgo, BSPEnforcer bspEnforcer |
| ) throws WSSecurityException { |
| String attribute = elem.getAttributeNS(null, "Type"); |
| if (attribute != null && !"".equals(attribute)) { |
| bspEnforcer.handleBSPRule(BSPRule.R3209); |
| } |
| attribute = elem.getAttributeNS(null, "MimeType"); |
| if (attribute != null && !"".equals(attribute)) { |
| bspEnforcer.handleBSPRule(BSPRule.R5622); |
| } |
| attribute = elem.getAttributeNS(null, "Encoding"); |
| if (attribute != null && !"".equals(attribute)) { |
| bspEnforcer.handleBSPRule(BSPRule.R5623); |
| } |
| attribute = elem.getAttributeNS(null, "Recipient"); |
| if (attribute != null && !"".equals(attribute)) { |
| bspEnforcer.handleBSPRule(BSPRule.R5602); |
| } |
| |
| // EncryptionAlgorithm must be RSA15, or RSAOEP. |
| if (!(WSConstants.KEYTRANSPORT_RSA15.equals(encAlgo) |
| || WSConstants.KEYTRANSPORT_RSAOAEP.equals(encAlgo) |
| || WSConstants.KEYTRANSPORT_RSAOAEP_XENC11.equals(encAlgo))) { |
| bspEnforcer.handleBSPRule(BSPRule.R5621); |
| } |
| } |
| |
| } |