Chat
Ask me anything
Ithy Logo

MATLAB Implementation for XML Canonicalization and RSA Signed SOAP Messaging

Step-by-step guide to create and sign a SOAP message using MATLAB

scenic code setup

Highlights

  • DOM Creation: The code demonstrates converting XML data into a Document Object Model (DOM) representation using MATLAB functions and Java classes.
  • Canonicalization & SHA-256 Digest: A process is provided for generating a canonicalized version of XML data (following the W3C specification with comments) and computing its SHA-256 digest.
  • RSA Signature & SOAP Embedding: The workflow includes signing the digest with RSA using a private key, encoding the signature in base64, and integrating it into a SOAP envelope.

Introduction

When dealing with secure web services, it is often necessary to digitally sign SOAP messages to guarantee the authenticity and integrity of the transmitted data. This article describes a comprehensive MATLAB solution to perform the following:

  1. Create a DOM representation from an XML string.
  2. Canonicalize this XML representation according to the W3C standard (including comments as required by the XML Canonicalization specification).
  3. Generate a SHA-256 digest of the canonicalized XML data.
  4. Sign this digest using RSA encryption with a provided private key.
  5. Encode the resulting binary signature as a base64 string.
  6. Embed the base64-encoded signature into a SOAP message.

Our solution leverages MATLAB's built-in capabilities as well as Java interoperability to perform operations that are not natively supported by MATLAB. An entire code snippet is presented that integrates these operations in a coherent workflow.


Implementation Details

The following sections describe each step in detail.

1. Creating a DOM Representation of XML Data

The first step involves converting XML data into a Document Object Model (DOM). MATLAB’s matlab.io.xml.dom package or Java-based XML parsing can be used to accomplish this. The code snippet below demonstrates how to use MATLAB's Java integration capabilities to parse an XML string into a DOM Document object.

MATLAB Code for XML DOM Creation


% Import necessary packages for XML parsing and DOM manipulation
import matlab.io.xml.dom.*;
import javax.xml.parsers.DocumentBuilderFactory;

% Define your XML string – it can be any valid XML.
xmlString = ['<!-- Sample XML with comments -->' newline, ...
             '<root>', newline, ...
             '    <!-- This is a comment -->', newline, ...
             '    <data>Example content</data>', newline, ...
             '</root>'];

% Use Java's DocumentBuilder to parse the XML string.
factory = DocumentBuilderFactory.newInstance();
% Enable the processing of comments
factory.setIgnoringComments(false);
builder = factory.newDocumentBuilder();
isr = java.io.StringReader(xmlString);
inputSource = org.xml.sax.InputSource(isr);
doc = builder.parse(inputSource);

% The variable "doc" now holds the DOM representation of the XML document.
  

In the code above, comments in the XML are preserved by ensuring the document builder does not ignore them. This is important for canonicalization if comments are required to be included.


2. Creating a Canonicalized Representation

Canonicalization is the process of converting XML content into a standardized format. This is crucial for digital signatures, ensuring that semantically equivalent XML documents have an identical physical representation. The W3C canonicalization standard (inclusive of comments) specifies rules for whitespace, attribute order, and more. MATLAB does not provide a built-in function to achieve full canonicalization; thus, a simplified version using Java's transformation libraries can be used as a placeholder.

Canonicalization using Java Transformer


% Import Java classes for transformation
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;

% Create a Transformer instance with indentation properties.
transformerFactory = TransformerFactory.newInstance();
transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, 'no');
transformer.setOutputProperty(OutputKeys.INDENT, 'yes');
% Note: For true canonicalization, further customization or third-party libraries
% must be used to strictly follow the W3C canonicalization standard with comments.
  
% Use a StringWriter to capture the output of the transformer.
sw = java.io.StringWriter();
source = DOMSource(doc);
result = StreamResult(sw);

% Transform the DOM document to a canonicalized XML string.
transformer.transform(source, result);
canonicalizedXML = char(sw.toString());
  

The output of this transformation is a standardized XML string. Although this example uses basic Java transformations, for complete canonicalization according to the W3C spec (including proper treatment of namespaces and comments), consider using a dedicated library such as org.apache.xml.security.c14n.Canonicalizer if available.


3. Generating an RSA Signature of the SHA-256 Digest

At this stage, the canonicalized XML representation must be hashed using the SHA-256 algorithm. The resulting hash is then encrypted using the RSA algorithm. Java’s java.security package is employed via MATLAB to sign the digest with a private key.

