- Bugfix: corrected the use of XSD schema files when applying EXI encoding for signature creation. Distinguishes now between EXI encoding for the SignedInfoElement of the header's signature (where XMLdsig schema needs to be used) and EXI encoding for the reference elements of the header's signature.

- Bugfix: corrected the use of EXI encoding option when encoding signature header: Here the schema-informed fragment grammar option needs to be used. For EXI encoding of message bodies, this option is not to be used.
This commit is contained in:
Marc Mültin 2016-11-11 16:53:46 +09:00
parent 8cf20ba88a
commit 54759ee249
5 changed files with 87 additions and 28 deletions

View File

@ -34,6 +34,7 @@ import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import com.siemens.ct.exi.EXIFactory;
import com.siemens.ct.exi.EncodingOptions;
import com.siemens.ct.exi.GrammarFactory;
import com.siemens.ct.exi.api.sax.EXIResult;
import com.siemens.ct.exi.api.sax.EXISource;
@ -54,6 +55,7 @@ public final class EXIficientCodec extends ExiCodec {
private GrammarFactory grammarFactory;
private Grammars grammarAppProtocol;
private Grammars grammarMsgDef;
private Grammars grammarXMLDSig;
private OutputStream encodeOS;
private EXIficientCodec() {
@ -61,6 +63,7 @@ public final class EXIficientCodec extends ExiCodec {
setExiFactory(DefaultEXIFactory.newInstance());
getExiFactory().setValuePartitionCapacity(0);
setFragment(false); // needs to be set to true when encoding signatures
setGrammarFactory(GrammarFactory.newInstance());
/*
@ -73,6 +76,9 @@ public final class EXIficientCodec extends ExiCodec {
setGrammarMsgDef(getGrammarFactory().createGrammars(
getClass().getResourceAsStream(GlobalValues.SCHEMA_PATH_MSG_DEF.toString()),
XSDResolver.getInstance()));
setGrammarXMLDSig(getGrammarFactory().createGrammars(
getClass().getResourceAsStream(GlobalValues.SCHEMA_PATH_XMLDSIG.toString()),
XSDResolver.getInstance()));
} catch (EXIException e) {
getLogger().error("Error occurred while trying to initialize EXIficientCodec (EXIException)!", e);
}
@ -86,21 +92,30 @@ public final class EXIficientCodec extends ExiCodec {
public synchronized byte[] encodeEXI(Object jaxbObject, boolean supportedAppProtocolHandshake) {
public synchronized byte[] encodeEXI(Object jaxbObject, String xsdSchemaPath) {
Grammars grammar = null;
if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_APP_PROTOCOL.toString()))
grammar = getGrammarAppProtocol();
else if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_MSG_DEF.toString()))
grammar = getGrammarMsgDef();
else if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_XMLDSIG.toString()))
grammar = getGrammarXMLDSig();
else {
getLogger().error("False schema path provided for encoding jaxbObject into EXI");
return null;
}
InputStream inStream = marshalToInputStream(jaxbObject);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos = ((ByteArrayOutputStream) encode(inStream, supportedAppProtocolHandshake));
baos = ((ByteArrayOutputStream) encode(inStream, grammar));
// If needed for debugging
// getLogger().debug("Encoded EXI byte stream to be sent: " + ByteUtils.toHexString(baos.toByteArray()));
return baos.toByteArray();
}
private synchronized OutputStream encode(InputStream jaxbXML, boolean supportedAppProtocolHandshake) {
if (supportedAppProtocolHandshake) return encode(jaxbXML, getGrammarAppProtocol());
else return encode(jaxbXML, getGrammarMsgDef());
}
private synchronized OutputStream encode(InputStream jaxbXML, Grammars grammar) {
EXIResult exiResult = null;
@ -126,6 +141,9 @@ public final class EXIficientCodec extends ExiCodec {
@Override
public synchronized Object decodeEXI(byte[] exiEncodedMessage, boolean supportedAppProtocolHandshake) {
// If needed for debugging
// getLogger().debug("Decoded incoming EXI stream: " + ByteUtils.toHexString(exiEncodedMessage));
ByteArrayInputStream bais = new ByteArrayInputStream(exiEncodedMessage);
setDecodedExi(decode(bais, supportedAppProtocolHandshake));
@ -178,7 +196,16 @@ public final class EXIficientCodec extends ExiCodec {
this.grammarMsgDef = grammarMsgDef;
}
private EXIFactory getExiFactory() {
public Grammars getGrammarXMLDSig() {
return grammarXMLDSig;
}
public void setGrammarXMLDSig(Grammars grammarXMLDSig) {
this.grammarXMLDSig = grammarXMLDSig;
}
public EXIFactory getExiFactory() {
return exiFactory;
}
@ -193,4 +220,9 @@ public final class EXIficientCodec extends ExiCodec {
private void setGrammarFactory(GrammarFactory grammarFactory) {
this.grammarFactory = grammarFactory;
}
@Override
public void setFragment(boolean useFragmentGrammar) {
getExiFactory().setFragment(useFragmentGrammar);
}
}

View File

@ -15,14 +15,12 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.risev2g.shared.utils.MiscUtils;
@ -112,17 +110,18 @@ public abstract class ExiCodec {
if (getInStream() != null) getInStream().reset();
setInStream(new ByteArrayInputStream(decodedExiString.getBytes()));
return getUnmarshaller().unmarshal(getInStream());
} catch (IOException | JAXBException e) {
} catch (IOException | JAXBException | RuntimeException e) {
getLogger().error(e.getClass().getSimpleName() + " occurred while trying to unmarshall decoded message", e);
return null;
}
}
public abstract byte[] encodeEXI(Object jaxbXML, boolean supportedAppProtocolHandshake);
public abstract byte[] encodeEXI(Object jaxbXML, String xsdSchemaPath);
public abstract Object decodeEXI(byte[] exiEncodedMessage, boolean supportedAppProtocolHandshake);
public abstract void setFragment(boolean useFragmentGrammar);
public Marshaller getMarshaller() {
return marshaller;

View File

@ -49,6 +49,7 @@ public final class OpenEXICodec extends ExiCodec {
private InputStream schemaAppProtocolIS;
private EXISchema exiSchemaAppProtocol;
private EXISchema exiSchemaMsgDef;
private EXISchema exiSchemaXMLDSig;
private short options;
private SAXTransformerFactory saxTransformerFactory;
private SAXParserFactory saxParserFactory;
@ -64,7 +65,8 @@ public final class OpenEXICodec extends ExiCodec {
// The Transmogrifier performs the translation from XML to EXI format
setTransmogrifier(new Transmogrifier());
getTransmogrifier().setValuePartitionCapacity(0);
// getTransmogrifier().setDivertBuiltinGrammarToAnyType(true); // enable V2G's built-in grammar usage
getTransmogrifier().setFragment(false);
// getTransmogrifier().setDivertBuiltinGrammarToAnyType(true); // enable V2G's built-in grammar usage
// Standard SAX methods parse content and lexical values
setSaxTransformerFactory((SAXTransformerFactory) SAXTransformerFactory.newInstance());
@ -109,7 +111,7 @@ public final class OpenEXICodec extends ExiCodec {
@Override
public byte[] encodeEXI(Object jaxbObject, boolean supportedAppProtocolHandshake) {
public byte[] encodeEXI(Object jaxbObject, String xsdSchemaPath) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
@ -118,10 +120,16 @@ public final class OpenEXICodec extends ExiCodec {
* The Grammar Cache stores the XML schema and options used to encode an EXI file.
* The settings must match when encoding and subsequently decoding a data set.
*/
if (supportedAppProtocolHandshake)
if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_APP_PROTOCOL.toString()))
setGrammarCache(new GrammarCache(getExiSchemaAppProtocol(), getOptions()));
else
else if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_MSG_DEF.toString()))
setGrammarCache(new GrammarCache(getExiSchemaMsgDef(), getOptions()));
else if (xsdSchemaPath.equals(GlobalValues.SCHEMA_PATH_XMLDSIG.toString()))
setGrammarCache(new GrammarCache(getExiSchemaXMLDSig(), getOptions()));
else {
getLogger().error("False schema path provided for encoding jaxbObject into EXI");
return null;
}
// Set the configuration options in the Transmogrifier
getTransmogrifier().setGrammarCache(getGrammarCache());
@ -276,4 +284,17 @@ public final class OpenEXICodec extends ExiCodec {
public void setExiSchemaMsgDef(EXISchema exiSchemaMsgDef) {
this.exiSchemaMsgDef = exiSchemaMsgDef;
}
public EXISchema getExiSchemaXMLDSig() {
return exiSchemaXMLDSig;
}
public void setExiSchemaXMLDSig(EXISchema exiSchemaXMLDSig) {
this.exiSchemaXMLDSig = exiSchemaXMLDSig;
}
@Override
public void setFragment(boolean useFragmentGrammar) {
getTransmogrifier().setFragment(useFragmentGrammar);
}
}

