With my current console code, I feel that I am 90% there but it's the last 10% which is failing me. Before I start, this is my first ever app which works with XML so my knowledge on the subject is scarse!
So I have the XML document below, and I want to digitally sign only the section <patientRole>, but I cannot figger out how to do it in my code. With the code I have so far, I get the error "Malformed reference element".
The error occurs at the line:
signedXml.ComputeSignature()
Can someone please help me out here?
I can send you the full source code if you need it- just let me know.
My code:
Sub Main(ByVal args() As String) Try Call ReadCommandLineArgs() If Environment.ExitCode >= 5 Then Throw New ArgumentException("Bad Arguments Specified") ' Create a new CspParameters object to specify ' a key container. Dim cspParams As New CspParameters() cspParams.KeyContainerName = "XML_DSIG_RSA_KEY" ' Create a new RSA signing key and save it in the container. Dim rsaKey As New RSACryptoServiceProvider(cspParams) ' Create a new XML document. Dim xmlDoc As New XmlDocument() ' Load an XML file into the XmlDocument object. xmlDoc.PreserveWhitespace = True ' Try to load the file. An error will occur if this fails due to path or filename errors. Try xmlDoc.Load(gFileNameAndPath) Catch exFile As System.IO.DirectoryNotFoundException Environment.ExitCode = Result.ERROR_PATH_NOT_FOUND Throw New Exception("Folder Not Found") Catch exFile As System.IO.FileNotFoundException Environment.ExitCode = Result.ERROR_FILE_NOT_FOUND Throw New Exception("File Not Found") Catch exfile As Exception Environment.ExitCode = Result.ERROR_GENERAL_ERROR Throw New Exception("Unknown Error while opening XML document:" & vbNewLine & _"Description: " & exfile.Message.ToString & vbNewLine & _"Error Code: " & exfile.HResult) End Try Select Case gDirection Case "sign" ' Sign the XML document. SignXml(xmlDoc, gElementTag, rsaKey) Console.WriteLine("XML file signed.") ' Save the document. xmlDoc.Save(gFileNameAndPath) Environment.ExitCode = Result.RESULT_FILE_SIGNED_OK Case "read" ' Verify the signature of the signed XML. Console.WriteLine("Verifying signature...") Dim ReadSignatureResult As Boolean = VerifyXml(xmlDoc, gElementTag, rsaKey) ' Display the results of the signature verification to ' the console. If ReadSignatureResult Then Console.WriteLine("The XML signature is valid.") Environment.ExitCode = Result.RESULT_FILE_SIGNATURE_VERIFIED_OK Else Console.WriteLine("The XML signature is not valid.") Environment.ExitCode = Result.RESULT_FILE_SIGNATURE_VERIFIED_NOT_OK End If End Select Catch e As Exception ' Just catch all exceptions.... gExceptionFound = True gExceptionMessage = e.Message.ToString Finally If Not gExceptionFound Then gExceptionMessage = "OK" End If Console.WriteLine(gExceptionMessage & ":" & [Enum].GetName(GetType(Result), Environment.ExitCode)) End Try End Sub Private Sub ReadCommandLineArgs() Dim CommandLineArgs As System.Collections.ObjectModel.ReadOnlyCollection(Of String) = My.Application.CommandLineArgs Try gDirection = CommandLineArgs(0) gElementTag = CommandLineArgs(1) gFileNameAndPath = CommandLineArgs(2) Catch ex As Exception End Try gDirection = gDirection.ToLower Select Case gDirection.ToLower Case "sign" Case "read" Case Else Environment.ExitCode = Result.ERROR_NO_COMMAND_GIVEN Throw New Exception("No command given") End Select If String.IsNullOrEmpty(gElementTag) Then Environment.ExitCode = Result.ERROR_BAD_ARGUMENTS End If If String.IsNullOrEmpty(gFileNameAndPath) Then Environment.ExitCode = Result.ERROR_BAD_ARGUMENTS End If ' Catch ex As Exception If Environment.ExitCode >= 5 Then Throw New Exception("Something is wrong with the number of arguments given:" & vbNewLine & _"Direction: [" & gDirection & "]" & vbNewLine & _"Element Tag: [" & gElementTag & "]" & vbNewLine & _"Filename: [" & gFileNameAndPath & "]") End If End Sub ' Sign an XML file. ' This document cannot be verified unless the verifying ' code has the key with which it was signed. Sub SignXml(ByVal m_xmlDoc As XmlDocument, ByVal mElementTag As String, ByVal rsaKey As RSA) ' Check arguments. If m_xmlDoc Is Nothing Then Throw New ArgumentException("xmlDoc") End If If rsaKey Is Nothing Then Throw New ArgumentException("Key") End If ' Create a SignedXml object. Dim signedXml As New SignedXml(m_xmlDoc) ' Add the key to the SignedXml document. signedXml.SigningKey = rsaKey ' Create a reference to be signed. Dim reference As New Reference() ' Change the following string to sign part of a document. ' ********** reference.Uri = "#" & mElementTag ' ********** ' Find the "Signature" node and create a new ' XmlNodeList object. Dim nodeList As XmlNodeList = m_xmlDoc.GetElementsByTagName(mElementTag) If nodeList.Count = 0 Then Environment.ExitCode = Result.ERROR_TAG_NOT_FOUND Throw New CryptographicException("Signature failed. No tag named [" & reference.Uri & "] was found in the document.") End If If nodeList.Count > 1 Then Environment.ExitCode = Result.ERROR_TAG_NOT_UNIQUE Throw New CryptographicException("Signature failed. More than one tag named [" & reference.Uri & "] was found in the document.") End If ' Add an enveloped transformation to the reference. Dim env As New XmlDsigEnvelopedSignatureTransform() reference.AddTransform(env) ' Add the reference to the SignedXml object. signedXml.AddReference(reference) ' Compute the signature. signedXml.ComputeSignature() ' Get the XML representation of the signature and save ' it to an XmlElement object. Dim xmlDigitalSignature As XmlElement = signedXml.GetXml() ' Append the element to the XML document. m_xmlDoc.DocumentElement.AppendChild(m_xmlDoc.ImportNode(xmlDigitalSignature, True)) End Sub
This is the first part of the XML file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="CDA.xsl"?><!-- Title: US_Realm_Header_Template --><ClinicalDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:hl7-org:v3 Updated_CDA_Schema_Files_Extension_Support/CDA_Schema_Files/infrastructure/cda/CDA_SDTC.xsd" xmlns="urn:hl7-org:v3" xmlns:cda="urn:hl7-org:v3" xmlns:sdtc="urn:hl7-org:sdtc"><!-- ******************************************************** CDA Header ******************************************************** --><realmCode code="US"/><typeId root="2.16.840.1.113883.1.3" extension="POCD_HD000040"/><!-- US General Header Template --><templateId root="2.16.840.1.113883.10.20.22.1.1" /><!-- *** Note: The next templateId, code and title will differ depending on what type of document is being sent. *** --><!-- conforms to the document specific requirements --><templateId root="2.16.840.1.113883.10.20.22.1.2"/><id extension="TT988" root="2.16.840.1.113883.19.5.99999.1"/><code codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" code="34133-9" displayName="Summarization of Episode Note"/><title>Community Health and Hospitals: Health Summary</title><effectiveTime value="201209150000-0400"/><confidentialityCode code="N" codeSystem="2.16.840.1.113883.5.25"/><languageCode code="en-US"/><setId extension="sTT988" root="2.16.840.1.113883.19.5.99999.19"/><versionNumber value="1"/><recordTarget><patientRole><id extension="998991" root="2.16.840.1.113883.19.5.99999.2"/><!-- Fake ID using HL7 example OID. --><id extension="111-00-2330" root="2.16.840.1.113883.4.1"/><!-- Fake Social Security Number using the actual SSN OID. --><addr use="HP"><!-- HP is "primary home" from codeSystem 2.16.840.1.113883.5.1119 --><streetAddressLine>1357 Amber Drive</streetAddressLine><city>Beaverton</city><state>OR</state><postalCode>97867</postalCode><country>US</country><!-- US is "United States" from ISO 3166-1 Country Codes: 1.0.3166.1 --></addr><telecom value="tel:(816)276-6909(816)276-6909
(816)276-6909
(816)276-6909" use="HP"/><!-- HP is "primary home" from HL7 AddressUse 2.16.840.1.113883.5.1119 --><patient><name use="L"><!-- L is "Legal" from HL7 EntityNameUse 2.16.840.1.113883.5.45 --><given>Isabella</given><given>Isa</given><!-- CL is "Call me" from HL7 EntityNamePartQualifier 2.16.840.1.113883.5.43 --><family>Jones</family></name><administrativeGenderCode code="F" codeSystem="2.16.840.1.113883.5.1" displayName="Female"/><birthTime value="19750501"/></patient><providerOrganization><id root="2.16.840.1.113883.4.6"/><name>Community Health and Hospitals</name><telecom use="WP" value="tel: 555-555-5000"/><addr><streetAddressLine>1001 Village Avenue</streetAddressLine><city>Portland</city><state>OR</state><postalCode>99123</postalCode><country>US</country></addr></providerOrganization></patientRole></recordTarget>