From a7ed99084fb738c9af7fa8c43ae98b4cce7b135f Mon Sep 17 00:00:00 2001 From: Eric <71648843+sbplat@users.noreply.github.com> Date: Thu, 24 Oct 2024 02:08:09 -0400 Subject: [PATCH] visual certificate signing (#2084) add visual digital signature --- .../api/security/CertSignController.java | 173 +++++++++++++++--- .../resources/static/images/signature.png | Bin 0 -> 19683 bytes .../templates/security/cert-sign.html | 2 +- 3 files changed, 150 insertions(+), 25 deletions(-) create mode 100644 src/main/resources/static/images/signature.png diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java b/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java index c37fcc9c6e..b36f8c9077 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java @@ -1,8 +1,11 @@ package stirling.software.SPDF.controller.api.security; +import java.awt.Color; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.security.KeyStore; @@ -14,12 +17,38 @@ import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.util.Calendar; +import java.util.List; import org.apache.pdfbox.examples.signature.CreateSignatureBase; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.common.PDStream; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName; +import org.apache.pdfbox.pdmodel.graphics.blend.BlendMode; +import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; +import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; +import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDField; +import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; +import org.apache.pdfbox.util.Matrix; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +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.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMDecryptorProvider; import org.bouncycastle.openssl.PEMEncryptedKeyPair; @@ -35,6 +64,7 @@ import org.bouncycastle.pkcs.PKCSException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; @@ -62,13 +92,103 @@ public class CertSignController { } class CreateSignature extends CreateSignatureBase { + File imageFile; + public CreateSignature(KeyStore keystore, char[] pin) throws KeyStoreException, - UnrecoverableKeyException, - NoSuchAlgorithmException, - IOException, - CertificateException { + UnrecoverableKeyException, + NoSuchAlgorithmException, + IOException, + CertificateException { super(keystore, pin); + ClassPathResource resource = new ClassPathResource("static/images/signature.png"); + imageFile = resource.getFile(); + } + + public InputStream createVisibleSignature(PDDocument srcDoc, PDSignature signature, Integer pageNumber, + Boolean showImage) throws IOException { + // modified from org.apache.pdfbox.examples.signature.CreateVisibleSignature2 + try (PDDocument doc = new PDDocument()) { + PDPage page = new PDPage(srcDoc.getPage(pageNumber).getMediaBox()); + doc.addPage(page); + PDAcroForm acroForm = new PDAcroForm(doc); + doc.getDocumentCatalog().setAcroForm(acroForm); + PDSignatureField signatureField = new PDSignatureField(acroForm); + PDAnnotationWidget widget = signatureField.getWidgets().get(0); + List acroFormFields = acroForm.getFields(); + acroForm.setSignaturesExist(true); + acroForm.setAppendOnly(true); + acroForm.getCOSObject().setDirect(true); + acroFormFields.add(signatureField); + + PDRectangle rect = new PDRectangle(0, 0, 200, 50); + + widget.setRectangle(rect); + + // from PDVisualSigBuilder.createHolderForm() + PDStream stream = new PDStream(doc); + PDFormXObject form = new PDFormXObject(stream); + PDResources res = new PDResources(); + form.setResources(res); + form.setFormType(1); + PDRectangle bbox = new PDRectangle(rect.getWidth(), rect.getHeight()); + float height = bbox.getHeight(); + form.setBBox(bbox); + PDFont font = new PDType1Font(FontName.TIMES_BOLD); + + // from PDVisualSigBuilder.createAppearanceDictionary() + PDAppearanceDictionary appearance = new PDAppearanceDictionary(); + appearance.getCOSObject().setDirect(true); + PDAppearanceStream appearanceStream = new PDAppearanceStream(form.getCOSObject()); + appearance.setNormalAppearance(appearanceStream); + widget.setAppearance(appearance); + + try (PDPageContentStream cs = new PDPageContentStream(doc, appearanceStream)) { + if (showImage) { + cs.saveGraphicsState(); + PDExtendedGraphicsState extState = new PDExtendedGraphicsState(); + extState.setBlendMode(BlendMode.MULTIPLY); + extState.setNonStrokingAlphaConstant(0.5f); + cs.setGraphicsStateParameters(extState); + cs.transform(Matrix.getScaleInstance(0.08f, 0.08f)); + PDImageXObject img = PDImageXObject.createFromFileByExtension(imageFile, + doc); + cs.drawImage(img, 100, 0); + cs.restoreGraphicsState(); + } + + // show text + float fontSize = 10; + float leading = fontSize * 1.5f; + cs.beginText(); + cs.setFont(font, fontSize); + cs.setNonStrokingColor(Color.black); + cs.newLineAtOffset(fontSize, height - leading); + cs.setLeading(leading); + + X509Certificate cert = (X509Certificate) getCertificateChain()[0]; + + // https://stackoverflow.com/questions/2914521/ + X500Name x500Name = new X500Name(cert.getSubjectX500Principal().getName()); + RDN cn = x500Name.getRDNs(BCStyle.CN)[0]; + String name = IETFUtils.valueToString(cn.getFirst().getValue()); + + String date = signature.getSignDate().getTime().toString(); + String reason = signature.getReason(); + + cs.showText("Signed by " + name); + cs.newLine(); + cs.showText(date); + cs.newLine(); + cs.showText(reason); + + cs.endText(); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + doc.save(baos); + return new ByteArrayInputStream(baos.toByteArray()); + } } } @@ -80,10 +200,7 @@ public class CertSignController { } @PostMapping(consumes = "multipart/form-data", value = "/cert-sign") - @Operation( - summary = "Sign PDF with a Digital Certificate", - description = - "This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:SISO") + @Operation(summary = "Sign PDF with a Digital Certificate", description = "This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:SISO") public ResponseEntity signPDFWithCert(@ModelAttribute SignPDFWithCertRequest request) throws Exception { MultipartFile pdf = request.getFileInput(); @@ -97,7 +214,7 @@ public class CertSignController { String reason = request.getReason(); String location = request.getLocation(); String name = request.getName(); - Integer pageNumber = request.getPageNumber(); + Integer pageNumber = request.getPageNumber() - 1; if (certType == null) { throw new IllegalArgumentException("Cert type must be provided"); @@ -112,7 +229,7 @@ public class CertSignController { PrivateKey privateKey = getPrivateKeyFromPEM(privateKeyFile.getBytes(), password); Certificate cert = (Certificate) getCertificateFromPEM(certFile.getBytes()); ks.setKeyEntry( - "alias", privateKey, password.toCharArray(), new Certificate[] {cert}); + "alias", privateKey, password.toCharArray(), new Certificate[] { cert }); break; case "PKCS12": ks = KeyStore.getInstance("PKCS12"); @@ -126,11 +243,10 @@ public class CertSignController { throw new IllegalArgumentException("Invalid cert type: " + certType); } - // TODO: page number - CreateSignature createSignature = new CreateSignature(ks, password.toCharArray()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - sign(pdfDocumentFactory, pdf.getBytes(), baos, createSignature, name, location, reason); + sign(pdfDocumentFactory, pdf.getBytes(), baos, createSignature, showSignature, pageNumber, name, location, + reason); return WebResponseUtils.boasToWebResponse( baos, Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "") @@ -142,6 +258,8 @@ public class CertSignController { byte[] input, OutputStream output, CreateSignature instance, + Boolean showSignature, + Integer pageNumber, String name, String location, String reason) { @@ -154,7 +272,17 @@ public class CertSignController { signature.setReason(reason); signature.setSignDate(Calendar.getInstance()); - doc.addSignature(signature, instance); + if (showSignature) { + SignatureOptions signatureOptions = new SignatureOptions(); + signatureOptions + .setVisualSignature(instance.createVisibleSignature(doc, signature, pageNumber, true)); + signatureOptions.setPage(pageNumber); + + doc.addSignature(signature, instance, signatureOptions); + + } else { + doc.addSignature(signature, instance); + } doc.saveIncremental(output); } catch (Exception e) { logger.error("exception", e); @@ -163,22 +291,19 @@ public class CertSignController { private PrivateKey getPrivateKeyFromPEM(byte[] pemBytes, String password) throws IOException, OperatorCreationException, PKCSException { - try (PEMParser pemParser = - new PEMParser(new InputStreamReader(new ByteArrayInputStream(pemBytes)))) { + try (PEMParser pemParser = new PEMParser(new InputStreamReader(new ByteArrayInputStream(pemBytes)))) { Object pemObject = pemParser.readObject(); JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); PrivateKeyInfo pkInfo; if (pemObject instanceof PKCS8EncryptedPrivateKeyInfo) { - InputDecryptorProvider decProv = - new JceOpenSSLPKCS8DecryptorProviderBuilder().build(password.toCharArray()); + InputDecryptorProvider decProv = new JceOpenSSLPKCS8DecryptorProviderBuilder() + .build(password.toCharArray()); pkInfo = ((PKCS8EncryptedPrivateKeyInfo) pemObject).decryptPrivateKeyInfo(decProv); } else if (pemObject instanceof PEMEncryptedKeyPair) { - PEMDecryptorProvider decProv = - new JcePEMDecryptorProviderBuilder().build(password.toCharArray()); - pkInfo = - ((PEMEncryptedKeyPair) pemObject) - .decryptKeyPair(decProv) - .getPrivateKeyInfo(); + PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray()); + pkInfo = ((PEMEncryptedKeyPair) pemObject) + .decryptKeyPair(decProv) + .getPrivateKeyInfo(); } else { pkInfo = ((PEMKeyPair) pemObject).getPrivateKeyInfo(); } diff --git a/src/main/resources/static/images/signature.png b/src/main/resources/static/images/signature.png new file mode 100644 index 0000000000000000000000000000000000000000..1adfcedc3c2fe809dcbecedf3253d103094e9d65 GIT binary patch literal 19683 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

EY#VzfUQBzswx{h+Ao= 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

- +