root namespace is added into the <xades:SignedProperties> - xml-signature

library: apache Santuario + xades4j.
using xpathto select elements and sign them.
If I try to sign a simple XML without a namespace and verify the signature, it works well , but if the XML defines a namespace, for example the XML following:
<ClinicalDocument xmlns="urn:hl7-org:v3">
<element1tobesigned.../>
<element2tobesigned.../>
</ClinicalDocument>
and the exception was found when verifying the signature
858 WARN [main] org.apache.xml.security.signature.Reference - Verification failed for URI "#xmldsig-5fb20abe-b14c-4d84-a908-e22e776cd6f1-signedprops"
858 WARN [main] org.apache.xml.security.signature.Reference - Expected Digest: q0WnWFf9j0kcT46t5cXmcPnVvu5o51oAcmej/SjCazQ=
858 WARN [main] org.apache.xml.security.signature.Reference - Actual Digest: 41zXKVkRCsxUYpNZXW5b9KkZlTC9LM9WA8O7WHQz1Rg=
xades4j.verification.ReferenceValueException: Reference '#xmldsig-5fb20abe-b14c-4d84-a908-e22e776cd6f1-signedprops' cannot be validated
the cause is that XML namespace (urn:hl7-org:v3) was added into the xades:SignedProperties then the digest became different .
858 DEBUG [main] org.apache.xml.security.utils.DigesterOutputStream - Pre-digested input
858 DEBUG [main] org.apache.xml.security.utils.DigesterOutputStream - <xades:SignedProperties xmlns="urn:hl7-org:v3" ........./>
here is the signature generation code
XadesTSigningProfile profile = new XadesTSigningProfile(keyProvider);
profile.withTimeStampTokenProvider(TestTimeStampTokenProvider.class)
.withAlgorithmsProviderEx(ExclusiveC14nForTimeStampsAlgorithmsProvider.class);
XadesSigner signer = profile.newSigner();
DataObjectDesc obj1 = new DataObjectReference("")
.withTransform(new ExclusiveCanonicalXMLWithoutComments())
.withTransform( new XPathTransform(xPath);
SignedDataObjects dataObjs = new SignedDataObjects().withSignedDataObject(obj1);
changed 2012-11-20 begin
// signer.sign(dataObjs, docToSign.getDocumentElement() );
new Enveloped(signer).sign(docToSign.getDocumentElement());
changed 2012-11-20 end
and here is the verify code
NodeList signatureNodeList = getSigElement(getDocument("my/my-document.signed.bes.countersign.xml"));
for (int i = 0; i < signatureNodeList.getLength(); i++) {
Element signatureNode = (Element) signatureNodeList.item(i);
verifySignature(signatureNode, new XadesVerificationProfile(VerifierTestBase.validationProviderMySigs));
log.info("successful validation");
}
public static XAdESForm verifySignature(Element sigElem,
XadesVerificationProfile p) throws Exception {
XAdESVerificationResult res = p.newVerifier().verify(sigElem, null);
return res.getSignatureForm();
}
It looks like that there is a document about this problem in Apache Santuario FAQ ,
2.6. I sign a document and when I try to verify using the same key, it fails
After you have created the XMLSignature object, before you sign the document, you must embed the signature element in the owning document (using a call to XMLSignature.getElement() to retrieve the newly created Element node from the signature) before calling the XMLSignature.sign() method,
During canonicalisation of the SignedInfo element, the library looks at the parent and ancestor nodes of the Signature element to find any namespaces that the SignedInfo node has inherited. Any that are found are embedded in the canonical form of the SignedInfo. (This is not true when Exclusive Canonicalisation is used, but it is still good practice to insert the element node prior to the sign() method being called).
If you have not embedded the signature node in the document, it will not have any parent or ancestor nodes, so it will not inherit their namespaces. If you then embed it in the document and call verify(), the namespaces will be found and the canonical form of SignedInfo will be different to that generated during sign().
also there is a document about this problem as following
https://stackoverflow.com/a/12759909/1809884
It looks like that it is not a bug of xades4j, but a xml signature problem.
--add 2012-11-15
here is how to get the docToSign . in fact , i just reused the code in class SignatureServicesTestBase . so i am sure that it is namespaceaware.
static
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
db = dbf.newDocumentBuilder();
}
public static Document getDocument(String fileName) throws Exception
{
String path = toPlatformSpecificXMLDirFilePath(fileName);
Document doc = db.parse(new FileInputStream(path));
// Apache Santuario now uses Document.getElementById; use this convention for tests.
Element elem = doc.getDocumentElement();
DOMHelper.useIdAsXmlId(elem);
return doc;
}
and docToSign is return by calling SignatureServicesTestBase.getDocument()
Document docToSign = SignatureServicesTestBase.getDocument("my/cdamessage.xml");
and the SignedProperties element as following
<xades:SignedSignatureProperties>
<xades:SigningTime>2012-11-15T13:58:26.167+09:00</xades:SigningTime>
<xades:SigningCertificate>
<xades:Cert>
<xades:CertDigest>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>4btVb5gQ5cdcNhGpvDSWQZabPQrR9jf1x8e3YF9Ajss=</ds:DigestValue>
</xades:CertDigest>
<xades:IssuerSerial>
<ds:X509IssuerName>CN=Itermediate,OU=CC,O=ISEL,C=PT</ds:X509IssuerName>
<ds:X509SerialNumber>-119284162484605703133798696662099777223</ds:X509SerialNumber>
</xades:IssuerSerial>
</xades:Cert>
<xades:Cert>
<xades:CertDigest>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>vm5QpbblsWV7fCYXotPhNTeCt4nk8cLFuF36L5RJ4Ok=</ds:DigestValue>
</xades:CertDigest>
<xades:IssuerSerial>
<ds:X509IssuerName>CN=TestCA,OU=CC,O=ISEL,C=PT</ds:X509IssuerName>
<ds:X509SerialNumber>-46248926895392336918291885380930606289</ds:X509SerialNumber>
</xades:IssuerSerial>
</xades:Cert>
<xades:Cert>
<xades:CertDigest>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>AUaN+IdhKQqxIVmEOrFwq+Dn22ebTkXJqD3BoOP/x8E=</ds:DigestValue>
</xades:CertDigest>
<xades:IssuerSerial>
<ds:X509IssuerName>CN=TestCA,OU=CC,O=ISEL,C=PT</ds:X509IssuerName>
<ds:X509SerialNumber>-99704378678639105802976522062798066869</ds:X509SerialNumber>
</xades:IssuerSerial>
</xades:Cert>
</xades:SigningCertificate>
</xades:SignedSignatureProperties>
</xades:SignedProperties>
also , i use xpath to get the elements to be signed, and namespace(xmlns="urn:hl7-org:v3" ) is add into the result as well .
543 DEBUG [main] org.apache.xml.security.utils.ElementProxy - setElement("ds:Transform", "null")
544 DEBUG [main] org.apache.xml.security.utils.ElementProxy - setElement("dsig-xpath:XPath", "null")
658 DEBUG [main] org.apache.xml.security.utils.DigesterOutputStream - Pre-digested input:
658 DEBUG [main] org.apache.xml.security.utils.DigesterOutputStream - <component xmlns="urn:hl7-org:v3" Id="ES" contextConductionInd="true" typeCode="COMP">
<section classCode="DOCSECT" moodCode="EVN">
<code code="ES" codeSystem="2.16.840.1.113883.6.1" codeSystemName="SectionCode" codeSystemVersion="1.0" displayName="english"></code>
<text>english</text>
</section>
</component>
something wrong with xpath ? xpath is driving my crazy . I think i have to study xpath from beginning now.
chris

