Skip to content
This repository has been archived by the owner on May 26, 2020. It is now read-only.

Commit

Permalink
SANTUARIO-525 Made Base64 line length and line separator configurable…
Browse files Browse the repository at this point in the history
…, such that "
" in Base64 encoded elements can be avoided
  • Loading branch information
peterdemaeyer committed Apr 24, 2020
1 parent f4b7525 commit 686a1a5
Show file tree
Hide file tree
Showing 8 changed files with 419 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -661,11 +661,6 @@ private void setSignatureValueElement(byte[] bytes) {
}

String base64codedValue = XMLUtils.encodeToString(bytes);

if (base64codedValue.length() > 76 && !XMLUtils.ignoreLineBreaks()) {
base64codedValue = "\n" + base64codedValue + "\n";
}

Text t = createText(base64codedValue);
signatureValueElement.appendChild(t);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.xml.security.stax.ext.stax.XMLSecEventFactory;
import org.apache.xml.security.stax.ext.stax.XMLSecNamespace;
import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
Expand Down Expand Up @@ -72,6 +73,7 @@ public void setAction(XMLSecurityConstants.Action action) {

@Override
public void init(OutputProcessorChain outputProcessorChain) throws XMLSecurityException {
XMLUtils.setThreadLocalBase64Parameters(securityProperties.getBase64LineLength(), securityProperties.getBase64LineSeparator());
outputProcessorChain.addProcessor(this);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@
*/
package org.apache.xml.security.stax.ext;

import org.apache.xml.security.stax.securityToken.SecurityTokenConstants;

import java.security.Key;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.util.*;

import javax.xml.namespace.QName;

import org.apache.xml.security.stax.securityToken.SecurityTokenConstants;
import org.apache.xml.security.utils.XMLUtils;


/**
* Main configuration class to supply keys etc.
Expand Down Expand Up @@ -80,6 +81,8 @@ public class XMLSecurityProperties {
private QName signaturePositionQName;
private boolean signaturePositionStart = false;
private AlgorithmParameterSpec algorithmParameterSpec;
private int base64LineLength = XMLUtils.DEFAULT_BASE64_LINE_LENGTH;
private byte[] base64LineSeparator = XMLUtils.DEFAULT_BASE64_LINE_SEPARATOR;

public XMLSecurityProperties() {
}
Expand Down Expand Up @@ -120,6 +123,8 @@ protected XMLSecurityProperties(XMLSecurityProperties xmlSecurityProperties) {
this.signaturePositionQName = xmlSecurityProperties.signaturePositionQName;
this.signaturePositionStart = xmlSecurityProperties.signaturePositionStart;
this.algorithmParameterSpec = xmlSecurityProperties.algorithmParameterSpec;
this.base64LineSeparator = xmlSecurityProperties.base64LineSeparator;
this.base64LineLength = xmlSecurityProperties.base64LineLength;
}

public boolean isSignaturePositionStart() {
Expand Down Expand Up @@ -539,4 +544,44 @@ public AlgorithmParameterSpec getAlgorithmParameterSpec() {
public void setAlgorithmParameterSpec(AlgorithmParameterSpec algorithmParameterSpec) {
this.algorithmParameterSpec = algorithmParameterSpec;
}

/**
* @return the Base64 line separator, or {@code null} for no line separator.
*/
public byte[] getBase64LineSeparator() {
return base64LineSeparator;
}

/**
* Sets the Base64 line separator to the given US-ASCII bytes.
* The default is CRLF.
* For no line separator, use the combination of {@code base64LineLength = 4} and
* {@code base64LineSeparator = null}.
*
* @param base64LineSeparator a Base64 line separator, or {@code null} for no line separator.
* @see #setBase64LineLength(int)
*/
public void setBase64LineSeparator(byte[] base64LineSeparator) {
this.base64LineSeparator = base64LineSeparator;
}

/**
* @return the Base64 line length, possibly ≤ {@code 0} for no line separator.
*/
public int getBase64LineLength() {
return base64LineLength;
}

/**
* Sets the Base64 line length, which must be a multiple of 4.
* The default is 76.
* For no line separator, use the combination of {@code base64LineLength = 4} and
* {@code base64LineSeparator = null}.
*
* @param base64LineLength a Base64 line length, or {@code 0} for no line separator.
* @see #setBase64LineSeparator(byte[])
*/
public void setBase64LineLength(int base64LineLength) {
this.base64LineLength = base64LineLength;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,7 @@ public void init(OutputProcessorChain outputProcessorChain) throws XMLSecurityEx
symmetricCipher.init(Cipher.ENCRYPT_MODE, encryptionPartDef.getSymmetricKey(), parameterSpec);

characterEventGeneratorOutputStream = new CharacterEventGeneratorOutputStream();
Base64OutputStream base64EncoderStream = null;
if (XMLUtils.isIgnoreLineBreaks()) {
base64EncoderStream = new Base64OutputStream(characterEventGeneratorOutputStream, true, 0, null);
} else {
base64EncoderStream = new Base64OutputStream(characterEventGeneratorOutputStream, true);
}
Base64OutputStream base64EncoderStream = XMLUtils.createBase64OutputStream(characterEventGeneratorOutputStream, true);
base64EncoderStream.write(iv);

OutputStream outputStream = new CipherOutputStream(base64EncoderStream, symmetricCipher);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,6 @@ public void addBase64Element(byte[] bytes, String localname) {
el.appendChild(text);

appendSelf(el);
if (!XMLUtils.ignoreLineBreaks()) {
appendSelf(createText("\n"));
}
}
}

Expand All @@ -320,9 +317,7 @@ public void addTextElement(String text, String localname) {
*/
public void addBase64Text(byte[] bytes) {
if (bytes != null) {
Text t = XMLUtils.ignoreLineBreaks()
? createText(XMLUtils.encodeToString(bytes))
: createText("\n" + XMLUtils.encodeToString(bytes) + "\n");
Text t = createText(XMLUtils.encodeToString(bytes));
appendSelf(t);
}
}
Expand Down
51 changes: 47 additions & 4 deletions src/main/java/org/apache/xml/security/utils/XMLUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@
import java.util.List;
import java.util.Set;

import org.apache.commons.codec.binary.Base64OutputStream;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.apache.xml.security.parser.XMLParser;
import org.apache.xml.security.parser.XMLParserException;
import org.apache.xml.security.parser.XMLParserImpl;
import org.apache.xml.security.stax.impl.util.KeyValue;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
Expand Down Expand Up @@ -77,6 +79,12 @@ public final class XMLUtils {
private static volatile String xencPrefix = "xenc";
private static volatile String xenc11Prefix = "xenc11";

public static final int DEFAULT_BASE64_LINE_LENGTH = 76;
public static final byte[] DEFAULT_BASE64_LINE_SEPARATOR = {13, 10};
private static final KeyValue<Integer, byte[]> DEFAULT_BASE64_PARAMETERS = new KeyValue<>(DEFAULT_BASE64_LINE_LENGTH, DEFAULT_BASE64_LINE_SEPARATOR);
private static final KeyValue<Integer, byte[]> IGNORE_LINE_BREAKS_BASE64_PARAMETERS = new KeyValue<>(0, null);
private static final ThreadLocal<KeyValue<Integer, byte[]>> BASE64_PARAMETERS = ThreadLocal.withInitial(() -> DEFAULT_BASE64_PARAMETERS);

/**
* Constructor XMLUtils
*
Expand Down Expand Up @@ -525,10 +533,20 @@ public static void addReturnBeforeChild(Element e, Node child) {
}

public static String encodeToString(byte[] bytes) {
if (ignoreLineBreaks) {
KeyValue<Integer, byte[]> base64Parameters = getEffectiveBase64Parameters();
int lineLength = base64Parameters.getKey();
byte[] lineSeparator = base64Parameters.getValue();
if (lineSeparator == null) {
return Base64.getEncoder().encodeToString(bytes);
}
return Base64.getMimeEncoder().encodeToString(bytes);
return Base64.getMimeEncoder(lineLength, lineSeparator).encodeToString(bytes);
}

private static KeyValue<Integer, byte[]> getEffectiveBase64Parameters() {
if (ignoreLineBreaks) {
return IGNORE_LINE_BREAKS_BASE64_PARAMETERS;
}
return BASE64_PARAMETERS.get();
}

public static byte[] decode(String encodedString) {
Expand All @@ -539,10 +557,24 @@ public static byte[] decode(byte[] encodedBytes) {
return Base64.getMimeDecoder().decode(encodedBytes);
}

@Deprecated
public static boolean isIgnoreLineBreaks() {
return ignoreLineBreaks;
}

/**
* Creates a new Base64 output stream around a given output stream, using the thread-local Base64 parameters
* which were configured on this thread using {@link #setThreadLocalBase64Parameters(int, byte[])}.
*
* @param out The delegate output stream, which must not be {@code null}.
* @param doEncode {@code true} to encode, {@code false} to decode Base64.
* @return A new Base64 output stream, never {@code null}.
*/
public static Base64OutputStream createBase64OutputStream(OutputStream out, boolean doEncode) {
KeyValue<Integer, byte[]> base64Parameters = getEffectiveBase64Parameters();
return new Base64OutputStream(out, true, base64Parameters.getKey(), base64Parameters.getValue());
}

/**
* Method convertNodelistToSet
*
Expand Down Expand Up @@ -854,6 +886,7 @@ public static boolean isDescendantOrSelf(Node ctx, Node descendantOrSelf) {
}
}

@Deprecated
public static boolean ignoreLineBreaks() {
return ignoreLineBreaks;
}
Expand Down Expand Up @@ -1050,6 +1083,16 @@ public static byte[] getBytes(BigInteger big, int bitlen) {
return resizedBytes;
}



/**
* Sets the thread-local Base64 parameters that will be used by this thread in further calls to
* {@link #encodeToString(byte[])} and {@link #createBase64OutputStream(OutputStream, boolean)}.
* Any thread-local parameters set here will be overruled (have no effect) when the system property
* {@code "org.apache.xml.security.ignoreLineBreaks"} is set.
*
* @param lineLength a line length, 76 by default. Use 0 for no line separator.
* @param lineSeparator a line separator, CRLF {@code {13, 10}} by default. Use {@code null} for no line separator.
*/
public static void setThreadLocalBase64Parameters(int lineLength, byte[] lineSeparator) {
BASE64_PARAMETERS.set(new KeyValue<>(lineLength, lineSeparator));
}
}
Loading

0 comments on commit 686a1a5

Please sign in to comment.