3

We are trying to send data to IRS through an exposed web service for the ACA data transmission and we could not make the WSE 3.0 approach to work because of the order of Timestamp and Signature elements in the Security Header. XSD validation at the IRS side is showing an error when the TimeStamp element is appearing before Signature element. When we used policy assertion for manually generating the security header with the right order of Signature and Timestamp elements, IRS web service is showing "Invalid WS Security Header" Error.

Can anyone having the same problem, please let us know what could be a possible fix. Using WCF 4.5 instead of WSE 3.0 is the solution, can you please provide a working sample which handles both MTOM attachment & GZip encoding using WCF 4.5

Any help would be greatly appreciated.

EDIT: Following is the Status Request Soap Envelope we are sending now with the whole XML created by manually. It still shows TPE - 1122 Invalid Security Header Error. Are there any mistakes with this request?

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:oas1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:us:gov:treasury:irs:msg:irstransmitterstatusrequest" xmlns:urn1="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:urn2="urn:us:gov:treasury:irs:common" xmlns:urn3="urn:us:gov:treasury:irs:msg:acasecurityheader">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <ds:Signature Id="SIG-E68EBBF1696C5DD4AA143353323390579" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:SignedInfo>
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" />
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
                    <ds:Reference URI="#TS-82E7E6716E615C14D6144736030985954">
                        <ds:Transforms>
                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                                <InclusiveNamespaces PrefixList="wsse wsa oas1 soapenv urn urn1 urn2 urn3" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" />
                            </ds:Transform>
                        </ds:Transforms>
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                        <ds:DigestValue>[Digest_Value_Replaced]</ds:DigestValue>
                    </ds:Reference>
                    <ds:Reference URI="#id-82E7E6716E615C14D6144736030986559">
                        <ds:Transforms>
                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                                <InclusiveNamespaces PrefixList="oas1 soapenv urn1 urn2 urn3" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" />
                            </ds:Transform>
                        </ds:Transforms>
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                        <ds:DigestValue>[Digest_Value_Replaced]</ds:DigestValue>
                    </ds:Reference>
                    <ds:Reference URI="#id-82E7E6716E615C14D6144736030986558">
                        <ds:Transforms>
                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                                <InclusiveNamespaces PrefixList="wsa oas1 soapenv urn1 urn2 urn3" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" />
                            </ds:Transform>
                        </ds:Transforms>
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                        <ds:DigestValue>[Digest_Value_Replaced]</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>[Signature_Value_Replaced]</ds:SignatureValue>
                <ds:KeyInfo Id="KI-82E7E6716E615C14D6144736030986456">
                    <wsse:SecurityTokenReference wsu:Id="STR-82E7E6716E615C14D6144736030986457" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                        <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">[Cert_Value_Replaced]</wsse:KeyIdentifier>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
            </ds:Signature>
            <wsu:Timestamp wsu:Id="TS-82E7E6716E615C14D6144736030985954">
                <wsu:Created>2016-03-23T09:53:23:55Z</wsu:Created>
                <wsu:Expires>2016-03-23T10:03:23:55Z</wsu:Expires>
            </wsu:Timestamp>
        </wsse:Security>
        <urn:ACABusinessHeader wsu:Id="id-82E7E6716E615C14D6144736030986558" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <urn1:UniqueTransmissionId>uuid:SYS12:tcc_cd::T</urn1:UniqueTransmissionId>
            <urn2:Timestamp>2016-03-23T09:53:23:55Z</urn2:Timestamp>
        </urn:ACABusinessHeader>
        <urn3:ACASecurityHeader/>
        <wsa:Action>RequestSubmissionStatusDetail</wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <urn:ACABulkRequestTransmitterStatusDetailRequest version="1.0" wsu:Id="id-82E7E6716E615C14D6144736030986559" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <urn1:ACABulkReqTrnsmtStsReqGrpDtl>
                <urn2:ReceiptId>[ReceiptId_Value_Replaced]</urn2:ReceiptId>
            </urn1:ACABulkReqTrnsmtStsReqGrpDtl>
        </urn:ACABulkRequestTransmitterStatusDetailRequest>
    </soapenv:Body>