Creating SHA-256 Digest and RSA Signature


% Import Java security classes for digest and signature generation.
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.nio.file.Files;
import java.nio.file.Paths;

% Create a MessageDigest instance for SHA-256.
messageDigest = MessageDigest.getInstance('SHA-256');
% Calculate the digest of the canonicalized XML string.
% Ensure the string is converted to bytes.
digest = messageDigest.digest(uint8(canonicalizedXML));

% Load the private key from a file (assumes PEM format with no header/footer conversion).
% For a production environment, ensure that the key format is parsed correctly.
keyPath = 'privateKey.der'; % The key should be in DER format for this example.
privateKeyBytes = Files.readAllBytes(Paths.get(keyPath));
keySpec = PKCS8EncodedKeySpec(privateKeyBytes);
% Generate the private key using the RSA algorithm.
privateKey = KeyFactory.getInstance('RSA').generatePrivate(keySpec);

% Create a Signature object using SHA256withRSA.
signatureInstance = Signature.getInstance('SHA256withRSA');
% Initialize signature object with the private key.
signatureInstance.initSign(privateKey);
% Update the signature object with the digest bytes.
signatureInstance.update(digest);
% Generate the RSA signature.
signedBytes = signatureInstance.sign();
  

In this code, the SHA-256 digest of the XML is computed first. The digest is then signed using RSA with a private key which must be provided in an appropriate format. Adjust the file path and key format as necessary for your application.


4. Base64 Encoding of the Binary Signature

To ensure safe transmission of binary data in text-based formats such as XML, the signature is base64 encoded. MATLAB's Java interoperation allows us to use Java’s encoder.

Base64 Encoding Code


% Using Java's Base64 encoder to convert the byte array into a base64 encoded string.
encoder = Base64.getEncoder();
base64Signature = char(encoder.encodeToString(signedBytes));
  

The variable base64Signature now contains the signature as a base64 string, suitable for embedding within XML content.


5. Embedding the Signature in a SOAP Message

With the base64-encoded signature available, the final step is to embed it into a properly formatted SOAP message. The SOAP envelope includes a header for the security (Signature) information and a body where the primary XML content may reside.

Constructing the SOAP Message


% Construct a SOAP message as a string with placeholders for the signature and the XML payload.
% The XML payload can be the original XML or another message as per your application requirements.
xmlPayload = canonicalizedXML;  % This example reuses the canonicalized XML as the payload.

soapMessage = sprintf(['<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">' newline, ...
                       '    <soap:Header>' newline, ...
                       '        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">' newline, ...
                       '            <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">' newline, ...
                       '                <ds:SignatureValue>%s</ds:SignatureValue>' newline, ...
                       '            </ds:Signature>' newline, ...
                       '        </wsse:Security>' newline, ...
                       '    </soap:Header>' newline, ...
                       '    <soap:Body>' newline, ...
                       '        %s' newline, ...
                       '    </soap:Body>' newline, ...
                       '</soap:Envelope>'], base64Signature, xmlPayload);

% Display the SOAP message to the MATLAB Command Window.
disp(soapMessage);
  

This SOAP message includes a security header that houses the signature (according to XML digital signature standards) and a body that contains the XML payload.


Overview Table

The following table summarizes each step in the process, describing the purpose and key operations involved:

Step Operation Key MATLAB/Java Functions
1. DOM Representation Parse XML string into a DOM using Java DocumentBuilder DocumentBuilderFactory, parse, StringReader
2. Canonicalization Transform DOM into standardized XML; preserve comments Transformer, StreamResult, DOMSource
3. SHA-256 Digest & RSA Signature Generate hash digest and sign it using RSA with a private key MessageDigest, Signature, PKCS8EncodedKeySpec
4. Base64 Encoding Encode binary signature into a string for XML embedding java.util.Base64
5. SOAP Message Construction Embed the base64 signature and payload into a SOAP envelope sprintf, disp

Complete MATLAB Code Example

Combining all the steps discussed above, the following complete MATLAB code example demonstrates the entire process end-to-end:


%==========================================================================
% MATLAB Code: XML Digital Signature and SOAP Message Creation
%==========================================================================
try
    %% Step 1: Create a DOM Representation of the XML Data
    import matlab.io.xml.dom.*;
    import javax.xml.parsers.DocumentBuilderFactory;
    
    % Define XML string with comments
    xmlString = ['<!-- Sample XML with Comments -->' newline, ...
                 '<root>' newline, ...
                 '    <!-- Comment inside XML -->' newline, ...
                 '    <data>Example Content</data>' newline, ...
                 '</root>'];
    
    % Initialize the DocumentBuilderFactory
    factory = DocumentBuilderFactory.newInstance();
    % Ensure comments are preserved during parsing
    factory.setIgnoringComments(false);
    builder = factory.newDocumentBuilder();
    isr = java.io.StringReader(xmlString);
    inputSource = org.xml.sax.InputSource(isr);
    doc = builder.parse(inputSource);
    
    %% Step 2: Create a Canonicalized Representation of the DOM Data
    import javax.xml.transform.*;
    import javax.xml.transform.dom.*;
    import javax.xml.transform.stream.*;
    
    % Create a transformer instance with formatting properties
    transformerFactory = TransformerFactory.newInstance();
    transformer = transformerFactory.newTransformer();
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, 'no');
    transformer.setOutputProperty(OutputKeys.INDENT, 'yes');
    
    % Transform the DOM into a string using a StringWriter
    sw = java.io.StringWriter();
    source = DOMSource(doc);
    result = StreamResult(sw);
    transformer.transform(source, result);
    canonicalizedXML = char(sw.toString());
    
    %% Step 3: Compute SHA-256 Digest and Create RSA Signature
    import java.security.*;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.util.Base64;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    
    % Compute the SHA-256 digest of the canonicalized XML content
    messageDigest = MessageDigest.getInstance('SHA-256');
    digest = messageDigest.digest(uint8(canonicalizedXML));
    
    % Load RSA private key from a file (DER format)
    keyPath = 'privateKey.der';  % Make sure this file exists and is appropriately formatted.
    privateKeyBytes = Files.readAllBytes(Paths.get(keyPath));
    keySpec = PKCS8EncodedKeySpec(privateKeyBytes);
    privateKey = KeyFactory.getInstance('RSA').generatePrivate(keySpec);
    
    % Create RSA signature for the SHA-256 digest using SHA256withRSA algorithm
    signatureInstance = Signature.getInstance('SHA256withRSA');
    signatureInstance.initSign(privateKey);
    signatureInstance.update(digest);
    signedBytes = signatureInstance.sign();
    
    %% Step 4: Base64 Encode the Signature
    encoder = Base64.getEncoder();
    base64Signature = char(encoder.encodeToString(signedBytes));
    
    %% Step 5: Place the Signature in the SOAP Message
    % Prepare your SOAP message payload (here, we are using the canonicalized XML as an example)
    xmlPayload = canonicalizedXML;
    soapMessage = sprintf(['<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">' newline, ...
                           '    <soap:Header>' newline, ...
                           '        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">' newline, ...
                           '            <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">' newline, ...
                           '                <ds:SignatureValue>%s</ds:SignatureValue>' newline, ...
                           '            </ds:Signature>' newline, ...
                           '        </wsse:Security>' newline, ...
                           '    </soap:Header>' newline, ...
                           '    <soap:Body>' newline, ...
                           '        %s' newline, ...
                           '    </soap:Body>' newline, ...
                           '</soap:Envelope>'], base64Signature, xmlPayload);
    
    % Display the produced SOAP message
    disp(soapMessage);
    fprintf('SOAP message creation successful.\n');
catch ME
    fprintf('An error occurred: %s\n', ME.message);
end
%==========================================================================
  

This complete code handles XML parsing, canonicalization (simplified), digest computation, RSA signing, base64 encoding, and SOAP message construction. Adjust file paths, key formats, and parameters as necessary to fit your specific application environment.


Conclusion and Final Thoughts

This detailed MATLAB implementation demonstrates how to create a SOAP message with a digitally signed XML payload. It covers the entire workflow from transforming raw XML into a DOM representation and canonicalizing it (while preserving comments per W3C recommendations) to signing the resulting SHA-256 digest with RSA using a private key. The binary signature is encoded into a base64 string and then embedded in a SOAP envelope.

The provided code uses MATLAB’s integration with Java to accomplish tasks that are not directly supported by MATLAB, such as XML canonicalization and RSA signing. While the canonicalization implemented here is a simplified version, it serves as a solid foundation. For production-level applications, further enhancements may be necessary, including the use of dedicated libraries to fully adhere to the W3C canonicalization standard and robust error handling. This comprehensive solution thus provides a powerful template for ensuring secure communications through SOAP in MATLAB.


References


Recommended


Last updated February 24, 2025
Ask Ithy AI
Download Article
Delete Article