You're creating an enveloped signature but the enveloped signature transform is missing! Since the whole document is being signed the signature node itself has to be excluded, because some of its contents change after signature calculation.
Can't believe how I didn't see it until you mentioned the Enveloped class. Btw, this class is just an utility class for simple, straightforward enveloped sigantures. It robably shouldn't even be there. You can just add the transform yourself:
DataObjectDesc obj1 = new DataObjectReference("")
.withTransform(new EnvelopedSignatureTransform())
.withTransform(new ExclusiveCanonicalXMLWithoutComments())
...

Related

Getting text in <td> element using SpecFlow and Selenium

I am getting an error in my SpecFlow unit test:
System.Collections.Generic.KeyNotFoundException : The given key was not present in the dictionary.
at TechTalk.SpecFlow.SpecFlowContext.Get[T](String key)
at F*****.Live.PS.*******.Steps.*******.EnterStagingDateAndSaveSteps.ThenUserSeesInNEXTRE_ENROLMENTWINDOWTextFieldInPENSIONASSESSMENTDATESPageInPENSIONModule(String p0) in c:\Git\LivePeopleSystemTests\Fourth.Live.PS.AutomationTests\F*****.Live.PS.*******.Steps*******\EnterStagingDateAndSaveSteps.cs:line 175
Here is the referenced method in EnterStagingDateAndSaveSteps.cs
[Then(#"user sees ""(.*)"" in NEXT RE-ENROLMENT WINDOW Text Field in PENSION ASSESSMENT DATES page in PENSION module")]
public void ThenUserSeesInNEXTRE_ENROLMENTWINDOWTextFieldInPENSIONASSESSMENTDATESPageInPENSIONModule(string p0)
{
// GetNextReEnrollmentWindow
string validator =
ScenarioContext.Current.Get<PensionAssessmentDates>("_nextReEnrollmentWindow")
.GetNextReEnrollmentWindow();
Assert.IsTrue(validator == p0);
}
(I also tried return Driver.WaitAndGetText(_nextReEnrollmentWindow); in there)
so it looks like the key _nextReEnrollmentWindow doesn't exist, but here it is defined in PensionAssessmentDates.cs:
private readonly By _nextReEnrollmentWindow = By.Id("NextReEnrollmentWindow");
The PensionAssessmentSteps is set into the ScenarioContext.Current like this:
[Then(#"user sees ""(.*)"" in NEXT RE-ENROLMENT WINDOW Text Field in PENSION ASSESSMENT DATES page in PENSION module")]
public void ThenUserSeesInNEXTRE_ENROLMENTWINDOWTextFieldInPENSIONASSESSMENTDATESPageInPENSIONModule(string p0)
{
// GetNextReEnrollmentWindow
string validator =
ScenarioContext.Current.Get<PensionAssessmentDates>("_nextReEnrollmentWindow")
.GetNextReEnrollmentWindow();
Assert.IsTrue(validator == p0);
}
and here is the actual web-page I am trying to test showing the element exists:
I'd be grateful for any pointers or advice on what I have missed which is causing my unit test to stop as below:
EnterStagingDateAndSaveSteps.WhenUserClicksSAVEButtonUnderAUTOMATICENROLMENTATSTAGINGDATEFrameInPENSIONASSESSMENTDATESPageInPENSIONModule() (0.7s)
Then user sees "02 Oct 2019 to 02 Apr 2020" in NEXT RE-ENROLMENT WINDOW Text Field in PENSION ASSESSMENT DATES page in PENSION module
-> error: The given key was not present in the dictionary.
The ScenarioContext.Current.Get and Set methods simply allow you to add an object to the dictionary of values attached to the current scenario using a key.
Once you have added an element to the dictionary in one step, you can retrieve it in another step. The exception you are getting implies that you have not added anything to the dictionary using the key _nextReEnrollmentWindow.
Do you call ScenarioContext.Current.Set("_nextReEnrollmentWindow", something); anywhere in your code? I suspect not.
Given the way you have asked the question I'm suspecting that you expect the ScenarioContext.Current.Get<PensionAssessmentDates>("_nextReEnrollmentWindow") call to get you the current instance of the page object of type PensionAssessmentDates and then get the element using the selector _nextReEnrollmentWindow. This is not how it works.
you want to do one of two things I believe. Either add your page object PensionAssessmentDates to the ScenarioContext.Current and then get the page object out and call the method which uses the private field _nextReEnrollmentWindow.
Or (much better in my opinion) ditch your use of the ScenarioContext.Current altogether and instead create objects which hold your page objects and let Specflows internal DI framework provide those to your step classes using context injection.

Saxon XSLT .Net Transformation: What to give in BaseURI when xml and xsl both are passed as strings

This is the code I have for Saxon Transformation of XSLT files which accepts xml and xslt and returns a transformed string. I can have either xsl 1.0 or 2.0 get processed through this function.
DocumentBuilder requires a BaseURI, even if I don't have any file format. I have provided "c:\\" as the BaseURI, inspite I have nothing to do with this directory.
Is there any better way to achieve this thing or write this function?
public static string SaxonTransform(string xmlContent, string xsltContent)
{
// Create a Processor instance.
Processor processor = new Processor();
// Load the source document into a DocumentBuilder
DocumentBuilder builder = processor.NewDocumentBuilder();
Uri sUri = new Uri("c:\\");
// Now set the baseUri for the builder we created.
builder.BaseUri = sUri;
// Instantiating the Build method of the DocumentBuilder class will then
// provide the proper XdmNode type for processing.
XdmNode input = builder.Build(new StringReader(xmlContent));
// Create a transformer for the stylesheet.
XsltTransformer transformer = processor.NewXsltCompiler().Compile(new StringReader(xsltContent)).Load();
// Set the root node of the source document to be the initial context node.
transformer.InitialContextNode = input;
StringWriter results = new StringWriter();
// Create a serializer.
Serializer serializer = new Serializer();
serializer.SetOutputWriter(results);
transformer.Run(serializer);
return results.ToString();
}
If you think that the base URI will never be used (because you never do anything that depends on the base URI) then the best strategy is to set a base URI that will be instantly recognizable if your assumption turns out to be wrong, for example "file:///dummy/base/uri".
Choose something that is a legal URI (C:\ is not).

Adding SignedDataObjects (and consequently add proofOfApproval property) to an enveloped signature

I'm creating an Enveloped signature with xades4j following this statements:
Element elemToSign = doc.getDocumentElement();
XadesSigner signer = new XadesTSigningProfile(...).newSigner();
new Enveloped(signer).sign(elemToSign);
But I need to put in the signature also other properties like ProofOfApprova etc...
I see that in xades4j examples the proofOfApprovalProperties are addedto enveloped signature using different statements of signature, for example:
AllDataObjsCommitmentTypeProperty globalCommitment = AllDataObjsCommitmentTypeProperty.proofOfApproval();
CommitmentTypeProperty commitment = CommitmentTypeProperty.proofOfCreation();
DataObjectDesc obj1 = new DataObjectReference('#' + elemToSign.getAttribute("Id"))
.withTransform(new EnvelopedSignatureTransform())
.withDataObjectFormat(new DataObjectFormatProperty("text/xml", "MyEncoding")
.withDescription("Isto é uma descrição do elemento raiz")
.withDocumentationUri("http://doc1.txt")
.withDocumentationUri("http://doc2.txt"))
.withIdentifier("http://elem.root"))
.withCommitmentType(commitment)
.withDataObjectTimeStamp(dataObjsTimeStamp)
SignedDataObjects dataObjs = new SignedDataObjects(obj1)
.withCommitmentType(globalCommitment);
signer.sign(dataObjs, elemToSign);
I see here that another procedure of signature is used, more specificately the statement in which I create a DataObjectreference saying that I use "Id" attibute fo root tag is unusable for me because in input I can have any kind of xml document and I cannot know what kind of attribute (if present) I can use foe define root tag.
Briefly, can I have some examp'le code where I create an Enveloped signature and put a proofOfApproval property using "new Enveloped(signer).sign(elemToSign);", or anyway whitout knowing the xml source structure?
Thanks
M.
The proofOfApproval property has to be applied to data objects being signed, hence the need to use the SignedDataObjects class.
The Enveloped class is just a helper for straightforward scenarios. If I understood correctly you want to sign the whole XML document. The XML-Signatures spec defines that an empty URI on a reference (URI="") means exactly that. If you check the code on the Enveloped class you'll see that it adds a DataObjectReference with an empty uri.
To sum up, you'll need something like:
DataObjectDesc obj1 = new DataObjectReference("")
.withTransform(new EnvelopedSignatureTransform())
.withCommitmentType(CommitmentTypeProperty.proofOfApproval());
signer.sign(new SignedDataObjects(obj1), elemToSign);

Why can't I use xpath to parse nodes in the default namespace?

I'm an XML newbie and I have an XML document (which I can't edit because it comes from somewhere else) but it has a root node like this:
<Configuration xmlns="http://schemas.mycomp.com/product/settings" version="2.0.0">
I'm trying to parse this document with msxml and xpath and I've done it successfully if I remove the xmlns attribute. For some reason, with this xmlns attribute in place, the document won't parse. I've attempted to set the msxml parse to recognise the document using:
m_pXMLDoc->setProperty( _bstr_t(L"AllowDocumentFunction"), _variant_t(true));
m_pXMLDoc->setProperty( _bstr_t(L"AllowXsltScript"), _variant_t(true));
m_pXMLDoc->setProperty( _bstr_t(L"SelectionLanguage"), _variant_t(L"XPath"));
m_pXMLDoc->setProperty( _bstr_t(L"SelectionNamespaces"), _variant_t(L"xmlns='http://schemas.mycomp.com/product/settings'"));
m_pXMLDoc->preserveWhiteSpace = VARIANT_FALSE;
m_pXMLDoc->resolveExternals = VARIANT_TRUE;
m_pXMLDoc->validateOnParse = VARIANT_FALSE;
From reading around it looks like xpath only works on the "no name" namespace and this document sets the default namespace so that it's no longer "no name". Can I set the namespace that xpath uses using MSXML?
From Microsoft : This behaviour is by design ...
See http://support.microsoft.com/kb/288147
Use prefixes with the namespaces when you specify the SelectionNamespaces property

SharePoint SoapServerException calling GetListItems web service

I have the following statement in my code:
System.Xml.XmlNode items = lstWebs.GetListItems(
"Tasks", string.Empty, listQuery, listViewFields,
string.Empty, listQueryOptions, WorkspaceId);
When executing this, the following exception occurs:
Exception of type 'Microsoft.SharePoint.SoapServer.SoapServerException' was thrown.
Exception Source is:
System.Web.Services
Stack Trace:
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at ImpersonationConsoleApp.MossLists.Lists.GetListItems(String listName, String viewName, XmlNode query, XmlNode viewFields, String rowLimit, XmlNode queryOptions, String webID) in C:\Documents and Settings\david\My Documents\_Dew02SiteCreator\DeWProjectStarter\ImpersonationConsoleApp\Web References\MossLists\Reference.cs:line 435
at ImpersonationConsoleApp.Program.DeleteTasksIfNotExist(DataRow[] drTasksdel, String siteURL) in C:\Documents and Settings\david\My Documents\_Dew02SiteCreator\DeWProjectStarter\ImpersonationConsoleApp\Program.cs:line 1384
I have confirmed the site URL and it is fine.
Could you please help on why the exception is occurring? Do I need to reset IIS?
please find the detail.
SoapException.InnerException is Null.
However the soapExcetion.Detail.InnerText is showing: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
Is the name tasks also the actual listname in the url? i.e. http://siteurl/lists/tasks? is the list in a subsite and are you using the service under the site-collection?
IF the list is in a subsite the use http://sitecollectionurl/subsite/_vti_bin/lists.asmx as the Service url, otherwise the lists.asmx will try to find the tasks list in the rootweb instead of the subsite.
The signature for GetListItems is
GetListItems(ListID, "", queryNode, viewFieldsNode, Nothing, queryOptionsNode, Nothing)
Try simplifying queryNode, viewFieldsNode and queryOptionsNode to the minimal.
In VB.NET
Dim caml = New XmlDocument
Dim queryNode = caml.CreateElement("Query")
Dim viewFieldsNode = caml.CreateElement("ViewFields")
Dim queryOptionsNode = caml.CreateElement("QueryOptions")
queryOptionsNode.InnerXml = "<ViewAttributes Scope=""Recursive"" /><IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>"
In C#
var caml = new XmlDocument();
var queryNode = caml.CreateElement("Query");
var viewFieldsNode = caml.CreateElement("ViewFields");
var queryOptionsNode = caml.CreateElement("QueryOptions");
queryOptionsNode.InnerXml = "<ViewAttributes Scope=\"Recursive\" /><IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>";
If it works, then the web service setup is correct.
When I had the mentioned problem, it was my invalid XML that caused it. There is a missing 'type' attribute on the 'Value' element of the 'Where' element in queryNode. I found it here from Microsoft.
Type | Required Text. Specifies the data type for the value contained by this element.
It works after adding the Type attribute. Check if any missing requirements for the xml in one of the nodes mentioned above?
Have you tried running with elevated permissions, it looks like the running user does not hav sufficient privileges to query the data...
SPSecurity.RunWithElevatedPrivileges