View File

@ -109,12 +109,12 @@ public class MessageHandler {
public synchronized Object suppAppProtocolMsgToExi(Object suppAppProtocolObject) {
return getExiCodec().encodeEXI(suppAppProtocolObject, true);
return getExiCodec().encodeEXI(suppAppProtocolObject, GlobalValues.SCHEMA_PATH_APP_PROTOCOL.toString());
}
public synchronized Object v2gMsgToExi(Object jaxbObject) {
byte[] encodedEXI = getExiCodec().encodeEXI(jaxbObject, false);
byte[] encodedEXI = getExiCodec().encodeEXI(jaxbObject, GlobalValues.SCHEMA_PATH_MSG_DEF.toString());
// For test purposes you can log the byte array
// getLogger().debug("Encoded EXI byte array: " + ByteUtils.toHexString(encodedEXI));

View File

@ -60,7 +60,6 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
@ -79,7 +78,6 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.security.auth.x500.X500Principal;
import javax.xml.bind.JAXBElement;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.risev2g.shared.enumerations.GlobalValues;
@ -1567,16 +1565,25 @@ public final class SecurityUtils {
* needs to be set to false.
*
* @param messageOrField The message or field for which a digest is to be generated
* @param signature True if a digest for a signature is to be generated, false otherwise
* @param digestForSignedInfoElement True if a digest for the SignedInfoElement of the header's signature is to be generated, false otherwise
* @return The SHA-256 digest for message or field
*/
public static byte[] generateDigest(Object messageOrField, boolean signature) {
public static byte[] generateDigest(Object messageOrField, boolean digestForSignedInfoElement) {
JAXBElement jaxbElement = MiscUtils.getJaxbElement(messageOrField);
byte[] encoded;
// TODO what was again the difference?
if (signature) encoded = getExiCodec().encodeEXI(jaxbElement, false);
else encoded = getExiCodec().encodeEXI(jaxbElement, false);
// The schema-informed fragment grammar option needs to be used for EXI encodings in the header's signature
getExiCodec().setFragment(true);
/*
* When creating the signature value for the SignedInfoElement, we need to use the XMLdsig schema,
* whereas for creating the reference elements of the signature, we need to use the V2G_CI_MsgDef schema.
*/
if (digestForSignedInfoElement) encoded = getExiCodec().encodeEXI(jaxbElement, GlobalValues.SCHEMA_PATH_XMLDSIG.toString());
else encoded = getExiCodec().encodeEXI(jaxbElement, GlobalValues.SCHEMA_PATH_MSG_DEF.toString());
// Do not use the schema-informed fragment grammar option for other EXI encodings (message bodies)
getExiCodec().setFragment(false);
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");