Skip to content

Commit

Permalink
WSS-714 RecipientKeyInfo improved (#418)
Browse files Browse the repository at this point in the history
* WSS-714 RecipientKeyInfo improved

* Change findElement to getDirectChildElement

---------

Co-authored-by: Colm O hEigeartaigh <coheigea@users.noreply.github.com>
  • Loading branch information
mhaeusler and coheigea committed Jan 30, 2025
1 parent 21a82b0 commit b1bb162
Show file tree
Hide file tree
Showing 4 changed files with 472 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ protected WSS4JConstants() {
public static final String X509_ISSUER_SERIAL_LN = "X509IssuerSerial";
public static final String X509_ISSUER_NAME_LN = "X509IssuerName";
public static final String X509_SERIAL_NUMBER_LN = "X509SerialNumber";
public static final String X509_SKI_LN = "X509SKI";
public static final String X509_DATA_LN = "X509Data";
public static final String X509_CERT_LN = "X509Certificate";
public static final String KEYINFO_LN = "KeyInfo";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* 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.common.token;

import org.apache.wss4j.common.util.DOM2Writer;
import org.apache.wss4j.common.util.XMLUtils;
import org.w3c.dom.Element;


/**
* An X.509 SKI token.
*/
public final class DOMX509SKI {
private final Element element;
private final byte[] skiBytes;

/**
* Constructor.
*/
public DOMX509SKI(Element skiElement) {
element = skiElement;

String text = XMLUtils.getElementText(element);
if (text == null) {
skiBytes = new byte[0];
} else {
skiBytes = org.apache.xml.security.utils.XMLUtils.decode(text);
}
}

/**
* return the dom element.
*
* @return the dom element.
*/
public Element getElement() {
return element;
}

/**
* Return the SKI bytes.
*/
public byte[] getSKIBytes() {
return skiBytes;
}

/**
* return the string representation of the token.
*
* @return the string representation of the token.
*/
public String toString() {
return DOM2Writer.nodeToString(element);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,21 @@
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.OAEPParameterSpec;
import javax.xml.crypto.dsig.XMLSignatureFactory;

import org.apache.wss4j.common.WSS4JConstants;
import org.apache.wss4j.common.token.DOMX509SKI;
import org.apache.xml.security.encryption.AgreementMethod;
import org.apache.xml.security.encryption.KeyDerivationMethod;
import org.apache.xml.security.encryption.XMLCipherUtil;
import org.apache.xml.security.encryption.keys.RecipientKeyInfo;
import org.apache.xml.security.encryption.keys.content.AgreementMethodImpl;
import org.apache.xml.security.encryption.params.KeyAgreementParameters;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.content.keyvalues.DSAKeyValue;
import org.apache.xml.security.keys.content.keyvalues.ECKeyValue;
import org.apache.xml.security.keys.content.keyvalues.KeyValueContent;
import org.apache.xml.security.keys.content.keyvalues.RSAKeyValue;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.EncryptionConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
Expand Down Expand Up @@ -75,14 +81,7 @@ public class EncryptedKeyProcessor implements Processor {
private static final org.slf4j.Logger LOG =
org.slf4j.LoggerFactory.getLogger(EncryptedKeyProcessor.class);

private final Provider provider;

public EncryptedKeyProcessor() {
this(null);
}

public EncryptedKeyProcessor(Provider provider) {
this.provider = provider;
}

public List<WSSecurityEngineResult> handleToken(
Expand Down Expand Up @@ -276,27 +275,42 @@ private CertificateResult getPublicKey(Element keyValueElement, RequestData data
X509Certificate[] certs = getCertificatesFromX509Data(keyValueElement, data);
builder.certificates(certs);
if (certs == null || certs.length == 0) {
XMLSignatureFactory signatureFactory;
if (provider == null) {
// Try to install the Santuario Provider - fall back to the JDK provider if this does
// not work
try {
signatureFactory = XMLSignatureFactory.getInstance("DOM", "ApacheXMLDSig");
} catch (NoSuchProviderException ex) {
signatureFactory = XMLSignatureFactory.getInstance("DOM");
}
} else {
signatureFactory = XMLSignatureFactory.getInstance("DOM", provider);
}

PublicKey publicKey = X509Util.parseKeyValue((Element) keyValueElement.getParentNode(),
signatureFactory);
PublicKey publicKey = getPublicKeyFromKeyValue(keyValueElement);
builder.publicKey(publicKey);
}
}
return builder.build();
}

private PublicKey getPublicKeyFromKeyValue(Element keyValueElement) throws WSSecurityException {
PublicKey publicKey = null;
KeyValueContent keyValue;
try {
Element keyValueChild = getFirstElement(keyValueElement);
if (keyValueChild == null) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "unsupportedKeyInfo");
}
switch (keyValueChild.getLocalName()) {
case "ECKeyValue":
keyValue = new ECKeyValue(keyValueChild, Constants.SignatureSpec11NS);
break;
case "RSAKeyValue":
keyValue = new RSAKeyValue(keyValueChild, Constants.SignatureSpecNS);
break;
case "DSAKeyValue":
keyValue = new DSAKeyValue(keyValueChild, Constants.SignatureSpecNS);
break;
default:
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "unsupportedKeyInfo");
}

publicKey = keyValue.getPublicKey();
} catch (XMLSecurityException e) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "unsupportedKeyInfo");
}
return publicKey;
}

private PrivateKey getPrivateKey(
RequestData data, X509Certificate[] certs, PublicKey publicKey
) throws WSSecurityException {
Expand Down Expand Up @@ -594,40 +608,50 @@ private X509Certificate[] getCertificatesFromX509Data(
Element keyInfoChildElement,
RequestData data
) throws WSSecurityException {
X509Certificate[] certs = new X509Certificate[0];

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 || token.length == 0) {
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"
);
Element issuerSerialElement = XMLUtils.getDirectChildElement(keyInfoChildElement, WSS4JConstants.X509_ISSUER_SERIAL_LN,
WSS4JConstants.SIG_NS);
if (issuerSerialElement != null) {
DOMX509IssuerSerial issuerSerial = new DOMX509IssuerSerial(issuerSerialElement);
CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ISSUER_SERIAL);
cryptoType.setIssuerSerial(issuerSerial.getIssuer(), issuerSerial.getSerialNumber());
certs = data.getDecCrypto().getX509Certificates(cryptoType);
}

Element skiElement = XMLUtils.getDirectChildElement(keyInfoChildElement, WSS4JConstants.X509_SKI_LN, WSS4JConstants.SIG_NS);
if (skiElement != null && certs.length == 0) {
DOMX509SKI x509SKI = new DOMX509SKI(skiElement);
CryptoType cryptoType = new CryptoType(CryptoType.TYPE.SKI_BYTES);
cryptoType.setBytes(x509SKI.getSKIBytes());
certs = data.getDecCrypto().getX509Certificates(cryptoType);
}

Element x509CertElement = XMLUtils.getDirectChildElement(keyInfoChildElement, WSS4JConstants.X509_CERT_LN, WSS4JConstants.SIG_NS);
if (x509CertElement != null && certs.length == 0) {
byte[] token = EncryptionUtils.getDecodedBase64EncodedData(x509CertElement);
if (token == null || token.length == 0) {
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) {
certs = new X509Certificate[]{cert};
}
} catch (IOException e) {
throw new WSSecurityException(
WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, e, "parseError"
);
}
}
}

return new X509Certificate[0];
return certs;
}

private Element getFirstElement(Element element) {
Expand Down
Loading

0 comments on commit b1bb162

Please sign in to comment.