Signing sections added via custom filter

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Stewart Bourke (stewartbourke_at_eircom.net)
Date: 05/26/04


Date: 26 May 2004 07:12:03 -0700

Vs2003 .net, c#, wse1

First, apologies for the long post, but I have had to include some
soap messages...

I need to digitally sign a webservice call, having added a custom
filter to add a section to the soap header. I have managed to add the
custom section to a soap message with a custom filter. My problem now
is that I need to create a digest reference within the wse:security
section of the message, and I am not sure how to do it.

1. How can I remove the wsu reference? In my code, I have removed
all the filters, except the security and my cusom filter

2. Because I added a custom filter to add the 'Operation' section in
the soap header, it does not appear to have a digect calculated for
it. The 'correct' message has two 'Digest' references, whereas my
message only has one - how can I tell the application to generate
digests for both sections.

3. Me soap message has a huge ID reference:

<soap:Body wsu:Id="Id-9c18c809-de51-4d73-b748-67a8eb0a634c"

Whereas the 'correct' message has a simple one

<soap:Body id="MsgBody"> - without the wsu

How can I remove the wsu: before the 'Id'?
Also, can I control the format of the Id value - i.e. set
id='MsgBody'?

I have provided my (incorrect) soap message, and the correct one as
supplied by the service provider.

I have also provided some code snippets from the application.

I know it is a long message, but I would appreciate if anybody could
offer any assistance...

Regards,

Stewart Bourke

Message 1 - code generated from my application:

  <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Header>
      <wsse:Security soap:mustUnderstand="1"
xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext">
        <wsse:BinarySecurityToken ValueType="wsse:X509v3"
EncodingType="wsse:Base64Binary"
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"
wsu:Id="SecurityToken-ea6945eb-1414-4bc9-99f2-fab488315237">MIICOTCCAaagAwIBAgIQgQWWUbaPm6tO71vvsclQPzAJBgUrDgMCHQUAMFAxFjAUBgNVBAMTDUFkbWluaXN0cmF0b3IxDDAKBgNVBAcTA0VGUzEoMCYGA1UECxMfRUZTIEZpbGUgRW5jcnlwdGlvbiBDZXJ0aWZpY2F0ZTAgFw0wMzEyMTAxMDQ0MjlaGA8yMTAzMTExNjEwNDQyOVowUDEWMBQGA1UEAxMNQWRtaW5pc3RyYXRvcjEMMAoGA1UEBxMDRUZTMSgwJgYDVQQLEx9FRlMgRmlsZSBFbmNyeXB0aW9uIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEB
QUAA4GNADCBiQKBgQCbcO3b2QbGaPds6El98lEhN5HBvj8lCuqFcGL84WCZwn/qKc0uj6aWKw43AcqQegX2RchnZDd3iKj97U7Du67E+ikqUihtBGlFElpmk4AjeO6khZoTSPWE0A+OAFkZt37OTmFYiS0yx7p/JYWkz8zKLmu7Cgmh94sbcrWtDGjq9QIDAQABoxowGDAWBgNVHSUEDzANBgsrBgEEAYI3CgMEATAJBgUrDgMCHQUAA4GBAAcQ5jV3X9sPdaV/xx1ZjJyWhAZOptXlLfU2Y8EMiJlT/KhuAe1eyz6dtCNNtkWL2mq5gpzwZzrQJ4i+RsCLz0oQbdGKDMCrLdnQfzxH9/xvjucHmkDXKxzt0DhMtEVmgB+eHwOFVeVZQIM9EFWWk
eZbWRbmFr7O4iIwFCGjYXE</wsse:BinarySecurityToken>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
          <SignedInfo>
            <CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            <SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
            <Reference URI="#Id-9c18c809-de51-4d73-b748-67a8eb0a634c">
              <Transforms>
                <Transform
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
              </Transforms>
              <DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
              <DigestValue>OUDOeSEz7Dj6b4vSi6knUP3ZF6g=</DigestValue>
            </Reference>
          </SignedInfo>
          <SignatureValue>fNwBrI7xj491nvN83VJc10w1m9/72tLP+YZ9iEVJfdPkG97VR1SV+BjlcStOHxDAtJbVDuD3+//brHnJbfxf8rqN6rSd3EQESvAJuR/PkJ340hadpcJoloXOtNwyQZW39RIsmBTDWwvLQy1Qe+XkWDpV3mU2UGHONl/lCNiWh/U=</SignatureValue>
          <KeyInfo>
            <wsse:SecurityTokenReference>
              <wsse:Reference
