From bbc0740697f33f0774e150ac6c9efc6c69546be9 Mon Sep 17 00:00:00 2001 From: Florin Hillebrand Date: Wed, 18 May 2022 19:15:41 +0200 Subject: [PATCH 1/2] Add example to sign PDF documents like in Amtssignatur. Signed-off-by: Florin Hillebrand --- PdfSignDemoJava/.gitignore | 4 + PdfSignDemoJava/PdfSignDemo.java | 242 ++++++++++++++++++++++++ PdfSignDemoJava/README.md | 33 ++++ PdfSignDemoJava/output.pdf | Bin 0 -> 57754 bytes PdfSignDemoJava/pom.xml | 92 +++++++++ PdfSignDemoJava/run.bat | 6 + PdfSignDemoJava/run.sh | 6 + PdfSignDemoJava/signature-pen.png | Bin 0 -> 29926 bytes PdfSignDemoJava/testPDF_Version.8.x.pdf | Bin 0 -> 5903 bytes 9 files changed, 383 insertions(+) create mode 100644 PdfSignDemoJava/.gitignore create mode 100644 PdfSignDemoJava/PdfSignDemo.java create mode 100644 PdfSignDemoJava/README.md create mode 100644 PdfSignDemoJava/output.pdf create mode 100644 PdfSignDemoJava/pom.xml create mode 100644 PdfSignDemoJava/run.bat create mode 100755 PdfSignDemoJava/run.sh create mode 100644 PdfSignDemoJava/signature-pen.png create mode 100644 PdfSignDemoJava/testPDF_Version.8.x.pdf diff --git a/PdfSignDemoJava/.gitignore b/PdfSignDemoJava/.gitignore new file mode 100644 index 0000000..5126603 --- /dev/null +++ b/PdfSignDemoJava/.gitignore @@ -0,0 +1,4 @@ +target +*.iml +*.class +*.jar diff --git a/PdfSignDemoJava/PdfSignDemo.java b/PdfSignDemoJava/PdfSignDemo.java new file mode 100644 index 0000000..4e30569 --- /dev/null +++ b/PdfSignDemoJava/PdfSignDemo.java @@ -0,0 +1,242 @@ +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.europa.esig.dss.enumerations.SignatureAlgorithm; +import eu.europa.esig.dss.enumerations.SignatureLevel; +import eu.europa.esig.dss.model.*; +import eu.europa.esig.dss.model.x509.CertificateToken; +import eu.europa.esig.dss.pades.PAdESSignatureParameters; +import eu.europa.esig.dss.pades.SignatureFieldParameters; +import eu.europa.esig.dss.pades.SignatureImageParameters; +import eu.europa.esig.dss.pades.signature.PAdESService; +import eu.europa.esig.dss.pdf.pdfbox.PdfBoxNativeObjectFactory; +import eu.europa.esig.dss.validation.CommonCertificateVerifier; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.DERSequenceGenerator; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x500.style.IETFUtils; +import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; + +import java.io.*; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Base64; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +/** + * Standalone DSS A-Trust qualified signature test for the MCWE for A-Trust + */ +public class PdfSignDemo { + public static void main(String[] args) throws Exception { + char[] pfxPassword = "testpwd".toCharArray(); + String pfxFile = "./../test_credentials/authentication_certificate.p12"; + String baseurl = "http://hs-abnahme.a-trust.at/SealQualified/v1/"; // test system (HTTP) + //String baseurl = "https://hs-abnahme.a-trust.at/SealQualified/v1/"; // test system (HTTPS) + //String baseurl = "https://www.a-trust.at/SealQualified/v1/"; // live system (only HTTPS) + + // load pkcs12 + Security.setProperty("crypto.policy", "unlimited"); + + KeyStore keystore = KeyStore.getInstance("PKCS12"); + keystore.load(new FileInputStream(pfxFile), pfxPassword); + + String keyAlias = ""; + for (Enumeration en = keystore.aliases(); en.hasMoreElements();) { + String alias = (String)en.nextElement(); + if(keystore.isKeyEntry(alias)) { + keyAlias = alias; + break; + } + } + + PrivateKey key = (PrivateKey) keystore.getKey(keyAlias, pfxPassword); + X509Certificate cert = (X509Certificate) keystore.getCertificate(keyAlias); + String serial = cert.getSerialNumber().toString(); + + // get seal certificate + System.out.println("================="); + System.out.println("get seal certificate"); + String getUrl = baseurl + "/Certificate/" + serial + "/nosessionid"; + byte[] seal_certificate_raw = Get(getUrl); + + String seal_certificate_base64 = new String(Base64.getEncoder().encode(seal_certificate_raw)); + System.out.println("seal certificate: " + seal_certificate_base64); + + + System.out.println("================="); + System.out.println("sign with seal private key"); + + // START PART 1 - Until here this demo application is the same as DemoJava + + X509Certificate seal_certificate_x509 = (X509Certificate) CertificateFactory.getInstance("X.509") + .generateCertificates(new ByteArrayInputStream(seal_certificate_raw)).stream().findFirst().get(); + + // Downloaded sample from https://svn.apache.org/repos/asf/tika/trunk/tika-parsers/src/test/resources/test-documents/testPDF_Version.8.x.pdf + DSSDocument doc = new FileDocument("testPDF_Version.8.x.pdf"); + + PAdESSignatureParameters parameters = prepareSignParameters(seal_certificate_x509); + + // We need this because we are testing with an expired certificate + parameters.setSignWithExpiredCertificate(true); + + // Create common certificate verifier + CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); + // Create PAdESService for signature + PAdESService service = new PAdESService(commonCertificateVerifier); + service.setPdfObjFactory(new PdfBoxNativeObjectFactory()); + // Get the SignedInfo segment that need to be signed. + ToBeSigned dataToSignDSS = service.getDataToSign(doc, parameters); + byte[] dataToSign = dataToSignDSS.getBytes(); + + // END PART 2 - We now have data from the prepared PDF with certificate information and PDF structure for signature + // and sign it with the A-Trust qualified signature test service + + MessageDigest hashAlgo = MessageDigest.getInstance("SHA-256"); + byte[] hashToSign = hashAlgo.digest(dataToSign); + + // prepare Request + Signature sig = Signature.getInstance("SHA256WithRSA"); + sig.initSign(key); + sig.update(hashToSign); + byte[] HashSignature = sig.sign(); + + + String request = "{\"AuthSerial\": \"" + serial + "\", \"Hash\": \""; + request += new String(Base64.getEncoder().encode(hashToSign)); + request +="\", \"HashSignature\": \""; + request += new String(Base64.getEncoder().encode(HashSignature)); + request +="\", \"HashSignatureMechanism\": \"SHA256withRSA\" }"; + + String postUrl = baseurl + "/Sign/nosessionid"; + String result = Post(postUrl,request); + System.out.println("result: " + result); + + // START PART 2 - The returned signature is now integrated in the prepared PDF structure and written to file + Map resultMap = new ObjectMapper().readValue(result.getBytes(StandardCharsets.UTF_8), Map.class); + + byte[] jwsSignature = Base64.getDecoder().decode((String) resultMap.get("Signature")); + byte[] derSignature = convertJWSConcatenatedToDEREncodedSignature(jwsSignature); + + SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.ECDSA_SHA256, derSignature); + + // We invoke the PadesService to sign the document with the signature value obtained in + // the previous step. + DSSDocument signedDocument = service.signDocument(doc, parameters, signatureValue); + + signedDocument.writeTo(new FileOutputStream("output.pdf")); + } + + private static PAdESSignatureParameters prepareSignParameters(X509Certificate cert) throws Exception { + // Preparing parameters for the PAdES signature + PAdESSignatureParameters parameters = new PAdESSignatureParameters(); + // We choose the level of the signature (-B, -T, -LT, -LTA). + parameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B); + + parameters.setReason("Signature verification at: http://www.signature-verification.gv.at"); + parameters.setContactInfo("Amtssignatur contact info"); + + // get certificates holder name + X500Name x500name = new JcaX509CertificateHolder(cert).getSubject(); + RDN cn = x500name.getRDNs(BCStyle.CN)[0]; + parameters.setSignerName(IETFUtils.valueToString(cn.getFirst().getValue())); + + CertificateToken certToken = new CertificateToken(cert); + + // We set the signing certificate + parameters.setSigningCertificate(certToken); + + // We set the certificate chain + parameters.setCertificateChain(List.of(certToken)); + + // Initialize visual signature and configure + SignatureImageParameters imageParameters = new SignatureImageParameters(); + // set an image + imageParameters.setImage(new InMemoryDocument(new FileInputStream("signature-pen.png"))); + + // initialize signature field parameters + SignatureFieldParameters fieldParameters = new SignatureFieldParameters(); + imageParameters.setFieldParameters(fieldParameters); + // the origin is the left and top corner of the page + fieldParameters.setOriginX(20); + fieldParameters.setOriginY(40); + fieldParameters.setWidth(300); + fieldParameters.setHeight(200); + + parameters.setImageParameters(imageParameters); + + return parameters; + } + + /** + * Helper method to convert concatenated signature values (as used by the JWS-standard) to + * DER-encoded signature values (e.g. used by Java) + * + * Copied from: https://github.com/BMF-RKSV-Technik/at-registrierkassen-mustercode/blob/master/regkassen-common/src/main/java/at/asitplus/regkassen/common/util/CryptoUtil.java + * + * @param concatenatedSignatureValue + * concatenated signature value (as used by JWS standard) + * @return DER-encoded signature value + * @throws IOException + */ + private static byte[] convertJWSConcatenatedToDEREncodedSignature(final byte[] concatenatedSignatureValue) throws IOException { + + final byte[] r = new byte[33]; + final byte[] s = new byte[33]; + System.arraycopy(concatenatedSignatureValue, 0, r, 1, 32); + System.arraycopy(concatenatedSignatureValue, 32, s, 1, 32); + final BigInteger rBigInteger = new BigInteger(r); + final BigInteger sBigInteger = new BigInteger(s); + + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + final DERSequenceGenerator seqGen = new DERSequenceGenerator(bos); + + seqGen.addObject(new ASN1Integer(rBigInteger.toByteArray())); + seqGen.addObject(new ASN1Integer(sBigInteger.toByteArray())); + seqGen.close(); + bos.close(); + + final byte[] derEncodedSignatureValue = bos.toByteArray(); + + return derEncodedSignatureValue; + } + + private static String Post(String postUrl, String requestJson) throws Exception + { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost(postUrl); + httpPost.setHeader("Accept", "application/json"); + httpPost.setHeader("Content-type", "application/json"); + httpPost.setEntity(new ByteArrayEntity(requestJson.getBytes("UTF8"))); + + CloseableHttpResponse httpResponse = httpClient.execute(httpPost); + + HttpEntity resEntity = httpResponse.getEntity(); + String content = EntityUtils.toString(resEntity); + httpClient.close(); + return content; + } + + private static byte[] Get(String getUrl) throws Exception + { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpGet httpGet = new HttpGet(getUrl); + CloseableHttpResponse httpResponse = httpClient.execute(httpGet); + + byte[] content = EntityUtils.toByteArray(httpResponse.getEntity()); + httpClient.close(); + return content; + } +} diff --git a/PdfSignDemoJava/README.md b/PdfSignDemoJava/README.md new file mode 100644 index 0000000..b3c896b --- /dev/null +++ b/PdfSignDemoJava/README.md @@ -0,0 +1,33 @@ +# Amtssignatur with A-Trust Qualified Signature service + +This demo application builds on top of [DemoJava](../DemoJava) and uses [DSS](https://github.com/esig/dss) +to sign a [sample PDF (1.7)](https://svn.apache.org/repos/asf/tika/trunk/tika-parsers/src/test/resources/test-documents/testPDF_Version.8.x.pdf) +using ECDSA encrypted signature returned from A-Trust qualified signature service. + +## Prerequisites + +### Download dependencies + +To download dependencies used by this example, Maven can be used to copy dependencies into the +[lib](lib) directory: + +```shell +mvn dependency:copy-dependencies -DoutputDirectory=lib +``` + +### JDK + +A Java compiler is expected to be available on the `PATH` + +## Run the demo + +Use either [run.bat](run.bat) for Windows or [run.sh](run.sh) for Unix/Linux based systems. At the end the signed +document is written to [output.pdf](output.pdf) file. + +## Credits + +* Thanks to [A-Trust](https://github.com/A-Trust) for providing open-source examples for their signing service +* Thanks to [DSS](https://github.com/esig/dss) project for their implementation and extensive documentation and +examples +* Thanks to [BMF-RKSV-Technik](https://github.com/BMF-RKSV-Technik) project for their utility method to convert +raw ECDSA R+S values to DER encoded signature. diff --git a/PdfSignDemoJava/output.pdf b/PdfSignDemoJava/output.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b0d81a005d2a4a4b7c5b9840e8732fce09c8e932 GIT binary patch literal 57754 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 + 4.0.0 + + samples + pdf-sign-demo-java + 1 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + + + + + + + + eu.europa.ec.joinup.sd-dss + dss-bom + 5.10 + pom + import + + + + + + + + eu.europa.ec.joinup.sd-dss + dss-document + + + + eu.europa.ec.joinup.sd-dss + dss-model + + + + eu.europa.ec.joinup.sd-dss + dss-pades + + + + eu.europa.ec.joinup.sd-dss + dss-token + + + + eu.europa.ec.joinup.sd-dss + dss-pades-pdfbox + + + + eu.europa.ec.joinup.sd-dss + dss-utils + + + + eu.europa.ec.joinup.sd-dss + dss-utils-apache-commons + + + org.apache.httpcomponents + httpcore + 4.4.15 + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + com.fasterxml.jackson.core + jackson-databind + 2.13.2.2 + + + + + + esig-dss + esig-dss + https://ec.europa.eu/digital-building-blocks/artifact/content/repositories/esignaturedss/ + + + diff --git a/PdfSignDemoJava/run.bat b/PdfSignDemoJava/run.bat new file mode 100644 index 0000000..a57bee3 --- /dev/null +++ b/PdfSignDemoJava/run.bat @@ -0,0 +1,6 @@ +cls + +set CLASSPATH="./;./lib/*;" + +javac -classpath %CLASSPATH% DemoClient.java +java -classpath %CLASSPATH% DemoClient diff --git a/PdfSignDemoJava/run.sh b/PdfSignDemoJava/run.sh new file mode 100755 index 0000000..b2eba97 --- /dev/null +++ b/PdfSignDemoJava/run.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +CLASSPATH='./:./lib/*' + +javac -classpath "$CLASSPATH" PdfSignDemo.java +java -classpath "$CLASSPATH" PdfSignDemo diff --git a/PdfSignDemoJava/signature-pen.png b/PdfSignDemoJava/signature-pen.png new file mode 100644 index 0000000000000000000000000000000000000000..ae1ab69567ea3ea194312e27540272fa26121286 GIT binary patch literal 29926 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 L8*07NaEkdqO+1Ka literal 0 HcmV?d00001 diff --git a/PdfSignDemoJava/testPDF_Version.8.x.pdf b/PdfSignDemoJava/testPDF_Version.8.x.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6aad57a390e51cc5f1bd9f28299b319adaea466f GIT binary patch literal 5903 zcmeHLdu$W;9XElb)WloHqk~atzq#d6z`pz4%RbLB#5RT$n;1JK(16JK?q|nv_L=jU znDoK3P&!ainOcU526R*RP&I-!#?-Ems#4b$$e^@qsfM7{ij>iHTcI6n>-M{|9Xr9P z#?~~Hpu|>N+-@S6Od~-}b|VQu zA_!QXq=^G4=lTGDNRY9EW4V#+@JNK_;g z7SvQ0d-N%CE|ty#nh2{%N{X7I0!Vp0L?9_^NF@TYprOJRqS@c>Zeo32XMiKUUcSl6 zGESajd_InaB+bJ4J}2*SLx!jQ0SDVeQx2|);dn1QpK@}PGvI{&CI{zPNi?S=lyAq0 zJN4gj1wbc`FG2)SI-zv}2I|4A)AOW=h@xnKB8~YdMg~w0qIG=+5z8VdPPDZ{Kmi?r ztfnF%WifYNh{dFaj#$UvW3i4-{JnD9*=@o44GIaVIq@5P$0malCjQylQx-GEthlR) zURD!SEw7@u#Y|ev)27XD30TY}L@|n78ATs(l2tLnL{X(g93*CsV~8lAxj_+jbacc! zI*tgYn!tj(;E9(`Y#rb1^*OILznOWh`Q+)r@9&2NBK1G^1#Rf`yby=d-LB_uPC&5Z53L z#84ucZnS>%{BbKtN{!YwHbjOpKGd09*sY>y_u^KudyU9T*0~F?9cFHD_Bm^97hcwU7{2W|qAxV%t zK{;%YcF_(OE_%g})uY!!w<^V55r3fQ4&OCeJ2friB8aZ8E_)YkSJVUnd7dY5A*3i9 zUSZ3wPisQnmd@T)FjBJPM_Ex#X0)V|2D)7#rsT9nt9790>aL4Nw$BsZIcE|PQ;LsphO8#a9S zp@N@(Lv278%efe~(niI~AvQ`>-(;m)B*n6AtQ}&<@Sv!ziXwXoOg4$C5)*J?#Pzh0 zN#&a2b~m9TTY- z7_#~cV+LzD6dE9>>ghyRKTu^exUQ>??r&@sUlL!4k^MJi5n zoWRm7SF&5N_ls6AmR@y~@C24GJs2W9=nAWfloOHaDG8|!#eh%9XgORz3&(EIvd@jU zz&Ea)xNH*xb-O|&hTgxNOPQiC$G%~8#K|pzI|A1TT(^Y4EiE2V*9cs^*+=8+(v;c{JcKOiqpO3&GRNca;fb%-%X6YdZ9VwAG73qt#`>(2i^V6 z%`CO+_wUcRyY|DrPqQ;eZ$0$r>Q~M`{>honzC*80itKz~=cH-Lr?2d;d3oN$OW)eD z`tY`c{rlPTqlHH)*E^TKJv*}Z;kAFha`@^C{ipu;_Ppm3$DJ3x_0*Y`Ij3)UT8=+> z$BPFhq_SIQKY#hgH)guE$di9+$8Y{?{>qK6l5<6KuzHJ?`D$CNH?>t+$IZ=D$QRlX z70pyQq?u}}nI5=fdENB7ZST(8{I@B)FFszg_75A6t=f3x7i`mty1?Y#e|-IsantvH c7JCeSRy&q7Ju`Q#y$U`R%~c4wf%fWu0TevK=>Px# literal 0 HcmV?d00001 From 7c669e5d8e0fd4379ea70d5a76f4bf8c459c5f3d Mon Sep 17 00:00:00 2001 From: Florin Hillebrand Date: Thu, 19 May 2022 17:47:23 +0200 Subject: [PATCH 2/2] Document steps in the PDF demo. --- PdfSignDemoJava/PdfSignDemo.java | 69 +++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/PdfSignDemoJava/PdfSignDemo.java b/PdfSignDemoJava/PdfSignDemo.java index 4e30569..7817ce1 100644 --- a/PdfSignDemoJava/PdfSignDemo.java +++ b/PdfSignDemoJava/PdfSignDemo.java @@ -37,7 +37,7 @@ import java.util.Map; /** - * Standalone DSS A-Trust qualified signature test for the MCWE for A-Trust + * Standalone DSS A-Trust qualified signature test for the MCWE for A-Trust, based on the DemoJava example. */ public class PdfSignDemo { public static void main(String[] args) throws Exception { @@ -79,29 +79,39 @@ public static void main(String[] args) throws Exception { System.out.println("================="); System.out.println("sign with seal private key"); - // START PART 1 - Until here this demo application is the same as DemoJava + // START PART 1 - Until here this demo application is the same as DemoJava. We now have the signing certificate. + // TODO: A RSA based public key would be needed for PDF signatures (critical) + + // load the certificate into a compatible structure X509Certificate seal_certificate_x509 = (X509Certificate) CertificateFactory.getInstance("X.509") .generateCertificates(new ByteArrayInputStream(seal_certificate_raw)).stream().findFirst().get(); - // Downloaded sample from https://svn.apache.org/repos/asf/tika/trunk/tika-parsers/src/test/resources/test-documents/testPDF_Version.8.x.pdf + // load a sample PDF document from file + // downloaded sample from https://svn.apache.org/repos/asf/tika/trunk/tika-parsers/src/test/resources/test-documents/testPDF_Version.8.x.pdf DSSDocument doc = new FileDocument("testPDF_Version.8.x.pdf"); + // prepare parameters used to generate signature structure and visual signature + // this step requires the certificate to be present PAdESSignatureParameters parameters = prepareSignParameters(seal_certificate_x509); - // We need this because we are testing with an expired certificate + // we need this because we are testing with an expired certificate parameters.setSignWithExpiredCertificate(true); - // Create common certificate verifier + // create common certificate verifier CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(); - // Create PAdESService for signature + + // create PAdESService to create a PDF Advanced Electronic Signature PAdESService service = new PAdESService(commonCertificateVerifier); + + // use default signing services service.setPdfObjFactory(new PdfBoxNativeObjectFactory()); - // Get the SignedInfo segment that need to be signed. + + // extract the data to sign from the given sample document ToBeSigned dataToSignDSS = service.getDataToSign(doc, parameters); byte[] dataToSign = dataToSignDSS.getBytes(); - // END PART 2 - We now have data from the prepared PDF with certificate information and PDF structure for signature + // END PART 1 - We now have data from the prepared PDF with certificate information and PDF structure for signature // and sign it with the A-Trust qualified signature test service MessageDigest hashAlgo = MessageDigest.getInstance("SHA-256"); @@ -113,7 +123,6 @@ public static void main(String[] args) throws Exception { sig.update(hashToSign); byte[] HashSignature = sig.sign(); - String request = "{\"AuthSerial\": \"" + serial + "\", \"Hash\": \""; request += new String(Base64.getEncoder().encode(hashToSign)); request +="\", \"HashSignature\": \""; @@ -124,51 +133,73 @@ public static void main(String[] args) throws Exception { String result = Post(postUrl,request); System.out.println("result: " + result); - // START PART 2 - The returned signature is now integrated in the prepared PDF structure and written to file + // START PART 2 - The returned signature is now integrated in the prepared PDF structure and written to file. + // PAdESSignatureParameters and DDSDocument from before are reused now. + + // we use Jackson to parse the returned JSON Map resultMap = new ObjectMapper().readValue(result.getBytes(StandardCharsets.UTF_8), Map.class); + // decode base64 encoded ECDSA signature byte[] jwsSignature = Base64.getDecoder().decode((String) resultMap.get("Signature")); + + // convert R+S valued ECDSA signature to DER encoded signature. For PDF it would be perfect + // to get RSA encrypted, DER encoded signatures as a Base64 encoded string + // TODO: Get the signature already DER encoded (minor) byte[] derSignature = convertJWSConcatenatedToDEREncodedSignature(jwsSignature); + // fill the DSS structure with the signature and its algorithm SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.ECDSA_SHA256, derSignature); - // We invoke the PadesService to sign the document with the signature value obtained in - // the previous step. + // we invoke the PadesService to sign the document with the signature value obtained in + // the previous step from A-Trust. DSSDocument signedDocument = service.signDocument(doc, parameters, signatureValue); + // write the document to file for further testing signedDocument.writeTo(new FileOutputStream("output.pdf")); } private static PAdESSignatureParameters prepareSignParameters(X509Certificate cert) throws Exception { - // Preparing parameters for the PAdES signature + // preparing parameters for the PAdES signature PAdESSignatureParameters parameters = new PAdESSignatureParameters(); - // We choose the level of the signature (-B, -T, -LT, -LTA). + + // we choose the level of the signature (-B, -T, -LT, -LTA). + // while for Amtssignatur the basic level is enough since it doesn't require signed timestamps parameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B); + // add Amtssignatur related information, which gets added to the DSS structure + // TODO: Verify compliance with Amtssignatur in terms of PDF signature metadata (major) parameters.setReason("Signature verification at: http://www.signature-verification.gv.at"); parameters.setContactInfo("Amtssignatur contact info"); - // get certificates holder name + // extract CN from certificates holder subject and use it as signer name + // copied from https://stackoverflow.com/questions/2914521/how-to-extract-cn-from-x509certificate-in-java/5527171#5527171 X500Name x500name = new JcaX509CertificateHolder(cert).getSubject(); RDN cn = x500name.getRDNs(BCStyle.CN)[0]; parameters.setSignerName(IETFUtils.valueToString(cn.getFirst().getValue())); + // create a DSS compatible token CertificateToken certToken = new CertificateToken(cert); - // We set the signing certificate + // set the signing certificate parameters.setSigningCertificate(certToken); - // We set the certificate chain + // set the certificate chain, we just have a single one here, but we would add the whole trust chain + // when in production + // TODO: Add whole certificate chain (major) parameters.setCertificateChain(List.of(certToken)); - // Initialize visual signature and configure + // TODO: Implement a visual signature as of Amtssignatur layout spec (major) + + // initialize visual sample signature and configure SignatureImageParameters imageParameters = new SignatureImageParameters(); - // set an image + + // set a sample image imageParameters.setImage(new InMemoryDocument(new FileInputStream("signature-pen.png"))); // initialize signature field parameters SignatureFieldParameters fieldParameters = new SignatureFieldParameters(); imageParameters.setFieldParameters(fieldParameters); + // the origin is the left and top corner of the page fieldParameters.setOriginX(20); fieldParameters.setOriginY(40);