</soapenv:Envelope>

EDIT 2:: Here is the method I am using to sign the envelope and create the Signature Element. STILL GETTING SECURITY HEADER ERROR... :(

 public static string getSignedXML(XmlDocument xmlDoc, RSACryptoServiceProvider key, string signatureNamespacePrefix,
                                        string sTimeStampId, string sManifestId, string sBusHeaderId)
        {
            xmlDoc.PreserveWhitespace = false;  //Ignore the whitespace in XML   

            SignedXml signedXml = new CustomIdSignedXml(xmlDoc); //If Id attribute needs to have a prefix. This is not needed as per latest Reference Guide Info.
            //SignedXml signedXml = new SignedXml(xmlDoc);

            // Add the key to the SignedXml document.
            signedXml.SigningKey = key;
            signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NWithCommentsTransformUrl;
            signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
            signedXml.Signature.Id = "SIG-E68EBBF1696C5DD4AA143353323390579";

            //------------------------------------------------------------------------
            //START OF: Adding Manifest, BusinessHeader and TimeStamp References
            //------------------------------------------------------------------------
            //Adding Timestamp Reference
            XmlDsigExcC14NTransform timeStampTransform = new XmlDsigExcC14NTransform();
            timeStampTransform.InclusiveNamespacesPrefixList = "wsse wsa oas1 soapenv urn urn1 urn2 urn3";
            Reference reference = new Reference("#" + sTimeStampId);
            reference.AddTransform(timeStampTransform);
            // Add the reference to the SignedXml object.
            signedXml.AddReference(reference);

            //Adding Business Header Reference
            XmlDsigExcC14NTransform busHeaderTransform = new XmlDsigExcC14NTransform();
            busHeaderTransform.InclusiveNamespacesPrefixList = "wsa oas1 soapenv urn1 urn2 urn3";
            reference = new Reference("#" + sBusHeaderId);
            reference.AddTransform(busHeaderTransform);
            // Add the reference to the SignedXml object.
            signedXml.AddReference(reference);

            //Adding Manifest Request Dtl Reference
            XmlDsigExcC14NTransform manifestTransform = new XmlDsigExcC14NTransform();
            manifestTransform.InclusiveNamespacesPrefixList = "oas1 soapenv urn1 urn2 urn3";
            reference = new Reference("#" + sManifestId);
            reference.AddTransform(manifestTransform);
            // Add the reference to the SignedXml object.
            signedXml.AddReference(reference);
            //------------------------------------------------------------------------
            //END OF: Adding Manifest, BusinessHeader and TimeStamp References
            //------------------------------------------------------------------------

            signedXml.ComputeSignature();

            XmlElement xmlSignature = signedXml.GetXml(); //Get the singed XML block

            if (!string.IsNullOrEmpty(signatureNamespacePrefix))
            {
                //Here we set the namespace prefix on the signature element and all child elements to "ds", invalidating the signature.
                AssignNameSpacePrefixToElementTree(xmlSignature, "ds");

                //So let's recompute the SignatureValue based on our new SignatureInfo...

                //For XPath
                XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
                namespaceManager.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); //this prefix is arbitrary and used only for XPath
                XmlElement xmlSignedInfo = xmlSignature.SelectSingleNode("ds:SignedInfo", namespaceManager) as XmlElement;

                //Canonicalize the SignedInfo element
                XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
                XmlDocument signedInfoDoc = new XmlDocument();
                signedInfoDoc.LoadXml(xmlSignedInfo.OuterXml);
                transform.LoadInput(signedInfoDoc);

                //Compute the new SignatureValue
                string signatureValue = Convert.ToBase64String(key.SignData(transform.GetOutput() as MemoryStream, new SHA1CryptoServiceProvider()));
                //Set it in the xml
                XmlElement xmlSignatureValue = xmlSignature.SelectSingleNode("ds:SignatureValue", namespaceManager) as XmlElement;
                xmlSignatureValue.InnerText = signatureValue;
            }

            //xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlSignature, true));

            //----------------------------------------------------------------------------------
            //START OF: Add Key Info Element also to the XML after SignatureValue Node.
            //----------------------------------------------------------------------------------
            X509Certificate2 mycert = new X509Certificate2(<Cert_Path>, <Cert_Password>);
            //bulkReqTransmitService.ClientCertificates.Add(mycert);
            var exported = mycert.Export(X509ContentType.Cert, <Cert_Password>);
            var base64 = Convert.ToBase64String(exported);

            StringBuilder sbKeyInfo = new StringBuilder();
            string dsStartTagPrefix = "";
            string dsEndTagPrefix = "/";
            if (!string.IsNullOrEmpty(signatureNamespacePrefix))
            {
                dsStartTagPrefix = "ds:";
                dsEndTagPrefix = "/ds:";
            }
            sbKeyInfo.Append("<root xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">");
            sbKeyInfo.Append("<" + dsStartTagPrefix + "KeyInfo Id=\"KI-82E7E6716E615C14D6144736030986456\">");
            sbKeyInfo.Append("<wsse:SecurityTokenReference wsu:Id=\"STR-82E7E6716E615C14D6144736030986457\">");
            sbKeyInfo.Append("<wsse:KeyIdentifier EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\" ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\">" + base64.ToString());
            sbKeyInfo.Append("</wsse:KeyIdentifier>");
            sbKeyInfo.Append("</wsse:SecurityTokenReference>");
            sbKeyInfo.Append("<" + dsEndTagPrefix + "KeyInfo>");
            sbKeyInfo.Append("</root>");

            XmlDocument tempDoc = new XmlDocument();
            tempDoc.LoadXml(sbKeyInfo.ToString());
            XmlNode oNode = tempDoc.DocumentElement;
            //necessary for crossing XmlDocument contexts
            XmlNode importNode = xmlSignature.OwnerDocument.ImportNode(oNode.FirstChild, true);
            xmlSignature.AppendChild(importNode);
            //----------------------------------------------------------------------------------
            //END OF: Add Key Info Element also to the XML after SignatureValue Node.
            //----------------------------------------------------------------------------------

            return xmlSignature.OuterXml;
        }


public class CustomIdSignedXml : SignedXml
    {
        public CustomIdSignedXml(XmlDocument xml) : base(xml)
        {
        }

        public CustomIdSignedXml(XmlElement xmlElement)
            : base(xmlElement)
        {
        }

        public override XmlElement GetIdElement(XmlDocument doc, string id)
        {
            // check to see if it's a standard ID reference
            XmlElement idElem = base.GetIdElement(doc, id);

            if (idElem == null)
            {
                XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
                nsManager.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

                //idElem = doc.SelectSingleNode("//*[@p5:Id=\"" + id + "\"]", nsManager) as XmlElement;

                string xml = doc.SelectSingleNode("//*[@wsu:Id=\"" + id + "\"]", nsManager).OuterXml;
                XmlDocument tempDoc = new XmlDocument();
                tempDoc.LoadXml(xml);
                XmlElement xEle = tempDoc.DocumentElement;

                idElem = xEle;
            }

            return idElem;
        }
    }
Russ
  • 678
  • 8
  • 26
SubCoder
  • 57
  • 10
  • I got the gzip working from a combination of this: https://msdn.microsoft.com/en-us/library/ms751458.aspx (Custom Message Encoder: Compression Encoder). But it required tweaks. Had to change the content type to show up as "text/xml" instead of "application/x-gzip" as they have set. Then had to set the "Content-Encoding" header manually using this: http://blogs.msdn.com/b/wsdevsol/archive/2014/02/07/adding-custom-messageheader-and-http-header-to-a-wcf-method-call.aspx to the value "gzip" – Bon Feb 04 '16 at 22:45
  • I am now trying to set up the signature part. – Bon Feb 04 '16 at 22:45
  • Won't be able to verify MTOM is working properly until I'm past that, but right now I've got it set up as described here: http://stackoverflow.com/questions/3638552/mtom-encoding-and-custom-binding – Bon Feb 04 '16 at 22:48

2 Answers2

2

EDIT: Verified none of this will work due to WCF's messaging architecture. IRS structure requires modification of HTTP headers for MTOM to work properly which cannot be modified in WCF after the point during which XML serialization occurs. You will have to construct your XML manually and send it via HttpClient and do GZip and MTOM encoding yourself. Sorry for the bad news :(

WCF gzip: Take the sample here and integrate the classes and client config with your app. https://msdn.microsoft.com/en-us/library/ms751458.aspx

You'll have to tweak the content type to be "text/xml" instead of "application/x-gzip".

This still will be rejected by the IRS because this doesn't set the "Content-Encoding" header. You can set the content encoding this way:



using (new OperationContextScope(transmitterClient.InnerChannel))
{
// Add a HTTP Header to an outgoing request
HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
requestMessage.Headers["Content-Encoding"] = "gzip";
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
return port.BulkRequestTransmitter(request);
}


Thanks to this blog post for that: http://blogs.msdn.com/b/wsdevsol/archive/2014/02/07/adding-custom-messageheader-and-http-header-to-a-wcf-method-call.aspx

Additionally, IRS's response is NOT gzipped, so you need to modify the class to not try to decompress the response.

Additionally, additionally, the innerMessageEncoding messageVersion default is NOT compatible with the IRS. You have to modify the ApplyConfiguration method of the GZipMessageEncodingElement to instantiate the TextMessageEncodingBindingElement to the MessageVersion.Soap11WSAddressing10 enum with Encoding.UTF8

MTOM My bindings look like this:

<bindings>
  <customBinding>
    <binding name="BulkRequestTransmitterBinding">
      <gzipMessageEncoding innerMessageEncoding="textMessageEncoding" />
      <security enableUnsecuredResponse="true" authenticationMode="MutualCertificate" messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"/>
      <httpsTransport />
    </binding>
  </customBinding>
</bindings>  

And then a custom behavior aiming at my cert.

Russ
  • 678
  • 8
  • 26
Bon
  • 1,083
  • 12
  • 23
  • Signing is still broken in my solution though. So take this for what it is (or isn't) worth. – Bon Feb 04 '16 at 23:34
  • Thanks for the reply Bon. We already tried GZip custom encoding classes provided by Microsoft sample. But worried to use that in production since many blogs had mentioned that the custom Gzip encoder classes has the memory leakage issue. Is there any other simpler solution with WCF to incorporate GZip encoding and sending the pay load file as MTOM? – SubCoder Feb 16 '16 at 16:31
  • Not as far as I'm aware. I'm sure the memory leak issues could be debugged once they were observable and repeatable, though. I'm planning on using this solution in a console app fired on a scheduler to pick the next in a queue to send. So I'd expect that would release any of the unreleased memory inbetween executions. – Bon Feb 16 '16 at 16:39
  • Thanks for the reply Bon. So were you able to create a working .NET solution for IRS A2A transmission? – SubCoder Feb 23 '16 at 18:19
  • No, and I am pretty certain it is impossible when using WCF or Web Services client due to their strict namespace declaration and the fact that neither of those tools allow modification of the SOAP envelope, nor the declaration of multiple prefixed namespaces via object and property attributes. I am currently finishing my next pass using LINQ to Xml to construct the envelope and most headers, and will submit the SOAP request using HTTP POST manually within the next day or two. – Bon Feb 24 '16 at 17:23
  • Oh OK. Still it is an automated A2A solution right. We are also using LINQ to XML for creating our Form Data file. Were you able to get all the security elements in the security header with the manual XML Node creation approach and if it (HTTP POST) works could you post the working sample here which would be of great help. Currently we are doing transmissions using the UI channel as an alternate approach which is the manual process of uploading the Manifest file and Form Data file. – SubCoder Feb 24 '16 at 17:46
  • Nothing is working yet, but it will be automated once it is done. But I can't post the code unfortunately due to contractual obligations. I'll share what I can. – Bon Feb 24 '16 at 17:55
  • Sure not a problem. Thank you. – SubCoder Feb 24 '16 at 18:38
  • I got it working, SubCoder. For signing, only 1 part needs to be touched. The SignedXml GetXml output must be modified somewhat to use a BinarySecurityToken for the SignedInfo element. If you use LINQ to Xml to modify only that element and don't modify the 3 signed elements themselves, the digests remain in tact. – Bon Mar 02 '16 at 16:56
  • Bon, Thanks for letting us know. If you could give some pointers of the whole approach, we will try it on our end. We are really stuck with the A2A transmissions at this point. – SubCoder Mar 02 '16 at 23:10
  • Bon, Also how are you adding the MTOM payload file to the request if you are manually creating the XML file by-hand? – SubCoder Mar 03 '16 at 15:19
  • Bon, Also how are you doing GZip Compression for the manually created request? – SubCoder Mar 03 '16 at 15:58
  • Both MTOM and GZip happen after XML construction, before I assign the content to the post body of my pending HTTP Request. First MTOM, which is just done by string concatenation then gzip using the standard GZipStream class in .Net – Bon Mar 03 '16 at 19:50
  • Cool Thanks. Could you share code snippets for the Security Header, GZip and MTOM. – SubCoder Mar 03 '16 at 20:27
  • Sorry, not able to do that due to contractual requirements. There are no gotchas in this remaining part though, so standard documentation available on those features should get you this last bit to completion. – Bon Mar 03 '16 at 20:34
  • Bon, Not a problem. Where can I find an example of gzip using GZipStream class in .net? Also how will I get the digest values manually for the three sections. – SubCoder Mar 16 '16 at 19:53
  • http://www.dotnetperls.com/gzipstream was second result in Google. Digest values are calculated by using the SignedXml class and providing it with the Id attribute values for the 3 elements requiring signature. – Bon Mar 17 '16 at 19:20
  • Thanks a ton Bon. One more question. How did you calculate the "SignatureValue"? And how could we make sure that the Signature Value Calculated is right? – SubCoder Mar 17 '16 at 21:01
  • The SignedInfo class does it automatically when you call GetXml from the references you identified. There's a function in the SignedInfo class that runs the hash of the signed elements against the certificate it contains to verify they match. https://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.signedinfo%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396 – Bon Mar 18 '16 at 04:25
  • @SubCoder have a look at the following SO posts. [This SO](http://stackoverflow.com/questions/35735341/malformed-reference-element) explains how I am signing my signatures. [This SO](http://stackoverflow.com/questions/30579938/generate-digital-signature-but-with-a-specific-namespace-prefix-ds/30813170#30813170) goes over adding the "ds" prefix to the Signature elements (something that may or may not be necessary). [This SO](http://stackoverflow.com/questions/36021040/irs-a2a-bulkrequesttransmitter-message-not-formmatted-properly-and-or-cannot-be), I am stuck on and receiving a error from. – Russ Mar 18 '16 at 23:38
  • I just answered your question there, I believe. Talk to you in that thread. – Bon Mar 19 '16 at 19:44
  • Thanks a lot Bon and Russ. That was very good information and we are in the process of trying it out now. – SubCoder Mar 21 '16 at 13:55
  • @Bon: After hand-writing the whole XML, we are past the GZip and forming the Security Header portion of it. Trying the Status Request to AATS system which is the simpler one. My Soap Envelope XML matches exactly with the one in IRS reference guide. But still getting TPE1122 - Security Header Error. I am posting it here. Could you please let me know if there is any glaring mistake I am doing? Please find an "EDIT" to my original post above with the soap envelope XML – SubCoder Mar 23 '16 at 14:30
  • You are sure you aren't modifying the SignedInfo element or any of its descendants in the XML coming out of the GetXml function from the SignedXml class? It has been verified that the IRS will accept the SignedInfo (and entire Signature element) without the prefix and just the namespace inheritance override. My successful transmissions have namespace structure matching their docs exactly EXCEPT in the Signature element, and it works fine. – Bon Mar 23 '16 at 15:16
  • @Bon: I am modifying and adding "ds" prefixes and recalculating the Signature value. But just tried the transmission without "ds" prefix also and same Security Header Error. I have posted the code doing the signing also in my post "EDIT 2" above. Please have a look. How does your Signature Element look? Could you post a snippet here? – SubCoder Mar 23 '16 at 15:44
  • When you tried without modifying the ds prefix, did you use the SignatureValue generated from the SignedXml class, or did you calculate it yourself? In my solution I am not recalculating it. I am just grabbing the generated value from that Xml and replacing it with a structure matching how you've done to match their documentation. – Bon Mar 23 '16 at 15:56
  • And just another thing to make sure, you're using a certificate uploaded to the AE AIR TCC integration page and your submission references the proper corresponding ASID? – Bon Mar 23 '16 at 15:58
  • @Bon: Yes. I am also using the SignatureValue created by signedXML.ComputeSignature() method. Please refer my code above with "EDIT 2" in my original question. We just have one certificate which we uploaded and using the same in our application also. What is ASID? – SubCoder Mar 23 '16 at 16:04
  • 1
    @SubCoder 2 things that I notice that differ between yours and mine; which does not work either. **1.)** You have the `` element, which is not needed. This is needed only for UI submission. **2.)** The order of your `` element is different from mine: Timestamp, Header, Detail vs. (yours) Timestamp, Detail, Header. I'm not sure if this matters or not. Beyond that, I don't have the `osa1` prefix defined in the `Envelope`, although it is defined in my `InclusiveNamespaces.PrefixList`? – Russ Mar 23 '16 at 17:28
  • 1
    @SubCoder In your Signing: **1.)** You have `signedXml.SignedInfo.SignatureMethod` defined twice. I don't have this defined at all, but the `SignatureMethod` is still generated correctly. **2.)** I set `idElem` in the method you have commented out; and I don't have the other code you added. **3.)** The way you're creating the replacement `KeyInfo` element, we are doing differently as well. – Russ Mar 23 '16 at 17:34
  • @Russ: 1) `` element is available in the reference guide. Please refer Page #46 of latest reference guid. 2) I even tried the order you mentioned Timestamp, Header and Detail which does not make a difference. 3) `oas1` is defined in `InclusiveNameSpace` prefix list only in my envelope too 4) signedXml.SignedInfo.SignatureMethod declaring twice is removed and it does not make a difference. 5) I am not sure which line you were referring to for `idElem`. – SubCoder Mar 23 '16 at 17:55
  • @Russ: How can I make sure that my `SignatureValue` is correct and `KeyInfo` `KeyIdentifier` value is correct? – SubCoder Mar 23 '16 at 18:01
  • 1
    @SubCoder I think we have to trust the code is generating the `SignatureValue` appropriately. I was referring to the `idElem` in the `GetIdElement` method of `CustomIdSignedXml` class. **See Table 5-4 of page 45** For a clearer definition of what the `ACASecurityHeader`. I think you and I are actually having the same problems. I'm just trying to convey what I know as to be correct. – Russ Mar 23 '16 at 18:22
  • @Russ: Removed `ACASecurityHeader` and same security header error. Also `idElem` doe not make any difference either. Please let me know if you find anything positive. And I am out of clue now as to what more to try... :( – SubCoder Mar 23 '16 at 18:43
  • @Russ: For your information, couple months back when we were trying WSE3.0 to make this work, we got the status request working. But problem we had was, the response which was coming back as MTOM could not be handled by WSE3.0 classes. That is why we started researching other options. That time the issue was the correct certificate file was not uploaded to the IRS TCC Setup website. So check your certificate file which is uploaded to IRS website. – SubCoder Mar 23 '16 at 19:01
  • I have a strong feeling that it is because of the `SignatureValue` of the Security Header. Not sure how to validate that though. :( – SubCoder Mar 23 '16 at 21:25
  • @SubCoder @Bon: Can the `CheckSignature` method of the `SignedXml` class return false positives? I'm using that to validate my signature, but maybe you're running into a validation issue on the IRS side? – Russ Mar 23 '16 at 21:29
  • I've never heard of such a false positive. It is a straight forward comparison of cryptographic hashes, essentially just a byte-by-byte comparison. – Bon Mar 23 '16 at 22:01
  • @Bon What part of the Certificate is required for us to send as the value of the `KeyIdentifier` element? I'm programmatically retrieving the certificate through the `X509Store` and `X509CertificateCollection` objects. Basically, is there a specific `X509Certificate2` property I should be using? – Russ Mar 23 '16 at 22:28
  • 1
    Yeah but you need to make sure you're loading in the Microsoft.Web.Services3 namespace because that is where the BinarySecurityToken type comes from. In this next snippet, _cert is an X509Certificate2 object. BinarySecurityToken bst = new X509SecurityToken(_cert); var keyIdentifierValue = Convert.ToBase64String(bst.RawData); – Bon Mar 23 '16 at 22:52
  • 1
    I was using the following approach for calculating the base64 value from the certificate which is from `System.Security.Cryptography.X509Certificates.X509Certificate2` and this gives exact same value as the `BinarySecurityToken` from `Microsoft.Web.Services3`. Following is my code snippet. Still getting the security header error. `X509Certificate2 mycert = new X509Certificate2(Cert_Path, Cert_Password); var exported = mycert.Export(X509ContentType.Cert, Cert_Pass); var base64 = Convert.ToBase64String(exported);` – SubCoder Mar 24 '16 at 12:56
  • @Russ Any more progress on this that made this work? – SubCoder Mar 28 '16 at 13:55
  • @SubCoder Unfortunately, no. I am using the same snippet of code Bon posted to retrieve and use my Certificate. I am still receiving a **_message was not formatted properly and/or cannot be interpreted_** error against the Transmitter Service; and a **_WS Security Header invalid_** error against the Status Service. I am truly stumped here. – Russ Mar 28 '16 at 15:21
  • Here's another straw grasp attempt. Do I need to add the `X509Certificate2` object to the `HttpWebRequest` object (through `request.ClientCertificates.Add` method)? At the moment, I'm only using the certificate to create the signing in the SOAP Header. – Russ Mar 28 '16 at 21:49
  • No. There is no http level authentication. – Bon Mar 29 '16 at 18:22
  • @Bon Is the HttpWebRequest object the correct object to be using to submit the requests? – Russ Mar 30 '16 at 18:11
  • @Bon I have a question about how you used a custom behavior to pull in your cert. I have that part of it working, but did you also have to specify the ? If so, how did you know what values to use? Or is it possible to tell the application to not check for the serverCertificate? And thanks to all you guys for the comments -- it's been very helpful! – Nate Apr 01 '16 at 16:28
  • I abandoned WCF for this because I don't think it is possible to get it work with the required combination of MTOM, custom headers and outbound gzip. Sorry I don't think I can answer your question. – Bon Apr 01 '16 at 20:41
  • @Bon Oh, I misunderstood your original answer then. So that "edit" paragraph that you have means that the rest of the answer is no longer valid? I think I was reading it as though the entire thing was an edited response. I've started going down the manual route per your advice. – Nate Apr 02 '16 at 17:40
  • @Russ (and SubCoder) did either of you guys ever get yours to work? I've been reworking my project for the last several days and feel like I've correctly implemented everything manually, but I'm still getting TPE1105. Losing my mind over this thing :( – Nate Apr 07 '16 at 02:07
  • @Nate: No. Not working yet. I re-wrote the status request part alone manually to see if that works and I am still getting "WS Security Header Invalid (TPE1122)". I wanted to make that work and then try the bigger request with MTOM. If any of you get that working please let me know too. – SubCoder Apr 07 '16 at 16:29
  • @Nate (and SubCoder): I have not gotten either request to work yet. I have some certificate things to look into on Monday (when the person responsible for them gets back); but so far I have one solution which uses WCF for the Submission Request and manual SOAP XML (through HttpWebRequest) for the Status Request. The Submission is returning a WS Security error, and the Status is coming back and not being well-formed. I have another solution which does the Submission and Status both as Manual SOAP XML (through HttpWebRequest) and are returning the opposite errors on those. No progress :( – Russ Apr 07 '16 at 16:50
  • @Nate Trust me when I say I feel your pain in RE: to losing your mind over this. – Russ Apr 07 '16 at 16:50
  • We are currently using UI Channel for transmissions in production. No luck with the A2A yet. – SubCoder Apr 11 '16 at 20:17
  • Guys, Any updates or progress on the A2A transmissions? – SubCoder May 23 '16 at 18:35
  • @Russ: Did you find a solution for making A2A approach work with a .NET application? – SubCoder Nov 02 '16 at 20:49
  • @SubCoder yes, we are successfully transmitting to the IRS through the A2A via a .NET application. Please see http://stackoverflow.com/questions/36021040/irs-a2a-bulkrequesttransmitter-message-not-formmatted-properly-and-or-cannot-be/37889878#37889878. I believe that was the last post which took me down the correct path. – Russ Nov 03 '16 at 22:17
  • @Russ: Glad to know that it worked for you. I will have a look at the thread you mentioned. Thank you. – SubCoder Nov 21 '16 at 15:33
0

I do not yet have the reputation to actually post a comment on your posts >:(

Here are a couple of follow-up questions for you regarding the process you are using.

  1. Are you using the WSDL Service Reference/Proxy classes to make your calls to the IRS through the ISS-A2A Channel?
  2. After implementing the three class files from the samples, I am receiving the following error. Do you see anything out of the ordinary that I am doing incorrectly?

Additional information: The type '[Project].GZipEncoder.GzipMessageEncodingElement, GZipEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' registered for extension 'gzipMessageEncoding' could not be loaded.

The <gzipMessageEncoding> element in my <customBinding> is giving me a warning which I think is related to the above error.

app.config

<system.serviceModel>
  <extensions>
    <bindingElementExtensions>
      <add name="gzipMessageEncoding" type="[ProjectName].GZipEncoder.GzipMessageEncodingElement, GZipEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </bindingElementExtensions>
  </extensions>
  <client>
    <endpoint />
    <metadata>
      <policyImporters>
        <extension type="[ProjectName].GZipEncoder.GZipMessageEncodingBindingElementImporter, GZipEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </policyImporters>
    </metadata>
  </client>
  <bindings>
    <customBinding>
      <binding name="BulkRequestTransmitterBinding">
        <gzipMessageEncoding innerMessageEncoding="textMessageEncoding" />
        <httpsTransport />
      </binding>
    </customBinding>
  </bindings>
</system.serviceModel>
Russ
  • 678
  • 8
  • 26
  • Hi Russ, We using WSDL Service Reference/Proxy classes to make our calls to the IRS through the ISS-A2A Channel. We tried GZip custom encoder classes, but backed off from that approach since some of our online research show that it could cause memory leaks when large requests are processed. – SubCoder Feb 16 '16 at 16:37
  • @Subhash, Thank you for the response. If not using the GZip custom encoder classes, what approach have you ended up using in order to compress your request to the IRS? – Russ Feb 16 '16 at 17:52
  • Additionally, how large were the requests you were testing which were causing the memory leaks? – Russ Feb 17 '16 at 00:58
  • Russ, We tried WSE 3.0 which worked for the most part for us except for the one issue with TImestamp element order is not correct in the security header. We are still stuck with the Security Header Error issue. We did not try GZip custom encoder for large files. We used only AATS test scenarios. – SubCoder Feb 23 '16 at 23:10
  • @Russ did this specific issue ever have a solution in your config file? – Das Dec 18 '18 at 20:47
  • @Das Unfortunately, I don't recall the issue I was having above. My code is currently working without any errors. In reviewing at the app.config file, I do have a warning on the `gzipMessageEncoding` element saying it has an invalid child element; however, it is a warning and not an error, and it doesn't seem to be causing any issues. – Russ Dec 19 '18 at 21:06