Imports System Imports System.Text Imports System.Diagnostics Imports System.IO Imports Sc14n ' ' * $Id: TestSc14n.vb $ ' * Last updated: ' * $Date: 2019-12-11 09:01 $ ' * $Version: 2.1.0 $ ' ' Some tests using the SC14N .NET interface. ' * ' * Requires `Sc14n` to be installed on your system: available from <http://cryptosys.net/sc14n/> ' * Add a reference to `diSc14nNet.dll` ' * ' * Test files, e.g. `olamundo.xml`, are in `sc14n-testfiles.zip`. These must be in the CWD. ' * ' * This is a Console Application written for target .NET Framework 4.0 and above ' * Please report any bugs to <https://cryptosys.net/contact> ' '****************************** LICENSE *********************************** ' * Copyright (C) 2017-19 David Ireland, DI Management Services Pty Limited. ' * All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net> ' * The code in this module is licensed under the terms of the MIT license. ' * For a copy, see <http://opensource.org/licenses/MIT> '**************************************************************************** ' ' Ported from C# to VB.NET using icsharpcode.net's SharpDevelop. Namespace TestSc14nNet Class TestSc14nNet Public Shared Sub Main(args As String()) Dim n As Integer, r As Integer Dim s As String, fname As String, oname As String, digval As String, digval1 As String, digok As String Dim dig1 As String, dig2 As String, dig3 As String, dig4 As String, dig5 As String, dig6 As String Dim b As Byte() ' SHOW GENERAL INFO ABOUT THE CORE LIBRARY DLL n = Gen.Version() Console.WriteLine("Version={0}", n) Console.WriteLine("Platform={0}", Gen.Platform()) Console.WriteLine("ModuleName={0}", Gen.ModuleName()) Console.WriteLine("CompileTime={0}", Gen.CompileTime()) Console.WriteLine("LicenceType={0}", Gen.LicenceType()) ' DO TESTS ON INPUT.XML (these are from the manual) Console.WriteLine("FILE: {0}", "input.xml") ' Example 1. Excludes the first element with the tag name <Signature> r = C14n.ToFile("c14nfile1.txt", "input.xml", "Signature", Tran.OmitByTag) Debug.Assert(0 = r, "C14n.ToFile failed") ' Example 2. Finds and transforms the first element with the tag name <SignedInfo> r = C14n.ToFile("c14nfile2.txt", "input.xml", "SignedInfo", Tran.SubsetByTag) Debug.Assert(0 = r, "C14n.ToFile failed") ' Example 3. Finds and transforms the third element with the tag name <Data> r = C14n.ToFile("c14nfile3.txt", "input.xml", "Data[3]", Tran.SubsetByTag) Debug.Assert(0 = r, "C14n.ToFile failed") ' Example 4. Finds and transforms the element with attribute Id="foo" r = C14n.ToFile("c14nfile4.txt", "input.xml", "foo", Tran.SubsetById) Debug.Assert(0 = r, "C14n.ToFile failed") ' Example 5. Finds and transforms the element with attribute ID="bar" r = C14n.ToFile("c14nfile5.txt", "input.xml", "ID=bar", Tran.SubsetById) Debug.Assert(0 = r, "C14n.ToFile failed") ' Example 6. Excludes element with attribute Id="thesig" r = C14n.ToFile("c14nfile6.txt", "input.xml", "thesig", Tran.OmitById) Debug.Assert(0 = r, "C14n.ToFile failed") ' REDO LAST TESTS BUT COMPUTE DIGEST INSTEAD OF CREATING NEW FILE ' Example 1. Excludes the first element with the tag name <Signature> digval = C14n.ToDigest("input.xml", "Signature", Tran.OmitByTag, DigAlg.Sha1) Console.WriteLine("DIG1={0}", digval) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") dig1 = digval ' Example 2. Finds and transforms the first element with the tag name <SignedInfo> digval = C14n.ToDigest("input.xml", "SignedInfo", Tran.SubsetByTag, DigAlg.Sha1) Console.WriteLine("DIG2={0}", digval) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") dig2 = digval ' Example 3. Finds and transforms the third element with the tag name <Data> digval = C14n.ToDigest("input.xml", "Data[3]", Tran.SubsetByTag, DigAlg.Sha1) Console.WriteLine("DIG3={0}", digval) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") dig3 = digval ' Example 4. Finds and transforms the element with attribute Id="foo" digval = C14n.ToDigest("input.xml", "foo", Tran.SubsetById, DigAlg.Sha1) Console.WriteLine("DIG4={0}", digval) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") dig4 = digval ' Example 5. Finds and transforms the element with attribute ID="bar" digval = C14n.ToDigest("input.xml", "ID=bar", Tran.SubsetById, DigAlg.Sha1) Console.WriteLine("DIG5={0}", digval) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") dig5 = digval ' Example 6. Excludes element with attribute Id="thesig" digval = C14n.ToDigest("input.xml", "thesig", Tran.OmitById, DigAlg.Sha1) Console.WriteLine("DIG6={0}", digval) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") dig6 = digval Console.WriteLine("NOTE: Should have DIG1==DIG6 and DIG3==DIG4 above.") Debug.Assert(dig1 = dig6 AndAlso dig3 = dig4, "Digests do not match expected values") ' Transform entire file fname = "olamundo.xml" oname = "olamundo-out.xml" Console.WriteLine("FILE: {0}", fname) n = C14n.ToFile(oname, fname) Console.WriteLine("C14n.ToFile()->{0} returns {1} (expected 0 => OK)", oname, n) Debug.Assert(0 = n, "C14n.ToFile failed") ' Compute digest of entire file digval = C14n.ToDigest(fname, 0) Console.WriteLine("C14n.ToDigest({0})={1}", fname, digval) ' and do the same to the transformed file we made above digval1 = C14n.ToDigest(oname, 0) Console.WriteLine("C14n.ToDigest({0})={1}", oname, digval1) Debug.Assert(digval = digval1) ' Same data, different encoding plus UTF-8 Byte Order Mark fname = "olamundo-utf8bom.xml" oname = "olamundo-utf8bom-out.xml" Console.WriteLine("FILE: {0}", fname) digval = C14n.ToDigest(fname, 0) Console.WriteLine("C14n.ToDigest({0})={1}", fname, digval) ' -- we can transform (X)HTML files, too. ' This example is used in a detached signature: see `detached.xml` fname = "abc.html" oname = "abc-c14n-html.txt" Console.WriteLine("FILE: {0}", fname) n = C14n.ToFile(oname, fname) Console.WriteLine("C14n.ToFile()->{0} returns {1} (expected 0 => OK)", oname, n) If n <> 0 Then Console.WriteLine(displayError(n)) End If Debug.Assert(0 = n, "C14n.ToFile failed") ' Display entire file after transforming... s = System.Text.Encoding.UTF8.GetString(C14n.ToBytes(fname)) Console.WriteLine("C14N('{0}'):", fname) Console.WriteLine(s) ' Compute SHA-1 digest of entire file digval = C14n.ToDigest(fname, 0) Console.WriteLine("C14n.ToDigest({0})={1}", fname, digval) ' and do the same to the transformed file we made above digval1 = C14n.ToDigest(oname, 0) Console.WriteLine("C14n.ToDigest({0})={1}", oname, digval1) Debug.Assert(digval = digval1) ' Same again but using SHA-256 digval = C14n.ToDigest(fname, DigAlg.Sha256) Console.WriteLine("SHA256('{0}'): {1}", fname, digval) ' Extract and transform the body element ' Output to a byte array fname = "olamundo-base.xml" Console.WriteLine("FILE: {0}", fname) b = C14n.ToBytes(fname, "Body", Tran.SubsetByTag) Debug.Assert(b.Length > 0, "C14n.ToBytes failed") Console.WriteLine("C14n.ToBytes(SubsetByTag) returns {0} bytes.", b.Length) ' Note this a byte array containing UTF-8-encoded text, so be careful printing Console.WriteLine("C14N(Body):") Console.WriteLine(System.Text.Encoding.UTF8.GetString(b)) ' Compute SHA-1 digest value of the XML document excluding the <Signature> element ' ... this is the value to be inserted into <SignedInfo> digval = C14n.ToDigest(fname, "Signature", Tran.OmitByTag, DigAlg.Sha1) Console.WriteLine("DIGVAL:") Console.WriteLine(digval) ' Extract the SignedInfo element into memory ' Note %digval% parameter to be completed b = C14n.ToBytes(fname, "SignedInfo", Tran.SubsetByTag) Debug.Assert(b.Length > 0, "C14n.ToBytes failed") Console.WriteLine("SIGNEDINFO (BASE):") Console.WriteLine(System.Text.Encoding.UTF8.GetString(b)) ' Insert the required DigestValue we prepared earlier ' Note the SignedInfo element is *always* US-ASCII encoded, ' so we can use the more convenient String.Replace function s = System.Text.Encoding.UTF8.GetString(b).Replace("%digval%", digval) Console.WriteLine("SIGNEDINFO (COMPLETED):") Console.WriteLine(s) ' Now compute the digest value of this string ' We could use this to compute the required signature value. ' See the module `TestScn14PKI` for a full example using a cryptographic library. digval1 = C14n.ToDigest(System.Text.Encoding.UTF8.GetBytes(s), DigAlg.Sha1) Console.WriteLine("SHA1(signedinfo)= {0}", digval1) ' USE EXCLUSIVE C14N ' Examples from Section 2.2 of Exclusive XML Canonicalization Version 1.0 [RFC 3741] ' Use inclusive method fname = "example1.xml" oname = "example1-incl-out.xml" Console.WriteLine() Console.WriteLine("FILE: {0}", fname) Console.WriteLine("Using inclusive c14n:") r = C14n.ToFile(oname, fname, "n1:elem2", Tran.SubsetByTag) Debug.Assert(0 = r, "C14n.ToFile failed") b = C14n.ToBytes(fname, "n1:elem2", Tran.SubsetByTag) Debug.Assert(b.Length > 0, "C14n.ToBytes failed") Console.WriteLine(System.Text.Encoding.UTF8.GetString(b)) digval = C14n.ToDigest(fname, "n1:elem2", Tran.SubsetByTag, DigAlg.Sha1) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") digok = "RSTxYngjk7kroYxpMtbJP2g7Q3s=" Console.WriteLine("SHA1(subset)= {0}", digval) Console.WriteLine("Correct SHA1= {0}", digok) Debug.Assert(digval = digok, "Digests do not match") fname = "example2.xml" oname = "example2-incl-out.xml" Console.WriteLine() Console.WriteLine("FILE: {0}", fname) Console.WriteLine("Using inclusive c14n:") r = C14n.ToFile(oname, fname, "n1:elem2", Tran.SubsetByTag) Debug.Assert(0 = r, "C14n.ToFile failed") b = C14n.ToBytes(fname, "n1:elem2", Tran.SubsetByTag) Debug.Assert(b.Length > 0, "C14n.ToBytes failed") Console.WriteLine(System.Text.Encoding.UTF8.GetString(b)) digval = C14n.ToDigest(fname, "n1:elem2", Tran.SubsetByTag, DigAlg.Sha1) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") digok = "x9seNaaK3lTVs9n2WIIrIgDDU1E=" Console.WriteLine("SHA1(subset)= {0}", digval) Console.WriteLine("Correct SHA1= {0}", digok) Debug.Assert(digval = digok, "Digests do not match") ' Use exclusive method - outputs should be identical fname = "example1.xml" oname = "example1-excl-out.xml" Console.WriteLine() Console.WriteLine("FILE: {0}", fname) Console.WriteLine("Using exclusive c14n:") r = C14n.ToFile(oname, fname, "n1:elem2", Tran.SubsetByTag, TranMethod.Exclusive) Debug.Assert(0 = r, "C14n.ToFile failed") b = C14n.ToBytes(fname, "n1:elem2", Tran.SubsetByTag, TranMethod.Exclusive) Debug.Assert(b.Length > 0, "C14n.ToBytes failed") Console.WriteLine(System.Text.Encoding.UTF8.GetString(b)) digval = C14n.ToDigest(fname, "n1:elem2", Tran.SubsetByTag, DigAlg.Sha1, TranMethod.Exclusive) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") digok = "qYwgpdgV1/b3PQ3aSpMx9wKGtqY=" Console.WriteLine("SHA1(subset)= {0}", digval) Console.WriteLine("Correct SHA1= {0}", digok) ' Correct SHA1=qYwgpdgV1/b3PQ3aSpMx9wKGtqY= Debug.Assert(digval = digok, "Digests do not match") fname = "example2.xml" oname = "example2-excl-out.xml" Console.WriteLine() Console.WriteLine("FILE: {0}", fname) Console.WriteLine("Using exclusive c14n:") r = C14n.ToFile(oname, fname, "n1:elem2", Tran.SubsetByTag, TranMethod.Exclusive) Debug.Assert(0 = r, "C14n.ToFile failed") b = C14n.ToBytes(fname, "n1:elem2", Tran.SubsetByTag, TranMethod.Exclusive) Debug.Assert(b.Length > 0, "C14n.ToBytes failed") Console.WriteLine(System.Text.Encoding.UTF8.GetString(b)) digval = C14n.ToDigest(fname, "n1:elem2", Tran.SubsetByTag, DigAlg.Sha1, TranMethod.Exclusive) Debug.Assert(digval.Length > 0, "C14n.ToDigest failed") digok = "qYwgpdgV1/b3PQ3aSpMx9wKGtqY=" Console.WriteLine("SHA1(subset)= {0}", digval) Console.WriteLine("Correct SHA1= {0}", digok) ' Correct SHA1=qYwgpdgV1/b3PQ3aSpMx9wKGtqY= Debug.Assert(digval = digok, "Digests do not match") ' Show use of PrefixList with excl-c14n fname = "soap-ts3-signed-by-alice.xml" Console.WriteLine() Console.WriteLine("FILE: {0}", fname) Console.WriteLine("Using exclusive c14n with PrefixList...") ' ' <ds:Reference URI="#TS-3"> ' <ds:Transforms> ' <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> ' <ec:InclusiveNamespaces PrefixList="wsse SOAP-ENV" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" /> ' </ds:Transform> ' </ds:Transforms> ' <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> ' ' Transform element with wsu:Id="TS-3" using excl-c14n with PrefixList="wsse SOAP-ENV" b = C14n.ToBytes(fname, "wsu:Id=TS-3", Tran.SubsetById, TranMethod.Exclusive, "wsse SOAP-ENV") Debug.Assert(b.Length > 0, "C14n.ToBytes failed") Console.WriteLine(System.Text.Encoding.UTF8.GetString(b)) ' Compute SHA-256 digest (to be inserted into <DigestValue> element) digok = "a4cojI7ZDOI1lKvGD7OHNus7qy1DQgpqNdGZ/YEDJQo=" digval = C14n.ToDigest(fname, "wsu:Id=TS-3", Tran.SubsetById, DigAlg.Sha256, TranMethod.Exclusive, "wsse SOAP-ENV") Console.WriteLine("SHA256(#TS-3) = {0}", digval) Console.WriteLine("Correct SHA256 = {0}", digok) Debug.Assert(digval = digok, "Digests do not match") ' Transform SignedInfo using excl-c14n with PrefixList="SOAP-ENV" ' ' <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> ' <ec:InclusiveNamespaces PrefixList="SOAP-ENV" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" /> ' </ds:CanonicalizationMethod> ' ' Compute SHA-256 digest (to be used to compute the SignatureValue using crypto toolkit) digok = "VenfIoZjs3/LxtvQdQuHIizR3vKi7TViE1ZF7Ddnn8I=" digval = C14n.ToDigest(fname, "ds:SignedInfo", Tran.SubsetByTag, DigAlg.Sha256, TranMethod.Exclusive, "SOAP-ENV") Console.WriteLine("SHA256(ds:SignedInfo)= {0}", digval) Console.WriteLine("Correct SHA256 = {0}", digok) Debug.Assert(digval = digok, "Digests do not match") ' TEST "FLATTEN" OPTION ADDED IN V2.1 fname = "ignorable_ws.xml" Console.WriteLine() Console.WriteLine("FILE: {0}", fname) Console.WriteLine("Default without flatten:") b = C14n.ToBytes(fname, "", Tran.Entire, advOpts:=AdvOptions.[Default]) Debug.Assert(0 = r, "C14n.ToBytes failed") Console.WriteLine(System.Text.Encoding.UTF8.GetString(b)) digok = "JNluoz+Z+MbLrTX8W//wEEgeFpo=" digval = C14n.ToDigest(fname, "", Tran.Entire, DigAlg.Sha1, advOpts:=AdvOptions.[Default]) Console.WriteLine("SHA1(NO-FLATTEN)= {0}", digval) Console.WriteLine("Correct SHA1 = {0}", digok) Console.WriteLine("With flatten option:") b = C14n.ToBytes(fname, "", Tran.Entire, advOpts:=AdvOptions.Flatten) Debug.Assert(0 = r, "C14n.ToBytes failed") Console.WriteLine(System.Text.Encoding.UTF8.GetString(b)) digok = "4ZKWJnP7dUperStlOKrq7athzxw=" digval = C14n.ToDigest(fname, "", Tran.Entire, DigAlg.Sha1, advOpts:=AdvOptions.Flatten) Console.WriteLine("SHA1(FLATTEN)= {0}", digval) Console.WriteLine("Correct SHA1 = {0}", digok) Console.WriteLine(vbLf & "ALL DONE.") End Sub ''' <summary> ''' Display last error status ''' </summary> ''' <param name="errCode">Error code (+ve or -ve)</param> ''' <returns>String containing error status</returns> Private Shared Function displayError(errCode As Integer) As String Dim se As String = Err.LastError() Dim s As String = String.Format("ERROR {0}: ", (If(errCode < 0, -errCode, errCode))) s += Err.ErrorLookup(errCode) If se.Length > 0 Then s += ": " & se End If Return s End Function End Class End Namespace