How can I sign document with apache santuario so that The signature comes inside the tag instead of the end of the MyXML tag?
<MyXML>
<SignaturePlace></SignaturePlace>
<DataToSign>BlaBlaBla</DataToSign>
</MyXML>
Inside the standart JSE dsig library there is javax.xml.crypto.dsig.dom.DOMSignContext class which constructor takes 2 parameters - the RSA private key and the location of the resulting XMLSignature's parent element. Is there something similar inside the apache santuario's implementation?
Yes, you can do this with Apache Santuario.
Here is example code for doing this with for you example XML above:
// Assume "document" is the Document you want to sign, and that you have already have the cert and the key
// Construct the signature and add the necessary transforms, etc.
XMLSignature signature = new XMLSignature(document, null, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
final Transforms transforms = new Transforms(document);
transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
signature.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);
// Now insert the signature as the last child of the outermost node
document.getDocumentElement().appendChild(signature.getElement());
// Finally, actually sign the document.
signature.addKeyInfo(x509Certificate);
signature.addKeyInfo(x509Certificate.getPublicKey());
signature.sign(privateKey);
This case is easy because you wanted the signature to be the last child of the outermost node. If you want to insert the signature before the 3rd child node, you would first obtain a Node that points to the node you want to insert the signature before, and then use the "insertBefore()" method.
final Node thirdChildNode = document.getFirstChild().getNextSibling().getNextSibling();
document.getDocumentElement().insertBefore(signature.getElement(), thirdChildNode);
Related
For a signed PDF document, with invisible signature, I am using PDFBox library to extract signer information, but it's coming as null. Same code works fine for visible signature. Can someone help on this if we need to make?
//Load PDF Document
PDDocument document = PDDocument.load(doc);
//Iterate each Signature
for (PDSignature pdSignature : document.getSignatureDictionaries()) {
if (pdSignature != null) {
HashMap values = new HashMap();
String subFilter = pdSignature.getSubFilter();
if (subFilter != null) {
LOG.debug("---------Siganature Details---------- ");
LOG.debug("Signer Name : " + pdSignature.getName());
values.put(SignerName, pdSignature.getName());
pdSignature.getName() returns the value of the Name entry of the signature dictionary. But this entry is optional:
Name text string (Optional) The name of the person or authority signing the document.
This value should be used only when it is not possible to extract the name from the signature.
Generally you'll have to analyze the signer certificate in the embedded signature container to get the common name of the signer.
As #Tilman pointed out in a comment, the pdfbox example ShowSignature shows quite a number of means to retrieve data from a CMS signature container.
On Your Comment
In a comment you write
Only the complete principal string can be extracted which contains the complete string using the below code "certFromSignedData.getSubjectX500Principal().toString()" [...] Any direct way of querying CN name alone?
Indeed you only get the complete subject distinguished name if you apply toString() to the X500Principal returned by certFromSignedData.getSubjectX500Principal(). But if you create a sun.security.x509.X500Name for it, you can easily retrieve the common name:
X500Principal principal = certFromSignedData.getSubjectX500Principal();
sun.security.x509.X500Name name = sun.security.x509.X500Name.asX500Name(principal);
System.out.printf("Whole DN: %s\n", name);
System.out.printf("CN: %s\n", name.getCommonName());
If you don't want to use sun.security.x509 classes, you can similarly use BouncyCastle classes, starting from the matching BouncyCastle X509CertificateHolder:
org.bouncycastle.asn1.x500.X500Name name = certificateHolder.getSubject();
System.out.printf("Whole DN: %s\n", name);
RDN[] cns = name.getRDNs(BCStyle.CN);
System.out.printf("CN: %s\n", cns.length > 0 ? cns[0].getFirst().getValue() : null);
however it's in different format for invisible and visible signature. For visible signature: SERIALNUMBER=xxxx, DNQ=xxx, EMAILADDRESS=xx, SURNAME=xx, GIVENNAME=xx, C=xx, CN=xx and for invisible signature "CN="xx" + EMAILADDRESS=xx, OU=xx, O="xx", L=xx, ST=xx, C=xx".
Which attributes are used in the subject DN and whether RDNs with multiple attribute/value pairs are used, depends on the signer certificate alone, it does not have anything to do with visible and invisible signature. If you have distinct specific patterns for invisible and visible signatures, then your test PDF pool is biased.
I've been reading the official PDFBox examples to visually sign a PDF document, especifically the example from CreateVisualSignature2.java, which generates an empty document as a template to define the signature appearance and then sets it to the real document by calling SignatureOptions.setVisibleSignature().
In my case, I've been using an HSM service to do the signing for me, so I don't have direct access to private keys or certificates. I send the document hash to this service and it returns a PKCS7 byte array which I add to my document using ExternalSigningSupport.setSignature().
The code, which is based on the PDFBox example linked above, looks like this:
// Read the document and prepare a signature.
PDDocument document = PDDocument.load( "path/to/file.pdf" );
PDSignature signature = new PDSignature();
signature.setFilter( PDSignature.FILTER_ADOBE_PPKLITE );
signature.setSubFilter( PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED );
signature.setReason( "Test" );
InputStream template = createVisualSignatureTemplate( document ); // Implementation defined below.
SignatureOptions options = new SignatureOptions();
options.setVisibleSignature( template );
options.setPage( 0 );
document.addSignature( signature, options );
// Get the content to sign using PDFBox external signing support.
FileOutputStream outputStream = new FileOutputStream();
ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning( outputStream );
byte[] content = IOUtils.toByteArray( externalSigning.getContent() );
// Send the content to the HSM service and get the response.
byte[] hash = MessageDigest.getInstance( "SHA-256" ).digest( content );
byte[] pkcs7 = MyHSMService.getSignedHash( hash );
// Add the signature to the PDF.
externalSigning.setSignature( pkcs7 );
document.close();
And my template method, based on the method of the same name in the linked PDFBox example, simplified:
PDDocument emptyDocument = new PDDocument();
emptyDocument.addPage( new PDFPage( document.getPage(0).getMediaBox() ) );
// Create the PDAcroForm, PDSignatureField, PDAppearanceDictionary, etc,
// just like in the official example.
(...)
// Define the content stream of the visual signature.
PDPageContentStream content = new PDPageContentStream( emptyDocument, appearanceStream );
content.beginText();
content.showText( "Signed by: ... " ); // The signer name should be here.
content.newLine();
content.showText( "Date: ..." ); // The signature datetime should be here.
content.endText();
content.close();
// Convert the empty document as an input stream and return it, just like the example.
(...)
This works fine and I can add valid visual signatures without issues. My problem is that I need to add the signer name and sign date in the signature appearance, but since I create the template BEFORE calling my HSM service to sign, I don't have access to that data yet, which is why I need to define the content AFTER signing the document.
Is there a way to achieve this? I'm new to PDF signing, so my understanding of the fundamentals is pretty poor.
Thanks in advance!
The in-document visualization of a pdf signature is a pdf widget annotation and as such it is part of the signed content. Thus, it must be added before signing and only information can be used in it which is known before signing.
There is one option, though, most signature types allow changing annotations in a revision after the signed revision. Read here about allowed and disallowed changes to signed pdf documents.
But a pdf viewer then still may warn that changes have been applied to the document after signing. Such a warning would look like this:
(Here the signature appearance has been changed to a red diagonal cross.)
If you sign this changed document again, you can even get rid of the warning in the signature ribbon at the top:
(Images are from this answer where changes to signature appearances using itext have been tested.)
When it comes to the datetime, I could show the date of the PDSignature object itself, but in this case the time shown in the visualization won't be the same as the time shown in the signatures panel in the PDF viewer, since the actual signature will happen a few seconds later when I call the HSM service. In this case I have no other choice than to make a new revision just to correct the time, right?
Well, first of all there is no need for a signing time attribute in the CMS signature container embedded in a pdf signature because the signing time can also be given in the M entry if the signature dictionary.
Thus, one choice is to try and retrieve a signature container without signing time attribute. In that case the PDSignature signing time will be shown in the signature panel.
If you use digital time stamps, though, to document the signing time, it is part of the CMS signature container or even a separate document time stamp, so this's option wouldn't work.
Furthermore, you mention the signature panel. As the exact information can be found there, do you really need the signing time in the signature visualization? The visualization is only cosmetic in nature, it may contain arbitrary information, so nobody should trust it anyways. Adobe had warned about this already many years ago, even before pdf became an ISO standard...
Thus, another choice is simply to put a nice looking logo there and that's it!
Using itext I can get the signing name (Signed By) like this:
fields = reader.getAcroFields();
pk = fields.verifySignature(FieldName);
name = pk.getSignName();
How do I get the signing name using pdfBox?
document.getSignatureDictionaries() gets the signatures, and PDSignature.getName() gets the name. To see more, have a look at the ShowSignature.java example from the source code download in the examples subproject.
I need to add two QualifyingPropertiesReference nodes with given URI values into Object within a XadES Signature.
I'm generating an xml Signature which requires to pass a certificate via URL instead of attaching it in KeyInfo element. For this, QualifyingPropertiesReference looks like a good fit, however I could not find a way or an example in wiki/tests that would add this element. Looking at the code, I found XmlQualifyingPropertiesReferenceType, but did not see it being used anywhere. My signing code:
XadesSigningProfile signingProfile =
new XadesBesSigningProfile(keyingDP)
.withBasicSignatureOptions(new BasicSignatureOptions().includeSigningCertificate(SigningCertificateMode.NONE));
XadesSigner signer = signingProfile.newSigner();
Document doc = createDocument(xmlMessage);
DataObjectDesc obj = new DataObjectReference("")
.withTransform(new EnvelopedSignatureTransform());
SignedDataObjects dataObjects = new SignedDataObjects().withSignedDataObject(obj);
signer.sign(dataObjects, doc.getFirstChild());
Basically, I want this kind of Signature structure:
<Signature>
....
<Object>
<QualifyingPropertiesReference URI="some_url"/>
<QualifyingPropertiesReference URI="some_url2"/>
<QualifyingProperties>
....
</Object>
</Signature>
If there's no way, would adding them to doc manually make Signature invalid? Are <Object> contents used for hashing?
xades4j doesn't support QualifyingPropertiesReference for two main reasons: 1) no real use cases for it; 2) XAdES Baseline profiles do not allow it section 6.1 of baseline profiles spec.
That said, I'm not sure your use-case is one for QualifyingPropertiesReference. This element is just a means of pointing to another XML resource where the qualifying properties are present. Maybe you misunderstood it. I don't think it has anything to do with certificates or how to obtain them.
It is ok that a signature doesn't include the certificates needed for validation. In this case the verifier is expected to know how to obtain them. Another option is to add "application-specific" data to the signature, where you pass the URL.
Is there any way to take an unknown schema xml file and convert the values, tags, etc from the xml file into pojo? I looked at jaxb and it seems like the best way to use that is if you already know the xml schema. So basically, I want to be able to parse the tags from the xml put each into its own object maybe through the use of an arraylist. Did I just not fully understand what jaxb can or is there a better tool that can do this, or is it just too hard to implement?
In the hope that this helps you to understand your situation!
public static void dumpAllNodes( String path ) throws Exception {
DocumentBuilder parser =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = parser.parse(new File(path));
NodeList nodes = doc.getElementsByTagNameNS( "*", "*" );
for( int i = 0; i < nodes.getLength(); i++ ){
Node node = nodes.item( i );
System.out.println( node.getNodeType() + " " + node.getNodeName() );
}
}
The NodeList nodes contains all element nodes, in document order (opening tag). Thus, elements contained within elements will be in that list, all alike. To obtain the attributes of a node, call
NamedNodeMap map = node.getAttributes();
The text content of a node is available by
String text = node.getTextContent();
but be aware that calling this returns the text in all elements of a subtree.
OTOH, you may call
Element root = doc.getDocumentElement();
to obtain the root element and then descend the tree recursively by calling Element.getChildNodes() and process the nodes (Element, Attr, Text,...) one by one. Also, note that Node.getParentNode() returns the parent node, so you could construct the XPath for each node even from the flat list by repeating this call to the root.
It simply depends what you expect from the resulting data structure (what you call ArrayList). If, for instance, you create a generic element type (MyElement) containing one map for attributes and another one for child elements, the second map would have to be
Map<String,List<MyElement>> name2elements
to provide for repeated elements - which makes access to elements occurring only once a little awkward.
I hope that I have illustrated the problems of generic XML parsing, which is not a task where JAXB can help you.