URI="#SecurityToken-ea6945eb-1414-4bc9-99f2-fab488315237" />
            </wsse:SecurityTokenReference>
          </KeyInfo>
        </Signature>
      </wsse:Security>
      <Operation id="MsgOperation"
xmlns="http://www.ros.ie/schemas/inbox/">Inbox/List</Operation>
    </soap:Header>
    <soap:Body wsu:Id="Id-9c18c809-de51-4d73-b748-67a8eb0a634c"
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
      <DocumentSearch xmlns="http://www.ros.ie/schemas/inbox/" />
    </soap:Body>
  </soap:Envelope>

Message 2: What the message should look like...

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext">
<wsse:BinarySecurityToken valueType="wsse:X509v3"
encodingType="wsse:Base64Binary" id="X509Token">
        MIIEZzCcA9cgwaABQfd86afd2g...
</wsse:BinarySecurityToken>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod>Algorithm="http://www.w3.org/2001/10/xml-enc-c14n#"/>
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>

-- First digest reference is the MsgOperation section in the header..

<ds:Reference URI="#MsgOperation">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>DJbchm5gk...</ds:DigestValue>
</ds:Reference>

-- Second digest reference is the MsgBody section in the header..

<ds:Reference URI="#MsgBody">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>DJbchm5gk...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>LyLsF0pi4wPu...</ds:SignatureValue>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#X509Token"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
<Operation xmlns="http://www.ros.ie/schemas/inbox/"
id="MsgOperation">Inbox/Document/Retrieve</Operation>
</soap:Header>
<soap:Body id="MsgBody">
<DocumentSelection xmlns="http://www.ros.ie/schemas/inbox/"
prn="12G"/>
</soap:Body>
</soap:Envelope>

============================================
Code:

....

        public class Form1 : System.Windows.Forms.Form
        {
                private System.Windows.Forms.TextBox textBox1;
                private System.Windows.Forms.TextBox textBox2;
                private System.Windows.Forms.Button button1;

                private System.Windows.Forms.TextBox txtMessage;
                private System.Windows.Forms.Label label4;
                private System.Windows.Forms.ComboBox cboCertsEncrypt;
                private System.Windows.Forms.Button btnEcho;
                private System.Windows.Forms.CheckBox chkEncrypt;
                private System.Windows.Forms.ComboBox cboCertsSign;
                private System.Windows.Forms.CheckBox chkSigned;

                private DocumentDescription[] DocList;
                private System.Windows.Forms.RichTextBox richTextBox1;

                private System.ComponentModel.Container components = null;

                public Form1()
                {
                        //
                        // Required for Windows Form Designer support
                        //
                        InitializeComponent();

                        Microsoft.Web.Services.SoapInputFilterCollection inputFilters =
Microsoft.Web.Services.Configuration.WebServicesConfiguration.FilterConfiguration.InputFilters;
                        Microsoft.Web.Services.SoapOutputFilterCollection outputFilters =
Microsoft.Web.Services.Configuration.WebServicesConfiguration.FilterConfiguration.OutputFilters;

                        // remove the unused input filters
                        inputFilters.Remove(typeof(Microsoft.Web.Services.Referral.ReferralInputFilter));
                        inputFilters.Remove(typeof(Microsoft.Web.Services.Routing.RoutingInputFilter));
                        inputFilters.Remove(typeof(Microsoft.Web.Services.Timestamp.TimestampInputFilter));

                        // remove the unused output filters
                        outputFilters.Remove(typeof(Microsoft.Web.Services.Referral.ReferralOutputFilter));
                        outputFilters.Remove(typeof(Microsoft.Web.Services.Routing.RoutingOutputFilter));
                        outputFilters.Remove(typeof(Microsoft.Web.Services.Timestamp.TimestampOutputFilter));
                        outputFilters.Remove(typeof(Microsoft.Web.Services.Security.SecurityOutputFilter));

                }

                /// <summary>
                /// Clean up any resources being used.
                /// </summary>
                protected override void Dispose( bool disposing )
                {
                        if( disposing )
                        {
                                if (components != null)
                                {
                                        components.Dispose();
                                }
                        }
                        base.Dispose( disposing );
                }

                #region Windows Form Designer generated code
                /// <summary>
                /// Required method for Designer support - do not modify
                /// the contents of this method with the code editor.
                /// </summary>
                private void InitializeComponent()
                {
                       ..... removed lots of setup for space reasons
from here...

                        this.Text = "X509 Client";
                        this.Load += new System.EventHandler(this.Form1_Load);
                        this.ResumeLayout(false);

                }
                #endregion

                /// <summary>
                /// The main entry point for the application.
                /// </summary>
                [STAThread]
                static void Main()
                {
                        Application.Run(new Form1());
                }

                private void btnEcho_Click(object sender, System.EventArgs e)
                {
                        // create the reference and make the call
                        try
                        {
                                // create the proxy class

                                RevenueOnlineServiceWse proxy = new RevenueOnlineServiceWse();
                proxy.Pipeline.OutputFilters.Add(new
CustomOutputFilter());
                                proxy.Pipeline.OutputFilters.Add(new SecurityOutputFilter());

                                // open the correct certificate store
                                X509CertificateStore certStore =
X509CertificateStore.CurrentUserStore(X509CertificateStore.MyStore);
                                certStore.OpenRead();

                                // get the certificate and create the security token
                                X509Certificate certSignCertificate =
certStore.FindCertificateBySubjectString(cboCertsSign.Text)[0];
                                X509SecurityToken secSignToken = new
X509SecurityToken(certSignCertificate);
                    
                                // add public key to message
                                proxy.RequestSoapContext.Security.Tokens.Add(secSignToken);

                                // create the signing details and add to the message
                                Signature certSignature = new Signature(secSignToken);
                                proxy.RequestSoapContext.Security.Elements.Add(certSignature);
                                                        
                                // close the certificate store
                                certStore.Close();

                                // make the call
                                proxy.RequestSoapContext["Operation"] =
                                        "Inbox/List";

                                DocumentSearch DocSrch;
                                DocSrch = new DocumentSearch();
                                taxtype tt;
                                tt = taxtype.Transit;
                                DocSrch.taxtype = tt;
                                DocList = proxy.InboxList(DocSrch);

                        }
                        catch (Exception error)
                        {
                                MessageBox.Show(error.Message, "Error!!");
                        }
                }

                private void Form1_Load(object sender, System.EventArgs e)
                {
                        X509CertificateStore certStore;
                        int cntr=0;

                        // loop through the local certificate store and add to the signing
list
                        certStore = X509CertificateStore.CurrentUserStore(X509CertificateStore.MyStore);
                        certStore.OpenRead();

                        foreach(X509Certificate certCertificate in certStore.Certificates)
                        {
                                // can we sign with this key
                                if(certCertificate.SupportsDigitalSignature == true && cntr++ > 0)
                                {
                                        cboCertsSign.Items.Add(GetCommonName(certCertificate.GetName()));
                                }
                        }

                        // close the open store
                        certStore.Close();

                        // loop through the local certificate store and add to the
encrypting list
                        certStore = X509CertificateStore.CurrentUserStore(X509CertificateStore.TrustStore);
                        certStore.Open();

                        foreach(X509Certificate certCertificate in certStore.Certificates)
                        {
                                // can we encrypt to this key
                                if(certCertificate.SupportsDataEncryption == true)
                                {
                                        cboCertsEncrypt.Items.Add(GetCommonName(certCertificate.GetName()));
                                }
                        }

                        // close the store
                        certStore.Close();

                        // select the first entry
                        if(cboCertsSign.Items.Count != 0) cboCertsSign.SelectedIndex = 0;
                        if(cboCertsEncrypt.Items.Count != 0) cboCertsEncrypt.SelectedIndex
= 0;
                }

                private static string GetCommonName(string strName)
                {
                        int intStart, intEnd;
                        string strReturn = strName;

                        // find the "CN=" tag
                        intStart = strName.IndexOf("CN=");

                        if(intStart != - 1)
                        {
                                // skip the "CN=" tag
                                intStart += 3;

                                // find the next "," after the "CN=" tag
                                intEnd = strName.IndexOf(",",intStart);

                                // split the string (on found position or EOF)
                                if(intEnd == -1)
                                {
                                        strReturn = strName.Substring(intStart);
                                }
                                else
                                {
                                        strReturn = strName.Substring(intStart, intEnd-intStart);
                                }
                        }
                        // return the string
                        return strReturn;
                }

}

        public class CustomOutputFilter : SoapOutputFilter
        {
                const string CustomHeaderName = "Operation";
                const string CustomHeaderUri = "http://www.ros.ie/schemas/inbox";
                const string CustomHeaderEchoAttributeName = "id";

                public override void ProcessMessage(SoapEnvelope envelope)
                {
                        //
                        // Look for any data stuffed in the SoapEnvelope's context that we
care about
                        //
                        string echoText = envelope.Context["Operation"] as string;
                        if (echoText != null)
                        {
                                //
                                // Create a new SOAP Header or retrieves a reference
                                // to an existing one.
                                //
                                XmlElement soapHeader = envelope.CreateHeader();

                                //
                                // Create a new CustomHeader and add it to the message
                                //
                                soapHeader.AppendChild(CreateCustomHeader(soapHeader, echoText));
                        }
                }

                XmlElement CreateCustomHeader(XmlElement header, string echoText)
                {
                        XmlDocument document = header.OwnerDocument;
                        XmlElement customHeader = document.CreateElement("", "Operation",
"http://www.ros.ie/schemas/inbox/");
                        customHeader.InnerText = "Inbox/List";
                        customHeader.SetAttribute("id", "", "MsgOperation");
                        return customHeader;
                }
        }
}



Relevant Pages

  • Re: how do I make lye? (sodium hydroxide)
    ... >said its made from slacked lime and sodium carbonate? ... Is the lime rock ... If for some reason you want to make soap in instead of buying you may ... After the mixture has set over night filter out the ...
    (sci.chem)
  • Re: OT-Political junk
    ... I filter non-OLTL threads to the extent that I ... the posts seem to be in the bra discussion, ... people that this is a soap group and that *I* don't want to talk about bras, ... There's still soap talk. ...
    (rec.arts.tv.soaps.abc)
  • Soap Exception and Filters
    ... If a SoapException (with a detail element) is thrown from a Soap ... filter on the server, ...
    (microsoft.public.dotnet.framework.aspnet.security)
  • Re: Inserting a SOAP Header in a client request
    ... Every Soap based ... So all you need to do is write to the chained stream using an xml writer. ... custom SoapHeader and modify the ws client proxy by hand to ... > SoapMessage before adding the soap header but that would be ...
    (microsoft.public.dotnet.framework.webservices)
  • Re: SOAP Input Filter to SOAP Extension
    ... What's a SOAP Input Filter? ... > I'd like to create a client API, so users can add security tokens and ... Should this be implemented as Filter or Extension? ...
    (microsoft.public.dotnet.framework.webservices)